Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/subrepo.py @ 20176:4c96c50ef937
subrepo: check phase of state in each subrepositories before committing
Before this patch, phase of newly created commit is determined by
"phases.new-commit" configuration regardless of phase of state in each
subrepositories.
For example, this may cause the "public" revision in the parent
repository referring the "secret" one in subrepository.
This patch checks phase of state in each subrepositories before
committing in the parent, and aborts or changes phase of newly created
commit if subrepositories have more restricted phase than the parent.
This patch uses "follow" as default value of "phases.checksubrepos"
configuration, because it can keep consistency between phases of the
parent and subrepositories without breaking existing tool chains.
author | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> |
---|---|
date | Wed, 13 Nov 2013 15:55:30 +0900 |
parents | af12f58e2aa0 |
children | d6939f29b3b3 |
comparison
equal
deleted
inserted
replaced
20175:5ff0fd023850 | 20176:4c96c50ef937 |
---|---|
8 import errno, os, re, shutil, posixpath, sys | 8 import errno, os, re, shutil, posixpath, sys |
9 import xml.dom.minidom | 9 import xml.dom.minidom |
10 import stat, subprocess, tarfile | 10 import stat, subprocess, tarfile |
11 from i18n import _ | 11 from i18n import _ |
12 import config, util, node, error, cmdutil, bookmarks, match as matchmod | 12 import config, util, node, error, cmdutil, bookmarks, match as matchmod |
13 import phases | |
13 import pathutil | 14 import pathutil |
14 hg = None | 15 hg = None |
15 propertycache = util.propertycache | 16 propertycache = util.propertycache |
16 | 17 |
17 nullstate = ('', '', 'empty') | 18 nullstate = ('', '', 'empty') |
349 state = ctx.substate[path] | 350 state = ctx.substate[path] |
350 if state[2] not in types: | 351 if state[2] not in types: |
351 raise util.Abort(_('unknown subrepo type %s') % state[2]) | 352 raise util.Abort(_('unknown subrepo type %s') % state[2]) |
352 return types[state[2]](ctx, path, state[:2]) | 353 return types[state[2]](ctx, path, state[:2]) |
353 | 354 |
355 def newcommitphase(ui, ctx): | |
356 commitphase = phases.newcommitphase(ui) | |
357 substate = getattr(ctx, "substate", None) | |
358 if not substate: | |
359 return commitphase | |
360 check = ui.config('phases', 'checksubrepos', 'follow') | |
361 if check not in ('ignore', 'follow', 'abort'): | |
362 raise util.Abort(_('invalid phases.checksubrepos configuration: %s') | |
363 % (check)) | |
364 if check == 'ignore': | |
365 return commitphase | |
366 maxphase = phases.public | |
367 maxsub = None | |
368 for s in sorted(substate): | |
369 sub = ctx.sub(s) | |
370 subphase = sub.phase(substate[s][1]) | |
371 if maxphase < subphase: | |
372 maxphase = subphase | |
373 maxsub = s | |
374 if commitphase < maxphase: | |
375 if check == 'abort': | |
376 raise util.Abort(_("can't commit in %s phase" | |
377 " conflicting %s from subrepository %s") % | |
378 (phases.phasenames[commitphase], | |
379 phases.phasenames[maxphase], maxsub)) | |
380 ui.warn(_("warning: changes are committed in" | |
381 " %s phase from subrepository %s\n") % | |
382 (phases.phasenames[maxphase], maxsub)) | |
383 return maxphase | |
384 return commitphase | |
385 | |
354 # subrepo classes need to implement the following abstract class: | 386 # subrepo classes need to implement the following abstract class: |
355 | 387 |
356 class abstractsubrepo(object): | 388 class abstractsubrepo(object): |
357 | 389 |
358 def storeclean(self, path): | 390 def storeclean(self, path): |
382 """commit the current changes to the subrepo with the given | 414 """commit the current changes to the subrepo with the given |
383 log message. Use given user and date if possible. Return the | 415 log message. Use given user and date if possible. Return the |
384 new state of the subrepo. | 416 new state of the subrepo. |
385 """ | 417 """ |
386 raise NotImplementedError | 418 raise NotImplementedError |
419 | |
420 def phase(self, state): | |
421 """returns phase of specified state in the subrepository. | |
422 """ | |
423 return phases.public | |
387 | 424 |
388 def remove(self): | 425 def remove(self): |
389 """remove the subrepo | 426 """remove the subrepo |
390 | 427 |
391 (should verify the dirstate is not dirty first) | 428 (should verify the dirstate is not dirty first) |
648 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self)) | 685 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self)) |
649 n = self._repo.commit(text, user, date) | 686 n = self._repo.commit(text, user, date) |
650 if not n: | 687 if not n: |
651 return self._repo['.'].hex() # different version checked out | 688 return self._repo['.'].hex() # different version checked out |
652 return node.hex(n) | 689 return node.hex(n) |
690 | |
691 @annotatesubrepoerror | |
692 def phase(self, state): | |
693 return self._repo[state].phase() | |
653 | 694 |
654 @annotatesubrepoerror | 695 @annotatesubrepoerror |
655 def remove(self): | 696 def remove(self): |
656 # we can't fully delete the repository as it may contain | 697 # we can't fully delete the repository as it may contain |
657 # local-only history | 698 # local-only history |