93 ui.warn(_("warning: subrepo spec file \'%s\' not found\n") % |
93 ui.warn(_("warning: subrepo spec file \'%s\' not found\n") % |
94 repo.pathto(f)) |
94 repo.pathto(f)) |
95 return |
95 return |
96 p.parse(f, data, sections, remap, read) |
96 p.parse(f, data, sections, remap, read) |
97 else: |
97 else: |
98 raise util.Abort(_("subrepo spec file \'%s\' not found") % |
98 raise error.Abort(_("subrepo spec file \'%s\' not found") % |
99 repo.pathto(f)) |
99 repo.pathto(f)) |
100 if '.hgsub' in ctx: |
100 if '.hgsub' in ctx: |
101 read('.hgsub') |
101 read('.hgsub') |
102 |
102 |
103 for path, src in ui.configitems('subpaths'): |
103 for path, src in ui.configitems('subpaths'): |
111 if not l: |
111 if not l: |
112 continue |
112 continue |
113 try: |
113 try: |
114 revision, path = l.split(" ", 1) |
114 revision, path = l.split(" ", 1) |
115 except ValueError: |
115 except ValueError: |
116 raise util.Abort(_("invalid subrepository revision " |
116 raise error.Abort(_("invalid subrepository revision " |
117 "specifier in \'%s\' line %d") |
117 "specifier in \'%s\' line %d") |
118 % (repo.pathto('.hgsubstate'), (i + 1))) |
118 % (repo.pathto('.hgsubstate'), (i + 1))) |
119 rev[path] = revision |
119 rev[path] = revision |
120 except IOError as err: |
120 except IOError as err: |
121 if err.errno != errno.ENOENT: |
121 if err.errno != errno.ENOENT: |
131 # extra escapes are needed because re.sub string decodes. |
131 # extra escapes are needed because re.sub string decodes. |
132 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl) |
132 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl) |
133 try: |
133 try: |
134 src = re.sub(pattern, repl, src, 1) |
134 src = re.sub(pattern, repl, src, 1) |
135 except re.error as e: |
135 except re.error as e: |
136 raise util.Abort(_("bad subrepository pattern in %s: %s") |
136 raise error.Abort(_("bad subrepository pattern in %s: %s") |
137 % (p.source('subpaths', pattern), e)) |
137 % (p.source('subpaths', pattern), e)) |
138 return src |
138 return src |
139 |
139 |
140 state = {} |
140 state = {} |
141 for path, src in p[''].items(): |
141 for path, src in p[''].items(): |
142 kind = 'hg' |
142 kind = 'hg' |
143 if src.startswith('['): |
143 if src.startswith('['): |
144 if ']' not in src: |
144 if ']' not in src: |
145 raise util.Abort(_('missing ] in subrepo source')) |
145 raise error.Abort(_('missing ] in subrepo source')) |
146 kind, src = src.split(']', 1) |
146 kind, src = src.split(']', 1) |
147 kind = kind[1:] |
147 kind = kind[1:] |
148 src = src.lstrip() # strip any extra whitespace after ']' |
148 src = src.lstrip() # strip any extra whitespace after ']' |
149 |
149 |
150 if not util.url(src).isabs(): |
150 if not util.url(src).isabs(): |
322 return repo.ui.config('paths', 'default') |
322 return repo.ui.config('paths', 'default') |
323 if repo.shared(): |
323 if repo.shared(): |
324 # chop off the .hg component to get the default path form |
324 # chop off the .hg component to get the default path form |
325 return os.path.dirname(repo.sharedpath) |
325 return os.path.dirname(repo.sharedpath) |
326 if abort: |
326 if abort: |
327 raise util.Abort(_("default path for subrepository not found")) |
327 raise error.Abort(_("default path for subrepository not found")) |
328 |
328 |
329 def _sanitize(ui, vfs, ignore): |
329 def _sanitize(ui, vfs, ignore): |
330 for dirname, dirs, names in vfs.walk(): |
330 for dirname, dirs, names in vfs.walk(): |
331 for i, d in enumerate(dirs): |
331 for i, d in enumerate(dirs): |
332 if d.lower() == ignore: |
332 if d.lower() == ignore: |
351 hg = h |
351 hg = h |
352 |
352 |
353 pathutil.pathauditor(ctx.repo().root)(path) |
353 pathutil.pathauditor(ctx.repo().root)(path) |
354 state = ctx.substate[path] |
354 state = ctx.substate[path] |
355 if state[2] not in types: |
355 if state[2] not in types: |
356 raise util.Abort(_('unknown subrepo type %s') % state[2]) |
356 raise error.Abort(_('unknown subrepo type %s') % state[2]) |
357 if allowwdir: |
357 if allowwdir: |
358 state = (state[0], ctx.subrev(path), state[2]) |
358 state = (state[0], ctx.subrev(path), state[2]) |
359 return types[state[2]](ctx, path, state[:2]) |
359 return types[state[2]](ctx, path, state[:2]) |
360 |
360 |
361 def nullsubrepo(ctx, path, pctx): |
361 def nullsubrepo(ctx, path, pctx): |
369 hg = h |
369 hg = h |
370 |
370 |
371 pathutil.pathauditor(ctx.repo().root)(path) |
371 pathutil.pathauditor(ctx.repo().root)(path) |
372 state = ctx.substate[path] |
372 state = ctx.substate[path] |
373 if state[2] not in types: |
373 if state[2] not in types: |
374 raise util.Abort(_('unknown subrepo type %s') % state[2]) |
374 raise error.Abort(_('unknown subrepo type %s') % state[2]) |
375 subrev = '' |
375 subrev = '' |
376 if state[2] == 'hg': |
376 if state[2] == 'hg': |
377 subrev = "0" * 40 |
377 subrev = "0" * 40 |
378 return types[state[2]](pctx, path, (state[0], subrev)) |
378 return types[state[2]](pctx, path, (state[0], subrev)) |
379 |
379 |
382 substate = getattr(ctx, "substate", None) |
382 substate = getattr(ctx, "substate", None) |
383 if not substate: |
383 if not substate: |
384 return commitphase |
384 return commitphase |
385 check = ui.config('phases', 'checksubrepos', 'follow') |
385 check = ui.config('phases', 'checksubrepos', 'follow') |
386 if check not in ('ignore', 'follow', 'abort'): |
386 if check not in ('ignore', 'follow', 'abort'): |
387 raise util.Abort(_('invalid phases.checksubrepos configuration: %s') |
387 raise error.Abort(_('invalid phases.checksubrepos configuration: %s') |
388 % (check)) |
388 % (check)) |
389 if check == 'ignore': |
389 if check == 'ignore': |
390 return commitphase |
390 return commitphase |
391 maxphase = phases.public |
391 maxphase = phases.public |
392 maxsub = None |
392 maxsub = None |
396 if maxphase < subphase: |
396 if maxphase < subphase: |
397 maxphase = subphase |
397 maxphase = subphase |
398 maxsub = s |
398 maxsub = s |
399 if commitphase < maxphase: |
399 if commitphase < maxphase: |
400 if check == 'abort': |
400 if check == 'abort': |
401 raise util.Abort(_("can't commit in %s phase" |
401 raise error.Abort(_("can't commit in %s phase" |
402 " conflicting %s from subrepository %s") % |
402 " conflicting %s from subrepository %s") % |
403 (phases.phasenames[commitphase], |
403 (phases.phasenames[commitphase], |
404 phases.phasenames[maxphase], maxsub)) |
404 phases.phasenames[maxphase], maxsub)) |
405 ui.warn(_("warning: changes are committed in" |
405 ui.warn(_("warning: changes are committed in" |
406 " %s phase from subrepository %s\n") % |
406 " %s phase from subrepository %s\n") % |
454 def bailifchanged(self, ignoreupdate=False): |
454 def bailifchanged(self, ignoreupdate=False): |
455 """raise Abort if subrepository is ``dirty()`` |
455 """raise Abort if subrepository is ``dirty()`` |
456 """ |
456 """ |
457 dirtyreason = self.dirtyreason(ignoreupdate=ignoreupdate) |
457 dirtyreason = self.dirtyreason(ignoreupdate=ignoreupdate) |
458 if dirtyreason: |
458 if dirtyreason: |
459 raise util.Abort(dirtyreason) |
459 raise error.Abort(dirtyreason) |
460 |
460 |
461 def basestate(self): |
461 def basestate(self): |
462 """current working directory base state, disregarding .hgsubstate |
462 """current working directory base state, disregarding .hgsubstate |
463 state and working directory modifications""" |
463 state and working directory modifications""" |
464 raise NotImplementedError |
464 raise NotImplementedError |
1071 def __init__(self, ctx, path, state): |
1071 def __init__(self, ctx, path, state): |
1072 super(svnsubrepo, self).__init__(ctx, path) |
1072 super(svnsubrepo, self).__init__(ctx, path) |
1073 self._state = state |
1073 self._state = state |
1074 self._exe = util.findexe('svn') |
1074 self._exe = util.findexe('svn') |
1075 if not self._exe: |
1075 if not self._exe: |
1076 raise util.Abort(_("'svn' executable not found for subrepo '%s'") |
1076 raise error.Abort(_("'svn' executable not found for subrepo '%s'") |
1077 % self._path) |
1077 % self._path) |
1078 |
1078 |
1079 def _svncommand(self, commands, filename='', failok=False): |
1079 def _svncommand(self, commands, filename='', failok=False): |
1080 cmd = [self._exe] |
1080 cmd = [self._exe] |
1081 extrakw = {} |
1081 extrakw = {} |
1106 universal_newlines=True, env=env, **extrakw) |
1106 universal_newlines=True, env=env, **extrakw) |
1107 stdout, stderr = p.communicate() |
1107 stdout, stderr = p.communicate() |
1108 stderr = stderr.strip() |
1108 stderr = stderr.strip() |
1109 if not failok: |
1109 if not failok: |
1110 if p.returncode: |
1110 if p.returncode: |
1111 raise util.Abort(stderr or 'exited with code %d' % p.returncode) |
1111 raise error.Abort(stderr or 'exited with code %d' |
|
1112 % p.returncode) |
1112 if stderr: |
1113 if stderr: |
1113 self.ui.warn(stderr + '\n') |
1114 self.ui.warn(stderr + '\n') |
1114 return stdout, stderr |
1115 return stdout, stderr |
1115 |
1116 |
1116 @propertycache |
1117 @propertycache |
1117 def _svnversion(self): |
1118 def _svnversion(self): |
1118 output, err = self._svncommand(['--version', '--quiet'], filename=None) |
1119 output, err = self._svncommand(['--version', '--quiet'], filename=None) |
1119 m = re.search(r'^(\d+)\.(\d+)', output) |
1120 m = re.search(r'^(\d+)\.(\d+)', output) |
1120 if not m: |
1121 if not m: |
1121 raise util.Abort(_('cannot retrieve svn tool version')) |
1122 raise error.Abort(_('cannot retrieve svn tool version')) |
1122 return (int(m.group(1)), int(m.group(2))) |
1123 return (int(m.group(1)), int(m.group(2))) |
1123 |
1124 |
1124 def _wcrevs(self): |
1125 def _wcrevs(self): |
1125 # Get the working directory revision as well as the last |
1126 # Get the working directory revision as well as the last |
1126 # commit revision so we can compare the subrepo state with |
1127 # commit revision so we can compare the subrepo state with |
1194 changed, extchanged, missing = self._wcchanged() |
1195 changed, extchanged, missing = self._wcchanged() |
1195 if not changed: |
1196 if not changed: |
1196 return self.basestate() |
1197 return self.basestate() |
1197 if extchanged: |
1198 if extchanged: |
1198 # Do not try to commit externals |
1199 # Do not try to commit externals |
1199 raise util.Abort(_('cannot commit svn externals')) |
1200 raise error.Abort(_('cannot commit svn externals')) |
1200 if missing: |
1201 if missing: |
1201 # svn can commit with missing entries but aborting like hg |
1202 # svn can commit with missing entries but aborting like hg |
1202 # seems a better approach. |
1203 # seems a better approach. |
1203 raise util.Abort(_('cannot commit missing svn entries')) |
1204 raise error.Abort(_('cannot commit missing svn entries')) |
1204 commitinfo, err = self._svncommand(['commit', '-m', text]) |
1205 commitinfo, err = self._svncommand(['commit', '-m', text]) |
1205 self.ui.status(commitinfo) |
1206 self.ui.status(commitinfo) |
1206 newrev = re.search('Committed revision ([0-9]+).', commitinfo) |
1207 newrev = re.search('Committed revision ([0-9]+).', commitinfo) |
1207 if not newrev: |
1208 if not newrev: |
1208 if not commitinfo.strip(): |
1209 if not commitinfo.strip(): |
1209 # Sometimes, our definition of "changed" differs from |
1210 # Sometimes, our definition of "changed" differs from |
1210 # svn one. For instance, svn ignores missing files |
1211 # svn one. For instance, svn ignores missing files |
1211 # when committing. If there are only missing files, no |
1212 # when committing. If there are only missing files, no |
1212 # commit is made, no output and no error code. |
1213 # commit is made, no output and no error code. |
1213 raise util.Abort(_('failed to commit svn changes')) |
1214 raise error.Abort(_('failed to commit svn changes')) |
1214 raise util.Abort(commitinfo.splitlines()[-1]) |
1215 raise error.Abort(commitinfo.splitlines()[-1]) |
1215 newrev = newrev.groups()[0] |
1216 newrev = newrev.groups()[0] |
1216 self.ui.status(self._svncommand(['update', '-r', newrev])[0]) |
1217 self.ui.status(self._svncommand(['update', '-r', newrev])[0]) |
1217 return newrev |
1218 return newrev |
1218 |
1219 |
1219 @annotatesubrepoerror |
1220 @annotatesubrepoerror |
1248 and (self._wcchanged()[:2] == (False, False))): |
1249 and (self._wcchanged()[:2] == (False, False))): |
1249 # obstructed but clean working copy, so just blow it away. |
1250 # obstructed but clean working copy, so just blow it away. |
1250 self.remove() |
1251 self.remove() |
1251 self.get(state, overwrite=False) |
1252 self.get(state, overwrite=False) |
1252 return |
1253 return |
1253 raise util.Abort((status or err).splitlines()[-1]) |
1254 raise error.Abort((status or err).splitlines()[-1]) |
1254 self.ui.status(status) |
1255 self.ui.status(status) |
1255 |
1256 |
1256 @annotatesubrepoerror |
1257 @annotatesubrepoerror |
1257 def merge(self, state): |
1258 def merge(self, state): |
1258 old = self._state[1] |
1259 old = self._state[1] |
1305 out, err = self._gitnodir(['--version']) |
1306 out, err = self._gitnodir(['--version']) |
1306 versionstatus = self._checkversion(out) |
1307 versionstatus = self._checkversion(out) |
1307 if versionstatus == 'unknown': |
1308 if versionstatus == 'unknown': |
1308 self.ui.warn(_('cannot retrieve git version\n')) |
1309 self.ui.warn(_('cannot retrieve git version\n')) |
1309 elif versionstatus == 'abort': |
1310 elif versionstatus == 'abort': |
1310 raise util.Abort(_('git subrepo requires at least 1.6.0 or later')) |
1311 raise error.Abort(_('git subrepo requires at least 1.6.0 or later')) |
1311 elif versionstatus == 'warning': |
1312 elif versionstatus == 'warning': |
1312 self.ui.warn(_('git subrepo requires at least 1.6.0 or later\n')) |
1313 self.ui.warn(_('git subrepo requires at least 1.6.0 or later\n')) |
1313 |
1314 |
1314 @staticmethod |
1315 @staticmethod |
1315 def _gitversion(out): |
1316 def _gitversion(out): |
1392 # there are certain error codes that are ok |
1393 # there are certain error codes that are ok |
1393 command = commands[0] |
1394 command = commands[0] |
1394 if command in ('cat-file', 'symbolic-ref'): |
1395 if command in ('cat-file', 'symbolic-ref'): |
1395 return retdata, p.returncode |
1396 return retdata, p.returncode |
1396 # for all others, abort |
1397 # for all others, abort |
1397 raise util.Abort('git %s error %d in %s' % |
1398 raise error.Abort('git %s error %d in %s' % |
1398 (command, p.returncode, self._relpath)) |
1399 (command, p.returncode, self._relpath)) |
1399 |
1400 |
1400 return retdata, p.returncode |
1401 return retdata, p.returncode |
1401 |
1402 |
1402 def _gitmissing(self): |
1403 def _gitmissing(self): |
1489 self.ui.status(_('pulling subrepo %s from %s\n') % |
1490 self.ui.status(_('pulling subrepo %s from %s\n') % |
1490 (self._relpath, self._gitremote('origin'))) |
1491 (self._relpath, self._gitremote('origin'))) |
1491 # try only origin: the originally cloned repo |
1492 # try only origin: the originally cloned repo |
1492 self._gitcommand(['fetch']) |
1493 self._gitcommand(['fetch']) |
1493 if not self._githavelocally(revision): |
1494 if not self._githavelocally(revision): |
1494 raise util.Abort(_("revision %s does not exist in subrepo %s\n") % |
1495 raise error.Abort(_("revision %s does not exist in subrepo %s\n") % |
1495 (revision, self._relpath)) |
1496 (revision, self._relpath)) |
1496 |
1497 |
1497 @annotatesubrepoerror |
1498 @annotatesubrepoerror |
1498 def dirty(self, ignoreupdate=False): |
1499 def dirty(self, ignoreupdate=False): |
1499 if self._gitmissing(): |
1500 if self._gitmissing(): |
1598 rawcheckout() |
1599 rawcheckout() |
1599 |
1600 |
1600 @annotatesubrepoerror |
1601 @annotatesubrepoerror |
1601 def commit(self, text, user, date): |
1602 def commit(self, text, user, date): |
1602 if self._gitmissing(): |
1603 if self._gitmissing(): |
1603 raise util.Abort(_("subrepo %s is missing") % self._relpath) |
1604 raise error.Abort(_("subrepo %s is missing") % self._relpath) |
1604 cmd = ['commit', '-a', '-m', text] |
1605 cmd = ['commit', '-a', '-m', text] |
1605 env = os.environ.copy() |
1606 env = os.environ.copy() |
1606 if user: |
1607 if user: |
1607 cmd += ['--author', user] |
1608 cmd += ['--author', user] |
1608 if date: |
1609 if date: |
1644 force = opts.get('force') |
1645 force = opts.get('force') |
1645 |
1646 |
1646 if not self._state[1]: |
1647 if not self._state[1]: |
1647 return True |
1648 return True |
1648 if self._gitmissing(): |
1649 if self._gitmissing(): |
1649 raise util.Abort(_("subrepo %s is missing") % self._relpath) |
1650 raise error.Abort(_("subrepo %s is missing") % self._relpath) |
1650 # if a branch in origin contains the revision, nothing to do |
1651 # if a branch in origin contains the revision, nothing to do |
1651 branch2rev, rev2branch = self._gitbranchmap() |
1652 branch2rev, rev2branch = self._gitbranchmap() |
1652 if self._state[1] in rev2branch: |
1653 if self._state[1] in rev2branch: |
1653 for b in rev2branch[self._state[1]]: |
1654 for b in rev2branch[self._state[1]]: |
1654 if b.startswith('refs/remotes/origin/'): |
1655 if b.startswith('refs/remotes/origin/'): |