Mercurial > hgsubversion
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 |