comparison svnexternals.py @ 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 ba8e91a7c077
children 4f4db3d2fdbb 75f082b5897e
comparison
equal deleted inserted replaced
314:2257bfc01749 315:963d27a0b1c2
76 class BadDefinition(Exception): 76 class BadDefinition(Exception):
77 pass 77 pass
78 78
79 re_defold = re.compile(r'^(.*?)\s+(?:-r\s*(\d+)\s+)?([a-zA-Z]+://.*)$') 79 re_defold = re.compile(r'^(.*?)\s+(?:-r\s*(\d+)\s+)?([a-zA-Z]+://.*)$')
80 re_defnew = re.compile(r'^(?:-r\s*(\d+)\s+)?((?:[a-zA-Z]+://|\^/).*)\s+(.*)$') 80 re_defnew = re.compile(r'^(?:-r\s*(\d+)\s+)?((?:[a-zA-Z]+://|\^/).*)\s+(.*)$')
81 re_pegrev = re.compile(r'^(.*)@(\d+)$')
82 re_scheme = re.compile(r'^[a-zA-Z]+://') 81 re_scheme = re.compile(r'^[a-zA-Z]+://')
83 82
84 def parsedefinition(line): 83 def parsedefinition(line):
85 """Parse an external definition line, return a tuple (path, rev, source) 84 """Parse an external definition line, return a tuple (path, rev, source)
86 or raise BadDefinition. 85 or raise BadDefinition.
87 """ 86 """
88 # The parsing is probably not correct wrt path with whitespaces or 87 # The parsing is probably not correct wrt path with whitespaces or
89 # potential quotes. svn documentation is not really talkative about 88 # potential quotes. svn documentation is not really talkative about
90 # these either. 89 # these either.
91 line = line.strip() 90 line = line.strip()
91 pegrev = None
92 m = re_defnew.search(line) 92 m = re_defnew.search(line)
93 if m: 93 if m:
94 rev, source, path = m.group(1, 2, 3) 94 rev, source, path = m.group(1, 2, 3)
95 if '@' in source:
96 source, pegrev = source.rsplit('@', 1)
95 else: 97 else:
96 m = re_defold.search(line) 98 m = re_defold.search(line)
97 if not m: 99 if not m:
98 raise BadDefinition() 100 raise BadDefinition()
99 path, rev, source = m.group(1, 2, 3) 101 path, rev, source = m.group(1, 2, 3)
100 # Look for peg revisions 102 return (path, rev, source, pegrev)
101 m = re_pegrev.search(source)
102 if m:
103 source, rev = m.group(1, 2)
104 return (path, rev, source)
105 103
106 def parsedefinitions(ui, repo, svnroot, exts): 104 def parsedefinitions(ui, repo, svnroot, exts):
107 """Return (targetdir, revision, source) tuples. Fail if nested 105 """Return (targetdir, revision, source) tuples. Fail if nested
108 targetdirs are detected. source is an svn project URL. 106 targetdirs are detected. source is an svn project URL.
109 """ 107 """
110 defs = [] 108 defs = []
111 for base in sorted(exts): 109 for base in sorted(exts):
112 for line in exts[base]: 110 for line in exts[base]:
113 try: 111 try:
114 path, rev, source = parsedefinition(line) 112 path, rev, source, pegrev = parsedefinition(line)
115 except BadDefinition: 113 except BadDefinition:
116 ui.warn(_('ignoring invalid external definition: %r' % line)) 114 ui.warn(_('ignoring invalid external definition: %r' % line))
117 continue 115 continue
118 if re_scheme.search(source): 116 if re_scheme.search(source):
119 pass 117 pass
122 else: 120 else:
123 ui.warn(_('ignoring unsupported non-fully qualified external: %r' % source)) 121 ui.warn(_('ignoring unsupported non-fully qualified external: %r' % source))
124 continue 122 continue
125 wpath = hgutil.pconvert(os.path.join(base, path)) 123 wpath = hgutil.pconvert(os.path.join(base, path))
126 wpath = hgutil.canonpath(repo.root, '', wpath) 124 wpath = hgutil.canonpath(repo.root, '', wpath)
127 defs.append((wpath, rev, source)) 125 defs.append((wpath, rev, source, pegrev))
128 # Check target dirs are not nested 126 # Check target dirs are not nested
129 defs.sort() 127 defs.sort()
130 for i, d in enumerate(defs): 128 for i, d in enumerate(defs):
131 for d2 in defs[i+1:]: 129 for d2 in defs[i+1:]:
132 if d2[0].startswith(d[0] + '/'): 130 if d2[0].startswith(d[0] + '/'):
187 class externalsupdater: 185 class externalsupdater:
188 def __init__(self, ui, repo): 186 def __init__(self, ui, repo):
189 self.repo = repo 187 self.repo = repo
190 self.ui = ui 188 self.ui = ui
191 189
192 def update(self, wpath, rev, source): 190 def update(self, wpath, rev, source, pegrev):
193 path = self.repo.wjoin(wpath) 191 path = self.repo.wjoin(wpath)
194 revspec = [] 192 revspec = []
195 if rev: 193 if rev:
196 revspec = ['-r', rev] 194 revspec = ['-r', rev]
197 if os.path.isdir(path): 195 if os.path.isdir(path):
198 exturl, extroot, extrev = getsvninfo(path) 196 exturl, extroot, extrev = getsvninfo(path)
197 # Comparing the source paths is not enough, but I don't
198 # know how to compare path+pegrev. The following update
199 # might fail if the path was replaced by another unrelated
200 # one. It can be fixed manually by deleting the externals
201 # and updating again.
199 if source == exturl: 202 if source == exturl:
200 if extrev != rev: 203 if extrev != rev:
201 self.ui.status(_('updating external on %s@%s\n') % 204 self.ui.status(_('updating external on %s@%s\n') %
202 (wpath, rev or 'HEAD')) 205 (wpath, rev or 'HEAD'))
203 cwd = os.path.join(self.repo.root, path) 206 cwd = os.path.join(self.repo.root, path)
206 self.delete(wpath) 209 self.delete(wpath)
207 cwd, dest = os.path.split(path) 210 cwd, dest = os.path.split(path)
208 cwd = os.path.join(self.repo.root, cwd) 211 cwd = os.path.join(self.repo.root, cwd)
209 if not os.path.isdir(cwd): 212 if not os.path.isdir(cwd):
210 os.makedirs(cwd) 213 os.makedirs(cwd)
214 if not pegrev and rev:
215 pegrev = rev
216 if pegrev:
217 source = '%s@%s' % (source, pegrev)
211 self.ui.status(_('fetching external %s@%s\n') % (wpath, rev or 'HEAD')) 218 self.ui.status(_('fetching external %s@%s\n') % (wpath, rev or 'HEAD'))
212 self.svn(['co'] + revspec + [source, dest], cwd) 219 self.svn(['co'] + revspec + [source, dest], cwd)
213 220
214 def delete(self, wpath): 221 def delete(self, wpath):
215 path = self.repo.wjoin(wpath) 222 path = self.repo.wjoin(wpath)
262 269
263 updater = externalsupdater(ui, repo) 270 updater = externalsupdater(ui, repo)
264 actions = computeactions(ui, repo, svnroot, oldext, newext) 271 actions = computeactions(ui, repo, svnroot, oldext, newext)
265 for action, ext in actions: 272 for action, ext in actions:
266 if action == 'u': 273 if action == 'u':
267 updater.update(ext[0], ext[1], ext[2]) 274 updater.update(ext[0], ext[1], ext[2], ext[3])
268 elif action == 'd': 275 elif action == 'd':
269 updater.delete(ext[0]) 276 updater.delete(ext[0])
270 else: 277 else:
271 raise hgutil.Abort(_('unknown update actions: %r') % action) 278 raise hgutil.Abort(_('unknown update actions: %r') % action)
272 279