##// END OF EJS Templates
mq: Do not translate import message that are appended to commits....
mq: Do not translate import message that are appended to commits. We should not translate the "imported patch" message. The translated message confuses the detection whether the user has not updated the commit message yet. We try to avoid to translate generated commit messages.

File last commit:

r10273:e898bc78 default
r10274:04207f5e stable
Show More
subrepo.py
232 lines | 7.8 KiB | text/x-python | PythonLexer
Matt Mackall
subrepo: introduce basic state parsing
r8812 # subrepo.py - sub-repository handling for Mercurial
#
# Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
subrepo: introduce basic state parsing
r8812
Matt Mackall
commit: recurse into subrepositories
r8813 import errno, os
Matt Mackall
subrepo: add update/merge logic
r8814 from i18n import _
Matt Mackall
commit: recurse into subrepositories
r8813 import config, util, node, error
Abderrahim Kitouni
subrepo: use hg.repository instead of creating localrepo directly...
r9092 hg = None
Matt Mackall
commit: recurse into subrepositories
r8813
nullstate = ('', '')
Matt Mackall
subrepo: introduce basic state parsing
r8812
def state(ctx):
p = config.config()
def read(f, sections=None, remap=None):
if f in ctx:
try:
p.parse(f, ctx[f].data(), sections, remap)
except IOError, err:
if err.errno != errno.ENOENT:
raise
read('.hgsub')
rev = {}
if '.hgsubstate' in ctx:
try:
for l in ctx['.hgsubstate'].data().splitlines():
Matt Mackall
subrepo: more robust split for .hgsubstate parsing
r9752 revision, path = l.split(" ", 1)
Matt Mackall
subrepo: introduce basic state parsing
r8812 rev[path] = revision
except IOError, err:
if err.errno != errno.ENOENT:
raise
state = {}
for path, src in p[''].items():
state[path] = (src, rev.get(path, ''))
return state
Matt Mackall
commit: recurse into subrepositories
r8813
def writestate(repo, state):
repo.wwrite('.hgsubstate',
''.join(['%s %s\n' % (state[s][1], s)
for s in sorted(state)]), '')
Matt Mackall
subrepo: add update/merge logic
r8814 def submerge(repo, wctx, mctx, actx):
if mctx == actx: # backwards?
actx = wctx.p1()
s1 = wctx.substate
s2 = mctx.substate
sa = actx.substate
sm = {}
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
Matt Mackall
subrepo: add some debug output to submerge
r9779 def debug(s, msg, r=""):
if r:
r = "%s:%s" % r
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
Matt Mackall
subrepo: add some debug output to submerge
r9779
Matt Mackall
subrepo: add update/merge logic
r8814 for s, l in s1.items():
Matt Mackall
submerge: properly deal with overwrites...
r9783 if wctx != actx and wctx.sub(s).dirty():
Matt Mackall
subrepo: notice dirty subrepo states when merging
r9780 l = (l[0], l[1] + "+")
Matt Mackall
subrepo: add update/merge logic
r8814 a = sa.get(s, nullstate)
if s in s2:
r = s2[s]
if l == r or r == a: # no change or local is newer
sm[s] = l
continue
elif l == a: # other side changed
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "other changed, get", r)
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).get(r)
sm[s] = r
elif l[0] != r[0]: # sources differ
Simon Heimberg
ui: extract choice from prompt...
r9048 if repo.ui.promptchoice(
Matt Mackall
subrepo: add update/merge logic
r8814 _(' subrepository sources for %s differ\n'
Dongsheng Song
Fix warning: Seen unexpected token "%"
r8908 'use (l)ocal source (%s) or (r)emote source (%s)?')
Matt Mackall
subrepo: add update/merge logic
r8814 % (s, l[0], r[0]),
Simon Heimberg
ui: extract choice from prompt...
r9048 (_('&Local'), _('&Remote')), 0):
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "prompt changed, get", r)
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).get(r)
sm[s] = r
elif l[1] == a[1]: # local side is unchanged
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "other side changed, get", r)
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).get(r)
sm[s] = r
else:
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "both sides changed, merge with", r)
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).merge(r)
sm[s] = l
elif l == a: # remote removed, local unchanged
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "remote removed, remove")
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).remove()
else:
Simon Heimberg
ui: extract choice from prompt...
r9048 if repo.ui.promptchoice(
Matt Mackall
subrepo: add update/merge logic
r8814 _(' local changed subrepository %s which remote removed\n'
Dongsheng Song
Fix warning: Seen unexpected token "%"
r8908 'use (c)hanged version or (d)elete?') % s,
Martin Geisler
filemerge, subrepo: correct indention
r9049 (_('&Changed'), _('&Delete')), 0):
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "prompt remove")
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).remove()
for s, r in s2.items():
if s in s1:
continue
elif s not in sa:
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "remote added, get", r)
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).get(r)
sm[s] = r
elif r != sa[s]:
Simon Heimberg
ui: extract choice from prompt...
r9048 if repo.ui.promptchoice(
Matt Mackall
subrepo: add update/merge logic
r8814 _(' remote changed subrepository %s which local removed\n'
Dongsheng Song
Fix warning: Seen unexpected token "%"
r8908 'use (c)hanged version or (d)elete?') % s,
Martin Geisler
filemerge, subrepo: correct indention
r9049 (_('&Changed'), _('&Delete')), 0) == 0:
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "prompt recreate", r)
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).get(r)
sm[s] = r
# record merged .hgsubstate
writestate(repo, sm)
Matt Mackall
subrepo: basic push support
r8815 def _abssource(repo, push=False):
Matt Mackall
subrepo: add update/merge logic
r8814 if hasattr(repo, '_subparent'):
source = repo._subsource
if source.startswith('/') or '://' in source:
return source
Matt Mackall
subrepo: use '/' for joining non-local paths
r9186 parent = _abssource(repo._subparent)
if '://' in parent:
if parent[-1] == '/':
parent = parent[:-1]
return parent + '/' + source
return os.path.join(parent, repo._subsource)
Matt Mackall
subrepo: basic push support
r8815 if push and repo.ui.config('paths', 'default-push'):
return repo.ui.config('paths', 'default-push', repo.root)
Matt Mackall
subrepo: add update/merge logic
r8814 return repo.ui.config('paths', 'default', repo.root)
Matt Mackall
commit: recurse into subrepositories
r8813 def subrepo(ctx, path):
# subrepo inherently violates our import layering rules
# because it wants to make repo objects from deep inside the stack
# so we manually delay the circular imports to not break
# scripts that don't use our demand-loading
Abderrahim Kitouni
subrepo: use hg.repository instead of creating localrepo directly...
r9092 global hg
import hg as h
Matt Mackall
subrepo: add update/merge logic
r8814 hg = h
Matt Mackall
commit: recurse into subrepositories
r8813
Matt Mackall
subrepo: audit subrepo paths
r8997 util.path_auditor(ctx._repo.root)(path)
Matt Mackall
commit: recurse into subrepositories
r8813 state = ctx.substate.get(path, nullstate)
if state[0].startswith('['): # future expansion
raise error.Abort('unknown subrepo source %s' % state[0])
return hgsubrepo(ctx, path, state)
class hgsubrepo(object):
def __init__(self, ctx, path, state):
self._path = path
self._state = state
r = ctx._repo
root = r.wjoin(path)
Matt Mackall
subrepo: add update/merge logic
r8814 if os.path.exists(os.path.join(root, '.hg')):
Abderrahim Kitouni
subrepo: use hg.repository instead of creating localrepo directly...
r9092 self._repo = hg.repository(r.ui, root)
Matt Mackall
subrepo: add update/merge logic
r8814 else:
util.makedirs(root)
Abderrahim Kitouni
subrepo: use hg.repository instead of creating localrepo directly...
r9092 self._repo = hg.repository(r.ui, root, create=True)
Matt Mackall
subrepo: add default path to new clones
r10068 f = file(os.path.join(root, '.hg', 'hgrc'), 'w')
f.write('[paths]\ndefault = %s\n' % state[0])
f.close()
Matt Mackall
subrepo: add update/merge logic
r8814 self._repo._subparent = r
self._repo._subsource = state[0]
Matt Mackall
commit: recurse into subrepositories
r8813
def dirty(self):
r = self._state[1]
if r == '':
return True
w = self._repo[None]
if w.p1() != self._repo[r]: # version checked out changed
return True
return w.dirty() # working directory changed
def commit(self, text, user, date):
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 self._repo.ui.debug("committing subrepo %s\n" % self._path)
Matt Mackall
commit: recurse into subrepositories
r8813 n = self._repo.commit(text, user, date)
if not n:
return self._repo['.'].hex() # different version checked out
return node.hex(n)
Matt Mackall
subrepo: add update/merge logic
r8814
def remove(self):
# we can't fully delete the repository as it may contain
# local-only history
self._repo.ui.note(_('removing subrepo %s\n') % self._path)
hg.clean(self._repo, node.nullid, False)
Matt Mackall
subrepo: add auto-pull for merge
r9507 def _get(self, state):
Matt Mackall
subrepo: add update/merge logic
r8814 source, revision = state
try:
self._repo.lookup(revision)
except error.RepoError:
self._repo._subsource = source
self._repo.ui.status(_('pulling subrepo %s\n') % self._path)
srcurl = _abssource(self._repo)
other = hg.repository(self._repo.ui, srcurl)
self._repo.pull(other)
Matt Mackall
subrepo: add auto-pull for merge
r9507 def get(self, state):
self._get(state)
source, revision = state
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 self._repo.ui.debug("getting subrepo %s\n" % self._path)
Matt Mackall
subrepo: add update/merge logic
r8814 hg.clean(self._repo, revision, False)
def merge(self, state):
Matt Mackall
subrepo: add auto-pull for merge
r9507 self._get(state)
Matt Mackall
subrepo: do a linear update when appropriate
r9781 cur = self._repo['.']
dst = self._repo[state[1]]
Benoit Boissinot
subrepo: fix merging of already merged subrepos (issue1986)...
r10251 anc = dst.ancestor(cur)
if anc == cur:
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 self._repo.ui.debug("updating subrepo %s\n" % self._path)
Matt Mackall
subrepo: do a linear update when appropriate
r9781 hg.update(self._repo, state[1])
Benoit Boissinot
subrepo: fix merging of already merged subrepos (issue1986)...
r10251 elif anc == dst:
self._repo.ui.debug("skipping subrepo %s\n" % self._path)
Matt Mackall
subrepo: do a linear update when appropriate
r9781 else:
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 self._repo.ui.debug("merging subrepo %s\n" % self._path)
Matt Mackall
subrepo: do a linear update when appropriate
r9781 hg.merge(self._repo, state[1], remind=False)
Matt Mackall
subrepo: basic push support
r8815
def push(self, force):
# push subrepos depth-first for coherent ordering
c = self._repo['']
subs = c.substate # only repos that are committed
for s in sorted(subs):
c.sub(s).push(force)
self._repo.ui.status(_('pushing subrepo %s\n') % self._path)
dsturl = _abssource(self._repo, True)
other = hg.repository(self._repo.ui, dsturl)
self._repo.push(other, force)