##// END OF EJS Templates
url: add --insecure option to bypass verification of ssl certificates...
url: add --insecure option to bypass verification of ssl certificates If --insecure specified, it behaves in the same way as no web.cacerts configured. Also shows hint for --insecure option when _verifycert() failed. But currently the hint isn't displayed on SSLError, because it needs a certain level of changes.

File last commit:

r13325:7ebdfa37 default
r13328:a939f08f stable
Show More
subrepo.py
622 lines | 21.8 KiB | text/x-python | PythonLexer
Matt Mackall
subrepo: introduce basic state parsing
r8812 # subrepo.py - sub-repository handling for Mercurial
#
David Soria Parra
subrepo: correct copyright
r10324 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
Matt Mackall
subrepo: introduce basic state parsing
r8812 #
# 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
Edouard Gomez
subrepo: normalize path part of URLs so that pulling subrepos from webdir works...
r11109 import errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath
Patrick Mezard
subrepo: use subprocess directly to avoid python 2.6 bug...
r13014 import stat, subprocess
Matt Mackall
subrepo: add update/merge logic
r8814 from i18n import _
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 import config, util, node, error, cmdutil
Abderrahim Kitouni
subrepo: use hg.repository instead of creating localrepo directly...
r9092 hg = None
Matt Mackall
commit: recurse into subrepositories
r8813
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 nullstate = ('', '', 'empty')
Matt Mackall
subrepo: introduce basic state parsing
r8812
Martin Geisler
subrepos: support remapping of .hgsub source paths...
r11775 def state(ctx, ui):
Mads Kiilerich
subrepo: docstrings
r11571 """return a state dict, mapping subrepo paths configured in .hgsub
to tuple: (source from .hgsub, revision from .hgsubstate, kind
(key in types dict))
"""
Matt Mackall
subrepo: introduce basic state parsing
r8812 p = config.config()
def read(f, sections=None, remap=None):
if f in ctx:
Patrick Mezard
subrepo: handle missing subrepo spec file as removed...
r13017 try:
data = ctx[f].data()
except IOError, err:
if err.errno != errno.ENOENT:
raise
# handle missing subrepo spec files as removed
ui.warn(_("warning: subrepo spec file %s not found\n") % f)
return
p.parse(f, data, sections, remap, read)
Matt Mackall
subrepo: fix includes support in .hgsub
r10174 else:
raise util.Abort(_("subrepo spec file %s not found") % f)
if '.hgsub' in ctx:
read('.hgsub')
Matt Mackall
subrepo: introduce basic state parsing
r8812
Martin Geisler
subrepos: support remapping of .hgsub source paths...
r11775 for path, src in ui.configitems('subpaths'):
p.set('subpaths', path, src, ui.configsource('subpaths', path))
Matt Mackall
subrepo: introduce basic state parsing
r8812 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():
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 kind = 'hg'
if src.startswith('['):
if ']' not in src:
raise util.Abort(_('missing ] in subrepo source'))
kind, src = src.split(']', 1)
kind = kind[1:]
Martin Geisler
subrepos: support remapping of .hgsub source paths...
r11775
for pattern, repl in p.items('subpaths'):
Martin Geisler
subrepos: handle backslashes in subpaths
r11961 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
# does a string decode.
repl = repl.encode('string-escape')
# However, we still want to allow back references to go
# through unharmed, so we turn r'\\1' into r'\1'. Again,
# extra escapes are needed because re.sub string decodes.
repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
Martin Geisler
subrepos: support remapping of .hgsub source paths...
r11775 try:
src = re.sub(pattern, repl, src, 1)
except re.error, e:
raise util.Abort(_("bad subrepository pattern in %s: %s")
% (p.source('subpaths', pattern), e))
David Soria Parra
subrepo: make sure that the source path is stripped...
r10457 state[path] = (src.strip(), rev.get(path, ''), kind)
Matt Mackall
subrepo: introduce basic state parsing
r8812
return state
Matt Mackall
commit: recurse into subrepositories
r8813
def writestate(repo, state):
Mads Kiilerich
subrepo: docstrings
r11571 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
Matt Mackall
commit: recurse into subrepositories
r8813 repo.wwrite('.hgsubstate',
''.join(['%s %s\n' % (state[s][1], s)
for s in sorted(state)]), '')
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 def submerge(repo, wctx, mctx, actx, overwrite):
Mads Kiilerich
subrepo: docstrings
r11571 """delegated from merge.applyupdates: merging of .hgsubstate file
in working context, merging context and ancestor context"""
Matt Mackall
subrepo: add update/merge logic
r8814 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:
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 r = "%s:%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
subrepo: correctly handle update -C with modified subrepos (issue2022)...
r11470 a = sa.get(s, nullstate)
Matt Mackall
subrepo: fix recording of + in .hgsubstate (issue2217)
r11463 ld = l # local state with possible dirty flag for compares
Matt Mackall
subrepo: correctly handle update -C with modified subrepos (issue2022)...
r11470 if wctx.sub(s).dirty():
Matt Mackall
subrepo: fix recording of + in .hgsubstate (issue2217)
r11463 ld = (l[0], l[1] + "+")
Matt Mackall
subrepo: correctly handle update -C with modified subrepos (issue2022)...
r11470 if wctx == actx: # overwrite
a = ld
Matt Mackall
subrepo: fix recording of + in .hgsubstate (issue2217)
r11463
Matt Mackall
subrepo: add update/merge logic
r8814 if s in s2:
r = s2[s]
Matt Mackall
subrepo: fix recording of + in .hgsubstate (issue2217)
r11463 if ld == r or r == a: # no change or local is newer
Matt Mackall
subrepo: add update/merge logic
r8814 sm[s] = l
continue
Matt Mackall
subrepo: fix recording of + in .hgsubstate (issue2217)
r11463 elif ld == a: # other side changed
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "other changed, get", r)
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 wctx.sub(s).get(r, overwrite)
Matt Mackall
subrepo: add update/merge logic
r8814 sm[s] = r
Matt Mackall
subrepo: fix recording of + in .hgsubstate (issue2217)
r11463 elif ld[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)
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 wctx.sub(s).get(r, overwrite)
Matt Mackall
subrepo: add update/merge logic
r8814 sm[s] = r
Matt Mackall
subrepo: fix recording of + in .hgsubstate (issue2217)
r11463 elif ld[1] == a[1]: # local side is unchanged
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "other side changed, get", r)
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 wctx.sub(s).get(r, overwrite)
Matt Mackall
subrepo: add update/merge logic
r8814 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
Matt Mackall
subrepo: fix recording of + in .hgsubstate (issue2217)
r11463 elif ld == 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)
Augie Fackler
subrepo: load from a context where the subrepo exists
r10175 mctx.sub(s).get(r)
Matt Mackall
subrepo: add update/merge logic
r8814 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)
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 def reporelpath(repo):
"""return path to this (sub)repo as seen from outermost repo"""
parent = repo
while hasattr(parent, '_subparent'):
parent = parent._subparent
return repo.root[len(parent.root)+1:]
def subrelpath(sub):
Mads Kiilerich
subrepo: docstrings
r11571 """return path to this subrepo as seen from outermost repo"""
Edouard Gomez
subrepo: print paths relative to upper repo root for push/pull/commit...
r11112 if not hasattr(sub, '_repo'):
return sub._path
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 return reporelpath(sub._repo)
Edouard Gomez
subrepo: print paths relative to upper repo root for push/pull/commit...
r11112
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 def _abssource(repo, push=False, abort=True):
"""return pull/push path of repo - either based on parent repo .hgsub info
or on the top repo config. Abort or return None if no source found."""
Matt Mackall
subrepo: add update/merge logic
r8814 if hasattr(repo, '_subparent'):
source = repo._subsource
if source.startswith('/') or '://' in source:
return source
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 parent = _abssource(repo._subparent, push, abort=False)
if parent:
if '://' in parent:
if parent[-1] == '/':
parent = parent[:-1]
r = urlparse.urlparse(parent + '/' + source)
r = urlparse.urlunparse((r[0], r[1],
posixpath.normpath(r[2]),
r[3], r[4], r[5]))
return r
else: # plain file system path
return posixpath.normpath(os.path.join(parent, repo._subsource))
else: # recursion reached top repo
Mads Kiilerich
subrepo: propagate non-default pull/push path to relative subrepos (issue1852)
r12852 if hasattr(repo, '_subtoppath'):
return repo._subtoppath
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 if push and repo.ui.config('paths', 'default-push'):
return repo.ui.config('paths', 'default-push')
if repo.ui.config('paths', 'default'):
return repo.ui.config('paths', 'default')
if abort:
Martin Geisler
check-code: find trailing whitespace
r12770 raise util.Abort(_("default path for subrepository %s not found") %
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 reporelpath(repo))
Matt Mackall
subrepo: add update/merge logic
r8814
Martin Geisler
subrepos: add function for iterating over ctx subrepos
r12176 def itersubrepos(ctx1, ctx2):
"""find subrepos in ctx1 or ctx2"""
# Create a (subpath, ctx) mapping where we prefer subpaths from
# ctx1. The subpaths from ctx2 are important when the .hgsub file
# has been modified (in ctx2) but not yet committed (in ctx1).
subpaths = dict.fromkeys(ctx2.substate, ctx2)
subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
for subpath, ctx in sorted(subpaths.iteritems()):
yield subpath, ctx.sub(subpath)
Matt Mackall
commit: recurse into subrepositories
r8813 def subrepo(ctx, path):
Mads Kiilerich
subrepo: docstrings
r11571 """return instance of the right subrepo class for subrepo in path"""
Matt Mackall
commit: recurse into subrepositories
r8813 # 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)
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 if state[2] not in types:
Benoit Boissinot
subrepo: fix errors reported by pylint
r10299 raise util.Abort(_('unknown subrepo type %s') % state[2])
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 return types[state[2]](ctx, path, state[:2])
Matt Mackall
commit: recurse into subrepositories
r8813
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 # subrepo classes need to implement the following abstract class:
class abstractsubrepo(object):
def dirty(self):
"""returns true if the dirstate of the subrepo does not match
current stored state
"""
raise NotImplementedError
Brodie Rao
subrepos: add missing self argument to abstractsubrepo.checknested
r12506 def checknested(self, path):
Martin Geisler
localrepo: add auditor attribute which knows about subrepos
r12162 """check if path is a subrepository within this repository"""
return False
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 def commit(self, text, user, date):
"""commit the current changes to the subrepo with the given
log message. Use given user and date if possible. Return the
new state of the subrepo.
"""
raise NotImplementedError
def remove(self):
"""remove the subrepo
Matt Mackall
commit: recurse into subrepositories
r8813
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 (should verify the dirstate is not dirty first)
"""
raise NotImplementedError
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 def get(self, state, overwrite=False):
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 """run whatever commands are needed to put the subrepo into
this state
"""
raise NotImplementedError
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 def merge(self, state, overwrite=False):
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 """merge currently-saved state with the new state."""
raise NotImplementedError
def push(self, force):
Martin Geisler
Merge with stable
r11572 """perform whatever action is analogous to 'hg push'
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559
This may be a no-op on some systems.
"""
raise NotImplementedError
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 def add(self, ui, match, dryrun, prefix):
return []
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559
Martin Geisler
status: recurse into subrepositories with --subrepos/-S flag
r12166 def status(self, rev2, **opts):
return [], [], [], [], [], [], []
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 def diff(self, diffopts, node2, match, prefix, **opts):
pass
Martin Geisler
outgoing: recurse into subrepositories with --subrepos/-S flag...
r12272 def outgoing(self, ui, dest, opts):
return 1
Martin Geisler
incoming: recurse into subrepositories with --subrepos/-S flag...
r12274 def incoming(self, ui, source, opts):
return 1
Martin Geisler
subrepo: introduce files and filedata methods for subrepo classes
r12322 def files(self):
"""return filename iterator"""
raise NotImplementedError
def filedata(self, name):
"""return file data"""
raise NotImplementedError
def fileflags(self, name):
"""return file flags"""
return ''
Martin Geisler
subrepo: add support for 'hg archive'
r12323 def archive(self, archiver, prefix):
for name in self.files():
flags = self.fileflags(name)
mode = 'x' in flags and 0755 or 0644
symlink = 'l' in flags
archiver.addfile(os.path.join(prefix, self._path, name),
mode, symlink, self.filedata(name))
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 class hgsubrepo(abstractsubrepo):
Matt Mackall
commit: recurse into subrepositories
r8813 def __init__(self, ctx, path, state):
self._path = path
self._state = state
r = ctx._repo
root = r.wjoin(path)
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666 create = False
if not os.path.exists(os.path.join(root, '.hg')):
create = True
Matt Mackall
subrepo: add update/merge logic
r8814 util.makedirs(root)
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666 self._repo = hg.repository(r.ui, root, create=create)
Matt Mackall
subrepo: add update/merge logic
r8814 self._repo._subparent = r
self._repo._subsource = state[0]
Matt Mackall
commit: recurse into subrepositories
r8813
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666 if create:
fp = self._repo.opener("hgrc", "w", text=True)
fp.write('[paths]\n')
def addpathconfig(key, value):
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 if value:
fp.write('%s = %s\n' % (key, value))
self._repo.ui.setconfig('paths', key, value)
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 defpath = _abssource(self._repo, abort=False)
defpushpath = _abssource(self._repo, True, abort=False)
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666 addpathconfig('default', defpath)
Edouard Gomez
subrepo: fix hgrc paths section during subrepo pulling...
r10697 if defpath != defpushpath:
addpathconfig('default-push', defpushpath)
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666 fp.close()
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 def add(self, ui, match, dryrun, prefix):
return cmdutil.add(ui, self._repo, match, dryrun, True,
os.path.join(prefix, self._path))
Martin Geisler
status: recurse into subrepositories with --subrepos/-S flag
r12166 def status(self, rev2, **opts):
try:
rev1 = self._state[1]
ctx1 = self._repo[rev1]
ctx2 = self._repo[rev2]
return self._repo.status(ctx1, ctx2, **opts)
except error.RepoLookupError, inst:
Wagner Bruna
subrepo: improve lookup error messages
r12503 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 % (inst, subrelpath(self)))
Martin Geisler
status: recurse into subrepositories with --subrepos/-S flag
r12166 return [], [], [], [], [], [], []
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 def diff(self, diffopts, node2, match, prefix, **opts):
try:
node1 = node.bin(self._state[1])
Patrick Mezard
subrepos: handle diff nodeids in subrepos, not before...
r12209 # We currently expect node2 to come from substate and be
# in hex format
Martin Geisler
subrepo: handle diff with working copy...
r12210 if node2 is not None:
node2 = node.bin(node2)
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts,
node1, node2, match,
prefix=os.path.join(prefix, self._path),
listsubrepos=True, **opts)
except error.RepoLookupError, inst:
Wagner Bruna
subrepo: improve lookup error messages
r12503 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 % (inst, subrelpath(self)))
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167
Martin Geisler
subrepo: add support for 'hg archive'
r12323 def archive(self, archiver, prefix):
abstractsubrepo.archive(self, archiver, prefix)
rev = self._state[1]
ctx = self._repo[rev]
for subpath in ctx.substate:
s = subrepo(ctx, subpath)
s.archive(archiver, os.path.join(prefix, self._path))
Matt Mackall
commit: recurse into subrepositories
r8813 def dirty(self):
r = self._state[1]
if r == '':
return True
w = self._repo[None]
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666 if w.p1() != self._repo[r]: # version checked out change
Matt Mackall
commit: recurse into subrepositories
r8813 return True
return w.dirty() # working directory changed
Martin Geisler
localrepo: add auditor attribute which knows about subrepos
r12162 def checknested(self, path):
return self._repo._checknested(self._repo.wjoin(path))
Matt Mackall
commit: recurse into subrepositories
r8813 def commit(self, text, user, date):
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
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
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
Matt Mackall
subrepo: add update/merge logic
r8814 hg.clean(self._repo, node.nullid, False)
Matt Mackall
subrepo: add auto-pull for merge
r9507 def _get(self, state):
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 source, revision, kind = state
Matt Mackall
subrepo: add update/merge logic
r8814 try:
self._repo.lookup(revision)
except error.RepoError:
self._repo._subsource = source
srcurl = _abssource(self._repo)
Martin Geisler
subrepo: wrap long line
r10671 self._repo.ui.status(_('pulling subrepo %s from %s\n')
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 % (subrelpath(self), srcurl))
Matt Mackall
subrepo: add update/merge logic
r8814 other = hg.repository(self._repo.ui, srcurl)
self._repo.pull(other)
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 def get(self, state, overwrite=False):
Matt Mackall
subrepo: add auto-pull for merge
r9507 self._get(state)
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 source, revision, kind = 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:
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
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:
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
Matt Mackall
subrepo: do a linear update when appropriate
r9781 else:
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
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):
Matt Mackall
subrepo: propagate and catch push failures
r11067 if not c.sub(s).push(force):
return False
Matt Mackall
subrepo: basic push support
r8815
dsturl = _abssource(self._repo, True)
Edouard Gomez
subrepo: print pushing url
r11111 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 (subrelpath(self), dsturl))
Matt Mackall
subrepo: basic push support
r8815 other = hg.repository(self._repo.ui, dsturl)
Matt Mackall
subrepo: propagate and catch push failures
r11067 return self._repo.push(other, force)
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177
Martin Geisler
outgoing: recurse into subrepositories with --subrepos/-S flag...
r12272 def outgoing(self, ui, dest, opts):
return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
Martin Geisler
incoming: recurse into subrepositories with --subrepos/-S flag...
r12274 def incoming(self, ui, source, opts):
return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
Martin Geisler
subrepo: introduce files and filedata methods for subrepo classes
r12322 def files(self):
rev = self._state[1]
ctx = self._repo[rev]
return ctx.manifest()
def filedata(self, name):
rev = self._state[1]
return self._repo[rev][name].data()
def fileflags(self, name):
rev = self._state[1]
ctx = self._repo[rev]
return ctx.flags(name)
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 class svnsubrepo(abstractsubrepo):
Augie Fackler
subrepo: Subversion support
r10178 def __init__(self, ctx, path, state):
self._path = path
self._state = state
self._ctx = ctx
self._ui = ctx._repo.ui
Martin Geisler
subrepos: let caller specify a filename for SVN commands
r11560 def _svncommand(self, commands, filename=''):
path = os.path.join(self._ctx._repo.origroot, self._path, filename)
Brett Cannon
subrepo: fix repo root path handling in svn subrepo
r10954 cmd = ['svn'] + commands + [path]
Augie Fackler
subrepo: Subversion support
r10178 cmd = [util.shellquote(arg) for arg in cmd]
cmd = util.quotecommand(' '.join(cmd))
Patrick Mezard
subrepo: force en_US.UTF-8 locale when calling svn...
r10199 env = dict(os.environ)
Patrick Mezard
subrepo: make svn use C locale for portability...
r10271 # Avoid localized output, preserve current locale for everything else.
env['LC_MESSAGES'] = 'C'
Patrick Mezard
subrepo: use subprocess directly to avoid python 2.6 bug...
r13014 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
close_fds=util.closefds,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True, env=env)
stdout, stderr = p.communicate()
stderr = stderr.strip()
if stderr:
raise util.Abort(stderr)
return stdout
Augie Fackler
subrepo: Subversion support
r10178
Patrick Mezard
subrepo: compare svn subrepo state to last committed revision...
r13287 def _wcrevs(self):
# Get the working directory revision as well as the last
# commit revision so we can compare the subrepo state with
# both. We used to store the working directory one.
Patrick Mezard
subrepo: svn xml output is much easier to parse...
r10272 output = self._svncommand(['info', '--xml'])
doc = xml.dom.minidom.parseString(output)
entries = doc.getElementsByTagName('entry')
Patrick Mezard
subrepo: compare svn subrepo state to last committed revision...
r13287 lastrev, rev = '0', '0'
if entries:
rev = str(entries[0].getAttribute('revision')) or '0'
commits = entries[0].getElementsByTagName('commit')
if commits:
lastrev = str(commits[0].getAttribute('revision')) or '0'
return (lastrev, rev)
def _wcrev(self):
return self._wcrevs()[0]
Augie Fackler
subrepo: Subversion support
r10178
Patrick Mezard
subrepo: handle svn externals and meta changes (issue1982)...
r10273 def _wcchanged(self):
"""Return (changes, extchanges) where changes is True
if the working directory was changed, and extchanges is
True if any of these changes concern an external entry.
"""
Patrick Mezard
subrepo: svn xml output is much easier to parse...
r10272 output = self._svncommand(['status', '--xml'])
Patrick Mezard
subrepo: handle svn externals and meta changes (issue1982)...
r10273 externals, changes = [], []
Patrick Mezard
subrepo: svn xml output is much easier to parse...
r10272 doc = xml.dom.minidom.parseString(output)
Patrick Mezard
subrepo: handle svn externals and meta changes (issue1982)...
r10273 for e in doc.getElementsByTagName('entry'):
s = e.getElementsByTagName('wc-status')
if not s:
continue
item = s[0].getAttribute('item')
props = s[0].getAttribute('props')
path = e.getAttribute('path')
if item == 'external':
externals.append(path)
if (item not in ('', 'normal', 'unversioned', 'external')
or props not in ('', 'none')):
changes.append(path)
for path in changes:
for ext in externals:
if path == ext or path.startswith(ext + os.sep):
return True, True
return bool(changes), False
Augie Fackler
subrepo: Subversion support
r10178
def dirty(self):
Patrick Mezard
subrepo: compare svn subrepo state to last committed revision...
r13287 if self._state[1] in self._wcrevs() and not self._wcchanged()[0]:
Augie Fackler
subrepo: Subversion support
r10178 return False
return True
def commit(self, text, user, date):
# user and date are out of our hands since svn is centralized
Patrick Mezard
subrepo: handle svn externals and meta changes (issue1982)...
r10273 changed, extchanged = self._wcchanged()
if not changed:
Augie Fackler
subrepo: Subversion support
r10178 return self._wcrev()
Patrick Mezard
subrepo: handle svn externals and meta changes (issue1982)...
r10273 if extchanged:
# Do not try to commit externals
raise util.Abort(_('cannot commit svn externals'))
Augie Fackler
subrepo: Subversion support
r10178 commitinfo = self._svncommand(['commit', '-m', text])
self._ui.status(commitinfo)
Martin Geisler
subrepo: use [0-9] instead of [\d] in svn subrepo regex...
r12060 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
Augie Fackler
subrepo: Subversion support
r10178 if not newrev:
raise util.Abort(commitinfo.splitlines()[-1])
newrev = newrev.groups()[0]
self._ui.status(self._svncommand(['update', '-r', newrev]))
return newrev
def remove(self):
if self.dirty():
Benoit Boissinot
subrepo: fix errors reported by pylint
r10299 self._ui.warn(_('not removing repo %s because '
'it has changes.\n' % self._path))
Augie Fackler
subrepo: Subversion support
r10178 return
Benoit Boissinot
i18n: mark more strings for translation
r10510 self._ui.note(_('removing subrepo %s\n') % self._path)
Patrick Mezard
subrepo: fix removing read-only svn files on Windows
r13013
def onerror(function, path, excinfo):
if function is not os.remove:
raise
# read-only files cannot be unlinked under Windows
s = os.stat(path)
if (s.st_mode & stat.S_IWRITE) != 0:
raise
os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
os.remove(path)
Patrick Mezard
subrepo: prune empty directories when removing svn subrepo
r13015 path = self._ctx._repo.wjoin(self._path)
shutil.rmtree(path, onerror=onerror)
try:
os.removedirs(os.path.dirname(path))
except OSError:
pass
Augie Fackler
subrepo: Subversion support
r10178
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 def get(self, state, overwrite=False):
if overwrite:
self._svncommand(['revert', '--recursive', self._path])
Augie Fackler
subrepo: Subversion support
r10178 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
Martin Geisler
subrepo: use [0-9] instead of [\d] in svn subrepo regex...
r12060 if not re.search('Checked out revision [0-9]+.', status):
Augie Fackler
subrepo: Subversion support
r10178 raise util.Abort(status.splitlines()[-1])
self._ui.status(status)
def merge(self, state):
old = int(self._state[1])
new = int(state[1])
if new > old:
self.get(state)
def push(self, force):
Matt Mackall
subrepo: fix silent push failure for SVN (issue2241)
r11455 # push is a no-op for SVN
return True
Augie Fackler
subrepo: Subversion support
r10178
Martin Geisler
subrepo: introduce files and filedata methods for subrepo classes
r12322 def files(self):
output = self._svncommand(['list'])
# This works because svn forbids \n in filenames.
return output.splitlines()
def filedata(self, name):
return self._svncommand(['cat'], name)
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 types = {
'hg': hgsubrepo,
Augie Fackler
subrepo: Subversion support
r10178 'svn': svnsubrepo,
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 }