# HG changeset patch # User Augie Fackler # Date 1241405093 18000 # Node ID c3c647aff97c180190522c81f84de55615a94ac6 # Parent 963d27a0b1c29a65f5bea08751f33af84b0d1ae9# Parent 15b8bab035041265c580ec965bc4abe382f1a47a Merge with danchr's changes. diff --git a/cmdutil.py b/cmdutil.py --- a/cmdutil.py +++ b/cmdutil.py @@ -230,7 +230,7 @@ def commit_from_rev(ui, repo, rev_ctx, h file_data[file] = base_data, new_data, action def svnpath(p): - return '%s/%s' % (branch_path, p) + return ('%s/%s' % (branch_path, p)).rstrip('/') changeddirs = [] for d, v1, v2 in extchanges: diff --git a/hg_delta_editor.py b/hg_delta_editor.py --- a/hg_delta_editor.py +++ b/hg_delta_editor.py @@ -299,8 +299,8 @@ class HgChangeReceiver(delta.Editor): return path[len(test)+1:], self._localname(test), test if existing: return None, None, None - if path.startswith('trunk/'): - path = test.split('/')[1:] + if path == 'trunk' or path.startswith('trunk/'): + path = path.split('/')[1:] test = 'trunk' elif path.startswith('branches/'): elts = path.split('/') @@ -460,7 +460,7 @@ class HgChangeReceiver(delta.Editor): return branch[3:] return 'branches/%s' % branch - def __determine_parent_branch(self, p, src_path, src_rev, revnum): + def _determine_parent_branch(self, p, src_path, src_rev, revnum): if src_path is not None: src_file, src_branch = self._path_and_branch_for_path(src_path) src_tag = self._is_path_tag(src_path) @@ -502,40 +502,50 @@ class HgChangeReceiver(delta.Editor): and t_name in self.tags): tags_to_delete.add(t_name) continue - # At this point we know the path is not a tag. In that case, we only care if it - # is the root of a new branch (in this function). This is determined by the - # following checks: - # 1. Is the file located inside any currently known branch? - # If yes, then we're done with it, this isn't interesting. - # 2. Does the file have copyfrom information that means it is a copy from the root - # of some other branch? - # If yes, then we're done: this is a new branch, and we record the copyfrom in - # added_branches - # 3. Neither of the above. This could be a branch, but it might never work out for - # us. It's only ever a branch (as far as we're concerned) if it gets committed - # to, which we have to detect at file-write time anyway. So we do nothing here. - # 4. It's the root of an already-known branch, with an action of 'D'. We mark the - # branch as deleted. - # 5. It's the parent directory of one or more already-known branches, so we mark them - # as deleted. - # 6. It's a branch being replaced by another branch - the action will be 'R'. + # At this point we know the path is not a tag. In that + # case, we only care if it is the root of a new branch (in + # this function). This is determined by the following + # checks: + # 1. Is the file located inside any currently known + # branch? If yes, then we're done with it, this isn't + # interesting. + # 2. Does the file have copyfrom information? If yes, then + # we're done: this is a new branch, and we record the + # copyfrom in added_branches if it comes from the root + # of another branch, or create it from scratch. + # 3. Neither of the above. This could be a branch, but it + # might never work out for us. It's only ever a branch + # (as far as we're concerned) if it gets committed to, + # which we have to detect at file-write time anyway. So + # we do nothing here. + # 4. It's the root of an already-known branch, with an + # action of 'D'. We mark the branch as deleted. + # 5. It's the parent directory of one or more + # already-known branches, so we mark them as deleted. + # 6. It's a branch being replaced by another branch - the + # action will be 'R'. fi, br = self._path_and_branch_for_path(p) if fi is not None: if fi == '': if paths[p].action == 'D': self.branches_to_delete.add(br) # case 4 elif paths[p].action == 'R': - added_branches.update(self.__determine_parent_branch(p, paths[p].copyfrom_path, - paths[p].copyfrom_rev, - revision.revnum)) + parent = self._determine_parent_branch( + p, paths[p].copyfrom_path, paths[p].copyfrom_rev, + revision.revnum) + added_branches.update(parent) continue # case 1 if paths[p].action == 'D': - # check for case 5 for known in self.branches: if self._svnpath(known).startswith(p): self.branches_to_delete.add(known) # case 5 - added_branches.update(self.__determine_parent_branch(p, paths[p].copyfrom_path, - paths[p].copyfrom_rev, revision.revnum)) + parent = self._determine_parent_branch( + p, paths[p].copyfrom_path, paths[p].copyfrom_rev, revision.revnum) + if not parent and paths[p].copyfrom_path: + bpath, branch = self._path_and_branch_for_path(p, False) + if bpath is not None and branch not in self.branches: + parent = {branch: (None, 0, revision.revnum)} + added_branches.update(parent) for t in tags_to_delete: del self.tags[t] for br in self.branches_to_delete: @@ -802,7 +812,7 @@ class HgChangeReceiver(delta.Editor): base = 'link ' + base self.set_file(svnpath, base, 'x' in fctx.flags(), 'l' in fctx.flags()) else: - self.missing_plaintexts.add(path) + self.missing_plaintexts.add(svnpath) def delete_entry(self, path, revision_bogus, parent_baton, pool=None): br_path, branch = self._path_and_branch_for_path(path) diff --git a/svnexternals.py b/svnexternals.py --- a/svnexternals.py +++ b/svnexternals.py @@ -78,7 +78,6 @@ class BadDefinition(Exception): re_defold = re.compile(r'^(.*?)\s+(?:-r\s*(\d+)\s+)?([a-zA-Z]+://.*)$') re_defnew = re.compile(r'^(?:-r\s*(\d+)\s+)?((?:[a-zA-Z]+://|\^/).*)\s+(.*)$') -re_pegrev = re.compile(r'^(.*)@(\d+)$') re_scheme = re.compile(r'^[a-zA-Z]+://') def parsedefinition(line): @@ -89,19 +88,18 @@ def parsedefinition(line): # potential quotes. svn documentation is not really talkative about # these either. line = line.strip() + pegrev = None m = re_defnew.search(line) if m: rev, source, path = m.group(1, 2, 3) + if '@' in source: + source, pegrev = source.rsplit('@', 1) else: m = re_defold.search(line) if not m: raise BadDefinition() path, rev, source = m.group(1, 2, 3) - # Look for peg revisions - m = re_pegrev.search(source) - if m: - source, rev = m.group(1, 2) - return (path, rev, source) + return (path, rev, source, pegrev) def parsedefinitions(ui, repo, svnroot, exts): """Return (targetdir, revision, source) tuples. Fail if nested @@ -111,7 +109,7 @@ def parsedefinitions(ui, repo, svnroot, for base in sorted(exts): for line in exts[base]: try: - path, rev, source = parsedefinition(line) + path, rev, source, pegrev = parsedefinition(line) except BadDefinition: ui.warn(_('ignoring invalid external definition: %r' % line)) continue @@ -124,7 +122,7 @@ def parsedefinitions(ui, repo, svnroot, continue wpath = hgutil.pconvert(os.path.join(base, path)) wpath = hgutil.canonpath(repo.root, '', wpath) - defs.append((wpath, rev, source)) + defs.append((wpath, rev, source, pegrev)) # Check target dirs are not nested defs.sort() for i, d in enumerate(defs): @@ -189,13 +187,18 @@ class externalsupdater: self.repo = repo self.ui = ui - def update(self, wpath, rev, source): + def update(self, wpath, rev, source, pegrev): path = self.repo.wjoin(wpath) revspec = [] if rev: revspec = ['-r', rev] if os.path.isdir(path): exturl, extroot, extrev = getsvninfo(path) + # Comparing the source paths is not enough, but I don't + # know how to compare path+pegrev. The following update + # might fail if the path was replaced by another unrelated + # one. It can be fixed manually by deleting the externals + # and updating again. if source == exturl: if extrev != rev: self.ui.status(_('updating external on %s@%s\n') % @@ -208,6 +211,10 @@ class externalsupdater: cwd = os.path.join(self.repo.root, cwd) if not os.path.isdir(cwd): os.makedirs(cwd) + if not pegrev and rev: + pegrev = rev + if pegrev: + source = '%s@%s' % (source, pegrev) self.ui.status(_('fetching external %s@%s\n') % (wpath, rev or 'HEAD')) self.svn(['co'] + revspec + [source, dest], cwd) @@ -264,7 +271,7 @@ def updateexternals(ui, args, repo, **op actions = computeactions(ui, repo, svnroot, oldext, newext) for action, ext in actions: if action == 'u': - updater.update(ext[0], ext[1], ext[2]) + updater.update(ext[0], ext[1], ext[2], ext[3]) elif action == 'd': updater.delete(ext[0]) else: diff --git a/tests/fixtures/externals.sh b/tests/fixtures/externals.sh --- a/tests/fixtures/externals.sh +++ b/tests/fixtures/externals.sh @@ -38,13 +38,13 @@ svn ci -m "set externals on ." # Add another one cat > externals < externals <> a +svn ci -m 'change a' cd ../.. svnadmin dump testrepo > ../externals.svndump diff --git a/tests/fixtures/externals.svndump b/tests/fixtures/externals.svndump --- a/tests/fixtures/externals.svndump +++ b/tests/fixtures/externals.svndump @@ -1,6 +1,6 @@ SVN-fs-dump-format-version: 2 -UUID: ab7049d2-24fc-4035-b126-5f7012d66a0d +UUID: ac40e40a-7fbf-47e1-90a7-c1de12a5b013 Revision-number: 0 Prop-content-length: 56 @@ -9,7 +9,7 @@ Content-length: 56 K 8 svn:date V 27 -2009-01-12T23:19:30.150669Z +2009-05-03T14:07:14.149596Z PROPS-END Revision-number: 1 @@ -27,7 +27,7 @@ pmezard K 8 svn:date V 27 -2009-01-12T23:19:30.267365Z +2009-05-03T14:07:14.234026Z PROPS-END Node-path: branches @@ -72,7 +72,7 @@ pmezard K 8 svn:date V 27 -2009-01-12T23:19:31.232927Z +2009-05-03T14:07:15.135488Z PROPS-END Node-path: externals/project1 @@ -90,6 +90,7 @@ Node-action: add Prop-content-length: 10 Text-content-length: 2 Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3 +Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b Content-length: 12 PROPS-END @@ -111,6 +112,7 @@ Node-action: add Prop-content-length: 10 Text-content-length: 2 Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3 +Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b Content-length: 12 PROPS-END @@ -132,7 +134,7 @@ pmezard K 8 svn:date V 27 -2009-01-12T23:19:32.212750Z +2009-05-03T14:07:16.180110Z PROPS-END Node-path: trunk @@ -155,6 +157,7 @@ Node-action: add Prop-content-length: 10 Text-content-length: 2 Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3 +Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b Content-length: 12 PROPS-END @@ -176,20 +179,20 @@ pmezard K 8 svn:date V 27 -2009-01-12T23:19:33.180250Z +2009-05-03T14:07:17.092210Z PROPS-END Node-path: trunk Node-kind: dir Node-action: change -Prop-content-length: 105 -Content-length: 105 +Prop-content-length: 111 +Content-length: 111 K 13 svn:externals -V 70 +V 76 ^/externals/project1 deps/project1 -^/externals/project2 deps/project2 +-r2 ^/externals/project2@2 deps/project2 PROPS-END @@ -209,19 +212,19 @@ pmezard K 8 svn:date V 27 -2009-01-12T23:19:34.270854Z +2009-05-03T14:07:18.165337Z PROPS-END Node-path: trunk Node-kind: dir Node-action: change -Prop-content-length: 70 -Content-length: 70 +Prop-content-length: 76 +Content-length: 76 K 13 svn:externals -V 35 -^/externals/project2 deps/project2 +V 41 +-r2 ^/externals/project2@2 deps/project2 PROPS-END @@ -269,7 +272,7 @@ pmezard K 8 svn:date V 27 -2009-01-12T23:19:37.185743Z +2009-05-03T14:07:21.092911Z PROPS-END Node-path: branches/branch1 @@ -277,19 +280,6 @@ Node-kind: dir Node-action: add Node-copyfrom-rev: 5 Node-copyfrom-path: trunk -Prop-content-length: 94 -Content-length: 94 - -K 13 -svn:externals -V 35 -^/externals/project2 deps/project2 - -K 13 -svn:mergeinfo -V 0 - -PROPS-END Node-path: branches/branch1/subdir2 @@ -316,7 +306,7 @@ pmezard K 8 svn:date V 27 -2009-01-12T23:19:39.198328Z +2009-05-03T14:07:23.097507Z PROPS-END Node-path: branches/branch2 @@ -324,12 +314,8 @@ Node-kind: dir Node-action: add Node-copyfrom-rev: 5 Node-copyfrom-path: trunk -Prop-content-length: 34 -Content-length: 34 - -K 13 -svn:mergeinfo -V 0 +Prop-content-length: 10 +Content-length: 10 PROPS-END @@ -358,7 +344,7 @@ pmezard K 8 svn:date V 27 -2009-01-12T23:19:40.183807Z +2009-05-03T14:07:24.086967Z PROPS-END Node-path: trunk/subdir @@ -380,7 +366,7 @@ pmezard K 8 svn:date V 27 -2009-01-12T23:19:41.180477Z +2009-05-03T14:07:25.093557Z PROPS-END Node-path: trunk/subdir2 @@ -392,3 +378,55 @@ Content-length: 10 PROPS-END +Revision-number: 10 +Prop-content-length: 127 +Content-length: 127 + +K 7 +svn:log +V 25 +remove externals project2 +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-03T14:07:27.088306Z +PROPS-END + +Node-path: externals/project2 +Node-action: delete + + +Revision-number: 11 +Prop-content-length: 109 +Content-length: 109 + +K 7 +svn:log +V 8 +change a +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-03T14:07:28.065953Z +PROPS-END + +Node-path: trunk/a +Node-kind: file +Node-action: change +Text-content-length: 4 +Text-content-md5: 0d227f1abf8c2932d342e9b99cc957eb +Text-content-sha1: d7c8127a20a396cff08af086a1c695b0636f0c29 +Content-length: 4 + +a +a + + diff --git a/tests/fixtures/renamedproject.sh b/tests/fixtures/renamedproject.sh new file mode 100755 --- /dev/null +++ b/tests/fixtures/renamedproject.sh @@ -0,0 +1,59 @@ +#!/bin/sh +# +# Convert a project moving from a non-canonical to canonical +# layout, exercizing the missing plaintext code paths. It also tests +# branch creations where the branch source is not a canonical branch. +# + +mkdir temp +cd temp + +svnadmin create testrepo +svnurl=file://`pwd`/testrepo + +mkdir project-orig +cd project-orig +echo a > a +echo b > b +echo c > c +mkdir d +echo a > d/a +cd .. + +# Let's suppose it was actually branched in a previous life +mkdir project-branch +cd project-branch +echo a > a +echo b > b +cd .. + +svn import project-orig $svnurl/project-orig -m "init project" +svn import project-branch $svnurl/project-branch -m "init branch" + +svn mkdir $svnurl/project -m "create new project hierarchy" +svn mv $svnurl/project-orig $svnurl/project/project -m "rename as project" +svn mv $svnurl/project/project $svnurl/project/trunk -m "rename as project" + +svn mkdir $svnurl/project/branches -m "add branches root" +svn mv $svnurl/project-branch $svnurl/project/misplaced -m "incorrect move of the branch" +svn mv $svnurl/project/misplaced $svnurl/project/branches/branch -m "move of the branch" + +svn co $svnurl/project +cd project +echo a >> trunk/a +svn ci -m "change a" +echo a >> trunk/a +echo b >> trunk/b +svn rm trunk/c +echo a >> trunk/d/a +svn ci -m "change files in trunk" +# Try the same thing with the branch +echo a >> branches/branch/a +svn rm branches/branch/b +svn ci -m "change a in branch" +cd .. + +# Add this to make test_rebuildmeta happy, needs something to convert +svn import project-orig $svnurl/trunk -m "init fake trunk for rebuild_meta" + +svnadmin dump testrepo > ../renamedproject.svndump diff --git a/tests/fixtures/renamedproject.svndump b/tests/fixtures/renamedproject.svndump new file mode 100644 --- /dev/null +++ b/tests/fixtures/renamedproject.svndump @@ -0,0 +1,536 @@ +SVN-fs-dump-format-version: 2 + +UUID: 169a5fe1-3c9f-4eef-ad86-f932c54e53dc + +Revision-number: 0 +Prop-content-length: 56 +Content-length: 56 + +K 8 +svn:date +V 27 +2009-05-01T17:53:40.957980Z +PROPS-END + +Revision-number: 1 +Prop-content-length: 114 +Content-length: 114 + +K 7 +svn:log +V 12 +init project +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:41.129010Z +PROPS-END + +Node-path: project-orig +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: project-orig/a +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3 +Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b +Content-length: 12 + +PROPS-END +a + + +Node-path: project-orig/b +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 3b5d5c3712955042212316173ccf37be +Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b +Content-length: 12 + +PROPS-END +b + + +Node-path: project-orig/c +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 2cd6ee2c70b0bde53fbe6cac3c8b8bb1 +Text-content-sha1: 2b66fd261ee5c6cfc8de7fa466bab600bcfe4f69 +Content-length: 12 + +PROPS-END +c + + +Node-path: project-orig/d +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: project-orig/d/a +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3 +Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b +Content-length: 12 + +PROPS-END +a + + +Revision-number: 2 +Prop-content-length: 113 +Content-length: 113 + +K 7 +svn:log +V 11 +init branch +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:41.193926Z +PROPS-END + +Node-path: project-branch +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: project-branch/a +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3 +Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b +Content-length: 12 + +PROPS-END +a + + +Node-path: project-branch/b +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 3b5d5c3712955042212316173ccf37be +Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b +Content-length: 12 + +PROPS-END +b + + +Revision-number: 3 +Prop-content-length: 130 +Content-length: 130 + +K 7 +svn:log +V 28 +create new project hierarchy +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:41.236131Z +PROPS-END + +Node-path: project +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Revision-number: 4 +Prop-content-length: 119 +Content-length: 119 + +K 7 +svn:log +V 17 +rename as project +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:41.288164Z +PROPS-END + +Node-path: project/project +Node-kind: dir +Node-action: add +Node-copyfrom-rev: 3 +Node-copyfrom-path: project-orig + + +Node-path: project-orig +Node-action: delete + + +Revision-number: 5 +Prop-content-length: 119 +Content-length: 119 + +K 7 +svn:log +V 17 +rename as project +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:41.335332Z +PROPS-END + +Node-path: project/trunk +Node-kind: dir +Node-action: add +Node-copyfrom-rev: 4 +Node-copyfrom-path: project/project + + +Node-path: project/project +Node-action: delete + + +Revision-number: 6 +Prop-content-length: 119 +Content-length: 119 + +K 7 +svn:log +V 17 +add branches root +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:41.377684Z +PROPS-END + +Node-path: project/branches +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Revision-number: 7 +Prop-content-length: 130 +Content-length: 130 + +K 7 +svn:log +V 28 +incorrect move of the branch +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:41.426928Z +PROPS-END + +Node-path: project/misplaced +Node-kind: dir +Node-action: add +Node-copyfrom-rev: 6 +Node-copyfrom-path: project-branch + + +Node-path: project-branch +Node-action: delete + + +Revision-number: 8 +Prop-content-length: 120 +Content-length: 120 + +K 7 +svn:log +V 18 +move of the branch +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:41.478644Z +PROPS-END + +Node-path: project/branches/branch +Node-kind: dir +Node-action: add +Node-copyfrom-rev: 7 +Node-copyfrom-path: project/misplaced + + +Node-path: project/misplaced +Node-action: delete + + +Revision-number: 9 +Prop-content-length: 109 +Content-length: 109 + +K 7 +svn:log +V 8 +change a +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:42.078428Z +PROPS-END + +Node-path: project/trunk/a +Node-kind: file +Node-action: change +Text-content-length: 4 +Text-content-md5: 0d227f1abf8c2932d342e9b99cc957eb +Text-content-sha1: d7c8127a20a396cff08af086a1c695b0636f0c29 +Content-length: 4 + +a +a + + +Revision-number: 10 +Prop-content-length: 123 +Content-length: 123 + +K 7 +svn:log +V 21 +change files in trunk +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:43.109915Z +PROPS-END + +Node-path: project/trunk/a +Node-kind: file +Node-action: change +Text-content-length: 6 +Text-content-md5: 7d4ebf8f298d22fc349a91725b00af1c +Text-content-sha1: 92f31bc48f52339253fce6cad9f2f0c95b302f7e +Content-length: 6 + +a +a +a + + +Node-path: project/trunk/b +Node-kind: file +Node-action: change +Text-content-length: 4 +Text-content-md5: 06ac26ed8b614fc0b141e4542aa067c2 +Text-content-sha1: f6980469e74f7125178e88ec571e06fe6ce86e95 +Content-length: 4 + +b +b + + +Node-path: project/trunk/d/a +Node-kind: file +Node-action: change +Text-content-length: 4 +Text-content-md5: 0d227f1abf8c2932d342e9b99cc957eb +Text-content-sha1: d7c8127a20a396cff08af086a1c695b0636f0c29 +Content-length: 4 + +a +a + + +Node-path: project/trunk/c +Node-action: delete + + +Revision-number: 11 +Prop-content-length: 120 +Content-length: 120 + +K 7 +svn:log +V 18 +change a in branch +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:44.100553Z +PROPS-END + +Node-path: project/branches/branch/a +Node-kind: file +Node-action: change +Text-content-length: 4 +Text-content-md5: 0d227f1abf8c2932d342e9b99cc957eb +Text-content-sha1: d7c8127a20a396cff08af086a1c695b0636f0c29 +Content-length: 4 + +a +a + + +Node-path: project/branches/branch/b +Node-action: delete + + +Revision-number: 12 +Prop-content-length: 134 +Content-length: 134 + +K 7 +svn:log +V 32 +init fake trunk for rebuild_meta +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2009-05-01T17:53:45.089483Z +PROPS-END + +Node-path: trunk +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: trunk/a +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3 +Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b +Content-length: 12 + +PROPS-END +a + + +Node-path: trunk/b +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 3b5d5c3712955042212316173ccf37be +Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b +Content-length: 12 + +PROPS-END +b + + +Node-path: trunk/c +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 2cd6ee2c70b0bde53fbe6cac3c8b8bb1 +Text-content-sha1: 2b66fd261ee5c6cfc8de7fa466bab600bcfe4f69 +Content-length: 12 + +PROPS-END +c + + +Node-path: trunk/d +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: trunk/d/a +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 2 +Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3 +Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b +Content-length: 12 + +PROPS-END +a + + diff --git a/tests/test_externals.py b/tests/test_externals.py --- a/tests/test_externals.py +++ b/tests/test_externals.py @@ -33,19 +33,19 @@ class TestFetchExternals(test_util.TestB # Taken from svn book samples = [ ('third-party/sounds http://svn.example.com/repos/sounds', - ('third-party/sounds', None, 'http://svn.example.com/repos/sounds')), + ('third-party/sounds', None, 'http://svn.example.com/repos/sounds', None)), ('third-party/skins -r148 http://svn.example.com/skinproj', - ('third-party/skins', '148', 'http://svn.example.com/skinproj')), + ('third-party/skins', '148', 'http://svn.example.com/skinproj', None)), ('third-party/skins -r 148 http://svn.example.com/skinproj', - ('third-party/skins', '148', 'http://svn.example.com/skinproj')), + ('third-party/skins', '148', 'http://svn.example.com/skinproj', None)), ('http://svn.example.com/repos/sounds third-party/sounds', - ('third-party/sounds', None, 'http://svn.example.com/repos/sounds')), + ('third-party/sounds', None, 'http://svn.example.com/repos/sounds', None)), ('-r148 http://svn.example.com/skinproj third-party/skins', - ('third-party/skins', '148', 'http://svn.example.com/skinproj')), + ('third-party/skins', '148', 'http://svn.example.com/skinproj', None)), ('-r 148 http://svn.example.com/skinproj third-party/skins', - ('third-party/skins', '148', 'http://svn.example.com/skinproj')), + ('third-party/skins', '148', 'http://svn.example.com/skinproj', None)), ('http://svn.example.com/skin-maker@21 third-party/skins/toolkit', - ('third-party/skins/toolkit', '21', 'http://svn.example.com/skin-maker')), + ('third-party/skins/toolkit', None, 'http://svn.example.com/skin-maker', '21')), ] for line, expected in samples: @@ -60,12 +60,12 @@ class TestFetchExternals(test_util.TestB self.assertEqual(ref0, repo[0]['.hgsvnexternals'].data()) ref1 = """[.] ^/externals/project1 deps/project1 - ^/externals/project2 deps/project2 + -r2 ^/externals/project2@2 deps/project2 """ self.assertEqual(ref1, repo[1]['.hgsvnexternals'].data()) ref2 = """[.] - ^/externals/project2 deps/project2 + -r2 ^/externals/project2@2 deps/project2 [subdir] ^/externals/project1 deps/project1 [subdir2] @@ -75,7 +75,7 @@ class TestFetchExternals(test_util.TestB self.assertEqual(ref2, actual) ref3 = """[.] - ^/externals/project2 deps/project2 + -r2 ^/externals/project2@2 deps/project2 [subdir] ^/externals/project1 deps/project1 """ @@ -87,14 +87,14 @@ class TestFetchExternals(test_util.TestB self.assertEqual(ref4, repo[4]['.hgsvnexternals'].data()) ref5 = """[.] - ^/externals/project2 deps/project2 + -r2 ^/externals/project2@2 deps/project2 [subdir2] ^/externals/project1 deps/project1 """ self.assertEqual(ref5, repo[5]['.hgsvnexternals'].data()) ref6 = """[.] - ^/externals/project2 deps/project2 + -r2 ^/externals/project2@2 deps/project2 """ self.assertEqual(ref6, repo[6]['.hgsvnexternals'].data()) diff --git a/tests/test_fetch_branches.py b/tests/test_fetch_branches.py --- a/tests/test_fetch_branches.py +++ b/tests/test_fetch_branches.py @@ -9,10 +9,11 @@ import wrappers class TestFetchBranches(test_util.TestBase): - def _load_fixture_and_fetch(self, fixture_name, stupid, noupdate=True): + def _load_fixture_and_fetch(self, fixture_name, stupid, noupdate=True, + subdir=''): return test_util.load_fixture_and_fetch(fixture_name, self.repo_path, self.wc_path, stupid=stupid, - noupdate=noupdate) + noupdate=noupdate, subdir=subdir) def _load_fixture_and_fetch_with_anchor(self, fixture_name, anchor): test_util.load_svndump_fixture(self.repo_path, fixture_name) @@ -84,6 +85,19 @@ class TestFetchBranches(test_util.TestBa self.assertEqual(repo[None].branch(), 'branch') self.assertEqual(repo[None].parents()[0], repo[repo.branchheads()[0]]) + def test_branches_weird_moves(self, stupid=False): + repo = self._load_fixture_and_fetch('renamedproject.svndump', stupid, + subdir='project') + heads = [repo[n] for n in repo.heads()] + heads = dict((ctx.branch(), ctx) for ctx in heads) + mdefault = sorted(heads['default'].manifest().keys()) + mbranch = sorted(heads['branch'].manifest().keys()) + self.assertEqual(mdefault, ['a', 'b', 'd/a']) + self.assertEqual(mbranch, ['a']) + + def test_branches_weird_moves_stupid(self): + self.test_branches_weird_moves(True) + def suite(): all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchBranches), ]