From ea12de8b05226cf24aa6edb8b99415157a901b10 Mon Sep 17 00:00:00 2001 From: Andy Grimm Date: Mon, 21 Nov 2011 18:07:40 -0500 Subject: Add --baseline option --- cmds.py | 18 ++++++++++++++++-- exporter.py | 20 +++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/cmds.py b/cmds.py index 7e20a1d..a92e326 100644 --- a/cmds.py +++ b/cmds.py @@ -606,6 +606,16 @@ class cmd_fast_export(Command): unsupported in git with an underscore instead, specify --rewrite-tag-names. + :History truncation: + + When code has been significantly refactored over time (e.g., to separate + proprietary code from open source code), it is sometimes convenient to + simply truncate the revision history at a certain point. The --baseline + option, to be used in conjunction with -r, emits a baseline commit + containing the state of the entire source tree immediately prior to the + first requested revision. This allows a user to produce a tree identical + to the original without munging multiple exports. + :Examples: To produce data destined for import into Bazaar:: @@ -656,12 +666,16 @@ class cmd_fast_export(Command): help="Replace characters invalid in git with '_'" " (plain mode only).", ), + Option('baseline', + help="Export an 'abolute' baseline commit prior to" + "the first relative commit", + ), ] encoding_type = 'exact' def run(self, source, destination=None, verbose=False, git_branch="master", checkpoint=10000, marks=None, import_marks=None, export_marks=None, revision=None, - plain=True, rewrite_tag_names=False): + plain=True, rewrite_tag_names=False, baseline=False): load_fastimport() from bzrlib.branch import Branch from bzrlib.plugins.fastimport import exporter @@ -676,7 +690,7 @@ class cmd_fast_export(Command): outf=outf, git_branch=git_branch, checkpoint=checkpoint, import_marks_file=import_marks, export_marks_file=export_marks, revision=revision, verbose=verbose, plain_format=plain, - rewrite_tags=rewrite_tag_names) + rewrite_tags=rewrite_tag_names, baseline=baseline) return exporter.run() diff --git a/exporter.py b/exporter.py index e4b5132..b5c6651 100644 --- a/exporter.py +++ b/exporter.py @@ -148,7 +148,8 @@ class BzrFastExporter(object): def __init__(self, source, outf, git_branch=None, checkpoint=-1, import_marks_file=None, export_marks_file=None, revision=None, - verbose=False, plain_format=False, rewrite_tags=False): + verbose=False, plain_format=False, rewrite_tags=False, + baseline=False): """Export branch data in fast import format. :param plain_format: if True, 'classic' fast-import format is @@ -170,6 +171,7 @@ class BzrFastExporter(object): self.excluded_revisions = set() self.plain_format = plain_format self.rewrite_tags = rewrite_tags + self.baseline = baseline self._multi_author_api_available = hasattr(bzrlib.revision.Revision, 'get_apparent_authors') self.properties_to_exclude = ['authors', 'author'] @@ -225,6 +227,9 @@ class BzrFastExporter(object): self._commit_total) if not self.plain_format: self.emit_features() + if self.baseline: + self._commit_total += 1 + self.emit_baseline(interesting[0], self.git_branch) for revid in interesting: self.emit_commit(revid, self.git_branch) if self.branch.supports_tags(): @@ -302,6 +307,19 @@ class BzrFastExporter(object): for feature in sorted(commands.FEATURE_NAMES): self.print_cmd(commands.FeatureCommand(feature)) + def emit_baseline(self, revid, git_branch): + # Emit a full source tree of the first commit's parent + git_ref = 'refs/heads/%s' % (git_branch,) + revobj = self.branch.repository.get_revision(revid) + assert(len(revobj.parent_ids)) + previd = revobj.parent_ids[0] + prevobj = self.branch.repository.get_revision(previd) + mark = 1 + self.revid_to_mark[previd] = mark + file_cmds = self._get_filecommands(bzrlib.revision.NULL_REVISION, previd) + self.print_cmd(self._get_commit_command(git_ref, mark, prevobj, + file_cmds)) + def emit_commit(self, revid, git_branch): if revid in self.revid_to_mark or revid in self.excluded_revisions: return -- cgit v1.2.1 From 92f2aa6376edd1518e89c2180b011715b5053e98 Mon Sep 17 00:00:00 2001 From: Andy Grimm Date: Tue, 22 Nov 2011 15:28:59 -0500 Subject: fix --baseline bugs, and add a couple of tests --- cmds.py | 2 +- exporter.py | 16 +++++------ tests/test_commands.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 9 deletions(-) diff --git a/cmds.py b/cmds.py index a92e326..dff6d3c 100644 --- a/cmds.py +++ b/cmds.py @@ -667,7 +667,7 @@ class cmd_fast_export(Command): " (plain mode only).", ), Option('baseline', - help="Export an 'abolute' baseline commit prior to" + help="Export an 'absolute' baseline commit prior to" "the first relative commit", ), ] diff --git a/exporter.py b/exporter.py index b5c6651..2094ff5 100644 --- a/exporter.py +++ b/exporter.py @@ -215,6 +215,10 @@ class BzrFastExporter(object): self.note("Calculating the revisions to exclude ...") self.excluded_revisions = set([rev_id for rev_id, _, _, _ in self.branch.iter_merge_sorted_revisions(start_rev_id)]) + if self.baseline: + # needed so the first relative commit knows its parent + self.excluded_revisions.remove(start_rev_id) + view_revisions.insert(0, start_rev_id) return list(view_revisions) def run(self): @@ -228,8 +232,7 @@ class BzrFastExporter(object): if not self.plain_format: self.emit_features() if self.baseline: - self._commit_total += 1 - self.emit_baseline(interesting[0], self.git_branch) + self.emit_baseline(interesting.pop(0), self.git_branch) for revid in interesting: self.emit_commit(revid, self.git_branch) if self.branch.supports_tags(): @@ -311,13 +314,10 @@ class BzrFastExporter(object): # Emit a full source tree of the first commit's parent git_ref = 'refs/heads/%s' % (git_branch,) revobj = self.branch.repository.get_revision(revid) - assert(len(revobj.parent_ids)) - previd = revobj.parent_ids[0] - prevobj = self.branch.repository.get_revision(previd) mark = 1 - self.revid_to_mark[previd] = mark - file_cmds = self._get_filecommands(bzrlib.revision.NULL_REVISION, previd) - self.print_cmd(self._get_commit_command(git_ref, mark, prevobj, + self.revid_to_mark[revid] = mark + file_cmds = self._get_filecommands(bzrlib.revision.NULL_REVISION, revid) + self.print_cmd(self._get_commit_command(git_ref, mark, revobj, file_cmds)) def emit_commit(self, revid, git_branch): diff --git a/tests/test_commands.py b/tests/test_commands.py index 5729660..5053416 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -16,6 +16,7 @@ """Test the command implementations.""" import os +import re import tempfile import gzip @@ -58,6 +59,40 @@ class TestSourceStream(tests.TestCase): self.assertIsNot("bla", stream.read()) +fast_export_baseline_data = """commit refs/heads/master +mark :1 +committer +data 15 +add c, remove b +M 644 inline a +data 13 +test 1 +test 3 +M 644 inline c +data 6 +test 4 +commit refs/heads/master +mark :2 +committer +data 14 +modify a again +from :1 +M 644 inline a +data 20 +test 1 +test 3 +test 5 +commit refs/heads/master +mark :3 +committer +data 5 +add d +from :2 +M 644 inline d +data 6 +test 6 +""" + class TestFastExport(ExternalBase): def test_empty(self): @@ -99,6 +134,45 @@ class TestFastExport(ExternalBase): # "bad Tag" should be exported as bad_Tag self.assertNotEqual(-1, data.find("reset refs/tags/bad_Tag")) + def test_baseline_option(self): + tree = self.make_branch_and_tree("bl") + + # Revision 1 + file('bl/a', 'w').write('test 1') + tree.add('a') + tree.commit(message='add a') + + # Revision 2 + file('bl/b', 'w').write('test 2') + file('bl/a', 'a').write('\ntest 3') + tree.add('b') + tree.commit(message='add b, modify a') + + # Revision 3 + file('bl/c', 'w').write('test 4') + tree.add('c') + tree.remove('b') + tree.commit(message='add c, remove b') + + # Revision 4 + file('bl/a', 'a').write('\ntest 5') + tree.commit(message='modify a again') + + # Revision 5 + file('bl/d', 'w').write('test 6') + tree.add('d') + tree.commit(message='add d') + + # This exports the baseline state at Revision 3, + # followed by the deltas for 4 and 5 + data = self.run_bzr("fast-export --baseline -r 3.. bl")[0] + data = re.sub('committer.*', 'committer', data) + self.assertEquals(fast_export_baseline_data, data) + + # Also confirm that --baseline with no args is identical to full export + data1 = self.run_bzr("fast-export --baseline bl")[0] + data2 = self.run_bzr("fast-export bl")[0] + self.assertEquals(data1, data2) simple_fast_import_stream = """commit refs/heads/master mark :1 -- cgit v1.2.1 From 61bee05055314ea1de0788228da7c7c96cd2ef66 Mon Sep 17 00:00:00 2001 From: Andy Grimm Date: Tue, 22 Nov 2011 15:36:20 -0500 Subject: doc fix for --baseline --- cmds.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmds.py b/cmds.py index dff6d3c..157c9b2 100644 --- a/cmds.py +++ b/cmds.py @@ -608,13 +608,13 @@ class cmd_fast_export(Command): :History truncation: - When code has been significantly refactored over time (e.g., to separate - proprietary code from open source code), it is sometimes convenient to - simply truncate the revision history at a certain point. The --baseline - option, to be used in conjunction with -r, emits a baseline commit - containing the state of the entire source tree immediately prior to the - first requested revision. This allows a user to produce a tree identical - to the original without munging multiple exports. + When code has been significantly refactored over time (e.g., to separate + proprietary code from open source code), it is sometimes convenient to + simply truncate the revision history at a certain point. The --baseline + option, to be used in conjunction with -r, emits a baseline commit + containing the state of the entire source tree at the first requested + revision. This allows a user to produce a tree identical to the original + without munging multiple exports. :Examples: -- cgit v1.2.1