changeset 315:963d27a0b1c2

svnexternals: do not use peg revisions as --rev replacements Peg revisions are now parsed separately. If a revision is supplied but not a peg revision, we used the former as peg revision, as subversion seems to do.
author Patrick Mezard <pmezard@gmail.com>
date Sun, 03 May 2009 21:42:44 -0500
parents 2257bfc01749
children c3c647aff97c
files svnexternals.py tests/fixtures/externals.sh tests/fixtures/externals.svndump tests/test_externals.py
diffstat 4 files changed, 115 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- 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:
--- 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 <<EOF
 ^/externals/project1 deps/project1
-^/externals/project2 deps/project2
+-r2 ^/externals/project2@2 deps/project2
 EOF
 svn propset -F externals svn:externals .
 svn ci -m "update externals on ."
 # Suppress an external and add one on a subdir
 cat > externals <<EOF
-^/externals/project2 deps/project2
+-r2 ^/externals/project2@2 deps/project2
 EOF
 svn propset -F externals svn:externals .
 mkdir subdir
@@ -72,6 +72,14 @@ svn ci -m 'remove externals subdir'
 # Remove the property on subdir2
 svn propdel svn:externals subdir2
 svn ci -m 'remove externals subdir2'
+# Kill project2 externals, peg revision should preserve it
+cd ..
+svn up
+svn rm externals/project2
+svn ci -m 'remove externals project2'
+cd trunk
+echo a >> a
+svn ci -m 'change a'
 cd ../..
 
 svnadmin dump testrepo > ../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
+
+
--- 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())