Merge lp:~al-maisan/bzr-builddeb/merge-package into lp:~bzr-builddeb-hackers/bzr-builddeb/trunk-old
- merge-package
- Merge into trunk-old
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~al-maisan/bzr-builddeb/merge-package |
Merge into: | lp:~bzr-builddeb-hackers/bzr-builddeb/trunk-old |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~al-maisan/bzr-builddeb/merge-package |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Westby | Approve | ||
Review via email:
|
Commit message
Description of the change
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Muharem Hrnjadovic (al-maisan) wrote : | # |
- 391. By Muharem Hrnjadovic
-
More test clean-ups.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Muharem Hrnjadovic (al-maisan) wrote : | # |
Hmm .. some more test code clean-ups .. please see the attached
incremental diff.
Best regards
--
Muharem Hrnjadovic <email address hidden>
Public key id : B2BBFCFC
Key fingerprint : A5A3 CC67 2B87 D641 103F 5602 219F 6B60 B2BB FCFC
1 | === modified file 'merge_package.py' | |||
2 | --- merge_package.py 2009-08-19 09:19:38 +0000 | |||
3 | +++ merge_package.py 2009-08-19 10:06:11 +0000 | |||
4 | @@ -89,7 +89,8 @@ | |||
5 | 89 | def _upstream_version_data(source, target): | 89 | def _upstream_version_data(source, target): |
6 | 90 | """Most recent upstream versions/revision IDs of the merge source/target. | 90 | """Most recent upstream versions/revision IDs of the merge source/target. |
7 | 91 | 91 | ||
9 | 92 | Please note: both packaing branches must have been read-locked beforehand. | 92 | Please note: both packaging branches must have been read-locked |
10 | 93 | beforehand. | ||
11 | 93 | 94 | ||
12 | 94 | :param source: The merge source branch. | 95 | :param source: The merge source branch. |
13 | 95 | :param target: The merge target branch. | 96 | :param target: The merge target branch. |
14 | 96 | 97 | ||
15 | === modified file 'tests/test_merge_package.py' | |||
16 | --- tests/test_merge_package.py 2009-08-19 09:44:38 +0000 | |||
17 | +++ tests/test_merge_package.py 2009-08-19 10:08:00 +0000 | |||
18 | @@ -19,13 +19,10 @@ | |||
19 | 19 | # along with bzr-builddeb; if not, write to the Free Software | 19 | # along with bzr-builddeb; if not, write to the Free Software |
20 | 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
21 | 21 | 21 | ||
22 | 22 | import os | ||
23 | 23 | import random | ||
24 | 24 | import string | 22 | import string |
25 | 25 | import unittest | 23 | import unittest |
26 | 26 | 24 | ||
27 | 27 | from bzrlib.errors import ConflictsInTree | 25 | from bzrlib.errors import ConflictsInTree |
28 | 28 | from bzrlib.merge import WeaveMerger | ||
29 | 29 | from bzrlib.tests import TestCaseWithTransport | 26 | from bzrlib.tests import TestCaseWithTransport |
30 | 30 | 27 | ||
31 | 31 | from bzrlib.plugins.builddeb import merge_package as MP | 28 | from bzrlib.plugins.builddeb import merge_package as MP |
32 | @@ -474,8 +471,7 @@ | |||
33 | 474 | for version, paths, utree, urevid in vdata: | 471 | for version, paths, utree, urevid in vdata: |
34 | 475 | msg = '' | 472 | msg = '' |
35 | 476 | if utree is not None: | 473 | if utree is not None: |
38 | 477 | tree.merge_from_branch( | 474 | tree.merge_from_branch(utree.branch, to_revision=urevid) |
37 | 478 | utree.branch, to_revision=urevid, merge_type=WeaveMerger) | ||
39 | 479 | utree.branch.tags.merge_to(tree.branch.tags) | 475 | utree.branch.tags.merge_to(tree.branch.tags) |
40 | 480 | if urevid is not None: | 476 | if urevid is not None: |
41 | 481 | msg += 'Merged tree %s|%s. ' % (tree_nick(utree), urevid) | 477 | msg += 'Merged tree %s|%s. ' % (tree_nick(utree), urevid) |
42 | @@ -491,7 +487,6 @@ | |||
43 | 491 | 487 | ||
44 | 492 | 488 | ||
45 | 493 | if __name__ == '__main__': | 489 | if __name__ == '__main__': |
46 | 494 | # unittest.main() | ||
47 | 495 | suite = unittest.TestLoader().loadTestsFromTestCase(MergePackageTests) | 490 | suite = unittest.TestLoader().loadTestsFromTestCase(MergePackageTests) |
48 | 496 | unittest.TextTestRunner(verbosity=2).run(suite) | 491 | unittest.TextTestRunner(verbosity=2).run(suite) |
49 | 497 | 492 |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
James Westby (james-w) wrote : | # |
> Hello James,
>
> this branch implements the 'merge-package' command as specified here:
> http://
>
> Please take a look and let me know what you think.
=== modified file '__init__.py'
--- __init__.py 2009-07-26 15:51:02 +0000
+++ __init__.py 2009-08-06 09:59:34 +0000
@@ -39,7 +39,8 @@
"bd_do": [],
- "mark_uploaded": []
+ "mark_uploaded": [],
+ "merge_package": ["mp"]
}
for command, aliases in commands.
I fear this alias will conflict with something in the future (merge-proposal
perhaps), perhaps it is better to leave it off for now and let people set
it as they like.
=== modified file 'cmds.py'
--- cmds.py 2009-07-26 18:21:49 +0000
+++ cmds.py 2009-08-19 09:06:47 +0000
@@ -870,6 +871,39 @@
+class cmd_merge_
+ """Merges source packaging branch into target packaging branch.
+
+ This will first check whether the upstream branches have diverged.
+
+ If that's the case an attempt will be made to fix the upstream ancestry
+ so that the user only needs to deal wth packaging branch merge issues.
+
+ In the opposite case a normal merge will be performed.
+ """
+ takes_args = ['source']
+
+ def run(self, source):
+ source_branch = target_branch = None
+ # Get the target branch.
+ try:
+ tree = WorkingTree.
+ target_branch = tree.branch
+ except NotBranchError:
+ raise BzrCommandError(
+ "There is no tree to merge the source branch in to")
+ # Get the source branch.
+ try:
+ source_branch = Branch.open(source)
+ except NotBranchError:
+ raise BzrCommandError
+
+ fix_ancestry_
+
+ # Merge source packaging branch in to the target packaging branch.
+ tree.merge_
+
+
class cmd_test_
"""Run the builddeb test suite"""
@@ -880,4 +914,3 @@
passed = selftest(
# invert for shell exit code rules
return not passed
-
=== modified file 'import_dsc.py'
--- import_dsc.py 2009-07-26 16:44:17 +0000
+++ import_dsc.py 2009-08-19 08:58:47 +0000
@@ -1570,7 +1570,7 @@
finally:
- def _extract_
+ def extract_
# Extract that to a tempdir so we can get a working
# tree for it.
# TODO: should stack rather than trying to use the repository,
@@ -1582,6 +1582,13 @@
+ def _extract_
+ # This method is now being used outside this module and hence
+ # not really private any longer.
+ # TODO: obsolete/remove this method and start using
+ # extract_
+ self.extract_
- 392. By Muharem Hrnjadovic
-
Enhancements stemming from James' review comments, round 1
- 393. By Muharem Hrnjadovic
-
Minor fix.
- 394. By Muharem Hrnjadovic
-
Enhancements stemming from James' review comments, round 2
- 395. By Muharem Hrnjadovic
-
Enhancements stemming from James' review comments, round 3
- 396. By Muharem Hrnjadovic
-
Enhancements stemming from James' review comments, round 4
- 397. By Muharem Hrnjadovic
-
Enhancements stemming from James' review comments, round 5
- 398. By Muharem Hrnjadovic
-
Enhancements stemming from James' review comments, round 6
- 399. By Muharem Hrnjadovic
-
Enhancements stemming from James' review comments, round 7
- 400. By Muharem Hrnjadovic
-
Minor fix.
- 401. By Muharem Hrnjadovic
-
Minor test code fix.
- 402. By Muharem Hrnjadovic
-
Added test that checks the ancestry pre- and post-fix.
- 403. By Muharem Hrnjadovic
-
Added a more stringent test that checks the ancestry pre- and post-fix.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Muharem Hrnjadovic (al-maisan) wrote : | # |
James Westby wrote:
Hello James,
thank you very much for reviewing the branch at hand. I have revised it
to accommodate most of your suggestions.
Please have a look at the attached incremental/full diffs as well as at
my in-line responses below.
You are obviously free to track the changes made in the course of the
review here:
bzr+ssh:
> Review: Resubmit
>> Hello James,
>>
>> this branch implements the 'merge-package' command as specified here:
>> http://
>>
>> Please take a look and let me know what you think.
>
>
> === modified file '__init__.py'
> --- __init__.py 2009-07-26 15:51:02 +0000
> +++ __init__.py 2009-08-06 09:59:34 +0000
> @@ -39,7 +39,8 @@
> "merge_upstream": ["mu"],
> "import_dsc": [],
> "bd_do": [],
> - "mark_uploaded": []
> + "mark_uploaded": [],
> + "merge_package": ["mp"]
> }
>
> for command, aliases in commands.
>
>
> I fear this alias will conflict with something in the future (merge-proposal
> perhaps), perhaps it is better to leave it off for now and let people set
> it as they like.
Good point, alias removed.
> === modified file 'cmds.py'
> --- cmds.py 2009-07-26 18:21:49 +0000
> +++ cmds.py 2009-08-19 09:06:47 +0000
> @@ -870,6 +871,39 @@
> t.unlock()
>
>
> +class cmd_merge_
> + """Merges source packaging branch into target packaging branch.
> +
> + This will first check whether the upstream branches have diverged.
> +
> + If that's the case an attempt will be made to fix the upstream ancestry
> + so that the user only needs to deal wth packaging branch merge issues.
> +
> + In the opposite case a normal merge will be performed.
> + """
> + takes_args = ['source']
> +
> + def run(self, source):
> + source_branch = target_branch = None
> + # Get the target branch.
> + try:
> + tree = WorkingTree.
> + target_branch = tree.branch
> + except NotBranchError:
> + raise BzrCommandError(
> + "There is no tree to merge the source branch in to")
> + # Get the source branch.
> + try:
> + source_branch = Branch.open(source)
> + except NotBranchError:
> + raise BzrCommandError
> +
> + fix_ancestry_
> +
> + # Merge source packaging branch in to the target packaging branch.
> + tree.merge_
> +
> +
> class cmd_test_
> """Run the builddeb test suite"""
>
> @@ -880,4 +914,3 @@
> passed = selftest(
> # invert for shell exit code rules
> return not passed
> -
>
> === modified file 'import_dsc.py'
> --- import_dsc.py 2009-07-26 16:44:17 +0000
> +++ import_dsc.py 2009-08-19 08:58:47 +0000
> @@ -1570,7 +1570,7 @@
> finally:
> shutil.
>
> - def _extract_
> + def extract_
1 | === modified file '__init__.py' | |||
2 | --- __init__.py 2009-08-06 09:59:34 +0000 | |||
3 | +++ __init__.py 2009-08-19 11:39:16 +0000 | |||
4 | @@ -40,7 +40,7 @@ | |||
5 | 40 | "import_dsc": [], | 40 | "import_dsc": [], |
6 | 41 | "bd_do": [], | 41 | "bd_do": [], |
7 | 42 | "mark_uploaded": [], | 42 | "mark_uploaded": [], |
9 | 43 | "merge_package": ["mp"] | 43 | "merge_package": [] |
10 | 44 | } | 44 | } |
11 | 45 | 45 | ||
12 | 46 | for command, aliases in commands.iteritems(): | 46 | for command, aliases in commands.iteritems(): |
13 | 47 | 47 | ||
14 | === modified file 'errors.py' | |||
15 | --- errors.py 2009-04-16 09:30:49 +0000 | |||
16 | +++ errors.py 2009-08-19 14:08:39 +0000 | |||
17 | @@ -175,3 +175,22 @@ | |||
18 | 175 | 175 | ||
19 | 176 | def __init__(self, error): | 176 | def __init__(self, error): |
20 | 177 | BzrError.__init__(self, error=error) | 177 | BzrError.__init__(self, error=error) |
21 | 178 | |||
22 | 179 | |||
23 | 180 | class SharedUpstreamConflictsWithTargetPackaging(BzrError): | ||
24 | 181 | _fmt = ('''\ | ||
25 | 182 | The "merge-package" command has detected diverged upstream | ||
26 | 183 | branches for the merge source and target. A shared upstream | ||
27 | 184 | revision was constructed to remedy the problem. | ||
28 | 185 | |||
29 | 186 | However, merging the shared upstream revision into the merge | ||
30 | 187 | target resulted in conflicts. | ||
31 | 188 | |||
32 | 189 | Please proceed as follows: | ||
33 | 190 | |||
34 | 191 | 1 - Resolve the current merge conflicts in the merge target | ||
35 | 192 | directory and commit the changes. | ||
36 | 193 | 2 - Perform a plain "bzr merge <source-packaging-branch>" | ||
37 | 194 | command, resolve any ensuing packaging branch conflicts | ||
38 | 195 | and commit once satisfied with the changes. | ||
39 | 196 | ''') | ||
40 | 178 | 197 | ||
41 | === modified file 'import_dsc.py' | |||
42 | --- import_dsc.py 2009-08-19 08:58:47 +0000 | |||
43 | +++ import_dsc.py 2009-08-19 11:43:09 +0000 | |||
44 | @@ -1575,6 +1575,7 @@ | |||
45 | 1575 | # tree for it. | 1575 | # tree for it. |
46 | 1576 | # TODO: should stack rather than trying to use the repository, | 1576 | # TODO: should stack rather than trying to use the repository, |
47 | 1577 | # as that will be more efficient. | 1577 | # as that will be more efficient. |
48 | 1578 | # TODO: remove the _extract_upstream_tree alias below. | ||
49 | 1578 | to_location = os.path.join(basedir, "upstream") | 1579 | to_location = os.path.join(basedir, "upstream") |
50 | 1579 | dir_to = self.branch.bzrdir.sprout(to_location, | 1580 | dir_to = self.branch.bzrdir.sprout(to_location, |
51 | 1580 | revision_id=upstream_tip, | 1581 | revision_id=upstream_tip, |
52 | @@ -1582,12 +1583,7 @@ | |||
53 | 1582 | self.upstream_tree = dir_to.open_workingtree() | 1583 | self.upstream_tree = dir_to.open_workingtree() |
54 | 1583 | self.upstream_branch = self.upstream_tree.branch | 1584 | self.upstream_branch = self.upstream_tree.branch |
55 | 1584 | 1585 | ||
62 | 1585 | def _extract_upstream_tree(self, upstream_tip, basedir): | 1586 | _extract_upstream_tree = extract_upstream_tree |
57 | 1586 | # This method is now being used outside this module and hence | ||
58 | 1587 | # not really private any longer. | ||
59 | 1588 | # TODO: obsolete/remove this method and start using | ||
60 | 1589 | # extract_upstream_tree() instead. | ||
61 | 1590 | self.extract_upstream_tree(upstream_tip, basedir) | ||
63 | 1591 | 1587 | ||
64 | 1592 | def _create_empty_upstream_tree(self, basedir): | 1588 | def _create_empty_upstream_tree(self, basedir): |
65 | 1593 | to_location = os.path.join(basedir, "upstream") | 1589 | to_location = os.path.join(basedir, "upstream") |
66 | @@ -1622,11 +1618,11 @@ | |||
67 | 1622 | shutil.rmtree(tempdir) | 1618 | shutil.rmtree(tempdir) |
68 | 1623 | raise | 1619 | raise |
69 | 1624 | 1620 | ||
70 | 1625 | def _revid_of_upstream_version_from_branch(self, version): | ||
71 | 1626 | """The private method below will go away eventually.""" | 1621 | """The private method below will go away eventually.""" |
72 | 1627 | return self.revid_of_upstream_version_from_branch(version) | 1622 | return self.revid_of_upstream_version_from_branch(version) |
73 | 1628 | 1623 | ||
74 | 1629 | def revid_of_upstream_version_from_branch(self, version): | 1624 | def revid_of_upstream_version_from_branch(self, version): |
75 | 1625 | # TODO: remove the _revid_of_upstream_version_from_branch alias below. | ||
76 | 1630 | assert isinstance(version, str) | 1626 | assert isinstance(version, str) |
77 | 1631 | tag_name = self.upstream_tag_name(version) | 1627 | tag_name = self.upstream_tag_name(version) |
78 | 1632 | if self._has_version(self.branch, tag_name): | 1628 | if self._has_version(self.branch, tag_name): |
79 | @@ -1640,6 +1636,8 @@ | |||
80 | 1640 | tag_name = self.upstream_tag_name(version) | 1636 | tag_name = self.upstream_tag_name(version) |
81 | 1641 | return self.branch.tags.lookup_tag(tag_name) | 1637 | return self.branch.tags.lookup_tag(tag_name) |
82 | 1642 | 1638 | ||
83 | 1639 | _revid_of_upstream_version_from_branch = revid_of_upstream_version_from_branch | ||
84 | 1640 | |||
85 | 1643 | def merge_upstream(self, tarball_filename, version, previous_version, | 1641 | def merge_upstream(self, tarball_filename, version, previous_version, |
86 | 1644 | upstream_branch=None, upstream_revision=None, merge_type=None): | 1642 | upstream_branch=None, upstream_revision=None, merge_type=None): |
87 | 1645 | assert self.upstream_branch is None, \ | 1643 | assert self.upstream_branch is None, \ |
88 | 1646 | 1644 | ||
89 | === modified file 'merge_package.py' | |||
90 | --- merge_package.py 2009-08-19 09:19:38 +0000 | |||
91 | +++ merge_package.py 2009-08-19 16:31:25 +0000 | |||
92 | @@ -30,37 +30,7 @@ | |||
93 | 30 | from bzrlib import errors | 30 | from bzrlib import errors |
94 | 31 | 31 | ||
95 | 32 | from bzrlib.plugins.builddeb.import_dsc import DistributionBranch | 32 | from bzrlib.plugins.builddeb.import_dsc import DistributionBranch |
127 | 33 | 33 | from bzrlib.plugins.builddeb.util import find_changelog | |
97 | 34 | |||
98 | 35 | class WrongBranchType(errors.BzrError): | ||
99 | 36 | _fmt = "The merge target is not a packaging branch." | ||
100 | 37 | |||
101 | 38 | |||
102 | 39 | class InvalidChangelogFormat(errors.BzrError): | ||
103 | 40 | _fmt = "The debian/changelog is empty or not in valid format." | ||
104 | 41 | |||
105 | 42 | |||
106 | 43 | class SourceUpstreamConflictsWithTargetPackaging(errors.BzrError): | ||
107 | 44 | _fmt = ( | ||
108 | 45 | "The source upstream branch conflicts with " | ||
109 | 46 | "the target packaging branch") | ||
110 | 47 | |||
111 | 48 | |||
112 | 49 | def _read_file(branch, path): | ||
113 | 50 | """Get content of file for given `branch` and `path. | ||
114 | 51 | |||
115 | 52 | :param branch: A Branch object containing the file of interest. | ||
116 | 53 | :param path: The path of the file to read. | ||
117 | 54 | """ | ||
118 | 55 | try: | ||
119 | 56 | tree = branch.basis_tree() | ||
120 | 57 | tree.lock_read() | ||
121 | 58 | content = tree.get_file_text(tree.path2id(path)) | ||
122 | 59 | tree.unlock() | ||
123 | 60 | except errors.NoSuchId: | ||
124 | 61 | raise WrongBranchType() | ||
125 | 62 | |||
126 | 63 | return content | ||
128 | 64 | 34 | ||
129 | 65 | 35 | ||
130 | 66 | def _latest_version(branch): | 36 | def _latest_version(branch): |
131 | @@ -68,28 +38,16 @@ | |||
132 | 68 | 38 | ||
133 | 69 | :param branch: A Branch object containing the source upload of interest. | 39 | :param branch: A Branch object containing the source upload of interest. |
134 | 70 | """ | 40 | """ |
151 | 71 | upload_version = '' | 41 | changelog, _ignore = find_changelog(branch.basis_tree(), False) |
152 | 72 | changelog = _read_file(branch, "debian/changelog") | 42 | |
153 | 73 | 43 | return changelog.version | |
138 | 74 | for line in changelog.splitlines(): | ||
139 | 75 | # Look for the top-level changelog stanza, extract the | ||
140 | 76 | # upload version from it and break on success. | ||
141 | 77 | match = re.search('^.+\(([^)]+)\).*$', line) | ||
142 | 78 | if match is not None: | ||
143 | 79 | (upload_version,) = match.groups(1) | ||
144 | 80 | break | ||
145 | 81 | |||
146 | 82 | upload_version = upload_version.strip() | ||
147 | 83 | if len(upload_version) <= 0: | ||
148 | 84 | raise InvalidChangelogFormat() | ||
149 | 85 | |||
150 | 86 | return Version(upload_version) | ||
154 | 87 | 44 | ||
155 | 88 | 45 | ||
156 | 89 | def _upstream_version_data(source, target): | 46 | def _upstream_version_data(source, target): |
157 | 90 | """Most recent upstream versions/revision IDs of the merge source/target. | 47 | """Most recent upstream versions/revision IDs of the merge source/target. |
158 | 91 | 48 | ||
160 | 92 | Please note: both packaing branches must have been read-locked beforehand. | 49 | Please note: both packaging branches must have been read-locked |
161 | 50 | beforehand. | ||
162 | 93 | 51 | ||
163 | 94 | :param source: The merge source branch. | 52 | :param source: The merge source branch. |
164 | 95 | :param target: The merge target branch. | 53 | :param target: The merge target branch. |
165 | @@ -150,49 +108,48 @@ | |||
166 | 150 | t_upstream_reverted = False | 108 | t_upstream_reverted = False |
167 | 151 | target = tree.branch | 109 | target = tree.branch |
168 | 152 | 110 | ||
169 | 111 | source.lock_read() | ||
170 | 153 | try: | 112 | try: |
178 | 154 | source.lock_read() | 113 | tree.lock_read() |
179 | 155 | target.lock_read() | 114 | try: |
180 | 156 | upstream_vdata = _upstream_version_data(source, target) | 115 | # "Unpack" the upstream versions and revision ids for the merge |
181 | 157 | # Did the upstream branches of the merge source and target diverge? | 116 | # source and target branch respectively. |
182 | 158 | revids = [vdata[1] for vdata in upstream_vdata] | 117 | [(us_ver, us_revid), (ut_ver, ut_revid)] = _upstream_version_data(source, target) |
183 | 159 | graph = source.repository.get_graph(target.repository) | 118 | |
184 | 160 | upstreams_diverged = (len(graph.heads(revids)) > 1) | 119 | # Did the upstream branches of the merge source/target diverge? |
185 | 120 | graph = source.repository.get_graph(target.repository) | ||
186 | 121 | upstreams_diverged = (len(graph.heads([us_revid, ut_revid])) > 1) | ||
187 | 122 | finally: | ||
188 | 123 | tree.unlock() | ||
189 | 161 | finally: | 124 | finally: |
190 | 162 | source.unlock() | 125 | source.unlock() |
191 | 163 | target.unlock() | ||
192 | 164 | 126 | ||
193 | 165 | if not upstreams_diverged: | 127 | if not upstreams_diverged: |
194 | 166 | return (upstreams_diverged, t_upstream_reverted) | 128 | return (upstreams_diverged, t_upstream_reverted) |
195 | 167 | 129 | ||
196 | 168 | # "Unpack" the upstream versions and revision ids for the merge source and | ||
197 | 169 | # target branch respectively. | ||
198 | 170 | [(usource_v, usource_revid), (utarget_v, utarget_revid)] = upstream_vdata | ||
199 | 171 | |||
200 | 172 | # Instantiate a `DistributionBranch` object for the merge target | 130 | # Instantiate a `DistributionBranch` object for the merge target |
201 | 173 | # (packaging) branch. | 131 | # (packaging) branch. |
202 | 174 | db = DistributionBranch(tree.branch, tree.branch) | 132 | db = DistributionBranch(tree.branch, tree.branch) |
203 | 175 | tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..')) | 133 | tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..')) |
204 | 176 | 134 | ||
205 | 177 | # Extract the merge target's upstream tree into a temporary directory. | 135 | # Extract the merge target's upstream tree into a temporary directory. |
207 | 178 | db.extract_upstream_tree(utarget_revid, tempdir) | 136 | db.extract_upstream_tree(ut_revid, tempdir) |
208 | 179 | tmp_target_upstream_tree = db.upstream_tree | 137 | tmp_target_upstream_tree = db.upstream_tree |
209 | 180 | 138 | ||
210 | 181 | # Merge upstream branch tips to obtain a shared upstream parent. This | 139 | # Merge upstream branch tips to obtain a shared upstream parent. This |
211 | 182 | # will add revision K (see graph above) to a temporary merge target | 140 | # will add revision K (see graph above) to a temporary merge target |
212 | 183 | # upstream tree. | 141 | # upstream tree. |
213 | 142 | tmp_target_upstream_tree.lock_write() | ||
214 | 184 | try: | 143 | try: |
218 | 185 | tmp_target_upstream_tree.lock_write() | 144 | if us_ver > ut_ver: |
216 | 186 | |||
217 | 187 | if usource_v > utarget_v: | ||
219 | 188 | # The source upstream tree is more recent and the temporary | 145 | # The source upstream tree is more recent and the temporary |
220 | 189 | # target tree needs to be reshaped to match it. | 146 | # target tree needs to be reshaped to match it. |
221 | 190 | tmp_target_upstream_tree.revert( | 147 | tmp_target_upstream_tree.revert( |
223 | 191 | None, source.repository.revision_tree(usource_revid)) | 148 | None, source.repository.revision_tree(us_revid)) |
224 | 192 | t_upstream_reverted = True | 149 | t_upstream_reverted = True |
225 | 193 | 150 | ||
226 | 194 | tmp_target_upstream_tree.set_parent_ids( | 151 | tmp_target_upstream_tree.set_parent_ids( |
228 | 195 | (utarget_revid, usource_revid)) | 152 | (ut_revid, us_revid)) |
229 | 196 | 153 | ||
230 | 197 | tmp_target_upstream_tree.commit( | 154 | tmp_target_upstream_tree.commit( |
231 | 198 | 'Consolidated upstream tree for merging into target branch') | 155 | 'Consolidated upstream tree for merging into target branch') |
232 | @@ -201,13 +158,13 @@ | |||
233 | 201 | 158 | ||
234 | 202 | # Merge shared upstream parent into the target merge branch. This creates | 159 | # Merge shared upstream parent into the target merge branch. This creates |
235 | 203 | # revison L in the digram above. | 160 | # revison L in the digram above. |
236 | 161 | tree.lock_write() | ||
237 | 204 | try: | 162 | try: |
244 | 205 | tree.lock_write() | 163 | conflicts = tree.merge_from_branch(tmp_target_upstream_tree.branch) |
245 | 206 | try: | 164 | if conflicts > 0: |
246 | 207 | tree.merge_from_branch(tmp_target_upstream_tree.branch) | 165 | raise errors.SharedUpstreamConflictsWithTargetPackaging() |
247 | 208 | tree.commit('Merging source packaging branch in to target.') | 166 | else: |
248 | 209 | except ConflictsInTree: | 167 | tree.commit('Merging shared upstream rev in to target branch.') |
243 | 210 | raise SourceUpstreamConflictsWithTargetPackaging() | ||
249 | 211 | finally: | 168 | finally: |
250 | 212 | tree.unlock() | 169 | tree.unlock() |
251 | 213 | 170 | ||
252 | 214 | 171 | ||
253 | === modified file 'tests/test_merge_package.py' | |||
254 | --- tests/test_merge_package.py 2009-08-19 09:44:38 +0000 | |||
255 | +++ tests/test_merge_package.py 2009-08-21 12:40:48 +0000 | |||
256 | @@ -19,16 +19,16 @@ | |||
257 | 19 | # along with bzr-builddeb; if not, write to the Free Software | 19 | # along with bzr-builddeb; if not, write to the Free Software |
258 | 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
259 | 21 | 21 | ||
260 | 22 | import os | ||
261 | 23 | import random | ||
262 | 24 | import string | 22 | import string |
263 | 25 | import unittest | 23 | import unittest |
264 | 26 | 24 | ||
265 | 25 | from debian_bundle.changelog import Version | ||
266 | 26 | |||
267 | 27 | from bzrlib.errors import ConflictsInTree | 27 | from bzrlib.errors import ConflictsInTree |
268 | 28 | from bzrlib.merge import WeaveMerger | ||
269 | 29 | from bzrlib.tests import TestCaseWithTransport | 28 | from bzrlib.tests import TestCaseWithTransport |
270 | 30 | 29 | ||
271 | 31 | from bzrlib.plugins.builddeb import merge_package as MP | 30 | from bzrlib.plugins.builddeb import merge_package as MP |
272 | 31 | from bzrlib.plugins.builddeb.import_dsc import DistributionBranch | ||
273 | 32 | 32 | ||
274 | 33 | _Debian_changelog = '''\ | 33 | _Debian_changelog = '''\ |
275 | 34 | ipsec-tools (%s) unstable; urgency=high | 34 | ipsec-tools (%s) unstable; urgency=high |
276 | @@ -52,29 +52,31 @@ | |||
277 | 52 | def _prepend_log(text, path): | 52 | def _prepend_log(text, path): |
278 | 53 | content = open(path).read() | 53 | content = open(path).read() |
279 | 54 | fh = open(path, 'wb') | 54 | fh = open(path, 'wb') |
282 | 55 | fh.write(text+content) | 55 | try: |
283 | 56 | fh.close() | 56 | fh.write(text+content) |
284 | 57 | finally: | ||
285 | 58 | fh.close() | ||
286 | 57 | 59 | ||
287 | 58 | 60 | ||
288 | 59 | class MergePackageTests(TestCaseWithTransport): | 61 | class MergePackageTests(TestCaseWithTransport): |
289 | 60 | 62 | ||
290 | 61 | def test_latest_upstream_versions(self): | 63 | def test_latest_upstream_versions(self): |
291 | 62 | """Check correctness of upstream version computation.""" | 64 | """Check correctness of upstream version computation.""" |
293 | 63 | ubup_o, debp_n = self._setup_debian_upstrem_newer() | 65 | ubup_o, debp_n, _ubuu, _debu = self._setup_debian_upstream_newer() |
294 | 64 | # Ubuntu upstream. | 66 | # Ubuntu upstream. |
295 | 65 | self.assertEquals( | 67 | self.assertEquals( |
297 | 66 | MP._latest_version(ubup_o.branch).upstream_version, '1.1.2') | 68 | MP._latest_version(ubup_o).upstream_version, '1.1.2') |
298 | 67 | # Debian upstream. | 69 | # Debian upstream. |
299 | 68 | self.assertEquals( | 70 | self.assertEquals( |
301 | 69 | MP._latest_version(debp_n.branch).upstream_version, '2.0') | 71 | MP._latest_version(debp_n).upstream_version, '2.0') |
302 | 70 | 72 | ||
303 | 71 | ubuntup, debianp = self._setup_upstreams_not_diverged() | 73 | ubuntup, debianp = self._setup_upstreams_not_diverged() |
304 | 72 | # Ubuntu upstream. | 74 | # Ubuntu upstream. |
305 | 73 | self.assertEquals( | 75 | self.assertEquals( |
307 | 74 | MP._latest_version(ubuntup.branch).upstream_version, '1.4') | 76 | MP._latest_version(ubuntup).upstream_version, '1.4') |
308 | 75 | # Debian upstream. | 77 | # Debian upstream. |
309 | 76 | self.assertEquals( | 78 | self.assertEquals( |
311 | 77 | MP._latest_version(debianp.branch).upstream_version, '2.2') | 79 | MP._latest_version(debianp).upstream_version, '2.2') |
312 | 78 | 80 | ||
313 | 79 | def test_debian_upstream_newer(self): | 81 | def test_debian_upstream_newer(self): |
314 | 80 | """Diverging upstreams (debian newer) don't cause merge conflicts. | 82 | """Diverging upstreams (debian newer) don't cause merge conflicts. |
315 | @@ -88,23 +90,39 @@ | |||
316 | 88 | The upstream conflict will be resolved by fix_ancestry_as_needed(). | 90 | The upstream conflict will be resolved by fix_ancestry_as_needed(). |
317 | 89 | Please note that the debian ancestry is more recent. | 91 | Please note that the debian ancestry is more recent. |
318 | 90 | """ | 92 | """ |
320 | 91 | ubup_o, debp_n = self._setup_debian_upstrem_newer() | 93 | ubup, debp, ubuu, debu = self._setup_debian_upstream_newer() |
321 | 92 | 94 | ||
322 | 93 | # Attempt a plain merge first. | 95 | # Attempt a plain merge first. |
325 | 94 | conflicts = ubup_o.merge_from_branch( | 96 | conflicts = ubup.merge_from_branch( |
326 | 95 | debp_n.branch, to_revision=self.revid_debp_n_C) | 97 | debp.branch, to_revision=self.revid_debp_n_C) |
327 | 96 | 98 | ||
328 | 97 | # There are two conflicts in the 'c' and the 'debian/changelog' files | 99 | # There are two conflicts in the 'c' and the 'debian/changelog' files |
329 | 98 | # respectively. | 100 | # respectively. |
330 | 99 | self.assertEquals(conflicts, 2) | 101 | self.assertEquals(conflicts, 2) |
332 | 100 | conflict_paths = sorted([c.path for c in ubup_o.conflicts()]) | 102 | conflict_paths = sorted([c.path for c in ubup.conflicts()]) |
333 | 101 | self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog']) | 103 | self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog']) |
334 | 102 | 104 | ||
335 | 103 | # Undo the failed merge. | 105 | # Undo the failed merge. |
337 | 104 | ubup_o.revert() | 106 | ubup.revert() |
338 | 107 | |||
339 | 108 | # Check the versions present in the tree with the fixed ancestry. | ||
340 | 109 | v3 = "1.1.2" | ||
341 | 110 | v4 = "2.0" | ||
342 | 111 | db1 = DistributionBranch(ubup.branch, ubup.branch) | ||
343 | 112 | self.assertEqual(db1.has_upstream_version(v3), True) | ||
344 | 113 | # This version is in the diverged debian upstream tree and will | ||
345 | 114 | # hence not be present in the target ubuntu packaging branch. | ||
346 | 115 | self.assertEqual(db1.has_upstream_version(v4), False) | ||
347 | 116 | |||
348 | 117 | # The ubuntu upstream branch tip. | ||
349 | 118 | ubuu_tip = ubuu.branch.revision_history()[-1] | ||
350 | 119 | # The debian upstream branch tip. | ||
351 | 120 | debu_tip = debu.branch.revision_history()[-1] | ||
352 | 121 | # The ubuntu packaging branch tip. | ||
353 | 122 | ubup_tip_pre_fix = ubup.branch.revision_history()[-1] | ||
354 | 105 | 123 | ||
355 | 106 | # The first conflict is resolved by calling fix_ancestry_as_needed(). | 124 | # The first conflict is resolved by calling fix_ancestry_as_needed(). |
357 | 107 | upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup_o, debp_n.branch) | 125 | upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup, debp.branch) |
358 | 108 | 126 | ||
359 | 109 | # The ancestry did diverge and needed to be fixed. | 127 | # The ancestry did diverge and needed to be fixed. |
360 | 110 | self.assertEquals(upstreams_diverged, True) | 128 | self.assertEquals(upstreams_diverged, True) |
361 | @@ -112,13 +130,35 @@ | |||
362 | 112 | # source upstream branch since the latter was more recent. | 130 | # source upstream branch since the latter was more recent. |
363 | 113 | self.assertEquals(t_upstream_reverted, True) | 131 | self.assertEquals(t_upstream_reverted, True) |
364 | 114 | 132 | ||
365 | 133 | # Check the versions present in the tree with the fixed ancestry. | ||
366 | 134 | db2 = DistributionBranch(ubup.branch, ubup.branch) | ||
367 | 135 | self.assertEqual(db2.has_upstream_version(v3), True) | ||
368 | 136 | # The ancestry has been fixed and the missing debian upstream | ||
369 | 137 | # version should now be present in the target ubuntu packaging | ||
370 | 138 | # branch. | ||
371 | 139 | self.assertEqual(db2.has_upstream_version(v4), True) | ||
372 | 140 | |||
373 | 141 | # Now let's take a look at the fixed ubuntu packaging branch. | ||
374 | 142 | ubup_tip_post_fix = ubup.branch.revision_history()[-1] | ||
375 | 143 | ubup_parents_post_fix = ubup.branch.repository.revision_tree(ubup_tip_post_fix).get_parent_ids() | ||
376 | 144 | |||
377 | 145 | # The tip of the fixed ubuntu packaging branch has 2 parents. | ||
378 | 146 | self.assertEquals(len(ubup_parents_post_fix), 2) | ||
379 | 147 | |||
380 | 148 | # The left parent is the packaging branch tip before fixing. | ||
381 | 149 | self.assertEquals(ubup_parents_post_fix[0], ubup_tip_pre_fix) | ||
382 | 150 | |||
383 | 151 | # The right parent is derived from a merge | ||
384 | 152 | ubup_parents_sharedupstream = ubup.branch.repository.revision_tree(ubup_parents_post_fix[1]).get_parent_ids() | ||
385 | 153 | self.assertEquals(ubup_parents_sharedupstream, [ubuu_tip, debu_tip]) | ||
386 | 154 | |||
387 | 115 | # Try merging again. | 155 | # Try merging again. |
390 | 116 | conflicts = ubup_o.merge_from_branch( | 156 | conflicts = ubup.merge_from_branch( |
391 | 117 | debp_n.branch, to_revision=self.revid_debp_n_C) | 157 | debp.branch, to_revision=self.revid_debp_n_C) |
392 | 118 | 158 | ||
393 | 119 | # And, voila, only the packaging branch conflict remains. | 159 | # And, voila, only the packaging branch conflict remains. |
394 | 120 | self.assertEquals(conflicts, 1) | 160 | self.assertEquals(conflicts, 1) |
396 | 121 | conflict_paths = sorted([c.path for c in ubup_o.conflicts()]) | 161 | conflict_paths = sorted([c.path for c in ubup.conflicts()]) |
397 | 122 | self.assertEquals(conflict_paths, [u'debian/changelog']) | 162 | self.assertEquals(conflict_paths, [u'debian/changelog']) |
398 | 123 | 163 | ||
399 | 124 | def test_debian_upstream_older(self): | 164 | def test_debian_upstream_older(self): |
400 | @@ -208,9 +248,9 @@ | |||
401 | 208 | conflict_paths = sorted([c.path for c in ubuntup.conflicts()]) | 248 | conflict_paths = sorted([c.path for c in ubuntup.conflicts()]) |
402 | 209 | self.assertEquals(conflict_paths, [u'debian/changelog']) | 249 | self.assertEquals(conflict_paths, [u'debian/changelog']) |
403 | 210 | 250 | ||
405 | 211 | def _setup_debian_upstrem_newer(self): | 251 | def _setup_debian_upstream_newer(self): |
406 | 212 | """ | 252 | """ |
408 | 213 | Set up the following test configuration (debian upstrem newer). | 253 | Set up the following test configuration (debian upstream newer). |
409 | 214 | 254 | ||
410 | 215 | debian-upstream ,------------------H | 255 | debian-upstream ,------------------H |
411 | 216 | A-----------B \ | 256 | A-----------B \ |
412 | @@ -280,11 +320,11 @@ | |||
413 | 280 | self._setup_branch(name, vdata, ubup_o, 'u') | 320 | self._setup_branch(name, vdata, ubup_o, 'u') |
414 | 281 | 321 | ||
415 | 282 | # Return the ubuntu and the debian packaging branches. | 322 | # Return the ubuntu and the debian packaging branches. |
417 | 283 | return (ubup_o, debp_n) | 323 | return (ubup_o, debp_n, ubuu_o, debu_n) |
418 | 284 | 324 | ||
419 | 285 | def _setup_debian_upstream_older(self): | 325 | def _setup_debian_upstream_older(self): |
420 | 286 | """ | 326 | """ |
422 | 287 | Set up the following test configuration (debian upstrem older). | 327 | Set up the following test configuration (debian upstream older). |
423 | 288 | 328 | ||
424 | 289 | debian-upstream ,----H-------------. | 329 | debian-upstream ,----H-------------. |
425 | 290 | A-----------B \ | 330 | A-----------B \ |
426 | @@ -434,6 +474,9 @@ | |||
427 | 434 | if tree is None: | 474 | if tree is None: |
428 | 435 | tree = self.make_branch_and_tree(name) | 475 | tree = self.make_branch_and_tree(name) |
429 | 436 | 476 | ||
430 | 477 | tree.lock_write() | ||
431 | 478 | self.addCleanup(tree.unlock) | ||
432 | 479 | |||
433 | 437 | def revid_name(vid): | 480 | def revid_name(vid): |
434 | 438 | return 'revid_%s_%s' % (name.replace('-', '_'), vid) | 481 | return 'revid_%s_%s' % (name.replace('-', '_'), vid) |
435 | 439 | 482 | ||
436 | @@ -464,7 +507,7 @@ | |||
437 | 464 | cle = changelog(version, vid) | 507 | cle = changelog(version, vid) |
438 | 465 | p = '%s/work/%s/debian/changelog' % (self.test_base_dir, name) | 508 | p = '%s/work/%s/debian/changelog' % (self.test_base_dir, name) |
439 | 466 | _prepend_log(cle, p) | 509 | _prepend_log(cle, p) |
441 | 467 | revid = tree.commit('%s: %s' % (vid, msg), rev_id='%s-%s' % (name, vid)) | 510 | revid = tree.commit('%s: %s' % (vid, msg)) |
442 | 468 | setattr(self, revid_name(vid), revid) | 511 | setattr(self, revid_name(vid), revid) |
443 | 469 | tree.branch.tags.set_tag(version, revid) | 512 | tree.branch.tags.set_tag(version, revid) |
444 | 470 | 513 | ||
445 | @@ -474,8 +517,7 @@ | |||
446 | 474 | for version, paths, utree, urevid in vdata: | 517 | for version, paths, utree, urevid in vdata: |
447 | 475 | msg = '' | 518 | msg = '' |
448 | 476 | if utree is not None: | 519 | if utree is not None: |
451 | 477 | tree.merge_from_branch( | 520 | tree.merge_from_branch(utree.branch, to_revision=urevid) |
450 | 478 | utree.branch, to_revision=urevid, merge_type=WeaveMerger) | ||
452 | 479 | utree.branch.tags.merge_to(tree.branch.tags) | 521 | utree.branch.tags.merge_to(tree.branch.tags) |
453 | 480 | if urevid is not None: | 522 | if urevid is not None: |
454 | 481 | msg += 'Merged tree %s|%s. ' % (tree_nick(utree), urevid) | 523 | msg += 'Merged tree %s|%s. ' % (tree_nick(utree), urevid) |
455 | @@ -491,7 +533,5 @@ | |||
456 | 491 | 533 | ||
457 | 492 | 534 | ||
458 | 493 | if __name__ == '__main__': | 535 | if __name__ == '__main__': |
459 | 494 | # unittest.main() | ||
460 | 495 | suite = unittest.TestLoader().loadTestsFromTestCase(MergePackageTests) | 536 | suite = unittest.TestLoader().loadTestsFromTestCase(MergePackageTests) |
461 | 496 | unittest.TextTestRunner(verbosity=2).run(suite) | 537 | unittest.TextTestRunner(verbosity=2).run(suite) |
462 | 497 |
1 | === modified file '__init__.py' | |||
2 | --- __init__.py 2009-07-26 15:51:02 +0000 | |||
3 | +++ __init__.py 2009-08-19 11:39:16 +0000 | |||
4 | @@ -39,7 +39,8 @@ | |||
5 | 39 | "merge_upstream": ["mu"], | 39 | "merge_upstream": ["mu"], |
6 | 40 | "import_dsc": [], | 40 | "import_dsc": [], |
7 | 41 | "bd_do": [], | 41 | "bd_do": [], |
9 | 42 | "mark_uploaded": [] | 42 | "mark_uploaded": [], |
10 | 43 | "merge_package": [] | ||
11 | 43 | } | 44 | } |
12 | 44 | 45 | ||
13 | 45 | for command, aliases in commands.iteritems(): | 46 | for command, aliases in commands.iteritems(): |
14 | 46 | 47 | ||
15 | === modified file 'cmds.py' | |||
16 | --- cmds.py 2009-07-26 18:21:49 +0000 | |||
17 | +++ cmds.py 2009-08-19 09:01:30 +0000 | |||
18 | @@ -69,6 +69,7 @@ | |||
19 | 69 | DscCache, | 69 | DscCache, |
20 | 70 | DscComp, | 70 | DscComp, |
21 | 71 | ) | 71 | ) |
22 | 72 | from bzrlib.plugins.builddeb.merge_package import fix_ancestry_as_needed | ||
23 | 72 | from bzrlib.plugins.builddeb.source_distiller import ( | 73 | from bzrlib.plugins.builddeb.source_distiller import ( |
24 | 73 | FullSourceDistiller, | 74 | FullSourceDistiller, |
25 | 74 | MergeModeDistiller, | 75 | MergeModeDistiller, |
26 | @@ -719,9 +720,9 @@ | |||
27 | 719 | "the previous upstream version, %s, in the " | 720 | "the previous upstream version, %s, in the " |
28 | 720 | "branch: %s" % (last_version, | 721 | "branch: %s" % (last_version, |
29 | 721 | db.upstream_tag_name(last_version))) | 722 | db.upstream_tag_name(last_version))) |
31 | 722 | upstream_tip = db._revid_of_upstream_version_from_branch( | 723 | upstream_tip = db.revid_of_upstream_version_from_branch( |
32 | 723 | last_version) | 724 | last_version) |
34 | 724 | db._extract_upstream_tree(upstream_tip, tempdir) | 725 | db.extract_upstream_tree(upstream_tip, tempdir) |
35 | 725 | else: | 726 | else: |
36 | 726 | db._create_empty_upstream_tree(tempdir) | 727 | db._create_empty_upstream_tree(tempdir) |
37 | 727 | self.import_many(db, files_list, orig_target) | 728 | self.import_many(db, files_list, orig_target) |
38 | @@ -870,6 +871,39 @@ | |||
39 | 870 | t.unlock() | 871 | t.unlock() |
40 | 871 | 872 | ||
41 | 872 | 873 | ||
42 | 874 | class cmd_merge_package(Command): | ||
43 | 875 | """Merges source packaging branch into target packaging branch. | ||
44 | 876 | |||
45 | 877 | This will first check whether the upstream branches have diverged. | ||
46 | 878 | |||
47 | 879 | If that's the case an attempt will be made to fix the upstream ancestry | ||
48 | 880 | so that the user only needs to deal wth packaging branch merge issues. | ||
49 | 881 | |||
50 | 882 | In the opposite case a normal merge will be performed. | ||
51 | 883 | """ | ||
52 | 884 | takes_args = ['source'] | ||
53 | 885 | |||
54 | 886 | def run(self, source): | ||
55 | 887 | source_branch = target_branch = None | ||
56 | 888 | # Get the target branch. | ||
57 | 889 | try: | ||
58 | 890 | tree = WorkingTree.open_containing('.')[0] | ||
59 | 891 | target_branch = tree.branch | ||
60 | 892 | except NotBranchError: | ||
61 | 893 | raise BzrCommandError( | ||
62 | 894 | "There is no tree to merge the source branch in to") | ||
63 | 895 | # Get the source branch. | ||
64 | 896 | try: | ||
65 | 897 | source_branch = Branch.open(source) | ||
66 | 898 | except NotBranchError: | ||
67 | 899 | raise BzrCommandError("Invalid source branch URL?") | ||
68 | 900 | |||
69 | 901 | fix_ancestry_as_needed(tree, source_branch) | ||
70 | 902 | |||
71 | 903 | # Merge source packaging branch in to the target packaging branch. | ||
72 | 904 | tree.merge_from_branch(source_branch) | ||
73 | 905 | |||
74 | 906 | |||
75 | 873 | class cmd_test_builddeb(Command): | 907 | class cmd_test_builddeb(Command): |
76 | 874 | """Run the builddeb test suite""" | 908 | """Run the builddeb test suite""" |
77 | 875 | 909 | ||
78 | @@ -880,4 +914,3 @@ | |||
79 | 880 | passed = selftest(test_suite_factory=test_suite) | 914 | passed = selftest(test_suite_factory=test_suite) |
80 | 881 | # invert for shell exit code rules | 915 | # invert for shell exit code rules |
81 | 882 | return not passed | 916 | return not passed |
82 | 883 | |||
83 | 884 | 917 | ||
84 | === modified file 'errors.py' | |||
85 | --- errors.py 2009-04-16 09:30:49 +0000 | |||
86 | +++ errors.py 2009-08-19 14:08:39 +0000 | |||
87 | @@ -175,3 +175,22 @@ | |||
88 | 175 | 175 | ||
89 | 176 | def __init__(self, error): | 176 | def __init__(self, error): |
90 | 177 | BzrError.__init__(self, error=error) | 177 | BzrError.__init__(self, error=error) |
91 | 178 | |||
92 | 179 | |||
93 | 180 | class SharedUpstreamConflictsWithTargetPackaging(BzrError): | ||
94 | 181 | _fmt = ('''\ | ||
95 | 182 | The "merge-package" command has detected diverged upstream | ||
96 | 183 | branches for the merge source and target. A shared upstream | ||
97 | 184 | revision was constructed to remedy the problem. | ||
98 | 185 | |||
99 | 186 | However, merging the shared upstream revision into the merge | ||
100 | 187 | target resulted in conflicts. | ||
101 | 188 | |||
102 | 189 | Please proceed as follows: | ||
103 | 190 | |||
104 | 191 | 1 - Resolve the current merge conflicts in the merge target | ||
105 | 192 | directory and commit the changes. | ||
106 | 193 | 2 - Perform a plain "bzr merge <source-packaging-branch>" | ||
107 | 194 | command, resolve any ensuing packaging branch conflicts | ||
108 | 195 | and commit once satisfied with the changes. | ||
109 | 196 | ''') | ||
110 | 178 | 197 | ||
111 | === modified file 'import_dsc.py' | |||
112 | --- import_dsc.py 2009-07-26 16:44:17 +0000 | |||
113 | +++ import_dsc.py 2009-08-19 11:43:09 +0000 | |||
114 | @@ -1570,11 +1570,12 @@ | |||
115 | 1570 | finally: | 1570 | finally: |
116 | 1571 | shutil.rmtree(tempdir) | 1571 | shutil.rmtree(tempdir) |
117 | 1572 | 1572 | ||
119 | 1573 | def _extract_upstream_tree(self, upstream_tip, basedir): | 1573 | def extract_upstream_tree(self, upstream_tip, basedir): |
120 | 1574 | # Extract that to a tempdir so we can get a working | 1574 | # Extract that to a tempdir so we can get a working |
121 | 1575 | # tree for it. | 1575 | # tree for it. |
122 | 1576 | # TODO: should stack rather than trying to use the repository, | 1576 | # TODO: should stack rather than trying to use the repository, |
123 | 1577 | # as that will be more efficient. | 1577 | # as that will be more efficient. |
124 | 1578 | # TODO: remove the _extract_upstream_tree alias below. | ||
125 | 1578 | to_location = os.path.join(basedir, "upstream") | 1579 | to_location = os.path.join(basedir, "upstream") |
126 | 1579 | dir_to = self.branch.bzrdir.sprout(to_location, | 1580 | dir_to = self.branch.bzrdir.sprout(to_location, |
127 | 1580 | revision_id=upstream_tip, | 1581 | revision_id=upstream_tip, |
128 | @@ -1582,6 +1583,8 @@ | |||
129 | 1582 | self.upstream_tree = dir_to.open_workingtree() | 1583 | self.upstream_tree = dir_to.open_workingtree() |
130 | 1583 | self.upstream_branch = self.upstream_tree.branch | 1584 | self.upstream_branch = self.upstream_tree.branch |
131 | 1584 | 1585 | ||
132 | 1586 | _extract_upstream_tree = extract_upstream_tree | ||
133 | 1587 | |||
134 | 1585 | def _create_empty_upstream_tree(self, basedir): | 1588 | def _create_empty_upstream_tree(self, basedir): |
135 | 1586 | to_location = os.path.join(basedir, "upstream") | 1589 | to_location = os.path.join(basedir, "upstream") |
136 | 1587 | to_transport = get_transport(to_location) | 1590 | to_transport = get_transport(to_location) |
137 | @@ -1615,7 +1618,11 @@ | |||
138 | 1615 | shutil.rmtree(tempdir) | 1618 | shutil.rmtree(tempdir) |
139 | 1616 | raise | 1619 | raise |
140 | 1617 | 1620 | ||
142 | 1618 | def _revid_of_upstream_version_from_branch(self, version): | 1621 | """The private method below will go away eventually.""" |
143 | 1622 | return self.revid_of_upstream_version_from_branch(version) | ||
144 | 1623 | |||
145 | 1624 | def revid_of_upstream_version_from_branch(self, version): | ||
146 | 1625 | # TODO: remove the _revid_of_upstream_version_from_branch alias below. | ||
147 | 1619 | assert isinstance(version, str) | 1626 | assert isinstance(version, str) |
148 | 1620 | tag_name = self.upstream_tag_name(version) | 1627 | tag_name = self.upstream_tag_name(version) |
149 | 1621 | if self._has_version(self.branch, tag_name): | 1628 | if self._has_version(self.branch, tag_name): |
150 | @@ -1629,6 +1636,8 @@ | |||
151 | 1629 | tag_name = self.upstream_tag_name(version) | 1636 | tag_name = self.upstream_tag_name(version) |
152 | 1630 | return self.branch.tags.lookup_tag(tag_name) | 1637 | return self.branch.tags.lookup_tag(tag_name) |
153 | 1631 | 1638 | ||
154 | 1639 | _revid_of_upstream_version_from_branch = revid_of_upstream_version_from_branch | ||
155 | 1640 | |||
156 | 1632 | def merge_upstream(self, tarball_filename, version, previous_version, | 1641 | def merge_upstream(self, tarball_filename, version, previous_version, |
157 | 1633 | upstream_branch=None, upstream_revision=None, merge_type=None): | 1642 | upstream_branch=None, upstream_revision=None, merge_type=None): |
158 | 1634 | assert self.upstream_branch is None, \ | 1643 | assert self.upstream_branch is None, \ |
159 | @@ -1639,14 +1648,14 @@ | |||
160 | 1639 | if previous_version is not None: | 1648 | if previous_version is not None: |
161 | 1640 | if self.has_upstream_version_in_packaging_branch( | 1649 | if self.has_upstream_version_in_packaging_branch( |
162 | 1641 | previous_version.upstream_version): | 1650 | previous_version.upstream_version): |
164 | 1642 | upstream_tip = self._revid_of_upstream_version_from_branch( | 1651 | upstream_tip = self.revid_of_upstream_version_from_branch( |
165 | 1643 | previous_version.upstream_version) | 1652 | previous_version.upstream_version) |
167 | 1644 | self._extract_upstream_tree(upstream_tip, tempdir) | 1653 | self.extract_upstream_tree(upstream_tip, tempdir) |
168 | 1645 | elif (upstream_branch is not None and | 1654 | elif (upstream_branch is not None and |
169 | 1646 | previous_upstream_revision is not None): | 1655 | previous_upstream_revision is not None): |
170 | 1647 | upstream_tip = RevisionSpec.from_string(previous_upstream_revision).as_revision_id(upstream_branch) | 1656 | upstream_tip = RevisionSpec.from_string(previous_upstream_revision).as_revision_id(upstream_branch) |
171 | 1648 | assert isinstance(upstream_tip, str) | 1657 | assert isinstance(upstream_tip, str) |
173 | 1649 | self._extract_upstream_tree(upstream_tip, tempdir) | 1658 | self.extract_upstream_tree(upstream_tip, tempdir) |
174 | 1650 | else: | 1659 | else: |
175 | 1651 | raise BzrCommandError("Unable to find the tag for the " | 1660 | raise BzrCommandError("Unable to find the tag for the " |
176 | 1652 | "previous upstream version, %s, in the branch: " | 1661 | "previous upstream version, %s, in the branch: " |
177 | 1653 | 1662 | ||
178 | === added file 'merge_package.py' | |||
179 | --- merge_package.py 1970-01-01 00:00:00 +0000 | |||
180 | +++ merge_package.py 2009-08-19 16:31:25 +0000 | |||
181 | @@ -0,0 +1,171 @@ | |||
182 | 1 | # merge_package.py -- The plugin for bzr | ||
183 | 2 | # Copyright (C) 2009 Canonical Ltd. | ||
184 | 3 | # | ||
185 | 4 | # :Author: Muharem Hrnjadovic <muharem@ubuntu.com> | ||
186 | 5 | # | ||
187 | 6 | # This file is part of bzr-builddeb. | ||
188 | 7 | # | ||
189 | 8 | # bzr-builddeb is free software; you can redistribute it and/or modify | ||
190 | 9 | # it under the terms of the GNU General Public License as published by | ||
191 | 10 | # the Free Software Foundation; either version 2 of the License, or | ||
192 | 11 | # (at your option) any later version. | ||
193 | 12 | # | ||
194 | 13 | # bzr-builddeb is distributed in the hope that it will be useful, | ||
195 | 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
196 | 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
197 | 16 | # GNU General Public License for more details. | ||
198 | 17 | # | ||
199 | 18 | # You should have received a copy of the GNU General Public License | ||
200 | 19 | # along with bzr-builddeb; if not, write to the Free Software | ||
201 | 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
202 | 21 | # | ||
203 | 22 | |||
204 | 23 | import os | ||
205 | 24 | import re | ||
206 | 25 | import sys | ||
207 | 26 | import tempfile | ||
208 | 27 | |||
209 | 28 | from debian_bundle.changelog import Version | ||
210 | 29 | |||
211 | 30 | from bzrlib import errors | ||
212 | 31 | |||
213 | 32 | from bzrlib.plugins.builddeb.import_dsc import DistributionBranch | ||
214 | 33 | from bzrlib.plugins.builddeb.util import find_changelog | ||
215 | 34 | |||
216 | 35 | |||
217 | 36 | def _latest_version(branch): | ||
218 | 37 | """Version of the most recent source package upload in the given `branch`. | ||
219 | 38 | |||
220 | 39 | :param branch: A Branch object containing the source upload of interest. | ||
221 | 40 | """ | ||
222 | 41 | changelog, _ignore = find_changelog(branch.basis_tree(), False) | ||
223 | 42 | |||
224 | 43 | return changelog.version | ||
225 | 44 | |||
226 | 45 | |||
227 | 46 | def _upstream_version_data(source, target): | ||
228 | 47 | """Most recent upstream versions/revision IDs of the merge source/target. | ||
229 | 48 | |||
230 | 49 | Please note: both packaging branches must have been read-locked | ||
231 | 50 | beforehand. | ||
232 | 51 | |||
233 | 52 | :param source: The merge source branch. | ||
234 | 53 | :param target: The merge target branch. | ||
235 | 54 | """ | ||
236 | 55 | results = list() | ||
237 | 56 | for branch in (source, target): | ||
238 | 57 | db = DistributionBranch(branch, branch) | ||
239 | 58 | uver = _latest_version(branch).upstream_version | ||
240 | 59 | results.append((uver, db.revid_of_upstream_version_from_branch(uver))) | ||
241 | 60 | |||
242 | 61 | return results | ||
243 | 62 | |||
244 | 63 | |||
245 | 64 | def fix_ancestry_as_needed(tree, source): | ||
246 | 65 | """Manipulate the merge target's ancestry to avoid upstream conflicts. | ||
247 | 66 | |||
248 | 67 | Merging J->I given the following ancestry tree is likely to result in | ||
249 | 68 | upstream merge conflicts: | ||
250 | 69 | |||
251 | 70 | debian-upstream ,------------------H | ||
252 | 71 | A-----------B \ | ||
253 | 72 | ubuntu-upstream \ \`-------G \ | ||
254 | 73 | \ \ \ \ | ||
255 | 74 | debian-packaging \ ,---------D--------\-----------J | ||
256 | 75 | C \ \ | ||
257 | 76 | ubuntu-packaging `----E------F--------I | ||
258 | 77 | |||
259 | 78 | Here there was a new upstream release (G) that Ubuntu packaged (I), and | ||
260 | 79 | then another one that Debian packaged, skipping G, at H and J. | ||
261 | 80 | |||
262 | 81 | Now, the way to solve this is to introduce the missing link. | ||
263 | 82 | |||
264 | 83 | debian-upstream ,------------------H------. | ||
265 | 84 | A-----------B \ \ | ||
266 | 85 | ubuntu-upstream \ \`-------G-----------\------K | ||
267 | 86 | \ \ \ \ | ||
268 | 87 | debian-packaging \ ,---------D--------\-----------J | ||
269 | 88 | C \ \ | ||
270 | 89 | ubuntu-packaging `----E------F--------I | ||
271 | 90 | |||
272 | 91 | at K, which isn't a real merge, as we just use the tree from H, but add | ||
273 | 92 | G as a parent and then we merge that in to Ubuntu. | ||
274 | 93 | |||
275 | 94 | debian-upstream ,------------------H------. | ||
276 | 95 | A-----------B \ \ | ||
277 | 96 | ubuntu-upstream \ \`-------G-----------\------K | ||
278 | 97 | \ \ \ \ \ | ||
279 | 98 | debian-packaging \ ,---------D--------\-----------J \ | ||
280 | 99 | C \ \ \ | ||
281 | 100 | ubuntu-packaging `----E------F--------I------------------L | ||
282 | 101 | |||
283 | 102 | At this point we can merge J->L to merge the Debian and Ubuntu changes. | ||
284 | 103 | |||
285 | 104 | :param tree: The `WorkingTree` of the merge target branch. | ||
286 | 105 | :param source: The merge source (packaging) branch. | ||
287 | 106 | """ | ||
288 | 107 | upstreams_diverged = False | ||
289 | 108 | t_upstream_reverted = False | ||
290 | 109 | target = tree.branch | ||
291 | 110 | |||
292 | 111 | source.lock_read() | ||
293 | 112 | try: | ||
294 | 113 | tree.lock_read() | ||
295 | 114 | try: | ||
296 | 115 | # "Unpack" the upstream versions and revision ids for the merge | ||
297 | 116 | # source and target branch respectively. | ||
298 | 117 | [(us_ver, us_revid), (ut_ver, ut_revid)] = _upstream_version_data(source, target) | ||
299 | 118 | |||
300 | 119 | # Did the upstream branches of the merge source/target diverge? | ||
301 | 120 | graph = source.repository.get_graph(target.repository) | ||
302 | 121 | upstreams_diverged = (len(graph.heads([us_revid, ut_revid])) > 1) | ||
303 | 122 | finally: | ||
304 | 123 | tree.unlock() | ||
305 | 124 | finally: | ||
306 | 125 | source.unlock() | ||
307 | 126 | |||
308 | 127 | if not upstreams_diverged: | ||
309 | 128 | return (upstreams_diverged, t_upstream_reverted) | ||
310 | 129 | |||
311 | 130 | # Instantiate a `DistributionBranch` object for the merge target | ||
312 | 131 | # (packaging) branch. | ||
313 | 132 | db = DistributionBranch(tree.branch, tree.branch) | ||
314 | 133 | tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..')) | ||
315 | 134 | |||
316 | 135 | # Extract the merge target's upstream tree into a temporary directory. | ||
317 | 136 | db.extract_upstream_tree(ut_revid, tempdir) | ||
318 | 137 | tmp_target_upstream_tree = db.upstream_tree | ||
319 | 138 | |||
320 | 139 | # Merge upstream branch tips to obtain a shared upstream parent. This | ||
321 | 140 | # will add revision K (see graph above) to a temporary merge target | ||
322 | 141 | # upstream tree. | ||
323 | 142 | tmp_target_upstream_tree.lock_write() | ||
324 | 143 | try: | ||
325 | 144 | if us_ver > ut_ver: | ||
326 | 145 | # The source upstream tree is more recent and the temporary | ||
327 | 146 | # target tree needs to be reshaped to match it. | ||
328 | 147 | tmp_target_upstream_tree.revert( | ||
329 | 148 | None, source.repository.revision_tree(us_revid)) | ||
330 | 149 | t_upstream_reverted = True | ||
331 | 150 | |||
332 | 151 | tmp_target_upstream_tree.set_parent_ids( | ||
333 | 152 | (ut_revid, us_revid)) | ||
334 | 153 | |||
335 | 154 | tmp_target_upstream_tree.commit( | ||
336 | 155 | 'Consolidated upstream tree for merging into target branch') | ||
337 | 156 | finally: | ||
338 | 157 | tmp_target_upstream_tree.unlock() | ||
339 | 158 | |||
340 | 159 | # Merge shared upstream parent into the target merge branch. This creates | ||
341 | 160 | # revison L in the digram above. | ||
342 | 161 | tree.lock_write() | ||
343 | 162 | try: | ||
344 | 163 | conflicts = tree.merge_from_branch(tmp_target_upstream_tree.branch) | ||
345 | 164 | if conflicts > 0: | ||
346 | 165 | raise errors.SharedUpstreamConflictsWithTargetPackaging() | ||
347 | 166 | else: | ||
348 | 167 | tree.commit('Merging shared upstream rev in to target branch.') | ||
349 | 168 | finally: | ||
350 | 169 | tree.unlock() | ||
351 | 170 | |||
352 | 171 | return (upstreams_diverged, t_upstream_reverted) | ||
353 | 0 | 172 | ||
354 | === modified file 'tests/__init__.py' | |||
355 | --- tests/__init__.py 2009-07-04 20:45:01 +0000 | |||
356 | +++ tests/__init__.py 2009-08-19 09:55:06 +0000 | |||
357 | @@ -118,6 +118,7 @@ | |||
358 | 118 | 'test_config', | 118 | 'test_config', |
359 | 119 | 'test_hooks', | 119 | 'test_hooks', |
360 | 120 | 'test_import_dsc', | 120 | 'test_import_dsc', |
361 | 121 | 'test_merge_package', | ||
362 | 121 | 'test_merge_upstream', | 122 | 'test_merge_upstream', |
363 | 122 | 'test_repack_tarball_extra', | 123 | 'test_repack_tarball_extra', |
364 | 123 | 'test_revspec', | 124 | 'test_revspec', |
365 | 124 | 125 | ||
366 | === added file 'tests/test_merge_package.py' | |||
367 | --- tests/test_merge_package.py 1970-01-01 00:00:00 +0000 | |||
368 | +++ tests/test_merge_package.py 2009-08-21 12:40:48 +0000 | |||
369 | @@ -0,0 +1,537 @@ | |||
370 | 1 | #!/usr/bin/env python | ||
371 | 2 | # -*- coding: iso-8859-15 -*- | ||
372 | 3 | # test_merge_package.py -- Merge packaging branches, fix ancestry as needed. | ||
373 | 4 | # Copyright (C) 2008 Canonical Ltd. | ||
374 | 5 | # | ||
375 | 6 | # This file is part of bzr-builddeb. | ||
376 | 7 | # | ||
377 | 8 | # bzr-builddeb is free software; you can redistribute it and/or modify | ||
378 | 9 | # it under the terms of the GNU General Public License as published by | ||
379 | 10 | # the Free Software Foundation; either version 2 of the License, or | ||
380 | 11 | # (at your option) any later version. | ||
381 | 12 | # | ||
382 | 13 | # bzr-builddeb is distributed in the hope that it will be useful, | ||
383 | 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
384 | 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
385 | 16 | # GNU General Public License for more details. | ||
386 | 17 | # | ||
387 | 18 | # You should have received a copy of the GNU General Public License | ||
388 | 19 | # along with bzr-builddeb; if not, write to the Free Software | ||
389 | 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
390 | 21 | |||
391 | 22 | import string | ||
392 | 23 | import unittest | ||
393 | 24 | |||
394 | 25 | from debian_bundle.changelog import Version | ||
395 | 26 | |||
396 | 27 | from bzrlib.errors import ConflictsInTree | ||
397 | 28 | from bzrlib.tests import TestCaseWithTransport | ||
398 | 29 | |||
399 | 30 | from bzrlib.plugins.builddeb import merge_package as MP | ||
400 | 31 | from bzrlib.plugins.builddeb.import_dsc import DistributionBranch | ||
401 | 32 | |||
402 | 33 | _Debian_changelog = '''\ | ||
403 | 34 | ipsec-tools (%s) unstable; urgency=high | ||
404 | 35 | |||
405 | 36 | * debian packaging -- %s | ||
406 | 37 | |||
407 | 38 | -- Nico Golde <nion@debian.org> Tue, %02d May 2009 13:26:14 +0200 | ||
408 | 39 | |||
409 | 40 | ''' | ||
410 | 41 | |||
411 | 42 | _Ubuntu_changelog = '''\ | ||
412 | 43 | ipsec-tools (%s) karmic; urgency=low | ||
413 | 44 | |||
414 | 45 | * ubuntu packaging -- %s | ||
415 | 46 | |||
416 | 47 | -- Jamie Strandboge <jamie@ubuntu.com> Fri, %02d Jul 2009 13:24:17 -0500 | ||
417 | 48 | |||
418 | 49 | ''' | ||
419 | 50 | |||
420 | 51 | |||
421 | 52 | def _prepend_log(text, path): | ||
422 | 53 | content = open(path).read() | ||
423 | 54 | fh = open(path, 'wb') | ||
424 | 55 | try: | ||
425 | 56 | fh.write(text+content) | ||
426 | 57 | finally: | ||
427 | 58 | fh.close() | ||
428 | 59 | |||
429 | 60 | |||
430 | 61 | class MergePackageTests(TestCaseWithTransport): | ||
431 | 62 | |||
432 | 63 | def test_latest_upstream_versions(self): | ||
433 | 64 | """Check correctness of upstream version computation.""" | ||
434 | 65 | ubup_o, debp_n, _ubuu, _debu = self._setup_debian_upstream_newer() | ||
435 | 66 | # Ubuntu upstream. | ||
436 | 67 | self.assertEquals( | ||
437 | 68 | MP._latest_version(ubup_o).upstream_version, '1.1.2') | ||
438 | 69 | # Debian upstream. | ||
439 | 70 | self.assertEquals( | ||
440 | 71 | MP._latest_version(debp_n).upstream_version, '2.0') | ||
441 | 72 | |||
442 | 73 | ubuntup, debianp = self._setup_upstreams_not_diverged() | ||
443 | 74 | # Ubuntu upstream. | ||
444 | 75 | self.assertEquals( | ||
445 | 76 | MP._latest_version(ubuntup).upstream_version, '1.4') | ||
446 | 77 | # Debian upstream. | ||
447 | 78 | self.assertEquals( | ||
448 | 79 | MP._latest_version(debianp).upstream_version, '2.2') | ||
449 | 80 | |||
450 | 81 | def test_debian_upstream_newer(self): | ||
451 | 82 | """Diverging upstreams (debian newer) don't cause merge conflicts. | ||
452 | 83 | |||
453 | 84 | The debian and ubuntu upstream branches will differ with regard to | ||
454 | 85 | the content of the file 'c'. | ||
455 | 86 | |||
456 | 87 | Furthermore the respective packaging branches will have a text | ||
457 | 88 | conflict in 'debian/changelog'. | ||
458 | 89 | |||
459 | 90 | The upstream conflict will be resolved by fix_ancestry_as_needed(). | ||
460 | 91 | Please note that the debian ancestry is more recent. | ||
461 | 92 | """ | ||
462 | 93 | ubup, debp, ubuu, debu = self._setup_debian_upstream_newer() | ||
463 | 94 | |||
464 | 95 | # Attempt a plain merge first. | ||
465 | 96 | conflicts = ubup.merge_from_branch( | ||
466 | 97 | debp.branch, to_revision=self.revid_debp_n_C) | ||
467 | 98 | |||
468 | 99 | # There are two conflicts in the 'c' and the 'debian/changelog' files | ||
469 | 100 | # respectively. | ||
470 | 101 | self.assertEquals(conflicts, 2) | ||
471 | 102 | conflict_paths = sorted([c.path for c in ubup.conflicts()]) | ||
472 | 103 | self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog']) | ||
473 | 104 | |||
474 | 105 | # Undo the failed merge. | ||
475 | 106 | ubup.revert() | ||
476 | 107 | |||
477 | 108 | # Check the versions present in the tree with the fixed ancestry. | ||
478 | 109 | v3 = "1.1.2" | ||
479 | 110 | v4 = "2.0" | ||
480 | 111 | db1 = DistributionBranch(ubup.branch, ubup.branch) | ||
481 | 112 | self.assertEqual(db1.has_upstream_version(v3), True) | ||
482 | 113 | # This version is in the diverged debian upstream tree and will | ||
483 | 114 | # hence not be present in the target ubuntu packaging branch. | ||
484 | 115 | self.assertEqual(db1.has_upstream_version(v4), False) | ||
485 | 116 | |||
486 | 117 | # The ubuntu upstream branch tip. | ||
487 | 118 | ubuu_tip = ubuu.branch.revision_history()[-1] | ||
488 | 119 | # The debian upstream branch tip. | ||
489 | 120 | debu_tip = debu.branch.revision_history()[-1] | ||
490 | 121 | # The ubuntu packaging branch tip. | ||
491 | 122 | ubup_tip_pre_fix = ubup.branch.revision_history()[-1] | ||
492 | 123 | |||
493 | 124 | # The first conflict is resolved by calling fix_ancestry_as_needed(). | ||
494 | 125 | upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup, debp.branch) | ||
495 | 126 | |||
496 | 127 | # The ancestry did diverge and needed to be fixed. | ||
497 | 128 | self.assertEquals(upstreams_diverged, True) | ||
498 | 129 | # The (temporary) target upstream branch had to be reverted to the | ||
499 | 130 | # source upstream branch since the latter was more recent. | ||
500 | 131 | self.assertEquals(t_upstream_reverted, True) | ||
501 | 132 | |||
502 | 133 | # Check the versions present in the tree with the fixed ancestry. | ||
503 | 134 | db2 = DistributionBranch(ubup.branch, ubup.branch) | ||
504 | 135 | self.assertEqual(db2.has_upstream_version(v3), True) | ||
505 | 136 | # The ancestry has been fixed and the missing debian upstream | ||
506 | 137 | # version should now be present in the target ubuntu packaging | ||
507 | 138 | # branch. | ||
508 | 139 | self.assertEqual(db2.has_upstream_version(v4), True) | ||
509 | 140 | |||
510 | 141 | # Now let's take a look at the fixed ubuntu packaging branch. | ||
511 | 142 | ubup_tip_post_fix = ubup.branch.revision_history()[-1] | ||
512 | 143 | ubup_parents_post_fix = ubup.branch.repository.revision_tree(ubup_tip_post_fix).get_parent_ids() | ||
513 | 144 | |||
514 | 145 | # The tip of the fixed ubuntu packaging branch has 2 parents. | ||
515 | 146 | self.assertEquals(len(ubup_parents_post_fix), 2) | ||
516 | 147 | |||
517 | 148 | # The left parent is the packaging branch tip before fixing. | ||
518 | 149 | self.assertEquals(ubup_parents_post_fix[0], ubup_tip_pre_fix) | ||
519 | 150 | |||
520 | 151 | # The right parent is derived from a merge | ||
521 | 152 | ubup_parents_sharedupstream = ubup.branch.repository.revision_tree(ubup_parents_post_fix[1]).get_parent_ids() | ||
522 | 153 | self.assertEquals(ubup_parents_sharedupstream, [ubuu_tip, debu_tip]) | ||
523 | 154 | |||
524 | 155 | # Try merging again. | ||
525 | 156 | conflicts = ubup.merge_from_branch( | ||
526 | 157 | debp.branch, to_revision=self.revid_debp_n_C) | ||
527 | 158 | |||
528 | 159 | # And, voila, only the packaging branch conflict remains. | ||
529 | 160 | self.assertEquals(conflicts, 1) | ||
530 | 161 | conflict_paths = sorted([c.path for c in ubup.conflicts()]) | ||
531 | 162 | self.assertEquals(conflict_paths, [u'debian/changelog']) | ||
532 | 163 | |||
533 | 164 | def test_debian_upstream_older(self): | ||
534 | 165 | """Diverging upstreams (debian older) don't cause merge conflicts. | ||
535 | 166 | |||
536 | 167 | The debian and ubuntu upstream branches will differ with regard to | ||
537 | 168 | the content of the file 'c'. | ||
538 | 169 | |||
539 | 170 | Furthermore the respective packaging branches will have a text | ||
540 | 171 | conflict in 'debian/changelog'. | ||
541 | 172 | |||
542 | 173 | The upstream conflict will be resolved by fix_ancestry_as_needed(). | ||
543 | 174 | Please note that the debian ancestry is older in this case. | ||
544 | 175 | """ | ||
545 | 176 | ubup_n, debp_o = self._setup_debian_upstream_older() | ||
546 | 177 | |||
547 | 178 | # Attempt a plain merge first. | ||
548 | 179 | conflicts = ubup_n.merge_from_branch( | ||
549 | 180 | debp_o.branch, to_revision=self.revid_debp_o_C) | ||
550 | 181 | |||
551 | 182 | # There are two conflicts in the 'c' and the 'debian/changelog' files | ||
552 | 183 | # respectively. | ||
553 | 184 | self.assertEquals(conflicts, 2) | ||
554 | 185 | conflict_paths = sorted([c.path for c in ubup_n.conflicts()]) | ||
555 | 186 | self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog']) | ||
556 | 187 | |||
557 | 188 | # Undo the failed merge. | ||
558 | 189 | ubup_n.revert() | ||
559 | 190 | |||
560 | 191 | # The first conflict is resolved by calling fix_ancestry_as_needed(). | ||
561 | 192 | upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup_n, debp_o.branch) | ||
562 | 193 | |||
563 | 194 | # The ancestry did diverge and needed to be fixed. | ||
564 | 195 | self.assertEquals(upstreams_diverged, True) | ||
565 | 196 | # The target upstream branch was more recent in this case and hence | ||
566 | 197 | # was not reverted to the source upstream branch. | ||
567 | 198 | self.assertEquals(t_upstream_reverted, False) | ||
568 | 199 | |||
569 | 200 | # Try merging again. | ||
570 | 201 | conflicts = ubup_n.merge_from_branch( | ||
571 | 202 | debp_o.branch, to_revision=self.revid_debp_o_C) | ||
572 | 203 | |||
573 | 204 | # And, voila, only the packaging branch conflict remains. | ||
574 | 205 | self.assertEquals(conflicts, 1) | ||
575 | 206 | conflict_paths = sorted([c.path for c in ubup_n.conflicts()]) | ||
576 | 207 | self.assertEquals(conflict_paths, [u'debian/changelog']) | ||
577 | 208 | |||
578 | 209 | def test_upstreams_not_diverged(self): | ||
579 | 210 | """Non-diverging upstreams result in a normal merge. | ||
580 | 211 | |||
581 | 212 | The debian and ubuntu upstream branches will not have diverged | ||
582 | 213 | this time. | ||
583 | 214 | |||
584 | 215 | The packaging branches will have a conflict in 'debian/changelog'. | ||
585 | 216 | fix_ancestry_as_needed() will return as soon as establishing that | ||
586 | 217 | the upstreams have not diverged. | ||
587 | 218 | """ | ||
588 | 219 | ubuntup, debianp = self._setup_upstreams_not_diverged() | ||
589 | 220 | |||
590 | 221 | # Attempt a plain merge first. | ||
591 | 222 | conflicts = ubuntup.merge_from_branch( | ||
592 | 223 | debianp.branch, to_revision=self.revid_debianp_C) | ||
593 | 224 | |||
594 | 225 | # There is only a conflict in the 'debian/changelog' file. | ||
595 | 226 | self.assertEquals(conflicts, 1) | ||
596 | 227 | conflict_paths = sorted([c.path for c in ubuntup.conflicts()]) | ||
597 | 228 | self.assertEquals(conflict_paths, [u'debian/changelog']) | ||
598 | 229 | |||
599 | 230 | # Undo the failed merge. | ||
600 | 231 | ubuntup.revert() | ||
601 | 232 | |||
602 | 233 | # The conflict is *not* resolved by calling fix_ancestry_as_needed(). | ||
603 | 234 | upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubuntup, debianp.branch) | ||
604 | 235 | |||
605 | 236 | # The ancestry did *not* diverge. | ||
606 | 237 | self.assertEquals(upstreams_diverged, False) | ||
607 | 238 | # The upstreams have not diverged, hence no need to fix/revert | ||
608 | 239 | # either of them. | ||
609 | 240 | self.assertEquals(t_upstream_reverted, False) | ||
610 | 241 | |||
611 | 242 | # Try merging again. | ||
612 | 243 | conflicts = ubuntup.merge_from_branch( | ||
613 | 244 | debianp.branch, to_revision=self.revid_debianp_C) | ||
614 | 245 | |||
615 | 246 | # The packaging branch conflict we saw above is still there. | ||
616 | 247 | self.assertEquals(conflicts, 1) | ||
617 | 248 | conflict_paths = sorted([c.path for c in ubuntup.conflicts()]) | ||
618 | 249 | self.assertEquals(conflict_paths, [u'debian/changelog']) | ||
619 | 250 | |||
620 | 251 | def _setup_debian_upstream_newer(self): | ||
621 | 252 | """ | ||
622 | 253 | Set up the following test configuration (debian upstream newer). | ||
623 | 254 | |||
624 | 255 | debian-upstream ,------------------H | ||
625 | 256 | A-----------B \ | ||
626 | 257 | ubuntu-upstream \ \`-------G \ | ||
627 | 258 | \ \ \ \ | ||
628 | 259 | debian-packaging \ ,---------D--------\-----------J | ||
629 | 260 | C \ | ||
630 | 261 | ubuntu-packaging `----E---------------I | ||
631 | 262 | |||
632 | 263 | where: | ||
633 | 264 | - A = 1.0 | ||
634 | 265 | - B = 1.1 | ||
635 | 266 | - H = 2.0 | ||
636 | 267 | |||
637 | 268 | - G = 1.1.2 | ||
638 | 269 | |||
639 | 270 | - C = 1.0-1 | ||
640 | 271 | - D = 1.1-1 | ||
641 | 272 | - J = 2.0-1 | ||
642 | 273 | |||
643 | 274 | - E = 1.0-1ubuntu1 | ||
644 | 275 | - I = 1.1.2-0ubuntu1 | ||
645 | 276 | |||
646 | 277 | Please note that the debian and ubuntu branches will have a conflict | ||
647 | 278 | with respect to the file 'c'. | ||
648 | 279 | """ | ||
649 | 280 | # Set up the debian upstream branch. | ||
650 | 281 | name = 'debu-n' | ||
651 | 282 | vdata = [ | ||
652 | 283 | ('upstream-1.0', ('a',), None, None), | ||
653 | 284 | ('upstream-1.1', ('b',), None, None), | ||
654 | 285 | ('upstream-2.0', ('c',), None, None), | ||
655 | 286 | ] | ||
656 | 287 | debu_n = self._setup_branch(name, vdata) | ||
657 | 288 | |||
658 | 289 | # Set up the debian packaging branch. | ||
659 | 290 | name = 'debp-n' | ||
660 | 291 | debp_n = self.make_branch_and_tree(name) | ||
661 | 292 | debp_n.pull(debu_n.branch, stop_revision=self.revid_debu_n_A) | ||
662 | 293 | |||
663 | 294 | vdata = [ | ||
664 | 295 | ('1.0-1', ('debian/', 'debian/changelog'), None, None), | ||
665 | 296 | ('1.1-1', ('o',), debu_n, self.revid_debu_n_B), | ||
666 | 297 | ('2.0-1', ('p',), debu_n, self.revid_debu_n_C), | ||
667 | 298 | ] | ||
668 | 299 | self._setup_branch(name, vdata, debp_n, 'd') | ||
669 | 300 | |||
670 | 301 | # Set up the ubuntu upstream branch. | ||
671 | 302 | name = 'ubuu-o' | ||
672 | 303 | ubuu_o = debu_n.bzrdir.sprout( | ||
673 | 304 | name, revision_id=self.revid_debu_n_B).open_workingtree() | ||
674 | 305 | |||
675 | 306 | vdata = [ | ||
676 | 307 | ('upstream-1.1.2', ('c',), None, None), | ||
677 | 308 | ] | ||
678 | 309 | self._setup_branch(name, vdata, ubuu_o) | ||
679 | 310 | |||
680 | 311 | # Set up the ubuntu packaging branch. | ||
681 | 312 | name = 'ubup-o' | ||
682 | 313 | ubup_o = debu_n.bzrdir.sprout( | ||
683 | 314 | name, revision_id=self.revid_debu_n_A).open_workingtree() | ||
684 | 315 | |||
685 | 316 | vdata = [ | ||
686 | 317 | ('1.0-1ubuntu1', (), debp_n, self.revid_debp_n_A), | ||
687 | 318 | ('1.1.2-0ubuntu1', (), ubuu_o, self.revid_ubuu_o_A), | ||
688 | 319 | ] | ||
689 | 320 | self._setup_branch(name, vdata, ubup_o, 'u') | ||
690 | 321 | |||
691 | 322 | # Return the ubuntu and the debian packaging branches. | ||
692 | 323 | return (ubup_o, debp_n, ubuu_o, debu_n) | ||
693 | 324 | |||
694 | 325 | def _setup_debian_upstream_older(self): | ||
695 | 326 | """ | ||
696 | 327 | Set up the following test configuration (debian upstream older). | ||
697 | 328 | |||
698 | 329 | debian-upstream ,----H-------------. | ||
699 | 330 | A-----------B \ | ||
700 | 331 | ubuntu-upstream \ \`-----------G \ | ||
701 | 332 | \ \ \ \ | ||
702 | 333 | debian-packaging \ ,---------D------------\-------J | ||
703 | 334 | C \ | ||
704 | 335 | ubuntu-packaging `----E-------------------I | ||
705 | 336 | |||
706 | 337 | where: | ||
707 | 338 | - A = 1.0 | ||
708 | 339 | - B = 1.1 | ||
709 | 340 | - H = 1.1.3 | ||
710 | 341 | |||
711 | 342 | - G = 2.1 | ||
712 | 343 | |||
713 | 344 | - C = 1.0-1 | ||
714 | 345 | - D = 1.1-1 | ||
715 | 346 | - J = 1.1.3-1 | ||
716 | 347 | |||
717 | 348 | - E = 1.0-1ubuntu1 | ||
718 | 349 | - I = 2.1-0ubuntu1 | ||
719 | 350 | |||
720 | 351 | Please note that the debian and ubuntu branches will have a conflict | ||
721 | 352 | with respect to the file 'c'. | ||
722 | 353 | """ | ||
723 | 354 | # Set up the debian upstream branch. | ||
724 | 355 | name = 'debu-o' | ||
725 | 356 | vdata = [ | ||
726 | 357 | ('upstream-1.0', ('a',), None, None), | ||
727 | 358 | ('upstream-1.1', ('b',), None, None), | ||
728 | 359 | ('upstream-1.1.3', ('c',), None, None), | ||
729 | 360 | ] | ||
730 | 361 | debu_o = self._setup_branch(name, vdata) | ||
731 | 362 | |||
732 | 363 | # Set up the debian packaging branch. | ||
733 | 364 | name = 'debp-o' | ||
734 | 365 | debp_o = self.make_branch_and_tree(name) | ||
735 | 366 | debp_o.pull(debu_o.branch, stop_revision=self.revid_debu_o_A) | ||
736 | 367 | |||
737 | 368 | vdata = [ | ||
738 | 369 | ('1.0-1', ('debian/', 'debian/changelog'), None, None), | ||
739 | 370 | ('1.1-1', ('o',), debu_o, self.revid_debu_o_B), | ||
740 | 371 | ('1.1.3-1', ('p',), debu_o, self.revid_debu_o_C), | ||
741 | 372 | ] | ||
742 | 373 | self._setup_branch(name, vdata, debp_o, 'd') | ||
743 | 374 | |||
744 | 375 | # Set up the ubuntu upstream branch. | ||
745 | 376 | name = 'ubuu-n' | ||
746 | 377 | ubuu_n = debu_o.bzrdir.sprout( | ||
747 | 378 | name, revision_id=self.revid_debu_o_B).open_workingtree() | ||
748 | 379 | |||
749 | 380 | vdata = [ | ||
750 | 381 | ('upstream-2.1', ('c',), None, None), | ||
751 | 382 | ] | ||
752 | 383 | self._setup_branch(name, vdata, ubuu_n) | ||
753 | 384 | |||
754 | 385 | # Set up the ubuntu packaging branch. | ||
755 | 386 | name = 'ubup-n' | ||
756 | 387 | ubup_n = debu_o.bzrdir.sprout( | ||
757 | 388 | name, revision_id=self.revid_debu_o_A).open_workingtree() | ||
758 | 389 | |||
759 | 390 | vdata = [ | ||
760 | 391 | ('1.0-1ubuntu1', (), debp_o, self.revid_debp_o_A), | ||
761 | 392 | ('2.1-0ubuntu1', (), ubuu_n, self.revid_ubuu_n_A), | ||
762 | 393 | ] | ||
763 | 394 | self._setup_branch(name, vdata, ubup_n, 'u') | ||
764 | 395 | |||
765 | 396 | # Return the ubuntu and the debian packaging branches. | ||
766 | 397 | return (ubup_n, debp_o) | ||
767 | 398 | |||
768 | 399 | def _setup_upstreams_not_diverged(self): | ||
769 | 400 | """ | ||
770 | 401 | Set up a test configuration where the usptreams have not diverged. | ||
771 | 402 | |||
772 | 403 | debian-upstream .-----G | ||
773 | 404 | A-----------B-----H \ | ||
774 | 405 | ubuntu-upstream \ \ \ \ | ||
775 | 406 | \ \ \ \ | ||
776 | 407 | debian-packaging \ ,---------D-----\-------J | ||
777 | 408 | C \ | ||
778 | 409 | ubuntu-packaging `----E------------I | ||
779 | 410 | |||
780 | 411 | where: | ||
781 | 412 | - A = 1.0 | ||
782 | 413 | - B = 1.1 | ||
783 | 414 | - H = 1.4 | ||
784 | 415 | |||
785 | 416 | - G = 2.2 | ||
786 | 417 | |||
787 | 418 | - C = 1.0-1 | ||
788 | 419 | - D = 1.1-1 | ||
789 | 420 | - J = 2.2-1 | ||
790 | 421 | |||
791 | 422 | - E = 1.0-1ubuntu1 | ||
792 | 423 | - I = 1.4-0ubuntu1 | ||
793 | 424 | |||
794 | 425 | Please note that there's only one shared upstream branch in this case. | ||
795 | 426 | """ | ||
796 | 427 | # Set up the upstream branch. | ||
797 | 428 | name = 'upstream' | ||
798 | 429 | vdata = [ | ||
799 | 430 | ('upstream-1.0', ('a',), None, None), | ||
800 | 431 | ('upstream-1.1', ('b',), None, None), | ||
801 | 432 | ('upstream-1.4', ('c',), None, None), | ||
802 | 433 | ] | ||
803 | 434 | upstream = self._setup_branch(name, vdata) | ||
804 | 435 | |||
805 | 436 | # Set up the debian upstream branch. | ||
806 | 437 | name = 'dupstream' | ||
807 | 438 | dupstream = upstream.bzrdir.sprout(name).open_workingtree() | ||
808 | 439 | vdata = [ | ||
809 | 440 | ('upstream-2.2', (), None, None), | ||
810 | 441 | ] | ||
811 | 442 | dupstream = self._setup_branch(name, vdata, dupstream) | ||
812 | 443 | |||
813 | 444 | # Set up the debian packaging branch. | ||
814 | 445 | name = 'debianp' | ||
815 | 446 | debianp = self.make_branch_and_tree(name) | ||
816 | 447 | debianp.pull(dupstream.branch, stop_revision=self.revid_upstream_A) | ||
817 | 448 | |||
818 | 449 | vdata = [ | ||
819 | 450 | ('1.0-1', ('debian/', 'debian/changelog'), None, None), | ||
820 | 451 | ('1.1-1', ('o',), dupstream, self.revid_upstream_B), | ||
821 | 452 | ('2.2-1', ('p',), dupstream, self.revid_dupstream_A), | ||
822 | 453 | ] | ||
823 | 454 | self._setup_branch(name, vdata, debianp, 'd') | ||
824 | 455 | |||
825 | 456 | # Set up the ubuntu packaging branch. | ||
826 | 457 | name = 'ubuntup' | ||
827 | 458 | ubuntup = upstream.bzrdir.sprout( | ||
828 | 459 | name, revision_id=self.revid_upstream_A).open_workingtree() | ||
829 | 460 | |||
830 | 461 | vdata = [ | ||
831 | 462 | ('1.0-1ubuntu1', (), debianp, self.revid_debianp_A), | ||
832 | 463 | ('1.4-0ubuntu1', (), upstream, self.revid_upstream_C), | ||
833 | 464 | ] | ||
834 | 465 | self._setup_branch(name, vdata, ubuntup, 'u') | ||
835 | 466 | |||
836 | 467 | # Return the ubuntu and the debian packaging branches. | ||
837 | 468 | return (ubuntup, debianp) | ||
838 | 469 | |||
839 | 470 | def _setup_branch(self, name, vdata, tree=None, log_format=None): | ||
840 | 471 | vids = list(string.ascii_uppercase) | ||
841 | 472 | days = range(len(string.ascii_uppercase)) | ||
842 | 473 | |||
843 | 474 | if tree is None: | ||
844 | 475 | tree = self.make_branch_and_tree(name) | ||
845 | 476 | |||
846 | 477 | tree.lock_write() | ||
847 | 478 | self.addCleanup(tree.unlock) | ||
848 | 479 | |||
849 | 480 | def revid_name(vid): | ||
850 | 481 | return 'revid_%s_%s' % (name.replace('-', '_'), vid) | ||
851 | 482 | |||
852 | 483 | def add_paths(paths): | ||
853 | 484 | qpaths = ['%s/%s' % (name, path) for path in paths] | ||
854 | 485 | self.build_tree(qpaths) | ||
855 | 486 | tree.add(paths) | ||
856 | 487 | |||
857 | 488 | def changelog(vdata, vid): | ||
858 | 489 | result = '' | ||
859 | 490 | day = days.pop(0) | ||
860 | 491 | if isinstance(vdata, tuple): | ||
861 | 492 | uver, dver = vdata[:2] | ||
862 | 493 | ucle = _Ubuntu_changelog % (uver, vid, day) | ||
863 | 494 | dcle = _Debian_changelog % (dver, vid, day) | ||
864 | 495 | result = ucle + dcle | ||
865 | 496 | else: | ||
866 | 497 | if log_format == 'u': | ||
867 | 498 | result = _Ubuntu_changelog % (vdata, vid, day) | ||
868 | 499 | elif log_format == 'd': | ||
869 | 500 | result = _Debian_changelog % (vdata, vid, day) | ||
870 | 501 | |||
871 | 502 | return result | ||
872 | 503 | |||
873 | 504 | def commit(msg, version): | ||
874 | 505 | vid = vids.pop(0) | ||
875 | 506 | if log_format is not None: | ||
876 | 507 | cle = changelog(version, vid) | ||
877 | 508 | p = '%s/work/%s/debian/changelog' % (self.test_base_dir, name) | ||
878 | 509 | _prepend_log(cle, p) | ||
879 | 510 | revid = tree.commit('%s: %s' % (vid, msg)) | ||
880 | 511 | setattr(self, revid_name(vid), revid) | ||
881 | 512 | tree.branch.tags.set_tag(version, revid) | ||
882 | 513 | |||
883 | 514 | def tree_nick(tree): | ||
884 | 515 | return str(tree)[1:-1].split('/')[-1] | ||
885 | 516 | |||
886 | 517 | for version, paths, utree, urevid in vdata: | ||
887 | 518 | msg = '' | ||
888 | 519 | if utree is not None: | ||
889 | 520 | tree.merge_from_branch(utree.branch, to_revision=urevid) | ||
890 | 521 | utree.branch.tags.merge_to(tree.branch.tags) | ||
891 | 522 | if urevid is not None: | ||
892 | 523 | msg += 'Merged tree %s|%s. ' % (tree_nick(utree), urevid) | ||
893 | 524 | else: | ||
894 | 525 | msg += 'Merged tree %s. ' % utree | ||
895 | 526 | if paths is not None: | ||
896 | 527 | add_paths(paths) | ||
897 | 528 | msg += 'Added paths: %s. ' % str(paths) | ||
898 | 529 | |||
899 | 530 | commit(msg, version) | ||
900 | 531 | |||
901 | 532 | return tree | ||
902 | 533 | |||
903 | 534 | |||
904 | 535 | if __name__ == '__main__': | ||
905 | 536 | suite = unittest.TestLoader().loadTestsFromTestCase(MergePackageTests) | ||
906 | 537 | unittest.TextTestRunner(verbosity=2).run(suite) | ||
907 | 0 | 538 | ||
908 | === modified file 'upstream.py' | |||
909 | --- upstream.py 2009-07-26 18:21:49 +0000 | |||
910 | +++ upstream.py 2009-08-06 08:40:05 +0000 | |||
911 | @@ -79,7 +79,7 @@ | |||
912 | 79 | db = DistributionBranch(self.branch, None, tree=self.tree) | 79 | db = DistributionBranch(self.branch, None, tree=self.tree) |
913 | 80 | if not db.has_upstream_version_in_packaging_branch(version): | 80 | if not db.has_upstream_version_in_packaging_branch(version): |
914 | 81 | raise PackageVersionNotPresent(package, version, self) | 81 | raise PackageVersionNotPresent(package, version, self) |
916 | 82 | revid = db._revid_of_upstream_version_from_branch(version) | 82 | revid = db.revid_of_upstream_version_from_branch(version) |
917 | 83 | if not db.has_pristine_tar_delta(revid): | 83 | if not db.has_pristine_tar_delta(revid): |
918 | 84 | raise PackageVersionNotPresent(package, version, self) | 84 | raise PackageVersionNotPresent(package, version, self) |
919 | 85 | info("Using pristine-tar to reconstruct the needed tarball.") | 85 | info("Using pristine-tar to reconstruct the needed tarball.") |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
James Westby (james-w) wrote : | # |
Excerpts from Muharem Hrnjadovic's message of Fri Aug 21 12:51:08 UTC 2009:
> > This is the big question I have left though. How does the user continue
> > after this? There should be a clear way to continue once they have committed,
> > and the exception should tell them how to proceed.
>
> How about this?
>
> {{{
> The "merge-package" command has detected diverged upstream
> branches for the merge source and target. A shared upstream
> revision was constructed to remedy the problem.
>
> However, merging the shared upstream revision into the merge
> target resulted in conflicts.
>
> Please proceed as follows:
>
> 1 - Resolve the current merge conflicts in the merge target
> directory and commit the changes.
> 2 - Perform a plain "bzr merge <source-
> command, resolve any ensuing packaging branch conflicts
> and commit once satisfied with the changes.
> }}}
For starters this is bit verbose, we can't really format it like that
in an error message, so it needs to be a couple of sentences.
I don't think they need to know that a new "shared upstream" was
created, you can just say that there are conflicts but they are
not finished.
Should we direct them to "bzr merge-package" again? It becomes
equivalent, but I think it's better to not confuse them with
when they can use "bzr merge" and when they can't.
You don't need to tell them what to do after they've run that again,
it can just tell them when it is done.
Would it be worth saying that if they don't like what they see
they can just "bzr revert" to get back to where they started?
Looking at the incremental diff the major issue I see remaining
is that you lock and unlock the tree, only to lock it again.
Lock it once, and hold that lock until you don't reference the
tree or anything that makes use of it any more.
Writing this mail also interested me in whether you ever get any
conflicts in the case when merging the faked upstream merge
in to the packaging branch in the case where your upstream
version was newer than the other upstream version.
Thanks,
James
- 404. By Muharem Hrnjadovic
-
Target branch is now being locked once only; James' review comments, round 7
- 405. By Muharem Hrnjadovic
-
Enhanced error message for case where merging the shared upstreams revision results in conflicts; James' review comments, round 8
- 406. By Muharem Hrnjadovic
-
Minor fix.
- 407. By Muharem Hrnjadovic
-
Slightly cleaned-up test.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Muharem Hrnjadovic (al-maisan) wrote : | # |
James Westby wrote:
> Excerpts from Muharem Hrnjadovic's message of Fri Aug 21 12:51:08 UTC 2009:
>>> This is the big question I have left though. How does the user continue
>>> after this? There should be a clear way to continue once they have committed,
>>> and the exception should tell them how to proceed.
>> How about this?
>>
>> {{{
>> The "merge-package" command has detected diverged upstream
>> branches for the merge source and target. A shared upstream
>> revision was constructed to remedy the problem.
>>
>> However, merging the shared upstream revision into the merge
>> target resulted in conflicts.
>>
>> Please proceed as follows:
>>
>> 1 - Resolve the current merge conflicts in the merge target
>> directory and commit the changes.
>> 2 - Perform a plain "bzr merge <source-
>> command, resolve any ensuing packaging branch conflicts
>> and commit once satisfied with the changes.
>> }}}
>
> For starters this is bit verbose, we can't really format it like that
> in an error message, so it needs to be a couple of sentences.
>
> I don't think they need to know that a new "shared upstream" was
> created, you can just say that there are conflicts but they are
> not finished.
>
> Should we direct them to "bzr merge-package" again? It becomes
> equivalent, but I think it's better to not confuse them with
> when they can use "bzr merge" and when they can't.
>
> You don't need to tell them what to do after they've run that again,
> it can just tell them when it is done.
>
> Would it be worth saying that if they don't like what they see
> they can just "bzr revert" to get back to where they started?
Hello James,
thank you very much for your suggestions above. They are all good. I
hope the following text is more suitable.
{{{
The upstream branches for the merge source and target have diverged.
Unfortunately, the attempt to fix this problem resulted in conflicts.
Please resolve these and re-run the "merge-package" command to finish.
Alternatively, you can restore the original merge target state by
running "bzr revert".
}}}
>
> Looking at the incremental diff the major issue I see remaining
> is that you lock and unlock the tree, only to lock it again.
> Lock it once, and hold that lock until you don't reference the
> tree or anything that makes use of it any more.
Done.
> Writing this mail also interested me in whether you ever get any
> conflicts in the case when merging the faked upstream merge
> in to the packaging branch in the case where your upstream
> version was newer than the other upstream version.
That would be the test_debian_
get any conflicts.
Please find the incremental diff enclosed.
Best regards
--
Muharem Hrnjadovic <email address hidden>
Public key id : B2BBFCFC
Key fingerprint : A5A3 CC67 2B87 D641 103F 5602 219F 6B60 B2BB FCFC
1 | === modified file 'cmds.py' | |||
2 | --- cmds.py 2009-08-19 09:06:47 +0000 | |||
3 | +++ cmds.py 2009-08-24 10:28:15 +0000 | |||
4 | @@ -901,7 +901,13 @@ | |||
5 | 901 | fix_ancestry_as_needed(tree, source_branch) | 901 | fix_ancestry_as_needed(tree, source_branch) |
6 | 902 | 902 | ||
7 | 903 | # Merge source packaging branch in to the target packaging branch. | 903 | # Merge source packaging branch in to the target packaging branch. |
9 | 904 | tree.merge_from_branch(source_branch) | 904 | conflicts = tree.merge_from_branch(source_branch) |
10 | 905 | if conflicts > 0: | ||
11 | 906 | info('The merge resulted in %s conflicts. Please resolve these ' | ||
12 | 907 | 'and commit the changes with "bzr commit".' % conflicts) | ||
13 | 908 | else: | ||
14 | 909 | info('The merge resulted in no conflicts. You may commit the ' | ||
15 | 910 | 'changes by running "bzr commit".') | ||
16 | 905 | 911 | ||
17 | 906 | 912 | ||
18 | 907 | class cmd_test_builddeb(Command): | 913 | class cmd_test_builddeb(Command): |
19 | 908 | 914 | ||
20 | === modified file 'errors.py' | |||
21 | --- errors.py 2009-08-19 14:09:53 +0000 | |||
22 | +++ errors.py 2009-08-24 10:36:04 +0000 | |||
23 | @@ -179,18 +179,5 @@ | |||
24 | 179 | 179 | ||
25 | 180 | class SharedUpstreamConflictsWithTargetPackaging(BzrError): | 180 | class SharedUpstreamConflictsWithTargetPackaging(BzrError): |
26 | 181 | _fmt = ('''\ | 181 | _fmt = ('''\ |
42 | 182 | The "merge-package" command has detected diverged upstream | 182 | The upstream branches for the merge source and target have diverged. Unfortunately, the attempt to fix this problem resulted in conflicts. Please resolve these and re-run the "merge-package" command to finish. |
43 | 183 | branches for the merge source and target. A shared upstream | 183 | Alternatively, you can restore the original merge target state by running "bzr revert".''') |
29 | 184 | revision was constructed to remedy the problem. | ||
30 | 185 | |||
31 | 186 | However, merging the shared upstream revision into the merge | ||
32 | 187 | target resulted in conflicts. | ||
33 | 188 | |||
34 | 189 | Please proceed as follows: | ||
35 | 190 | |||
36 | 191 | 1 - Resolve the current merge conflicts in the merge target | ||
37 | 192 | directory and commit the changes. | ||
38 | 193 | 2 - Perform a plain "bzr merge <source-packaging-branch>" | ||
39 | 194 | command, resolve any ensuing packaging branch conflicts | ||
40 | 195 | and commit once satisfied with the changes. | ||
41 | 196 | ''') | ||
44 | 197 | 184 | ||
45 | === modified file 'merge_package.py' | |||
46 | --- merge_package.py 2009-08-20 07:39:39 +0000 | |||
47 | +++ merge_package.py 2009-08-24 10:22:13 +0000 | |||
48 | @@ -110,7 +110,7 @@ | |||
49 | 110 | 110 | ||
50 | 111 | source.lock_read() | 111 | source.lock_read() |
51 | 112 | try: | 112 | try: |
53 | 113 | tree.lock_read() | 113 | tree.lock_write() |
54 | 114 | try: | 114 | try: |
55 | 115 | # "Unpack" the upstream versions and revision ids for the merge | 115 | # "Unpack" the upstream versions and revision ids for the merge |
56 | 116 | # source and target branch respectively. | 116 | # source and target branch respectively. |
57 | @@ -119,53 +119,50 @@ | |||
58 | 119 | # Did the upstream branches of the merge source/target diverge? | 119 | # Did the upstream branches of the merge source/target diverge? |
59 | 120 | graph = source.repository.get_graph(target.repository) | 120 | graph = source.repository.get_graph(target.repository) |
60 | 121 | upstreams_diverged = (len(graph.heads([us_revid, ut_revid])) > 1) | 121 | upstreams_diverged = (len(graph.heads([us_revid, ut_revid])) > 1) |
61 | 122 | |||
62 | 123 | # No, we're done! | ||
63 | 124 | if not upstreams_diverged: | ||
64 | 125 | return (upstreams_diverged, t_upstream_reverted) | ||
65 | 126 | |||
66 | 127 | # Instantiate a `DistributionBranch` object for the merge target | ||
67 | 128 | # (packaging) branch. | ||
68 | 129 | db = DistributionBranch(tree.branch, tree.branch) | ||
69 | 130 | tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..')) | ||
70 | 131 | |||
71 | 132 | # Extract the merge target's upstream tree into a temporary | ||
72 | 133 | # directory. | ||
73 | 134 | db.extract_upstream_tree(ut_revid, tempdir) | ||
74 | 135 | tmp_target_utree = db.upstream_tree | ||
75 | 136 | |||
76 | 137 | # Merge upstream branch tips to obtain a shared upstream parent. | ||
77 | 138 | # This will add revision K (see graph above) to a temporary merge | ||
78 | 139 | # target upstream tree. | ||
79 | 140 | tmp_target_utree.lock_write() | ||
80 | 141 | try: | ||
81 | 142 | if us_ver > ut_ver: | ||
82 | 143 | # The source upstream tree is more recent and the | ||
83 | 144 | # temporary target tree needs to be reshaped to match it. | ||
84 | 145 | tmp_target_utree.revert( | ||
85 | 146 | None, source.repository.revision_tree(us_revid)) | ||
86 | 147 | t_upstream_reverted = True | ||
87 | 148 | |||
88 | 149 | tmp_target_utree.set_parent_ids((ut_revid, us_revid)) | ||
89 | 150 | tmp_target_utree.commit( | ||
90 | 151 | 'Prepared upstream tree for merging into target branch.') | ||
91 | 152 | finally: | ||
92 | 153 | tmp_target_utree.unlock() | ||
93 | 154 | |||
94 | 155 | # Merge shared upstream parent into the target merge branch. This | ||
95 | 156 | # creates revison L in the digram above. | ||
96 | 157 | conflicts = tree.merge_from_branch(tmp_target_utree.branch) | ||
97 | 158 | if conflicts > 0: | ||
98 | 159 | raise errors.SharedUpstreamConflictsWithTargetPackaging() | ||
99 | 160 | else: | ||
100 | 161 | tree.commit('Merging shared upstream rev into target branch.') | ||
101 | 162 | |||
102 | 122 | finally: | 163 | finally: |
103 | 123 | tree.unlock() | 164 | tree.unlock() |
104 | 124 | finally: | 165 | finally: |
105 | 125 | source.unlock() | 166 | source.unlock() |
106 | 126 | 167 | ||
107 | 127 | if not upstreams_diverged: | ||
108 | 128 | return (upstreams_diverged, t_upstream_reverted) | ||
109 | 129 | |||
110 | 130 | # Instantiate a `DistributionBranch` object for the merge target | ||
111 | 131 | # (packaging) branch. | ||
112 | 132 | db = DistributionBranch(tree.branch, tree.branch) | ||
113 | 133 | tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..')) | ||
114 | 134 | |||
115 | 135 | # Extract the merge target's upstream tree into a temporary directory. | ||
116 | 136 | db.extract_upstream_tree(ut_revid, tempdir) | ||
117 | 137 | tmp_target_upstream_tree = db.upstream_tree | ||
118 | 138 | |||
119 | 139 | # Merge upstream branch tips to obtain a shared upstream parent. This | ||
120 | 140 | # will add revision K (see graph above) to a temporary merge target | ||
121 | 141 | # upstream tree. | ||
122 | 142 | tmp_target_upstream_tree.lock_write() | ||
123 | 143 | try: | ||
124 | 144 | if us_ver > ut_ver: | ||
125 | 145 | # The source upstream tree is more recent and the temporary | ||
126 | 146 | # target tree needs to be reshaped to match it. | ||
127 | 147 | tmp_target_upstream_tree.revert( | ||
128 | 148 | None, source.repository.revision_tree(us_revid)) | ||
129 | 149 | t_upstream_reverted = True | ||
130 | 150 | |||
131 | 151 | tmp_target_upstream_tree.set_parent_ids( | ||
132 | 152 | (ut_revid, us_revid)) | ||
133 | 153 | |||
134 | 154 | tmp_target_upstream_tree.commit( | ||
135 | 155 | 'Consolidated upstream tree for merging into target branch') | ||
136 | 156 | finally: | ||
137 | 157 | tmp_target_upstream_tree.unlock() | ||
138 | 158 | |||
139 | 159 | # Merge shared upstream parent into the target merge branch. This creates | ||
140 | 160 | # revison L in the digram above. | ||
141 | 161 | tree.lock_write() | ||
142 | 162 | try: | ||
143 | 163 | conflicts = tree.merge_from_branch(tmp_target_upstream_tree.branch) | ||
144 | 164 | if conflicts > 0: | ||
145 | 165 | raise errors.SharedUpstreamConflictsWithTargetPackaging() | ||
146 | 166 | else: | ||
147 | 167 | tree.commit('Merging shared upstream rev in to target branch.') | ||
148 | 168 | finally: | ||
149 | 169 | tree.unlock() | ||
150 | 170 | |||
151 | 171 | return (upstreams_diverged, t_upstream_reverted) | 168 | return (upstreams_diverged, t_upstream_reverted) |
152 | 172 | 169 | ||
153 | === modified file 'tests/test_merge_package.py' | |||
154 | --- tests/test_merge_package.py 2009-08-21 12:41:34 +0000 | |||
155 | +++ tests/test_merge_package.py 2009-08-24 10:44:31 +0000 | |||
156 | @@ -173,23 +173,23 @@ | |||
157 | 173 | The upstream conflict will be resolved by fix_ancestry_as_needed(). | 173 | The upstream conflict will be resolved by fix_ancestry_as_needed(). |
158 | 174 | Please note that the debian ancestry is older in this case. | 174 | Please note that the debian ancestry is older in this case. |
159 | 175 | """ | 175 | """ |
161 | 176 | ubup_n, debp_o = self._setup_debian_upstream_older() | 176 | ubup, debp, _ubuu, _debu = self._setup_debian_upstream_older() |
162 | 177 | 177 | ||
163 | 178 | # Attempt a plain merge first. | 178 | # Attempt a plain merge first. |
166 | 179 | conflicts = ubup_n.merge_from_branch( | 179 | conflicts = ubup.merge_from_branch( |
167 | 180 | debp_o.branch, to_revision=self.revid_debp_o_C) | 180 | debp.branch, to_revision=self.revid_debp_o_C) |
168 | 181 | 181 | ||
169 | 182 | # There are two conflicts in the 'c' and the 'debian/changelog' files | 182 | # There are two conflicts in the 'c' and the 'debian/changelog' files |
170 | 183 | # respectively. | 183 | # respectively. |
171 | 184 | self.assertEquals(conflicts, 2) | 184 | self.assertEquals(conflicts, 2) |
173 | 185 | conflict_paths = sorted([c.path for c in ubup_n.conflicts()]) | 185 | conflict_paths = sorted([c.path for c in ubup.conflicts()]) |
174 | 186 | self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog']) | 186 | self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog']) |
175 | 187 | 187 | ||
176 | 188 | # Undo the failed merge. | 188 | # Undo the failed merge. |
178 | 189 | ubup_n.revert() | 189 | ubup.revert() |
179 | 190 | 190 | ||
180 | 191 | # The first conflict is resolved by calling fix_ancestry_as_needed(). | 191 | # The first conflict is resolved by calling fix_ancestry_as_needed(). |
182 | 192 | upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup_n, debp_o.branch) | 192 | upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup, debp.branch) |
183 | 193 | 193 | ||
184 | 194 | # The ancestry did diverge and needed to be fixed. | 194 | # The ancestry did diverge and needed to be fixed. |
185 | 195 | self.assertEquals(upstreams_diverged, True) | 195 | self.assertEquals(upstreams_diverged, True) |
186 | @@ -198,12 +198,12 @@ | |||
187 | 198 | self.assertEquals(t_upstream_reverted, False) | 198 | self.assertEquals(t_upstream_reverted, False) |
188 | 199 | 199 | ||
189 | 200 | # Try merging again. | 200 | # Try merging again. |
192 | 201 | conflicts = ubup_n.merge_from_branch( | 201 | conflicts = ubup.merge_from_branch( |
193 | 202 | debp_o.branch, to_revision=self.revid_debp_o_C) | 202 | debp.branch, to_revision=self.revid_debp_o_C) |
194 | 203 | 203 | ||
195 | 204 | # And, voila, only the packaging branch conflict remains. | 204 | # And, voila, only the packaging branch conflict remains. |
196 | 205 | self.assertEquals(conflicts, 1) | 205 | self.assertEquals(conflicts, 1) |
198 | 206 | conflict_paths = sorted([c.path for c in ubup_n.conflicts()]) | 206 | conflict_paths = sorted([c.path for c in ubup.conflicts()]) |
199 | 207 | self.assertEquals(conflict_paths, [u'debian/changelog']) | 207 | self.assertEquals(conflict_paths, [u'debian/changelog']) |
200 | 208 | 208 | ||
201 | 209 | def test_upstreams_not_diverged(self): | 209 | def test_upstreams_not_diverged(self): |
202 | @@ -394,7 +394,7 @@ | |||
203 | 394 | self._setup_branch(name, vdata, ubup_n, 'u') | 394 | self._setup_branch(name, vdata, ubup_n, 'u') |
204 | 395 | 395 | ||
205 | 396 | # Return the ubuntu and the debian packaging branches. | 396 | # Return the ubuntu and the debian packaging branches. |
207 | 397 | return (ubup_n, debp_o) | 397 | return (ubup_n, debp_o, ubuu_n, debu_o) |
208 | 398 | 398 | ||
209 | 399 | def _setup_upstreams_not_diverged(self): | 399 | def _setup_upstreams_not_diverged(self): |
210 | 400 | """ | 400 | """ |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
James Westby (james-w) wrote : | # |
Excerpts from Muharem Hrnjadovic's message of Mon Aug 24 10:57:08 UTC 2009:
> thank you very much for your suggestions above. They are all good. I
> hope the following text is more suitable.
>
> {{{
> The upstream branches for the merge source and target have diverged.
> Unfortunately, the attempt to fix this problem resulted in conflicts.
> Please resolve these and re-run the "merge-package" command to finish.
> Alternatively, you can restore the original merge target state by
> running "bzr revert".
> }}}
That's better. I think "resolve these and commit" is more explicit, and
I would prefer something other than "original merge target state", as
that sounds a bit jargonish, perhaps 'Alternatively, until you commit
you can use "bzr revert" to restore the state of the unmerged branch.'
It's not as clear what is going on, but I think that makes it easier
to understand :-)
> > Writing this mail also interested me in whether you ever get any
> > conflicts in the case when merging the faked upstream merge
> > in to the packaging branch in the case where your upstream
> > version was newer than the other upstream version.
>
> That would be the test_debian_
> get any conflicts.
Sure, there's one test, and I wouldn't expect any conflicts in that
test, I was thinking more of testing other situations though. Not
as unit tests, but one-off testing to investigate whether you can
provoke conflicts. If it is possible then we may want to investigate
ways to avoid that.
> Please find the incremental diff enclosed.
I'll review this shortly.
Thanks,
James
- 408. By Muharem Hrnjadovic
-
Clarified error message in accordance with James' suggestion.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
James Westby (james-w) wrote : | # |
Excerpts from Muharem Hrnjadovic's message of Mon Aug 24 10:57:08 UTC 2009:
> Please find the incremental diff enclosed.
My only quibble with this is the wrapping of the exception message. Please
make it wrap at <80 chars. You can make it resolve to a single string though.
_fmt = ('.....
Then I think we should be good to go.
There is documentation needed, but we can get this landed first.
Thanks,
James
- 409. By Muharem Hrnjadovic
-
Better formating of error string.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Muharem Hrnjadovic (al-maisan) wrote : | # |
James Westby wrote:
> Excerpts from Muharem Hrnjadovic's message of Mon Aug 24 10:57:08 UTC 2009:
>> Please find the incremental diff enclosed.
>
> My only quibble with this is the wrapping of the exception message. Please
> make it wrap at <80 chars. You can make it resolve to a single string though.
>
> _fmt = ('.....
> '......
> '......
>
> Then I think we should be good to go.
done.
> There is documentation needed, but we can get this landed first.
I see. Please point me to an example if available.
Best regards
--
Muharem Hrnjadovic <email address hidden>
Public key id : B2BBFCFC
Key fingerprint : A5A3 CC67 2B87 D641 103F 5602 219F 6B60 B2BB FCFC
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Muharem Hrnjadovic (al-maisan) wrote : | # |
James Westby wrote:
> Excerpts from Muharem Hrnjadovic's message of Mon Aug 24 10:57:08 UTC 2009:
>> thank you very much for your suggestions above. They are all good. I
>> hope the following text is more suitable.
>>
>> {{{
>> The upstream branches for the merge source and target have diverged.
>> Unfortunately, the attempt to fix this problem resulted in conflicts.
>> Please resolve these and re-run the "merge-package" command to finish.
>> Alternatively, you can restore the original merge target state by
>> running "bzr revert".
>> }}}
>
> That's better. I think "resolve these and commit" is more explicit, and
> I would prefer something other than "original merge target state", as
> that sounds a bit jargonish, perhaps 'Alternatively, until you commit
> you can use "bzr revert" to restore the state of the unmerged branch.'
>
> It's not as clear what is going on, but I think that makes it easier
> to understand :-)
Thank you very much for your help with this :)
>>> Writing this mail also interested me in whether you ever get any
>>> conflicts in the case when merging the faked upstream merge
>>> in to the packaging branch in the case where your upstream
>>> version was newer than the other upstream version.
>> That would be the test_debian_
>> get any conflicts.
>
> Sure, there's one test, and I wouldn't expect any conflicts in that
> test, I was thinking more of testing other situations though. Not
> as unit tests, but one-off testing to investigate whether you can
> provoke conflicts. If it is possible then we may want to investigate
> ways to avoid that.
I can think of a way to set up such a situation. There would need to
be a file that's shared and modified in all four branches: source
upstream, source packaging, target upstream and target packaging.
Furthermore the target upstream branch would have to be more recent one.
I will try to come up with this.
[..]
Best regards
--
Muharem Hrnjadovic <email address hidden>
Public key id : B2BBFCFC
Key fingerprint : A5A3 CC67 2B87 D641 103F 5602 219F 6B60 B2BB FCFC
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
James Westby (james-w) wrote : | # |
On Mon Aug 24 16:30:19 UTC 2009 Muharem Hrnjadovic wrote:
> > There is documentation needed, but we can get this landed first.
>
> I see. Please point me to an example if available.
Check the doc/user_manual/ directory. We will also want to put a quick
recipe type thing on https:/
as well.
One thing jumped to mind as well, perhaps there are some options of "merge"
we should support in "merge-package"? We can add these later if needed.
Thanks,
James
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Muharem Hrnjadovic (al-maisan) wrote : | # |
James Westby wrote:
> On Mon Aug 24 16:30:19 UTC 2009 Muharem Hrnjadovic wrote:
>>> There is documentation needed, but we can get this landed first.
>> I see. Please point me to an example if available.
>
> Check the doc/user_manual/ directory. We will also want to put a quick
> recipe type thing on https:/
> as well.
Thanks, I will take a look.
> One thing jumped to mind as well, perhaps there are some options of "merge"
> we should support in "merge-package"? We can add these later if needed.
Hey, that's a good idea :)
Best regards
--
Muharem Hrnjadovic <email address hidden>
Public key id : B2BBFCFC
Key fingerprint : A5A3 CC67 2B87 D641 103F 5602 219F 6B60 B2BB FCFC
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
James Westby (james-w) wrote : | # |
Looks good, thanks for all your work.
James
Preview Diff
1 | === modified file '__init__.py' | |||
2 | --- __init__.py 2009-07-26 15:51:02 +0000 | |||
3 | +++ __init__.py 2009-08-06 09:59:34 +0000 | |||
4 | @@ -39,7 +39,8 @@ | |||
5 | 39 | "merge_upstream": ["mu"], | 39 | "merge_upstream": ["mu"], |
6 | 40 | "import_dsc": [], | 40 | "import_dsc": [], |
7 | 41 | "bd_do": [], | 41 | "bd_do": [], |
9 | 42 | "mark_uploaded": [] | 42 | "mark_uploaded": [], |
10 | 43 | "merge_package": ["mp"] | ||
11 | 43 | } | 44 | } |
12 | 44 | 45 | ||
13 | 45 | for command, aliases in commands.iteritems(): | 46 | for command, aliases in commands.iteritems(): |
14 | 46 | 47 | ||
15 | === modified file 'cmds.py' | |||
16 | --- cmds.py 2009-07-26 18:21:49 +0000 | |||
17 | +++ cmds.py 2009-08-19 09:06:47 +0000 | |||
18 | @@ -69,6 +69,7 @@ | |||
19 | 69 | DscCache, | 69 | DscCache, |
20 | 70 | DscComp, | 70 | DscComp, |
21 | 71 | ) | 71 | ) |
22 | 72 | from bzrlib.plugins.builddeb.merge_package import fix_ancestry_as_needed | ||
23 | 72 | from bzrlib.plugins.builddeb.source_distiller import ( | 73 | from bzrlib.plugins.builddeb.source_distiller import ( |
24 | 73 | FullSourceDistiller, | 74 | FullSourceDistiller, |
25 | 74 | MergeModeDistiller, | 75 | MergeModeDistiller, |
26 | @@ -719,9 +720,9 @@ | |||
27 | 719 | "the previous upstream version, %s, in the " | 720 | "the previous upstream version, %s, in the " |
28 | 720 | "branch: %s" % (last_version, | 721 | "branch: %s" % (last_version, |
29 | 721 | db.upstream_tag_name(last_version))) | 722 | db.upstream_tag_name(last_version))) |
31 | 722 | upstream_tip = db._revid_of_upstream_version_from_branch( | 723 | upstream_tip = db.revid_of_upstream_version_from_branch( |
32 | 723 | last_version) | 724 | last_version) |
34 | 724 | db._extract_upstream_tree(upstream_tip, tempdir) | 725 | db.extract_upstream_tree(upstream_tip, tempdir) |
35 | 725 | else: | 726 | else: |
36 | 726 | db._create_empty_upstream_tree(tempdir) | 727 | db._create_empty_upstream_tree(tempdir) |
37 | 727 | self.import_many(db, files_list, orig_target) | 728 | self.import_many(db, files_list, orig_target) |
38 | @@ -870,6 +871,39 @@ | |||
39 | 870 | t.unlock() | 871 | t.unlock() |
40 | 871 | 872 | ||
41 | 872 | 873 | ||
42 | 874 | class cmd_merge_package(Command): | ||
43 | 875 | """Merges source packaging branch into target packaging branch. | ||
44 | 876 | |||
45 | 877 | This will first check whether the upstream branches have diverged. | ||
46 | 878 | |||
47 | 879 | If that's the case an attempt will be made to fix the upstream ancestry | ||
48 | 880 | so that the user only needs to deal wth packaging branch merge issues. | ||
49 | 881 | |||
50 | 882 | In the opposite case a normal merge will be performed. | ||
51 | 883 | """ | ||
52 | 884 | takes_args = ['source'] | ||
53 | 885 | |||
54 | 886 | def run(self, source): | ||
55 | 887 | source_branch = target_branch = None | ||
56 | 888 | # Get the target branch. | ||
57 | 889 | try: | ||
58 | 890 | tree = WorkingTree.open_containing('.')[0] | ||
59 | 891 | target_branch = tree.branch | ||
60 | 892 | except NotBranchError: | ||
61 | 893 | raise BzrCommandError( | ||
62 | 894 | "There is no tree to merge the source branch in to") | ||
63 | 895 | # Get the source branch. | ||
64 | 896 | try: | ||
65 | 897 | source_branch = Branch.open(source) | ||
66 | 898 | except NotBranchError: | ||
67 | 899 | raise BzrCommandError("Invalid source branch URL?") | ||
68 | 900 | |||
69 | 901 | fix_ancestry_as_needed(tree, source_branch) | ||
70 | 902 | |||
71 | 903 | # Merge source packaging branch in to the target packaging branch. | ||
72 | 904 | tree.merge_from_branch(source_branch) | ||
73 | 905 | |||
74 | 906 | |||
75 | 873 | class cmd_test_builddeb(Command): | 907 | class cmd_test_builddeb(Command): |
76 | 874 | """Run the builddeb test suite""" | 908 | """Run the builddeb test suite""" |
77 | 875 | 909 | ||
78 | @@ -880,4 +914,3 @@ | |||
79 | 880 | passed = selftest(test_suite_factory=test_suite) | 914 | passed = selftest(test_suite_factory=test_suite) |
80 | 881 | # invert for shell exit code rules | 915 | # invert for shell exit code rules |
81 | 882 | return not passed | 916 | return not passed |
82 | 883 | |||
83 | 884 | 917 | ||
84 | === modified file 'import_dsc.py' | |||
85 | --- import_dsc.py 2009-07-26 16:44:17 +0000 | |||
86 | +++ import_dsc.py 2009-08-19 08:58:47 +0000 | |||
87 | @@ -1570,7 +1570,7 @@ | |||
88 | 1570 | finally: | 1570 | finally: |
89 | 1571 | shutil.rmtree(tempdir) | 1571 | shutil.rmtree(tempdir) |
90 | 1572 | 1572 | ||
92 | 1573 | def _extract_upstream_tree(self, upstream_tip, basedir): | 1573 | def extract_upstream_tree(self, upstream_tip, basedir): |
93 | 1574 | # Extract that to a tempdir so we can get a working | 1574 | # Extract that to a tempdir so we can get a working |
94 | 1575 | # tree for it. | 1575 | # tree for it. |
95 | 1576 | # TODO: should stack rather than trying to use the repository, | 1576 | # TODO: should stack rather than trying to use the repository, |
96 | @@ -1582,6 +1582,13 @@ | |||
97 | 1582 | self.upstream_tree = dir_to.open_workingtree() | 1582 | self.upstream_tree = dir_to.open_workingtree() |
98 | 1583 | self.upstream_branch = self.upstream_tree.branch | 1583 | self.upstream_branch = self.upstream_tree.branch |
99 | 1584 | 1584 | ||
100 | 1585 | def _extract_upstream_tree(self, upstream_tip, basedir): | ||
101 | 1586 | # This method is now being used outside this module and hence | ||
102 | 1587 | # not really private any longer. | ||
103 | 1588 | # TODO: obsolete/remove this method and start using | ||
104 | 1589 | # extract_upstream_tree() instead. | ||
105 | 1590 | self.extract_upstream_tree(upstream_tip, basedir) | ||
106 | 1591 | |||
107 | 1585 | def _create_empty_upstream_tree(self, basedir): | 1592 | def _create_empty_upstream_tree(self, basedir): |
108 | 1586 | to_location = os.path.join(basedir, "upstream") | 1593 | to_location = os.path.join(basedir, "upstream") |
109 | 1587 | to_transport = get_transport(to_location) | 1594 | to_transport = get_transport(to_location) |
110 | @@ -1616,6 +1623,10 @@ | |||
111 | 1616 | raise | 1623 | raise |
112 | 1617 | 1624 | ||
113 | 1618 | def _revid_of_upstream_version_from_branch(self, version): | 1625 | def _revid_of_upstream_version_from_branch(self, version): |
114 | 1626 | """The private method below will go away eventually.""" | ||
115 | 1627 | return self.revid_of_upstream_version_from_branch(version) | ||
116 | 1628 | |||
117 | 1629 | def revid_of_upstream_version_from_branch(self, version): | ||
118 | 1619 | assert isinstance(version, str) | 1630 | assert isinstance(version, str) |
119 | 1620 | tag_name = self.upstream_tag_name(version) | 1631 | tag_name = self.upstream_tag_name(version) |
120 | 1621 | if self._has_version(self.branch, tag_name): | 1632 | if self._has_version(self.branch, tag_name): |
121 | @@ -1639,14 +1650,14 @@ | |||
122 | 1639 | if previous_version is not None: | 1650 | if previous_version is not None: |
123 | 1640 | if self.has_upstream_version_in_packaging_branch( | 1651 | if self.has_upstream_version_in_packaging_branch( |
124 | 1641 | previous_version.upstream_version): | 1652 | previous_version.upstream_version): |
126 | 1642 | upstream_tip = self._revid_of_upstream_version_from_branch( | 1653 | upstream_tip = self.revid_of_upstream_version_from_branch( |
127 | 1643 | previous_version.upstream_version) | 1654 | previous_version.upstream_version) |
129 | 1644 | self._extract_upstream_tree(upstream_tip, tempdir) | 1655 | self.extract_upstream_tree(upstream_tip, tempdir) |
130 | 1645 | elif (upstream_branch is not None and | 1656 | elif (upstream_branch is not None and |
131 | 1646 | previous_upstream_revision is not None): | 1657 | previous_upstream_revision is not None): |
132 | 1647 | upstream_tip = RevisionSpec.from_string(previous_upstream_revision).as_revision_id(upstream_branch) | 1658 | upstream_tip = RevisionSpec.from_string(previous_upstream_revision).as_revision_id(upstream_branch) |
133 | 1648 | assert isinstance(upstream_tip, str) | 1659 | assert isinstance(upstream_tip, str) |
135 | 1649 | self._extract_upstream_tree(upstream_tip, tempdir) | 1660 | self.extract_upstream_tree(upstream_tip, tempdir) |
136 | 1650 | else: | 1661 | else: |
137 | 1651 | raise BzrCommandError("Unable to find the tag for the " | 1662 | raise BzrCommandError("Unable to find the tag for the " |
138 | 1652 | "previous upstream version, %s, in the branch: " | 1663 | "previous upstream version, %s, in the branch: " |
139 | 1653 | 1664 | ||
140 | === added file 'merge_package.py' | |||
141 | --- merge_package.py 1970-01-01 00:00:00 +0000 | |||
142 | +++ merge_package.py 2009-08-19 09:19:38 +0000 | |||
143 | @@ -0,0 +1,214 @@ | |||
144 | 1 | # merge_package.py -- The plugin for bzr | ||
145 | 2 | # Copyright (C) 2009 Canonical Ltd. | ||
146 | 3 | # | ||
147 | 4 | # :Author: Muharem Hrnjadovic <muharem@ubuntu.com> | ||
148 | 5 | # | ||
149 | 6 | # This file is part of bzr-builddeb. | ||
150 | 7 | # | ||
151 | 8 | # bzr-builddeb is free software; you can redistribute it and/or modify | ||
152 | 9 | # it under the terms of the GNU General Public License as published by | ||
153 | 10 | # the Free Software Foundation; either version 2 of the License, or | ||
154 | 11 | # (at your option) any later version. | ||
155 | 12 | # | ||
156 | 13 | # bzr-builddeb is distributed in the hope that it will be useful, | ||
157 | 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
158 | 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
159 | 16 | # GNU General Public License for more details. | ||
160 | 17 | # | ||
161 | 18 | # You should have received a copy of the GNU General Public License | ||
162 | 19 | # along with bzr-builddeb; if not, write to the Free Software | ||
163 | 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
164 | 21 | # | ||
165 | 22 | |||
166 | 23 | import os | ||
167 | 24 | import re | ||
168 | 25 | import sys | ||
169 | 26 | import tempfile | ||
170 | 27 | |||
171 | 28 | from debian_bundle.changelog import Version | ||
172 | 29 | |||
173 | 30 | from bzrlib import errors | ||
174 | 31 | |||
175 | 32 | from bzrlib.plugins.builddeb.import_dsc import DistributionBranch | ||
176 | 33 | |||
177 | 34 | |||
178 | 35 | class WrongBranchType(errors.BzrError): | ||
179 | 36 | _fmt = "The merge target is not a packaging branch." | ||
180 | 37 | |||
181 | 38 | |||
182 | 39 | class InvalidChangelogFormat(errors.BzrError): | ||
183 | 40 | _fmt = "The debian/changelog is empty or not in valid format." | ||
184 | 41 | |||
185 | 42 | |||
186 | 43 | class SourceUpstreamConflictsWithTargetPackaging(errors.BzrError): | ||
187 | 44 | _fmt = ( | ||
188 | 45 | "The source upstream branch conflicts with " | ||
189 | 46 | "the target packaging branch") | ||
190 | 47 | |||
191 | 48 | |||
192 | 49 | def _read_file(branch, path): | ||
193 | 50 | """Get content of file for given `branch` and `path. | ||
194 | 51 | |||
195 | 52 | :param branch: A Branch object containing the file of interest. | ||
196 | 53 | :param path: The path of the file to read. | ||
197 | 54 | """ | ||
198 | 55 | try: | ||
199 | 56 | tree = branch.basis_tree() | ||
200 | 57 | tree.lock_read() | ||
201 | 58 | content = tree.get_file_text(tree.path2id(path)) | ||
202 | 59 | tree.unlock() | ||
203 | 60 | except errors.NoSuchId: | ||
204 | 61 | raise WrongBranchType() | ||
205 | 62 | |||
206 | 63 | return content | ||
207 | 64 | |||
208 | 65 | |||
209 | 66 | def _latest_version(branch): | ||
210 | 67 | """Version of the most recent source package upload in the given `branch`. | ||
211 | 68 | |||
212 | 69 | :param branch: A Branch object containing the source upload of interest. | ||
213 | 70 | """ | ||
214 | 71 | upload_version = '' | ||
215 | 72 | changelog = _read_file(branch, "debian/changelog") | ||
216 | 73 | |||
217 | 74 | for line in changelog.splitlines(): | ||
218 | 75 | # Look for the top-level changelog stanza, extract the | ||
219 | 76 | # upload version from it and break on success. | ||
220 | 77 | match = re.search('^.+\(([^)]+)\).*$', line) | ||
221 | 78 | if match is not None: | ||
222 | 79 | (upload_version,) = match.groups(1) | ||
223 | 80 | break | ||
224 | 81 | |||
225 | 82 | upload_version = upload_version.strip() | ||
226 | 83 | if len(upload_version) <= 0: | ||
227 | 84 | raise InvalidChangelogFormat() | ||
228 | 85 | |||
229 | 86 | return Version(upload_version) | ||
230 | 87 | |||
231 | 88 | |||
232 | 89 | def _upstream_version_data(source, target): | ||
233 | 90 | """Most recent upstream versions/revision IDs of the merge source/target. | ||
234 | 91 | |||
235 | 92 | Please note: both packaing branches must have been read-locked beforehand. | ||
236 | 93 | |||
237 | 94 | :param source: The merge source branch. | ||
238 | 95 | :param target: The merge target branch. | ||
239 | 96 | """ | ||
240 | 97 | results = list() | ||
241 | 98 | for branch in (source, target): | ||
242 | 99 | db = DistributionBranch(branch, branch) | ||
243 | 100 | uver = _latest_version(branch).upstream_version | ||
244 | 101 | results.append((uver, db.revid_of_upstream_version_from_branch(uver))) | ||
245 | 102 | |||
246 | 103 | return results | ||
247 | 104 | |||
248 | 105 | |||
249 | 106 | def fix_ancestry_as_needed(tree, source): | ||
250 | 107 | """Manipulate the merge target's ancestry to avoid upstream conflicts. | ||
251 | 108 | |||
252 | 109 | Merging J->I given the following ancestry tree is likely to result in | ||
253 | 110 | upstream merge conflicts: | ||
254 | 111 | |||
255 | 112 | debian-upstream ,------------------H | ||
256 | 113 | A-----------B \ | ||
257 | 114 | ubuntu-upstream \ \`-------G \ | ||
258 | 115 | \ \ \ \ | ||
259 | 116 | debian-packaging \ ,---------D--------\-----------J | ||
260 | 117 | C \ \ | ||
261 | 118 | ubuntu-packaging `----E------F--------I | ||
262 | 119 | |||
263 | 120 | Here there was a new upstream release (G) that Ubuntu packaged (I), and | ||
264 | 121 | then another one that Debian packaged, skipping G, at H and J. | ||
265 | 122 | |||
266 | 123 | Now, the way to solve this is to introduce the missing link. | ||
267 | 124 | |||
268 | 125 | debian-upstream ,------------------H------. | ||
269 | 126 | A-----------B \ \ | ||
270 | 127 | ubuntu-upstream \ \`-------G-----------\------K | ||
271 | 128 | \ \ \ \ | ||
272 | 129 | debian-packaging \ ,---------D--------\-----------J | ||
273 | 130 | C \ \ | ||
274 | 131 | ubuntu-packaging `----E------F--------I | ||
275 | 132 | |||
276 | 133 | at K, which isn't a real merge, as we just use the tree from H, but add | ||
277 | 134 | G as a parent and then we merge that in to Ubuntu. | ||
278 | 135 | |||
279 | 136 | debian-upstream ,------------------H------. | ||
280 | 137 | A-----------B \ \ | ||
281 | 138 | ubuntu-upstream \ \`-------G-----------\------K | ||
282 | 139 | \ \ \ \ \ | ||
283 | 140 | debian-packaging \ ,---------D--------\-----------J \ | ||
284 | 141 | C \ \ \ | ||
285 | 142 | ubuntu-packaging `----E------F--------I------------------L | ||
286 | 143 | |||
287 | 144 | At this point we can merge J->L to merge the Debian and Ubuntu changes. | ||
288 | 145 | |||
289 | 146 | :param tree: The `WorkingTree` of the merge target branch. | ||
290 | 147 | :param source: The merge source (packaging) branch. | ||
291 | 148 | """ | ||
292 | 149 | upstreams_diverged = False | ||
293 | 150 | t_upstream_reverted = False | ||
294 | 151 | target = tree.branch | ||
295 | 152 | |||
296 | 153 | try: | ||
297 | 154 | source.lock_read() | ||
298 | 155 | target.lock_read() | ||
299 | 156 | upstream_vdata = _upstream_version_data(source, target) | ||
300 | 157 | # Did the upstream branches of the merge source and target diverge? | ||
301 | 158 | revids = [vdata[1] for vdata in upstream_vdata] | ||
302 | 159 | graph = source.repository.get_graph(target.repository) | ||
303 | 160 | upstreams_diverged = (len(graph.heads(revids)) > 1) | ||
304 | 161 | finally: | ||
305 | 162 | source.unlock() | ||
306 | 163 | target.unlock() | ||
307 | 164 | |||
308 | 165 | if not upstreams_diverged: | ||
309 | 166 | return (upstreams_diverged, t_upstream_reverted) | ||
310 | 167 | |||
311 | 168 | # "Unpack" the upstream versions and revision ids for the merge source and | ||
312 | 169 | # target branch respectively. | ||
313 | 170 | [(usource_v, usource_revid), (utarget_v, utarget_revid)] = upstream_vdata | ||
314 | 171 | |||
315 | 172 | # Instantiate a `DistributionBranch` object for the merge target | ||
316 | 173 | # (packaging) branch. | ||
317 | 174 | db = DistributionBranch(tree.branch, tree.branch) | ||
318 | 175 | tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..')) | ||
319 | 176 | |||
320 | 177 | # Extract the merge target's upstream tree into a temporary directory. | ||
321 | 178 | db.extract_upstream_tree(utarget_revid, tempdir) | ||
322 | 179 | tmp_target_upstream_tree = db.upstream_tree | ||
323 | 180 | |||
324 | 181 | # Merge upstream branch tips to obtain a shared upstream parent. This | ||
325 | 182 | # will add revision K (see graph above) to a temporary merge target | ||
326 | 183 | # upstream tree. | ||
327 | 184 | try: | ||
328 | 185 | tmp_target_upstream_tree.lock_write() | ||
329 | 186 | |||
330 | 187 | if usource_v > utarget_v: | ||
331 | 188 | # The source upstream tree is more recent and the temporary | ||
332 | 189 | # target tree needs to be reshaped to match it. | ||
333 | 190 | tmp_target_upstream_tree.revert( | ||
334 | 191 | None, source.repository.revision_tree(usource_revid)) | ||
335 | 192 | t_upstream_reverted = True | ||
336 | 193 | |||
337 | 194 | tmp_target_upstream_tree.set_parent_ids( | ||
338 | 195 | (utarget_revid, usource_revid)) | ||
339 | 196 | |||
340 | 197 | tmp_target_upstream_tree.commit( | ||
341 | 198 | 'Consolidated upstream tree for merging into target branch') | ||
342 | 199 | finally: | ||
343 | 200 | tmp_target_upstream_tree.unlock() | ||
344 | 201 | |||
345 | 202 | # Merge shared upstream parent into the target merge branch. This creates | ||
346 | 203 | # revison L in the digram above. | ||
347 | 204 | try: | ||
348 | 205 | tree.lock_write() | ||
349 | 206 | try: | ||
350 | 207 | tree.merge_from_branch(tmp_target_upstream_tree.branch) | ||
351 | 208 | tree.commit('Merging source packaging branch in to target.') | ||
352 | 209 | except ConflictsInTree: | ||
353 | 210 | raise SourceUpstreamConflictsWithTargetPackaging() | ||
354 | 211 | finally: | ||
355 | 212 | tree.unlock() | ||
356 | 213 | |||
357 | 214 | return (upstreams_diverged, t_upstream_reverted) | ||
358 | 0 | 215 | ||
359 | === modified file 'tests/__init__.py' | |||
360 | --- tests/__init__.py 2009-07-04 20:45:01 +0000 | |||
361 | +++ tests/__init__.py 2009-08-19 09:56:50 +0000 | |||
362 | @@ -118,6 +118,7 @@ | |||
363 | 118 | 'test_config', | 118 | 'test_config', |
364 | 119 | 'test_hooks', | 119 | 'test_hooks', |
365 | 120 | 'test_import_dsc', | 120 | 'test_import_dsc', |
366 | 121 | 'test_merge_package', | ||
367 | 121 | 'test_merge_upstream', | 122 | 'test_merge_upstream', |
368 | 122 | 'test_repack_tarball_extra', | 123 | 'test_repack_tarball_extra', |
369 | 123 | 'test_revspec', | 124 | 'test_revspec', |
370 | 124 | 125 | ||
371 | === added file 'tests/test_merge_package.py' | |||
372 | --- tests/test_merge_package.py 1970-01-01 00:00:00 +0000 | |||
373 | +++ tests/test_merge_package.py 2009-08-19 09:44:38 +0000 | |||
374 | @@ -0,0 +1,497 @@ | |||
375 | 1 | #!/usr/bin/env python | ||
376 | 2 | # -*- coding: iso-8859-15 -*- | ||
377 | 3 | # test_merge_package.py -- Merge packaging branches, fix ancestry as needed. | ||
378 | 4 | # Copyright (C) 2008 Canonical Ltd. | ||
379 | 5 | # | ||
380 | 6 | # This file is part of bzr-builddeb. | ||
381 | 7 | # | ||
382 | 8 | # bzr-builddeb is free software; you can redistribute it and/or modify | ||
383 | 9 | # it under the terms of the GNU General Public License as published by | ||
384 | 10 | # the Free Software Foundation; either version 2 of the License, or | ||
385 | 11 | # (at your option) any later version. | ||
386 | 12 | # | ||
387 | 13 | # bzr-builddeb is distributed in the hope that it will be useful, | ||
388 | 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
389 | 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
390 | 16 | # GNU General Public License for more details. | ||
391 | 17 | # | ||
392 | 18 | # You should have received a copy of the GNU General Public License | ||
393 | 19 | # along with bzr-builddeb; if not, write to the Free Software | ||
394 | 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
395 | 21 | |||
396 | 22 | import os | ||
397 | 23 | import random | ||
398 | 24 | import string | ||
399 | 25 | import unittest | ||
400 | 26 | |||
401 | 27 | from bzrlib.errors import ConflictsInTree | ||
402 | 28 | from bzrlib.merge import WeaveMerger | ||
403 | 29 | from bzrlib.tests import TestCaseWithTransport | ||
404 | 30 | |||
405 | 31 | from bzrlib.plugins.builddeb import merge_package as MP | ||
406 | 32 | |||
407 | 33 | _Debian_changelog = '''\ | ||
408 | 34 | ipsec-tools (%s) unstable; urgency=high | ||
409 | 35 | |||
410 | 36 | * debian packaging -- %s | ||
411 | 37 | |||
412 | 38 | -- Nico Golde <nion@debian.org> Tue, %02d May 2009 13:26:14 +0200 | ||
413 | 39 | |||
414 | 40 | ''' | ||
415 | 41 | |||
416 | 42 | _Ubuntu_changelog = '''\ | ||
417 | 43 | ipsec-tools (%s) karmic; urgency=low | ||
418 | 44 | |||
419 | 45 | * ubuntu packaging -- %s | ||
420 | 46 | |||
421 | 47 | -- Jamie Strandboge <jamie@ubuntu.com> Fri, %02d Jul 2009 13:24:17 -0500 | ||
422 | 48 | |||
423 | 49 | ''' | ||
424 | 50 | |||
425 | 51 | |||
426 | 52 | def _prepend_log(text, path): | ||
427 | 53 | content = open(path).read() | ||
428 | 54 | fh = open(path, 'wb') | ||
429 | 55 | fh.write(text+content) | ||
430 | 56 | fh.close() | ||
431 | 57 | |||
432 | 58 | |||
433 | 59 | class MergePackageTests(TestCaseWithTransport): | ||
434 | 60 | |||
435 | 61 | def test_latest_upstream_versions(self): | ||
436 | 62 | """Check correctness of upstream version computation.""" | ||
437 | 63 | ubup_o, debp_n = self._setup_debian_upstrem_newer() | ||
438 | 64 | # Ubuntu upstream. | ||
439 | 65 | self.assertEquals( | ||
440 | 66 | MP._latest_version(ubup_o.branch).upstream_version, '1.1.2') | ||
441 | 67 | # Debian upstream. | ||
442 | 68 | self.assertEquals( | ||
443 | 69 | MP._latest_version(debp_n.branch).upstream_version, '2.0') | ||
444 | 70 | |||
445 | 71 | ubuntup, debianp = self._setup_upstreams_not_diverged() | ||
446 | 72 | # Ubuntu upstream. | ||
447 | 73 | self.assertEquals( | ||
448 | 74 | MP._latest_version(ubuntup.branch).upstream_version, '1.4') | ||
449 | 75 | # Debian upstream. | ||
450 | 76 | self.assertEquals( | ||
451 | 77 | MP._latest_version(debianp.branch).upstream_version, '2.2') | ||
452 | 78 | |||
453 | 79 | def test_debian_upstream_newer(self): | ||
454 | 80 | """Diverging upstreams (debian newer) don't cause merge conflicts. | ||
455 | 81 | |||
456 | 82 | The debian and ubuntu upstream branches will differ with regard to | ||
457 | 83 | the content of the file 'c'. | ||
458 | 84 | |||
459 | 85 | Furthermore the respective packaging branches will have a text | ||
460 | 86 | conflict in 'debian/changelog'. | ||
461 | 87 | |||
462 | 88 | The upstream conflict will be resolved by fix_ancestry_as_needed(). | ||
463 | 89 | Please note that the debian ancestry is more recent. | ||
464 | 90 | """ | ||
465 | 91 | ubup_o, debp_n = self._setup_debian_upstrem_newer() | ||
466 | 92 | |||
467 | 93 | # Attempt a plain merge first. | ||
468 | 94 | conflicts = ubup_o.merge_from_branch( | ||
469 | 95 | debp_n.branch, to_revision=self.revid_debp_n_C) | ||
470 | 96 | |||
471 | 97 | # There are two conflicts in the 'c' and the 'debian/changelog' files | ||
472 | 98 | # respectively. | ||
473 | 99 | self.assertEquals(conflicts, 2) | ||
474 | 100 | conflict_paths = sorted([c.path for c in ubup_o.conflicts()]) | ||
475 | 101 | self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog']) | ||
476 | 102 | |||
477 | 103 | # Undo the failed merge. | ||
478 | 104 | ubup_o.revert() | ||
479 | 105 | |||
480 | 106 | # The first conflict is resolved by calling fix_ancestry_as_needed(). | ||
481 | 107 | upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup_o, debp_n.branch) | ||
482 | 108 | |||
483 | 109 | # The ancestry did diverge and needed to be fixed. | ||
484 | 110 | self.assertEquals(upstreams_diverged, True) | ||
485 | 111 | # The (temporary) target upstream branch had to be reverted to the | ||
486 | 112 | # source upstream branch since the latter was more recent. | ||
487 | 113 | self.assertEquals(t_upstream_reverted, True) | ||
488 | 114 | |||
489 | 115 | # Try merging again. | ||
490 | 116 | conflicts = ubup_o.merge_from_branch( | ||
491 | 117 | debp_n.branch, to_revision=self.revid_debp_n_C) | ||
492 | 118 | |||
493 | 119 | # And, voila, only the packaging branch conflict remains. | ||
494 | 120 | self.assertEquals(conflicts, 1) | ||
495 | 121 | conflict_paths = sorted([c.path for c in ubup_o.conflicts()]) | ||
496 | 122 | self.assertEquals(conflict_paths, [u'debian/changelog']) | ||
497 | 123 | |||
498 | 124 | def test_debian_upstream_older(self): | ||
499 | 125 | """Diverging upstreams (debian older) don't cause merge conflicts. | ||
500 | 126 | |||
501 | 127 | The debian and ubuntu upstream branches will differ with regard to | ||
502 | 128 | the content of the file 'c'. | ||
503 | 129 | |||
504 | 130 | Furthermore the respective packaging branches will have a text | ||
505 | 131 | conflict in 'debian/changelog'. | ||
506 | 132 | |||
507 | 133 | The upstream conflict will be resolved by fix_ancestry_as_needed(). | ||
508 | 134 | Please note that the debian ancestry is older in this case. | ||
509 | 135 | """ | ||
510 | 136 | ubup_n, debp_o = self._setup_debian_upstream_older() | ||
511 | 137 | |||
512 | 138 | # Attempt a plain merge first. | ||
513 | 139 | conflicts = ubup_n.merge_from_branch( | ||
514 | 140 | debp_o.branch, to_revision=self.revid_debp_o_C) | ||
515 | 141 | |||
516 | 142 | # There are two conflicts in the 'c' and the 'debian/changelog' files | ||
517 | 143 | # respectively. | ||
518 | 144 | self.assertEquals(conflicts, 2) | ||
519 | 145 | conflict_paths = sorted([c.path for c in ubup_n.conflicts()]) | ||
520 | 146 | self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog']) | ||
521 | 147 | |||
522 | 148 | # Undo the failed merge. | ||
523 | 149 | ubup_n.revert() | ||
524 | 150 | |||
525 | 151 | # The first conflict is resolved by calling fix_ancestry_as_needed(). | ||
526 | 152 | upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup_n, debp_o.branch) | ||
527 | 153 | |||
528 | 154 | # The ancestry did diverge and needed to be fixed. | ||
529 | 155 | self.assertEquals(upstreams_diverged, True) | ||
530 | 156 | # The target upstream branch was more recent in this case and hence | ||
531 | 157 | # was not reverted to the source upstream branch. | ||
532 | 158 | self.assertEquals(t_upstream_reverted, False) | ||
533 | 159 | |||
534 | 160 | # Try merging again. | ||
535 | 161 | conflicts = ubup_n.merge_from_branch( | ||
536 | 162 | debp_o.branch, to_revision=self.revid_debp_o_C) | ||
537 | 163 | |||
538 | 164 | # And, voila, only the packaging branch conflict remains. | ||
539 | 165 | self.assertEquals(conflicts, 1) | ||
540 | 166 | conflict_paths = sorted([c.path for c in ubup_n.conflicts()]) | ||
541 | 167 | self.assertEquals(conflict_paths, [u'debian/changelog']) | ||
542 | 168 | |||
543 | 169 | def test_upstreams_not_diverged(self): | ||
544 | 170 | """Non-diverging upstreams result in a normal merge. | ||
545 | 171 | |||
546 | 172 | The debian and ubuntu upstream branches will not have diverged | ||
547 | 173 | this time. | ||
548 | 174 | |||
549 | 175 | The packaging branches will have a conflict in 'debian/changelog'. | ||
550 | 176 | fix_ancestry_as_needed() will return as soon as establishing that | ||
551 | 177 | the upstreams have not diverged. | ||
552 | 178 | """ | ||
553 | 179 | ubuntup, debianp = self._setup_upstreams_not_diverged() | ||
554 | 180 | |||
555 | 181 | # Attempt a plain merge first. | ||
556 | 182 | conflicts = ubuntup.merge_from_branch( | ||
557 | 183 | debianp.branch, to_revision=self.revid_debianp_C) | ||
558 | 184 | |||
559 | 185 | # There is only a conflict in the 'debian/changelog' file. | ||
560 | 186 | self.assertEquals(conflicts, 1) | ||
561 | 187 | conflict_paths = sorted([c.path for c in ubuntup.conflicts()]) | ||
562 | 188 | self.assertEquals(conflict_paths, [u'debian/changelog']) | ||
563 | 189 | |||
564 | 190 | # Undo the failed merge. | ||
565 | 191 | ubuntup.revert() | ||
566 | 192 | |||
567 | 193 | # The conflict is *not* resolved by calling fix_ancestry_as_needed(). | ||
568 | 194 | upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubuntup, debianp.branch) | ||
569 | 195 | |||
570 | 196 | # The ancestry did *not* diverge. | ||
571 | 197 | self.assertEquals(upstreams_diverged, False) | ||
572 | 198 | # The upstreams have not diverged, hence no need to fix/revert | ||
573 | 199 | # either of them. | ||
574 | 200 | self.assertEquals(t_upstream_reverted, False) | ||
575 | 201 | |||
576 | 202 | # Try merging again. | ||
577 | 203 | conflicts = ubuntup.merge_from_branch( | ||
578 | 204 | debianp.branch, to_revision=self.revid_debianp_C) | ||
579 | 205 | |||
580 | 206 | # The packaging branch conflict we saw above is still there. | ||
581 | 207 | self.assertEquals(conflicts, 1) | ||
582 | 208 | conflict_paths = sorted([c.path for c in ubuntup.conflicts()]) | ||
583 | 209 | self.assertEquals(conflict_paths, [u'debian/changelog']) | ||
584 | 210 | |||
585 | 211 | def _setup_debian_upstrem_newer(self): | ||
586 | 212 | """ | ||
587 | 213 | Set up the following test configuration (debian upstrem newer). | ||
588 | 214 | |||
589 | 215 | debian-upstream ,------------------H | ||
590 | 216 | A-----------B \ | ||
591 | 217 | ubuntu-upstream \ \`-------G \ | ||
592 | 218 | \ \ \ \ | ||
593 | 219 | debian-packaging \ ,---------D--------\-----------J | ||
594 | 220 | C \ | ||
595 | 221 | ubuntu-packaging `----E---------------I | ||
596 | 222 | |||
597 | 223 | where: | ||
598 | 224 | - A = 1.0 | ||
599 | 225 | - B = 1.1 | ||
600 | 226 | - H = 2.0 | ||
601 | 227 | |||
602 | 228 | - G = 1.1.2 | ||
603 | 229 | |||
604 | 230 | - C = 1.0-1 | ||
605 | 231 | - D = 1.1-1 | ||
606 | 232 | - J = 2.0-1 | ||
607 | 233 | |||
608 | 234 | - E = 1.0-1ubuntu1 | ||
609 | 235 | - I = 1.1.2-0ubuntu1 | ||
610 | 236 | |||
611 | 237 | Please note that the debian and ubuntu branches will have a conflict | ||
612 | 238 | with respect to the file 'c'. | ||
613 | 239 | """ | ||
614 | 240 | # Set up the debian upstream branch. | ||
615 | 241 | name = 'debu-n' | ||
616 | 242 | vdata = [ | ||
617 | 243 | ('upstream-1.0', ('a',), None, None), | ||
618 | 244 | ('upstream-1.1', ('b',), None, None), | ||
619 | 245 | ('upstream-2.0', ('c',), None, None), | ||
620 | 246 | ] | ||
621 | 247 | debu_n = self._setup_branch(name, vdata) | ||
622 | 248 | |||
623 | 249 | # Set up the debian packaging branch. | ||
624 | 250 | name = 'debp-n' | ||
625 | 251 | debp_n = self.make_branch_and_tree(name) | ||
626 | 252 | debp_n.pull(debu_n.branch, stop_revision=self.revid_debu_n_A) | ||
627 | 253 | |||
628 | 254 | vdata = [ | ||
629 | 255 | ('1.0-1', ('debian/', 'debian/changelog'), None, None), | ||
630 | 256 | ('1.1-1', ('o',), debu_n, self.revid_debu_n_B), | ||
631 | 257 | ('2.0-1', ('p',), debu_n, self.revid_debu_n_C), | ||
632 | 258 | ] | ||
633 | 259 | self._setup_branch(name, vdata, debp_n, 'd') | ||
634 | 260 | |||
635 | 261 | # Set up the ubuntu upstream branch. | ||
636 | 262 | name = 'ubuu-o' | ||
637 | 263 | ubuu_o = debu_n.bzrdir.sprout( | ||
638 | 264 | name, revision_id=self.revid_debu_n_B).open_workingtree() | ||
639 | 265 | |||
640 | 266 | vdata = [ | ||
641 | 267 | ('upstream-1.1.2', ('c',), None, None), | ||
642 | 268 | ] | ||
643 | 269 | self._setup_branch(name, vdata, ubuu_o) | ||
644 | 270 | |||
645 | 271 | # Set up the ubuntu packaging branch. | ||
646 | 272 | name = 'ubup-o' | ||
647 | 273 | ubup_o = debu_n.bzrdir.sprout( | ||
648 | 274 | name, revision_id=self.revid_debu_n_A).open_workingtree() | ||
649 | 275 | |||
650 | 276 | vdata = [ | ||
651 | 277 | ('1.0-1ubuntu1', (), debp_n, self.revid_debp_n_A), | ||
652 | 278 | ('1.1.2-0ubuntu1', (), ubuu_o, self.revid_ubuu_o_A), | ||
653 | 279 | ] | ||
654 | 280 | self._setup_branch(name, vdata, ubup_o, 'u') | ||
655 | 281 | |||
656 | 282 | # Return the ubuntu and the debian packaging branches. | ||
657 | 283 | return (ubup_o, debp_n) | ||
658 | 284 | |||
659 | 285 | def _setup_debian_upstream_older(self): | ||
660 | 286 | """ | ||
661 | 287 | Set up the following test configuration (debian upstrem older). | ||
662 | 288 | |||
663 | 289 | debian-upstream ,----H-------------. | ||
664 | 290 | A-----------B \ | ||
665 | 291 | ubuntu-upstream \ \`-----------G \ | ||
666 | 292 | \ \ \ \ | ||
667 | 293 | debian-packaging \ ,---------D------------\-------J | ||
668 | 294 | C \ | ||
669 | 295 | ubuntu-packaging `----E-------------------I | ||
670 | 296 | |||
671 | 297 | where: | ||
672 | 298 | - A = 1.0 | ||
673 | 299 | - B = 1.1 | ||
674 | 300 | - H = 1.1.3 | ||
675 | 301 | |||
676 | 302 | - G = 2.1 | ||
677 | 303 | |||
678 | 304 | - C = 1.0-1 | ||
679 | 305 | - D = 1.1-1 | ||
680 | 306 | - J = 1.1.3-1 | ||
681 | 307 | |||
682 | 308 | - E = 1.0-1ubuntu1 | ||
683 | 309 | - I = 2.1-0ubuntu1 | ||
684 | 310 | |||
685 | 311 | Please note that the debian and ubuntu branches will have a conflict | ||
686 | 312 | with respect to the file 'c'. | ||
687 | 313 | """ | ||
688 | 314 | # Set up the debian upstream branch. | ||
689 | 315 | name = 'debu-o' | ||
690 | 316 | vdata = [ | ||
691 | 317 | ('upstream-1.0', ('a',), None, None), | ||
692 | 318 | ('upstream-1.1', ('b',), None, None), | ||
693 | 319 | ('upstream-1.1.3', ('c',), None, None), | ||
694 | 320 | ] | ||
695 | 321 | debu_o = self._setup_branch(name, vdata) | ||
696 | 322 | |||
697 | 323 | # Set up the debian packaging branch. | ||
698 | 324 | name = 'debp-o' | ||
699 | 325 | debp_o = self.make_branch_and_tree(name) | ||
700 | 326 | debp_o.pull(debu_o.branch, stop_revision=self.revid_debu_o_A) | ||
701 | 327 | |||
702 | 328 | vdata = [ | ||
703 | 329 | ('1.0-1', ('debian/', 'debian/changelog'), None, None), | ||
704 | 330 | ('1.1-1', ('o',), debu_o, self.revid_debu_o_B), | ||
705 | 331 | ('1.1.3-1', ('p',), debu_o, self.revid_debu_o_C), | ||
706 | 332 | ] | ||
707 | 333 | self._setup_branch(name, vdata, debp_o, 'd') | ||
708 | 334 | |||
709 | 335 | # Set up the ubuntu upstream branch. | ||
710 | 336 | name = 'ubuu-n' | ||
711 | 337 | ubuu_n = debu_o.bzrdir.sprout( | ||
712 | 338 | name, revision_id=self.revid_debu_o_B).open_workingtree() | ||
713 | 339 | |||
714 | 340 | vdata = [ | ||
715 | 341 | ('upstream-2.1', ('c',), None, None), | ||
716 | 342 | ] | ||
717 | 343 | self._setup_branch(name, vdata, ubuu_n) | ||
718 | 344 | |||
719 | 345 | # Set up the ubuntu packaging branch. | ||
720 | 346 | name = 'ubup-n' | ||
721 | 347 | ubup_n = debu_o.bzrdir.sprout( | ||
722 | 348 | name, revision_id=self.revid_debu_o_A).open_workingtree() | ||
723 | 349 | |||
724 | 350 | vdata = [ | ||
725 | 351 | ('1.0-1ubuntu1', (), debp_o, self.revid_debp_o_A), | ||
726 | 352 | ('2.1-0ubuntu1', (), ubuu_n, self.revid_ubuu_n_A), | ||
727 | 353 | ] | ||
728 | 354 | self._setup_branch(name, vdata, ubup_n, 'u') | ||
729 | 355 | |||
730 | 356 | # Return the ubuntu and the debian packaging branches. | ||
731 | 357 | return (ubup_n, debp_o) | ||
732 | 358 | |||
733 | 359 | def _setup_upstreams_not_diverged(self): | ||
734 | 360 | """ | ||
735 | 361 | Set up a test configuration where the usptreams have not diverged. | ||
736 | 362 | |||
737 | 363 | debian-upstream .-----G | ||
738 | 364 | A-----------B-----H \ | ||
739 | 365 | ubuntu-upstream \ \ \ \ | ||
740 | 366 | \ \ \ \ | ||
741 | 367 | debian-packaging \ ,---------D-----\-------J | ||
742 | 368 | C \ | ||
743 | 369 | ubuntu-packaging `----E------------I | ||
744 | 370 | |||
745 | 371 | where: | ||
746 | 372 | - A = 1.0 | ||
747 | 373 | - B = 1.1 | ||
748 | 374 | - H = 1.4 | ||
749 | 375 | |||
750 | 376 | - G = 2.2 | ||
751 | 377 | |||
752 | 378 | - C = 1.0-1 | ||
753 | 379 | - D = 1.1-1 | ||
754 | 380 | - J = 2.2-1 | ||
755 | 381 | |||
756 | 382 | - E = 1.0-1ubuntu1 | ||
757 | 383 | - I = 1.4-0ubuntu1 | ||
758 | 384 | |||
759 | 385 | Please note that there's only one shared upstream branch in this case. | ||
760 | 386 | """ | ||
761 | 387 | # Set up the upstream branch. | ||
762 | 388 | name = 'upstream' | ||
763 | 389 | vdata = [ | ||
764 | 390 | ('upstream-1.0', ('a',), None, None), | ||
765 | 391 | ('upstream-1.1', ('b',), None, None), | ||
766 | 392 | ('upstream-1.4', ('c',), None, None), | ||
767 | 393 | ] | ||
768 | 394 | upstream = self._setup_branch(name, vdata) | ||
769 | 395 | |||
770 | 396 | # Set up the debian upstream branch. | ||
771 | 397 | name = 'dupstream' | ||
772 | 398 | dupstream = upstream.bzrdir.sprout(name).open_workingtree() | ||
773 | 399 | vdata = [ | ||
774 | 400 | ('upstream-2.2', (), None, None), | ||
775 | 401 | ] | ||
776 | 402 | dupstream = self._setup_branch(name, vdata, dupstream) | ||
777 | 403 | |||
778 | 404 | # Set up the debian packaging branch. | ||
779 | 405 | name = 'debianp' | ||
780 | 406 | debianp = self.make_branch_and_tree(name) | ||
781 | 407 | debianp.pull(dupstream.branch, stop_revision=self.revid_upstream_A) | ||
782 | 408 | |||
783 | 409 | vdata = [ | ||
784 | 410 | ('1.0-1', ('debian/', 'debian/changelog'), None, None), | ||
785 | 411 | ('1.1-1', ('o',), dupstream, self.revid_upstream_B), | ||
786 | 412 | ('2.2-1', ('p',), dupstream, self.revid_dupstream_A), | ||
787 | 413 | ] | ||
788 | 414 | self._setup_branch(name, vdata, debianp, 'd') | ||
789 | 415 | |||
790 | 416 | # Set up the ubuntu packaging branch. | ||
791 | 417 | name = 'ubuntup' | ||
792 | 418 | ubuntup = upstream.bzrdir.sprout( | ||
793 | 419 | name, revision_id=self.revid_upstream_A).open_workingtree() | ||
794 | 420 | |||
795 | 421 | vdata = [ | ||
796 | 422 | ('1.0-1ubuntu1', (), debianp, self.revid_debianp_A), | ||
797 | 423 | ('1.4-0ubuntu1', (), upstream, self.revid_upstream_C), | ||
798 | 424 | ] | ||
799 | 425 | self._setup_branch(name, vdata, ubuntup, 'u') | ||
800 | 426 | |||
801 | 427 | # Return the ubuntu and the debian packaging branches. | ||
802 | 428 | return (ubuntup, debianp) | ||
803 | 429 | |||
804 | 430 | def _setup_branch(self, name, vdata, tree=None, log_format=None): | ||
805 | 431 | vids = list(string.ascii_uppercase) | ||
806 | 432 | days = range(len(string.ascii_uppercase)) | ||
807 | 433 | |||
808 | 434 | if tree is None: | ||
809 | 435 | tree = self.make_branch_and_tree(name) | ||
810 | 436 | |||
811 | 437 | def revid_name(vid): | ||
812 | 438 | return 'revid_%s_%s' % (name.replace('-', '_'), vid) | ||
813 | 439 | |||
814 | 440 | def add_paths(paths): | ||
815 | 441 | qpaths = ['%s/%s' % (name, path) for path in paths] | ||
816 | 442 | self.build_tree(qpaths) | ||
817 | 443 | tree.add(paths) | ||
818 | 444 | |||
819 | 445 | def changelog(vdata, vid): | ||
820 | 446 | result = '' | ||
821 | 447 | day = days.pop(0) | ||
822 | 448 | if isinstance(vdata, tuple): | ||
823 | 449 | uver, dver = vdata[:2] | ||
824 | 450 | ucle = _Ubuntu_changelog % (uver, vid, day) | ||
825 | 451 | dcle = _Debian_changelog % (dver, vid, day) | ||
826 | 452 | result = ucle + dcle | ||
827 | 453 | else: | ||
828 | 454 | if log_format == 'u': | ||
829 | 455 | result = _Ubuntu_changelog % (vdata, vid, day) | ||
830 | 456 | elif log_format == 'd': | ||
831 | 457 | result = _Debian_changelog % (vdata, vid, day) | ||
832 | 458 | |||
833 | 459 | return result | ||
834 | 460 | |||
835 | 461 | def commit(msg, version): | ||
836 | 462 | vid = vids.pop(0) | ||
837 | 463 | if log_format is not None: | ||
838 | 464 | cle = changelog(version, vid) | ||
839 | 465 | p = '%s/work/%s/debian/changelog' % (self.test_base_dir, name) | ||
840 | 466 | _prepend_log(cle, p) | ||
841 | 467 | revid = tree.commit('%s: %s' % (vid, msg), rev_id='%s-%s' % (name, vid)) | ||
842 | 468 | setattr(self, revid_name(vid), revid) | ||
843 | 469 | tree.branch.tags.set_tag(version, revid) | ||
844 | 470 | |||
845 | 471 | def tree_nick(tree): | ||
846 | 472 | return str(tree)[1:-1].split('/')[-1] | ||
847 | 473 | |||
848 | 474 | for version, paths, utree, urevid in vdata: | ||
849 | 475 | msg = '' | ||
850 | 476 | if utree is not None: | ||
851 | 477 | tree.merge_from_branch( | ||
852 | 478 | utree.branch, to_revision=urevid, merge_type=WeaveMerger) | ||
853 | 479 | utree.branch.tags.merge_to(tree.branch.tags) | ||
854 | 480 | if urevid is not None: | ||
855 | 481 | msg += 'Merged tree %s|%s. ' % (tree_nick(utree), urevid) | ||
856 | 482 | else: | ||
857 | 483 | msg += 'Merged tree %s. ' % utree | ||
858 | 484 | if paths is not None: | ||
859 | 485 | add_paths(paths) | ||
860 | 486 | msg += 'Added paths: %s. ' % str(paths) | ||
861 | 487 | |||
862 | 488 | commit(msg, version) | ||
863 | 489 | |||
864 | 490 | return tree | ||
865 | 491 | |||
866 | 492 | |||
867 | 493 | if __name__ == '__main__': | ||
868 | 494 | # unittest.main() | ||
869 | 495 | suite = unittest.TestLoader().loadTestsFromTestCase(MergePackageTests) | ||
870 | 496 | unittest.TextTestRunner(verbosity=2).run(suite) | ||
871 | 497 | |||
872 | 0 | 498 | ||
873 | === modified file 'upstream.py' | |||
874 | --- upstream.py 2009-07-26 18:21:49 +0000 | |||
875 | +++ upstream.py 2009-08-06 08:41:23 +0000 | |||
876 | @@ -79,7 +79,7 @@ | |||
877 | 79 | db = DistributionBranch(self.branch, None, tree=self.tree) | 79 | db = DistributionBranch(self.branch, None, tree=self.tree) |
878 | 80 | if not db.has_upstream_version_in_packaging_branch(version): | 80 | if not db.has_upstream_version_in_packaging_branch(version): |
879 | 81 | raise PackageVersionNotPresent(package, version, self) | 81 | raise PackageVersionNotPresent(package, version, self) |
881 | 82 | revid = db._revid_of_upstream_version_from_branch(version) | 82 | revid = db.revid_of_upstream_version_from_branch(version) |
882 | 83 | if not db.has_pristine_tar_delta(revid): | 83 | if not db.has_pristine_tar_delta(revid): |
883 | 84 | raise PackageVersionNotPresent(package, version, self) | 84 | raise PackageVersionNotPresent(package, version, self) |
884 | 85 | info("Using pristine-tar to reconstruct the needed tarball.") | 85 | info("Using pristine-tar to reconstruct the needed tarball.") |
Hello James,
this branch implements the 'merge-package' command as specified here: http:// pastebin. com/f7214e464.
Please take a look and let me know what you think.