Rev 57: Fix more tests. in http://people.samba.org/bzr/jelmer/bzr-git/trunk
Jelmer Vernooij
jelmer at samba.org
Sat Jul 26 17:27:37 BST 2008
At http://people.samba.org/bzr/jelmer/bzr-git/trunk
------------------------------------------------------------
revno: 57
revision-id: jelmer at samba.org-20080726002424-tvazkvugrgtgyonh
parent: jelmer at samba.org-20080725225643-o8adohxgoruo3goj
committer: Jelmer Vernooij <jelmer at samba.org>
branch nick: trunk
timestamp: Sat 2008-07-26 02:24:24 +0200
message:
Fix more tests.
modified:
git_branch.py git_branch.py-20071108230535-su8dxk529f4uk9fx-2
git_dir.py git_dir.py-20071108234408-ygidvy5hviixghsd-1
git_repository.py git_repository.py-20071108234408-ygidvy5hviixghsd-2
tests/test_git_repository.py test_git_repository.-20071108234408-ygidvy5hviixghsd-5
=== modified file 'git_branch.py'
--- a/git_branch.py 2007-12-29 21:35:28 +0000
+++ b/git_branch.py 2008-07-26 00:24:24 +0000
@@ -48,15 +48,12 @@
class GitBranch(branch.Branch):
"""An adapter to git repositories for bzr Branch objects."""
- def __init__(self, gitdir, lockfiles):
+ def __init__(self, repository, head, base, lockfiles):
super(GitBranch, self).__init__()
- from bzrlib.plugins.git import git_repository
- self.bzrdir = gitdir
self.control_files = lockfiles
- self.repository = git_repository.GitRepository(gitdir, lockfiles)
- self.base = gitdir.root_transport.base
- if '.git' not in gitdir.root_transport.list_dir('.'):
- raise errors.NotBranchError(self.base)
+ self.repository = repository
+ self.head = head
+ self.base = base
self._format = GitBranchFormat()
def lock_write(self):
@@ -65,25 +62,19 @@
@needs_read_lock
def last_revision(self):
# perhaps should escape this ?
- head_git_id = self.repository._git.get_head()
- if head_git_id is None:
+ if self.head is None:
return revision.NULL_REVISION
- return ids.convert_revision_id_git_to_bzr(head_git_id)
+ return ids.convert_revision_id_git_to_bzr(self.head.commit.id)
- @needs_read_lock
- def revision_history(self):
- node = self.last_revision()
- if node == revision.NULL_REVISION:
- return []
- ancestors = self.repository.get_revision_graph(node)
- history = []
- while node is not None:
- history.append(node)
- if len(ancestors[node]) > 0:
- node = ancestors[node][0]
- else:
- node = None
- return list(reversed(history))
+ def _gen_revision_history(self):
+ skip = 0
+ max_count = 1000
+ cms = []
+ ret = []
+ while cms != []:
+ cms = self.repository._git.commits(self.head.commit.id, max_count=1000, skip=skip)
+ ret += [ids.convert_revision_id_git_to_bzr(cm.id) for cm in cms]
+ return ret
def get_config(self):
return GitBranchConfig(self)
=== modified file 'git_dir.py'
--- a/git_dir.py 2007-12-30 06:58:28 +0000
+++ b/git_dir.py 2008-07-26 00:24:24 +0000
@@ -80,8 +80,14 @@
return True
def open_branch(self, ignored=None):
- """'crate' a branch for this dir."""
- return git_branch.GitBranch(self, self._lockfiles)
+ """'create' a branch for this dir."""
+ repo = self.open_repository()
+ if repo._git.heads == []:
+ head = None
+ else:
+ head = repo._git.heads[0]
+ return git_branch.GitBranch(repo, head,
+ self.root_transport.base, self._lockfiles)
def open_repository(self, shared=False):
"""'open' a repository for this dir."""
=== modified file 'git_repository.py'
--- a/git_repository.py 2008-07-25 22:56:43 +0000
+++ b/git_repository.py 2008-07-26 00:24:24 +0000
@@ -18,6 +18,7 @@
import git
import os
+import time
import bzrlib
from bzrlib import (
@@ -82,51 +83,12 @@
""")
self.cachedb.commit()
- def _ancestor_revisions(self, revision_ids):
- if revision_ids is not None:
- git_revisions = [gitrevid_from_bzr(r) for r in revision_ids]
- else:
- git_revisions = None
- for lines in self._git.ancestor_lines(git_revisions):
- yield self._parse_rev(lines)
- # print "fetched ancestors:", git_revisions
-
def is_shared(self):
return True
def supports_rich_root(self):
return False
- def get_revision_graph(self, revision_id=None):
- result = {}
- if revision_id is not None:
- param = [ids.convert_revision_id_bzr_to_git(revision_id)]
- else:
- param = None
- git_graph = self._git.get_revision_graph(param)
- # print "fetched revision graph:", param
- for node, parents in git_graph.iteritems():
- bzr_node = ids.convert_revision_id_git_to_bzr(node)
- bzr_parents = [ids.convert_revision_id_git_to_bzr(n)
- for n in parents]
- result[bzr_node] = bzr_parents
- return result
-
- def get_revision_graph_with_ghosts(self, revision_ids=None):
- graph = deprecated_graph.Graph()
- if revision_ids is not None:
- revision_ids = [ids.convert_revision_id_bzr_to_git(r)
- for r in revision_ids]
- git_graph = self._git.get_revision_graph(revision_ids)
- # print "fetched revision graph (ghosts):", revision_ids
- for node, parents in git_graph.iteritems():
- bzr_node = ids.convert_revision_id_git_to_bzr(node)
- bzr_parents = [ids.convert_revision_id_git_to_bzr(n)
- for n in parents]
-
- graph.add_node(bzr_node, bzr_parents)
- return graph
-
def get_ancestry(self, revision_id):
param = [ids.convert_revision_id_bzr_to_git(revision_id)]
git_ancestry = self._git.get_ancestry(param)
@@ -138,14 +100,20 @@
def get_signature_text(self, revision_id):
raise errors.NoSuchRevision(self, revision_id)
+ def get_parent_map(self, revision_ids):
+ ret = {}
+ for revid in revision_ids:
+ commit = self._git.commit(ids.convert_revision_id_bzr_to_git(revid))
+ ret[revid] = tuple([ids.convert_revision_id_git_to_bzr(p.commit.id) for p in commit.parents])
+ return ret
def get_revision(self, revision_id):
if revision_id in self._revision_cache:
return self._revision_cache[revision_id]
git_commit_id = ids.convert_revision_id_bzr_to_git(revision_id)
- raw = self._git.rev_list([git_commit_id], max_count=1, header=True)
+ commit = self._git.commit(git_commit_id)
# print "fetched revision:", git_commit_id
- revision = self._parse_rev(raw)
+ revision = self._parse_rev(commit)
self._revision_cache[revision_id] = revision
return revision
@@ -161,92 +129,33 @@
return [self.get_revision(r) for r in revisions]
@classmethod
- def _parse_rev(klass, raw):
- """Parse a single git revision.
-
- * The first line is the git commit id.
- * Following lines conform to the 'name value' structure, until the
- first blank line.
- * All lines after the first blank line and until the NULL line have 4
- leading spaces and constitute the commit message.
-
- :param raw: sequence of newline-terminated strings, its last item is a
- single NULL character.
+ def _parse_rev(klass, commit):
+ """Convert a git commit to a bzr revision.
+
:return: a `bzrlib.revision.Revision` object.
"""
- parents = []
- message_lines = []
- in_message = False
- committer_was_set = False
- revision_id = ids.convert_revision_id_git_to_bzr(raw[0][:-1])
- rev = revision.Revision(revision_id)
+ rev = revision.Revision(ids.convert_revision_id_git_to_bzr(commit.id))
+ rev.parent_ids = tuple([ids.convert_revision_id_git_to_bzr(p.id) for p in commit.parents])
rev.inventory_sha1 = ""
- assert raw[-1] == '\x00', (
- "Last item of raw was not a single NULL character.")
- for line in raw[1:-1]:
- if in_message:
- assert line[:4] == ' ', (
- "Unexpected line format in commit message: %r" % line)
- message_lines.append(line[4:])
- continue
- if line == '\n':
- in_message = True
- continue
- name, value = line[:-1].split(' ', 1)
- if name == 'parent':
- rev.parent_ids.append(
- ids.convert_revision_id_git_to_bzr(value))
- continue
- if name == 'author':
- author, timestamp, timezone = value.rsplit(' ', 2)
- rev.properties['author'] = author
- rev.properties['git-author-timestamp'] = timestamp
- rev.properties['git-author-timezone'] = timezone
- if not committer_was_set:
- rev.committer = author
- rev.timestamp = float(timestamp)
- rev.timezone = klass._parse_tz(timezone)
- continue
- if name == 'committer':
- committer_was_set = True
- committer, timestamp, timezone = value.rsplit(' ', 2)
- rev.committer = committer
- rev.timestamp = float(timestamp)
- rev.timezone = klass._parse_tz(timezone)
- continue
- if name == 'tree':
- rev.properties['git-tree-id'] = value
- continue
-
- rev.message = ''.join(message_lines)
-
- # XXX: That should not be needed, but current revision serializers do
- # not know how how to handle text that is illegal in xml. Note: when
- # this is fixed, we will need to rev up the revision namespace when
- # removing the escaping code. -- David Allouche 2007-12-30
- rev.message = escape_for_xml(rev.message)
- rev.committer = escape_for_xml(rev.committer)
- rev.properties['author'] = escape_for_xml(rev.properties['author'])
-
+ rev.message = commit.message
+ rev.committer = commit.committer
+ rev.properties['author'] = commit.author
+ rev.timestamp = time.mktime(commit.committed_date)
+ rev.timezone = 0
return rev
- @classmethod
- def _parse_tz(klass, tz):
- """Parse a timezone specification in the [+|-]HHMM format.
-
- :return: the timezone offset in seconds.
- """
- assert len(tz) == 5
- sign = {'+': +1, '-': -1}[tz[0]]
- hours = int(tz[1:3])
- minutes = int(tz[3:])
- return sign * 60 * (60 * hours + minutes)
-
def revision_trees(self, revids):
for revid in revids:
yield self.revision_tree(revid)
def revision_tree(self, revision_id):
+ revision_id = revision.ensure_null(revision_id)
+
+ if revision_id == revision.NULL_REVISION:
+ inv = inventory.Inventory(root_id=None)
+ inv.revision_id = revision_id
+ return revisiontree.RevisionTree(self, inv, revision_id)
+
return GitRevisionTree(self, revision_id)
def _fetch_blob(self, git_id):
@@ -281,76 +190,8 @@
return size, sha1
def get_inventory(self, revision_id):
- if revision_id is None:
- revision_id = revision.NULL_REVISION
- if revision_id == revision.NULL_REVISION:
- return inventory.Inventory(
- revision_id=revision_id, root_id=None)
-
- # First pass at building the inventory. We need this one to get the
- # git ids, so we do not have to cache the entire tree text. Ideally,
- # this should be all we need to do.
- git_commit = ids.convert_revision_id_bzr_to_git(revision_id)
- git_inventory = self._git.get_inventory(git_commit)
- # print "fetched inventory:", git_commit
- inv = self._parse_inventory(revision_id, git_inventory)
-
- # Second pass at building the inventory. There we retrieve additional
- # data that bzrlib requires: text sizes, sha1s, symlink targets and
- # revisions that introduced inventory entries
- self._building_inventory = inv
- self._building_inventory.git_file_data = {}
- for file_id in sorted(inv.git_ids.iterkeys()):
- git_id = inv.git_ids[file_id]
- entry = inv[file_id]
- self._set_entry_text_info(inv, entry, git_id)
- for file_id in sorted(inv.git_ids.iterkeys()):
- git_id = inv.git_ids[file_id]
- entry = inv[file_id]
- path = inv.id2path(file_id)
- self._set_entry_revision(entry, revision_id, path, git_id)
-
- # At this point the entry_revision table is fully populated for this
- # revision. So record that we have inventory data for this revision.
- self.cachedb.execute(
- "insert or ignore into inventory (revid) values (?)",
- (revision_id,))
- self.cachedb.commit()
- self._building_inventory = None
- return inv
-
- @classmethod
- def _parse_inventory(klass, revid, git_inv):
- # For now, git inventory do not have root ids. It is not clear that we
- # can reliably support root ids. -- David Allouche 2007-12-28
- inv = inventory.Inventory(revision_id=revid)
- inv.git_ids = {}
- for perms, git_kind, git_id, path in git_inv:
- text_sha1 = None
- executable = False
- if git_kind == 'blob':
- if perms[1] == '0':
- kind = 'file'
- executable = bool(int(perms[-3:], 8) & 0111)
- elif perms[1] == '2':
- kind = 'symlink'
- else:
- raise AssertionError(
- "Unknown blob kind, perms=%r." % (perms,))
- elif git_kind == 'tree':
- kind = 'directory'
- else:
- raise AssertionError(
- "Unknown git entry kind: %r" % (git_kind,))
- # XXX: Maybe the file id should be prefixed by file kind, so when
- # the kind of path changes, the id changes too.
- # -- David Allouche 2007-12-28.
- file_id = escape_file_id(path.encode('utf-8'))
- entry = inv.add_path(path, kind, file_id=file_id)
- entry.executable = executable
- inv.git_ids[file_id] = git_id
- inv.root.revision = revid
- return inv
+ assert revision_id != None
+ return self.revision_tree(revision_id).inventory
def _set_entry_text_info(self, inv, entry, git_id):
if entry.kind == 'directory':
@@ -430,37 +271,12 @@
return file_id.replace('_', '__').replace(' ', '_s')
-def escape_for_xml(message):
- """Replace xml-incompatible control characters."""
- # Copied from _escape_commit_message from bzr-svn.
- # -- David Allouche 2007-12-29.
- if message is None:
- return None
- import re
- # FIXME: RBC 20060419 this should be done by the revision
- # serialiser not by commit. Then we can also add an unescaper
- # in the deserializer and start roundtripping revision messages
- # precisely. See repository_implementations/test_repository.py
-
- # Python strings can include characters that can't be
- # represented in well-formed XML; escape characters that
- # aren't listed in the XML specification
- # (http://www.w3.org/TR/REC-xml/#NT-Char).
- message, _ = re.subn(
- u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
- lambda match: match.group(0).encode('unicode_escape'),
- message)
- return message
-
-
class GitRevisionTree(revisiontree.RevisionTree):
def __init__(self, repository, revision_id):
- if revision_id is None:
- revision_id = revision.NULL_REVISION
- self._inventory = repository.get_inventory(revision_id)
self._repository = repository
- self._revision_id = revision_id
+ git_id = ids.convert_revision_id_bzr_to_git(revision_id)
+ self.tree = repository._git.commit(git_id).tree
def get_file_lines(self, file_id):
entry = self._inventory[file_id]
=== modified file 'tests/test_git_repository.py'
--- a/tests/test_git_repository.py 2008-07-25 22:56:43 +0000
+++ b/tests/test_git_repository.py 2008-07-26 00:24:24 +0000
@@ -49,43 +49,6 @@
repo = repository.Repository.open('.')
self.assertIsInstance(repo._git, git.repo.Repo)
- def test_revision_graph(self):
- tests.run_git('init')
- builder = tests.GitBranchBuilder()
- builder.set_file('a', 'text for a\n', False)
- commit1_handle = builder.commit('Joe Foo <joe at foo.com>', u'message')
- builder.set_file('a', 'new a\n', False)
- commit2_handle = builder.commit('Joe Foo <joe at foo.com>', u'new a')
- builder.set_file('b', 'text for b\n', False)
- commit3_handle = builder.commit('Jerry Bar <jerry at foo.com>', u'b',
- base=commit1_handle)
- commit4_handle = builder.commit('Jerry Bar <jerry at foo.com>', u'merge',
- base=commit3_handle,
- merge=[commit2_handle],)
-
- mapping = builder.finish()
- commit1_id = mapping[commit1_handle]
- commit2_id = mapping[commit2_handle]
- commit3_id = mapping[commit3_handle]
- commit4_id = mapping[commit4_handle]
-
- revisions = tests.run_git('rev-list', '--topo-order',
- commit4_id)
- revisions = revisions.splitlines()
- self.assertEqual([commit4_id, commit2_id, commit3_id, commit1_id],
- revisions)
- bzr_revisions = [ids.convert_revision_id_git_to_bzr(r) for r in revisions]
- graph = {bzr_revisions[0]:[bzr_revisions[2], bzr_revisions[1]],
- bzr_revisions[1]:[bzr_revisions[3]],
- bzr_revisions[2]:[bzr_revisions[3]],
- bzr_revisions[3]:[],
- }
-
- repo = repository.Repository.open('.')
- self.assertEqual(graph, repo.get_revision_graph(bzr_revisions[0]))
- self.assertEqual({bzr_revisions[3]:[]},
- repo.get_revision_graph(bzr_revisions[3]))
-
def test_get_revision(self):
# GitRepository.get_revision gives a Revision object.
@@ -146,34 +109,12 @@
" sha1='67b75c3e49f31fcadddbf9df6a1d8be8c3e44290', len=12))")
-class MemoryGitRepository(git_repository.GitRepository):
- """A git repository without real git data on disk."""
-
- @classmethod
- def _make_model(klass, transport):
- return None
-
-
-class MemoryGitDir(git_dir.GitDir):
- """A git tree with real data on disk."""
-
- _gitrepository_class = MemoryGitRepository
-
-
-class MemoryGitBzrDirFormat(git_dir.GitBzrDirFormat):
- """Format for a git tree without real data on disk."""
-
- _gitdir_class = MemoryGitDir
-
-
class TestGitRepository(tests.TestCaseWithTransport):
def setUp(self):
tests.TestCaseWithTransport.setUp(self)
- self.transport = self.get_transport()
- self.transport.mkdir('.git')
- self.git_dir = MemoryGitBzrDirFormat().open(self.transport)
- self.git_repo = self.git_dir.open_repository()
+ git.repo.Repo.create(self.test_dir)
+ self.git_repo = repository.Repository.open(self.test_dir)
def test_supports_rich_root(self):
# GitRepository.supports_rich_root is False, at least for now.
@@ -188,106 +129,13 @@
def test_get_inventory_none(self):
# GitRepository.get_inventory(None) returns the null inventory.
repo = self.git_repo
- inv = repo.get_inventory(None)
+ inv = repo.get_inventory(revision.NULL_REVISION)
self.assertIsNullInventory(inv)
def test_revision_tree_none(self):
# GitRepository.revision_tree(None) returns the null tree.
repo = self.git_repo
- tree = repo.revision_tree(None)
+ tree = repo.revision_tree(revision.NULL_REVISION)
self.assertEqual(tree.get_revision_id(), revision.NULL_REVISION)
self.assertIsNullInventory(tree.inventory)
-
-class TestGitRepositoryParseRev(tests.TestCase):
- """Unit tests for GitRepository._parse_rev."""
-
- def test_base_commit(self):
- # GitRepository._parse_rev works for a simple base commit.
- rev = git_repository.GitRepository._parse_rev([
- "873a8ae0d682b0e63e9795bc53056d32ed3de93f\n",
- "tree aaff74984cccd156a469afa7d9ab10e4777beb24\n",
- "author Jane Bar <jane at bar.com> 1198784533 +0200\n",
- "committer Joe Foo <joe at foo.com> 1198784532 +0100\n",
- "\n",
- " message\n",
- "\x00"])
- self.assertEqual(rev.revision_id,
- 'git-experimental-r:873a8ae0d682b0e63e9795bc53056d32ed3de93f')
- self.assertEqual(rev.parent_ids, [])
- self.assertEqual(rev.committer, 'Joe Foo <joe at foo.com>')
- self.assertEqual(repr(rev.timestamp), '1198784532.0')
- self.assertEqual(repr(rev.timezone), '3600')
- self.assertEqual(rev.message, 'message\n')
- self.assertEqual(
- rev.properties,
- {'git-tree-id': 'aaff74984cccd156a469afa7d9ab10e4777beb24',
- 'author': 'Jane Bar <jane at bar.com>',
- 'git-author-timestamp': '1198784533',
- 'git-author-timezone': '+0200'})
-
- def test_merge_commit(self):
- # Multi-parent commits (merges) are parsed correctly.
- rev = git_repository.GitRepository._parse_rev([
- "873a8ae0d682b0e63e9795bc53056d32ed3de93f\n",
- "tree aaff74984cccd156a469afa7d9ab10e4777beb24\n",
- "parent 263ed20f0d4898be994404ca418bafe8e89abb8a\n",
- "parent 546563eb8f3e94a557f3bb779b6e5a2bd9658752\n",
- "parent 3116d42db7b5c5e69e58f651721e179791479c23\n",
- "author Jane Bar <jane at bar.com> 1198784533 +0200\n",
- "committer Joe Foo <joe at foo.com> 1198784532 +0100\n",
- "\n",
- " message\n",
- "\x00"])
- # Git records merges in the same way as bzr. The first parent is the
- # commit base, the following parents are the ordered merged revisions.
- self.assertEqual(
- rev.parent_ids,
- ['git-experimental-r:263ed20f0d4898be994404ca418bafe8e89abb8a',
- 'git-experimental-r:546563eb8f3e94a557f3bb779b6e5a2bd9658752',
- 'git-experimental-r:3116d42db7b5c5e69e58f651721e179791479c23'])
-
- def test_redundant_spaces(self):
- # Redundant spaces in author and committer are preserved.
- rev = git_repository.GitRepository._parse_rev([
- "873a8ae0d682b0e63e9795bc53056d32ed3de93f\n",
- "tree aaff74984cccd156a469afa7d9ab10e4777beb24\n",
- "author Jane Bar <jane at bar.com> 1198784533 +0200\n",
- "committer Joe Foo <joe at foo.com> 1198784532 +0100\n",
- "\n",
- " message\n",
- "\x00"])
- self.assertEqual(rev.committer, ' Joe Foo <joe at foo.com> ')
- self.assertEqual(
- rev.properties['author'], ' Jane Bar <jane at bar.com> ')
-
- def test_no_committer(self):
- # If committer is not set, then author is used.
- #
- # Folks in #git say that git fsck would likely accept commits that do
- # not set committer, but that author is a mandatory value.
- rev = git_repository.GitRepository._parse_rev([
- "873a8ae0d682b0e63e9795bc53056d32ed3de93f\n",
- "tree aaff74984cccd156a469afa7d9ab10e4777beb24\n",
- "author Jane Bar <jane at bar.com> 1198784533 +0200\n",
- "\n",
- " message\n",
- "\x00"])
- self.assertEqual(rev.committer, 'Jane Bar <jane at bar.com>')
- self.assertEqual(repr(rev.timestamp), '1198784533.0')
- self.assertEqual(repr(rev.timezone), '7200')
- self.assertEqual(rev.properties['author'], 'Jane Bar <jane at bar.com>')
- self.assertEqual(rev.properties['git-author-timestamp'], '1198784533')
- self.assertEqual(rev.properties['git-author-timezone'], '+0200')
-
- def test_parse_tz(self):
- # Simple tests for the _parse_tz helper.
- parse_tz = git_repository.GitRepository._parse_tz
- self.assertEqual(repr(parse_tz('+0000')), '0')
- self.assertEqual(repr(parse_tz('+0001')), '60')
- self.assertEqual(repr(parse_tz('-0001')), '-60')
- self.assertEqual(repr(parse_tz('+0100')), '3600')
- self.assertEqual(repr(parse_tz('-0100')), '-3600')
- self.assertEqual(repr(parse_tz('+9959')), '359940')
- self.assertEqual(repr(parse_tz('-9959')), '-359940')
-
More information about the bazaar-commits
mailing list