##// END OF EJS Templates
graft: record intermediate grafts in extras...
graft: record intermediate grafts in extras Previously the extra field for a graft only contained the original commit hash. This made it impossible to use graft to copy a commit more than once, because the extras fields did not change after the second graft. The fix is to add an extra.intermediate-source field that records the immediate predecessor to graft. This changes hashes for commits that have been grafted twice, which is why the test was affected.

File last commit:

r24471:1ff35d76 default
r24644:51930a71 default
Show More
subrepo.py
1810 lines | 65.9 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
Matt Harbison
addremove: automatically process a subrepository's subrepos...
r23540 import copy
Augie Fackler
subrepo: move import of xml.minidom.dom to its own line for check-code
r19788 import errno, os, re, shutil, posixpath, sys
import xml.dom.minidom
Eric Eisner
subrepo: archive git subrepos
r13027 import stat, subprocess, tarfile
Matt Mackall
subrepo: add update/merge logic
r8814 from i18n import _
Martin von Zweigbergk
status: update various other methods to return new class
r22914 import config, util, node, error, cmdutil, scmutil, match as matchmod
FUJIWARA Katsunori
subrepo: check phase of state in each subrepositories before committing...
r20176 import phases
Augie Fackler
pathutil: tease out a new library to break an import cycle from canonpath use
r20033 import pathutil
Pierre-Yves David
push: `exchange.push` instead of `localrepo.push`...
r22619 import exchange
Abderrahim Kitouni
subrepo: use hg.repository instead of creating localrepo directly...
r9092 hg = None
Patrick Mezard
subrepo: handle svn tracked/unknown directory collisions...
r14050 propertycache = util.propertycache
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
Angel Ezquerra
subrepo: do not push mercurial subrepos whose store is clean...
r18940 def _expandedabspath(path):
'''
get a path or url and if it is a path expand it and return an absolute path
'''
expandedpath = util.urllocalpath(util.expandpath(path))
u = util.url(expandedpath)
if not u.scheme:
path = util.normpath(os.path.abspath(u.path))
return path
Angel Ezquerra
subrepo: introduce storeclean helper functions...
r18936
def _getstorehashcachename(remotepath):
'''get a unique filename for the store hash cache of a remote repository'''
Angel Ezquerra
subrepo: do not push mercurial subrepos whose store is clean...
r18940 return util.sha1(_expandedabspath(remotepath)).hexdigest()[0:12]
Angel Ezquerra
subrepo: introduce storeclean helper functions...
r18936
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 class SubrepoAbort(error.Abort):
"""Exception class used to avoid handling a subrepo error more than once"""
Angel Ezquerra
subrepo: add subrepo property to SubrepoAbort exceptions...
r18263 def __init__(self, *args, **kw):
Brendan Cully
subrepo: fix python2.4 compatibility after 9aa6bee6e9f9...
r18296 error.Abort.__init__(self, *args, **kw)
Angel Ezquerra
subrepo: add subrepo property to SubrepoAbort exceptions...
r18263 self.subrepo = kw.get('subrepo')
Matt Harbison
subrepo: chain the original exception to SubrepoAbort...
r18964 self.cause = kw.get('cause')
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109
def annotatesubrepoerror(func):
def decoratedmethod(self, *args, **kargs):
try:
res = func(self, *args, **kargs)
except SubrepoAbort, ex:
# This exception has already been handled
raise ex
except error.Abort, ex:
Angel Ezquerra
subrepo: add subrepo property to SubrepoAbort exceptions...
r18263 subrepo = subrelpath(self)
Angel Ezquerra
subrepo: make 'in subrepo' string easier to find by external tools...
r18297 errormsg = str(ex) + ' ' + _('(in subrepo %s)') % subrepo
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 # avoid handling this exception by raising a SubrepoAbort exception
Matt Harbison
subrepo: chain the original exception to SubrepoAbort...
r18964 raise SubrepoAbort(errormsg, hint=ex.hint, subrepo=subrepo,
cause=sys.exc_info())
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 return res
return decoratedmethod
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:
Patrick Mezard
subrepo: do not traceback on .hgsubstate parsing errors...
r16596 for i, l in enumerate(ctx['.hgsubstate'].data().splitlines()):
Patrick Mezard
subrepo: ignore blank lines in .hgsubstate (issue3424)...
r16595 l = l.lstrip()
if not l:
continue
Patrick Mezard
subrepo: do not traceback on .hgsubstate parsing errors...
r16596 try:
revision, path = l.split(" ", 1)
except ValueError:
raise util.Abort(_("invalid subrepository revision "
"specifier in .hgsubstate line %d")
% (i + 1))
Matt Mackall
subrepo: introduce basic state parsing
r8812 rev[path] = revision
except IOError, err:
if err.errno != errno.ENOENT:
raise
Martin Geisler
subrepo: refactor state function
r15149 def remap(src):
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))
Martin Geisler
subrepo: refactor state function
r15149 return src
Martin Geisler
subrepos: support remapping of .hgsub source paths...
r11775
Martin Geisler
subrepo: refactor state function
r15149 state = {}
for path, src in p[''].items():
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
subrepo: try remapping subpaths using the "final" path...
r15150 src = src.lstrip() # strip any extra whitespace after ']'
if not util.url(src).isabs():
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 parent = _abssource(ctx.repo(), abort=False)
Martin Geisler
subrepo: try remapping subpaths using the "final" path...
r15150 if parent:
parent = util.url(parent)
parent.path = posixpath.join(parent.path or '', src)
parent.path = posixpath.normpath(parent.path)
joined = str(parent)
# Remap the full joined path and use it if it changes,
# else remap the original source.
remapped = remap(joined)
if remapped == joined:
src = remap(src)
else:
src = remapped
Martin Geisler
subrepo: refactor state function
r15149 src = remap(src)
FUJIWARA Katsunori
windows: use normalized path as path to subrepo...
r15723 state[util.pconvert(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"""
Martin Geisler
subrepo: refactor writestate for clarity
r14443 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)]
repo.wwrite('.hgsubstate', ''.join(lines), '')
Matt Mackall
commit: recurse into subrepositories
r8813
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
Mads Kiilerich
subrepos: process subrepos in sorted order...
r18364 for s, l in sorted(s1.iteritems()):
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'
Matt Mackall
ui: merge prompt text components into a singe string...
r19226 'use (l)ocal source (%s) or (r)emote source (%s)?'
'$$ &Local $$ &Remote') % (s, l[0], r[0]), 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:
Angel Ezquerra
merge: let the user choose to merge, keep local or keep remote subrepo revisions...
r19811 debug(s, "both sides changed")
Angel Ezquerra
subrepo: use subrepo shortid method to generate subrepo diverged promptchoice...
r21401 srepo = wctx.sub(s)
Angel Ezquerra
merge: let the user choose to merge, keep local or keep remote subrepo revisions...
r19811 option = repo.ui.promptchoice(
_(' subrepository %s diverged (local revision: %s, '
'remote revision: %s)\n'
'(M)erge, keep (l)ocal or keep (r)emote?'
'$$ &Merge $$ &Local $$ &Remote')
Angel Ezquerra
subrepo: use subrepo shortid method to generate subrepo diverged promptchoice...
r21401 % (s, srepo.shortid(l[1]), srepo.shortid(r[1])), 0)
Angel Ezquerra
merge: let the user choose to merge, keep local or keep remote subrepo revisions...
r19811 if option == 0:
wctx.sub(s).merge(r)
sm[s] = l
debug(s, "merge with", r)
elif option == 1:
sm[s] = l
debug(s, "keep local subrepo revision", l)
else:
wctx.sub(s).get(r, overwrite)
sm[s] = r
debug(s, "get remote subrepo revision", r)
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()
Matt Mackall
subrepo: handle local added subrepo case correctly
r14417 elif a == nullstate: # not present in remote or ancestor
debug(s, "local added, keep")
sm[s] = l
continue
Matt Mackall
subrepo: add update/merge logic
r8814 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'
Matt Mackall
ui: merge prompt text components into a singe string...
r19226 'use (c)hanged version or (d)elete?'
'$$ &Changed $$ &Delete') % s, 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()
Adrian Buehlmann
subrepo: process merge substate in sorted order in submerge()...
r13857 for s, r in sorted(s2.items()):
Matt Mackall
subrepo: add update/merge logic
r8814 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'
Matt Mackall
ui: merge prompt text components into a singe string...
r19226 'use (c)hanged version or (d)elete?'
'$$ &Changed $$ &Delete') % s, 0) == 0:
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "prompt recreate", r)
Martin von Zweigbergk
subrepo: add tests for change/remove conflicts...
r24110 mctx.sub(s).get(r)
Matt Mackall
subrepo: add update/merge logic
r8814 sm[s] = r
# record merged .hgsubstate
writestate(repo, sm)
Angel Ezquerra
subrepo: make submerge() return the merged substate...
r19637 return sm
Matt Mackall
subrepo: add update/merge logic
r8814
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 def _updateprompt(ui, sub, dirty, local, remote):
if dirty:
msg = (_(' subrepository sources for %s differ\n'
Mads Kiilerich
subrepo: remove superfluous newline from subrepo prompt
r22590 'use (l)ocal source (%s) or (r)emote source (%s)?'
Matt Mackall
ui: merge prompt text components into a singe string...
r19226 '$$ &Local $$ &Remote')
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 % (subrelpath(sub), local, remote))
else:
Brodie Rao
cleanup: eradicate long lines
r16683 msg = (_(' subrepository sources for %s differ (in checked out '
'version)\n'
Mads Kiilerich
subrepo: remove superfluous newline from subrepo prompt
r22590 'use (l)ocal source (%s) or (r)emote source (%s)?'
Matt Mackall
ui: merge prompt text components into a singe string...
r19226 '$$ &Local $$ &Remote')
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 % (subrelpath(sub), local, remote))
Matt Mackall
ui: merge prompt text components into a singe string...
r19226 return ui.promptchoice(msg, 0)
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417
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
Augie Fackler
subrepo: use safehasattr instead of hasattr...
r14963 while util.safehasattr(parent, '_subparent'):
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 parent = parent._subparent
FUJIWARA Katsunori
subrepo: normalize path in the specific way for problematic encodings...
r21568 return repo.root[len(pathutil.normasprefix(parent.root)):]
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752
def subrelpath(sub):
Mads Kiilerich
subrepo: docstrings
r11571 """return path to this subrepo as seen from outermost repo"""
Augie Fackler
subrepo: use safehasattr instead of hasattr...
r14963 if util.safehasattr(sub, '_relpath'):
Eric Eisner
subrepo: fix subrelpath for git subrepos...
r13181 return sub._relpath
Augie Fackler
subrepo: use safehasattr instead of hasattr...
r14963 if not util.safehasattr(sub, '_repo'):
Edouard Gomez
subrepo: print paths relative to upper repo root for push/pull/commit...
r11112 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."""
Augie Fackler
subrepo: use safehasattr instead of hasattr...
r14963 if util.safehasattr(repo, '_subparent'):
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 source = util.url(repo._subsource)
Matt Mackall
subrepos: be smarter about what's an absolute path (issue2808)
r14766 if source.isabs():
return str(source)
Brodie Rao
subrepos: use url.url when normalizing repo paths...
r13771 source.path = posixpath.normpath(source.path)
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 parent = _abssource(repo._subparent, push, abort=False)
if parent:
Mads Kiilerich
subrepo: use correct paths for subrepos with ..-relative paths on windows...
r15498 parent = util.url(util.pconvert(parent))
Mads Kiilerich
subrepo: fix cloning of repos from urls without slash after host (issue2970)...
r15055 parent.path = posixpath.join(parent.path or '', source.path)
Brodie Rao
subrepos: use url.url when normalizing repo paths...
r13771 parent.path = posixpath.normpath(parent.path)
return str(parent)
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 else: # recursion reached top repo
Augie Fackler
subrepo: use safehasattr instead of hasattr...
r14963 if util.safehasattr(repo, '_subtoppath'):
Mads Kiilerich
subrepo: propagate non-default pull/push path to relative subrepos (issue1852)
r12852 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')
Angel Ezquerra
localrepo: introduce shared method to check if a repository is shared...
r23666 if repo.shared():
Matt Harbison
subrepo: use sharepath if available when locating the source repo...
r18510 # chop off the .hg component to get the default path form
return os.path.dirname(repo.sharedpath)
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 if abort:
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 raise util.Abort(_("default path for subrepository not found"))
Matt Mackall
subrepo: add update/merge logic
r8814
FUJIWARA Katsunori
subrepo: avoid sanitizing ".hg/hgrc" in meta data area for non-hg subrepos...
r21567 def _sanitize(ui, path, ignore):
FUJIWARA Katsunori
subrepo: make "_sanitize()" work...
r21564 for dirname, dirs, names in os.walk(path):
FUJIWARA Katsunori
subrepo: avoid sanitizing ".hg/hgrc" in meta data area for non-hg subrepos...
r21567 for i, d in enumerate(dirs):
if d.lower() == ignore:
del dirs[i]
break
Matt Mackall
subrepo: sanitize non-hg subrepos
r20104 if os.path.basename(dirname).lower() != '.hg':
FUJIWARA Katsunori
subrepo: make "_sanitize()" work...
r21564 continue
Matt Mackall
subrepo: sanitize non-hg subrepos
r20104 for f in names:
if f.lower() == 'hgrc':
FUJIWARA Katsunori
subrepo: make "_sanitize()" work...
r21564 ui.warn(_("warning: removing potentially hostile 'hgrc' "
"in '%s'\n") % dirname)
Matt Mackall
subrepo: sanitize non-hg subrepos
r20104 os.unlink(os.path.join(dirname, f))
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 Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 pathutil.pathauditor(ctx.repo().root)(path)
Dov Feldstern
subrepo: make subrepo.subrepo(<not a subrepo path>) fail...
r16756 state = ctx.substate[path]
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
FUJIWARA Katsunori
subrepo: check phase of state in each subrepositories before committing...
r20176 def newcommitphase(ui, ctx):
commitphase = phases.newcommitphase(ui)
substate = getattr(ctx, "substate", None)
if not substate:
return commitphase
check = ui.config('phases', 'checksubrepos', 'follow')
if check not in ('ignore', 'follow', 'abort'):
raise util.Abort(_('invalid phases.checksubrepos configuration: %s')
% (check))
if check == 'ignore':
return commitphase
maxphase = phases.public
maxsub = None
for s in sorted(substate):
sub = ctx.sub(s)
subphase = sub.phase(substate[s][1])
if maxphase < subphase:
maxphase = subphase
maxsub = s
if commitphase < maxphase:
if check == 'abort':
raise util.Abort(_("can't commit in %s phase"
" conflicting %s from subrepository %s") %
(phases.phasenames[commitphase],
phases.phasenames[maxphase], maxsub))
ui.warn(_("warning: changes are committed in"
" %s phase from subrepository %s\n") %
(phases.phasenames[maxphase], maxsub))
return maxphase
return commitphase
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 # subrepo classes need to implement the following abstract class:
class abstractsubrepo(object):
Matt Harbison
subrepo: store the ui object in the base class...
r23536 def __init__(self, ui):
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui = ui
Matt Harbison
subrepo: store the ui object in the base class...
r23536
Angel Ezquerra
subrepo: introduce storeclean method...
r18937 def storeclean(self, path):
"""
returns true if the repository has not changed since it was last
cloned from or pushed to a given repository.
"""
return False
Kevin Bullock
mq: update .hgsubstate if subrepos are clean (issue2499)...
r13174 def dirty(self, ignoreupdate=False):
"""returns true if the dirstate of the subrepo is dirty or does not
match current stored state. If ignoreupdate is true, only check
whether the subrepo has uncommitted changes in its dirstate.
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 """
raise NotImplementedError
FUJIWARA Katsunori
subrepo: add dirtyreason to centralize composing dirty reason message...
r24470 def dirtyreason(self, ignoreupdate=False):
"""return reason string if it is ``dirty()``
Returned string should have enough information for the message
of exception.
This returns None, otherwise.
"""
if self.dirty(ignoreupdate=ignoreupdate):
return _("uncommitted changes in subrepository '%s'"
) % subrelpath(self)
FUJIWARA Katsunori
subrepo: add bailifchanged to centralize raising Abort if subrepo is dirty...
r24471 def bailifchanged(self, ignoreupdate=False):
"""raise Abort if subrepository is ``dirty()``
"""
dirtyreason = self.dirtyreason(ignoreupdate=ignoreupdate)
if dirtyreason:
raise util.Abort(dirtyreason)
Matt Mackall
subrepo: add basestate method...
r16072 def basestate(self):
"""current working directory base state, disregarding .hgsubstate
state and working directory modifications"""
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
FUJIWARA Katsunori
subrepo: check phase of state in each subrepositories before committing...
r20176 def phase(self, state):
"""returns phase of specified state in the subrepository.
"""
return phases.public
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 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: remove argument introduced by mistake in c19b9282d3a7
r13413 def merge(self, state):
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 """merge currently-saved state with the new state."""
raise NotImplementedError
Angel Ezquerra
push: propagate --new-branch and --ssh options when pushing subrepos...
r15708 def push(self, opts):
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
Matt Harbison
subrepo: don't abort in add when non-hg subrepos are present (issue4513)...
r23963 def add(self, ui, match, prefix, explicitonly, **opts):
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 return []
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537 def addremove(self, matcher, prefix, opts, dry_run, similarity):
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.warn("%s: %s" % (prefix, _("addremove is not supported")))
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537 return 1
Matt Harbison
subrepo: drop the 'ui' parameter to cat()...
r23576 def cat(self, match, prefix, **opts):
Matt Harbison
cat: support cat with explicit paths in subrepos...
r21041 return 1
Martin Geisler
status: recurse into subrepositories with --subrepos/-S flag
r12166 def status(self, rev2, **opts):
Martin von Zweigbergk
status: update various other methods to return new class
r22914 return scmutil.status([], [], [], [], [], [], [])
Martin Geisler
status: recurse into subrepositories with --subrepos/-S flag
r12166
FUJIWARA Katsunori
subrepo: add argument to "diff()" to pass "ui" of caller side (issue3712) (API)...
r18006 def diff(self, ui, diffopts, node2, match, prefix, **opts):
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 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 ''
Matt Harbison
subrepo: add basic support to hgsubrepo for the files command...
r24413 def printfiles(self, ui, m, fm, fmt):
"""handle the files command for this subrepo"""
return 1
Matt Harbison
subrepo: drop the 'ui' parameter to archive()...
r23575 def archive(self, archiver, prefix, match=None):
Matt Harbison
subrepo: propagate matcher to subrepos when archiving...
r17108 if match is not None:
files = [f for f in self.files() if match(f)]
else:
files = self.files()
Martin Geisler
subrepo: add progress bar support to archive
r13144 total = len(files)
relpath = subrelpath(self)
Matt Harbison
subrepo: drop the 'ui' parameter to archive()...
r23575 self.ui.progress(_('archiving (%s)') % relpath, 0,
unit=_('files'), total=total)
Martin Geisler
subrepo: add progress bar support to archive
r13144 for i, name in enumerate(files):
Martin Geisler
subrepo: add support for 'hg archive'
r12323 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))
Matt Harbison
subrepo: drop the 'ui' parameter to archive()...
r23575 self.ui.progress(_('archiving (%s)') % relpath, i + 1,
unit=_('files'), total=total)
self.ui.progress(_('archiving (%s)') % relpath, None)
Angel Ezquerra
archive: raise error.Abort if the file pattern matches no files...
r18967 return total
Martin Geisler
subrepo: add support for 'hg archive'
r12323
David M. Carr
add: support adding explicit files in subrepos...
r15410 def walk(self, match):
'''
walk recursively through the directory tree, finding all files
matched by the match function
'''
pass
Martin Geisler
subrepo: add support for 'hg archive'
r12323
Matt Harbison
subrepo: drop the 'ui' parameter to forget()...
r23577 def forget(self, match, prefix):
Patrick Mezard
subrepo: fix default implementation of forget() (issue3404)
r16527 return ([], [])
Martin Geisler
subrepo: add support for 'hg archive'
r12323
Matt Harbison
subrepo: drop the 'ui' parameter to removefiles()...
r23578 def removefiles(self, matcher, prefix, after, force, subrepos):
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325 """remove the matched files from the subrepository and the filesystem,
possibly by force and/or after the file has been removed from the
filesystem. Return 0 on success, 1 on any warning.
"""
return 1
Matt Harbison
subrepo: drop the 'ui' parameter to revert()...
r23579 def revert(self, substate, *pats, **opts):
self.ui.warn('%s: reverting %s subrepos is unsupported\n' \
Angel Ezquerra
revert: show warning when reverting subrepos that do not support revert...
r16468 % (substate[0], substate[2]))
Angel Ezquerra
revert: add support for reverting subrepos...
r16429 return []
Angel Ezquerra
subrepo: add shortid() method to subrepo classes...
r21400 def shortid(self, revid):
return revid
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):
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 super(hgsubrepo, self).__init__(ctx.repo().ui)
Matt Mackall
commit: recurse into subrepositories
r8813 self._path = path
self._state = state
Matt Harbison
subrepo: add the parent context to hgsubrepo...
r24409 self._ctx = ctx
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 r = ctx.repo()
Matt Mackall
commit: recurse into subrepositories
r8813 root = r.wjoin(path)
FUJIWARA Katsunori
subrepo: replace "os.path.exists" by "exists" via wvfs of the parent...
r23364 create = not r.wvfs.exists('%s/.hg' % path)
FUJIWARA Katsunori
subrepo: isolate configuration between each repositories in subrepo tree...
r17873 self._repo = hg.repository(r.baseui, root, create=create)
Matt Harbison
subrepo: reset 'self.ui' to the subrepo copy of 'ui' in the hgsubrepo class...
r23573 self.ui = self._repo.ui
FUJIWARA Katsunori
subrepo: isolate configuration between each repositories in subrepo tree...
r17873 for s, k in [('ui', 'commitsubrepos')]:
v = r.ui.config(s, k)
if v:
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.setconfig(s, k, v, 'subrepo')
self.ui.setconfig('ui', '_usedassubrepo', 'True', 'subrepo')
Martin Geisler
subrepo: create subrepos using clone instead of pull...
r14281 self._initrepo(r, state[0], create)
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 def storeclean(self, path):
FUJIWARA Katsunori
subrepo: ensure "lock.release()" execution at the end of "storeclean()"...
r21885 lock = self._repo.lock()
try:
return self._storeclean(path)
finally:
lock.release()
def _storeclean(self, path):
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 clean = True
itercache = self._calcstorehash(path)
try:
for filehash in self._readstorehashcache(path):
if filehash != itercache.next():
clean = False
break
except StopIteration:
# the cached and current pull states have a different size
clean = False
if clean:
try:
itercache.next()
# the cached and current pull states have a different size
clean = False
except StopIteration:
pass
return clean
def _calcstorehash(self, remotepath):
'''calculate a unique "store hash"
This method is used to to detect when there are changes that may
require a push to a given remote path.'''
# sort the files that will be hashed in increasing (likely) file size
filelist = ('bookmarks', 'store/phaseroots', 'store/00changelog.i')
Angel Ezquerra
subrepo: do not push mercurial subrepos whose store is clean...
r18940 yield '# %s\n' % _expandedabspath(remotepath)
FUJIWARA Katsunori
subrepo: replace "_calcfilehash" invocation by "vfs.tryread"...
r23365 vfs = self._repo.vfs
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 for relname in filelist:
FUJIWARA Katsunori
subrepo: replace "_calcfilehash" invocation by "vfs.tryread"...
r23365 filehash = util.sha1(vfs.tryread(relname)).hexdigest()
yield '%s = %s\n' % (relname, filehash)
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939
FUJIWARA Katsunori
subrepo: add "_cachestorehashvfs" to handle cache store hash files via vfs...
r23367 @propertycache
def _cachestorehashvfs(self):
return scmutil.vfs(self._repo.join('cache/storehash'))
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 def _readstorehashcache(self, remotepath):
'''read the store hash cache for a given remote repository'''
FUJIWARA Katsunori
subrepo: replace direct file APIs around "readlines" by "vfs.tryreadlines"...
r23369 cachefile = _getstorehashcachename(remotepath)
return self._cachestorehashvfs.tryreadlines(cachefile, 'r')
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939
def _cachestorehash(self, remotepath):
'''cache the current store hash
Each remote repo requires its own store hash cache, because a subrepo
store may be "clean" versus a given remote repo, but not versus another
'''
FUJIWARA Katsunori
subrepo: replace direct file APIs around "writelines" by "vfs.writelines"...
r23372 cachefile = _getstorehashcachename(remotepath)
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 lock = self._repo.lock()
FUJIWARA Katsunori
subrepo: ensure "lock.release()" execution at the end of "_cachestorehash()"...
r21886 try:
storehash = list(self._calcstorehash(remotepath))
FUJIWARA Katsunori
subrepo: replace direct file APIs around "writelines" by "vfs.writelines"...
r23372 vfs = self._cachestorehashvfs
vfs.writelines(cachefile, storehash, mode='w', notindexed=True)
FUJIWARA Katsunori
subrepo: ensure "lock.release()" execution at the end of "_cachestorehash()"...
r21886 finally:
lock.release()
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Martin Geisler
subrepo: create subrepos using clone instead of pull...
r14281 def _initrepo(self, parentrepo, source, create):
self._repo._subparent = parentrepo
self._repo._subsource = source
Matt Mackall
commit: recurse into subrepositories
r8813
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666 if create:
FUJIWARA Katsunori
subrepo: ensure "close()" execution at the end of "_initrepo()"...
r21891 lines = ['[paths]\n']
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666
def addpathconfig(key, value):
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 if value:
FUJIWARA Katsunori
subrepo: ensure "close()" execution at the end of "_initrepo()"...
r21891 lines.append('%s = %s\n' % (key, value))
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.setconfig('paths', key, value, 'subrepo')
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)
FUJIWARA Katsunori
subrepo: ensure "close()" execution at the end of "_initrepo()"...
r21891
Angel Ezquerra
localrepo: remove all external users of localrepo.opener...
r23877 fp = self._repo.vfs("hgrc", "w", text=True)
FUJIWARA Katsunori
subrepo: ensure "close()" execution at the end of "_initrepo()"...
r21891 try:
fp.write(''.join(lines))
finally:
fp.close()
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Matt Harbison
add: pass options via keyword args...
r23885 def add(self, ui, match, prefix, explicitonly, **opts):
return cmdutil.add(ui, self._repo, match,
os.path.join(prefix, self._path), explicitonly,
**opts)
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270
Matt Harbison
subrepo: annotate addremove with @annotatesubrepoerror
r24132 @annotatesubrepoerror
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537 def addremove(self, m, prefix, opts, dry_run, similarity):
Matt Harbison
addremove: automatically process a subrepository's subrepos...
r23540 # In the same way as sub directories are processed, once in a subrepo,
# always entry any of its subrepos. Don't corrupt the options that will
# be used to process sibling subrepos however.
opts = copy.copy(opts)
opts['subrepos'] = True
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537 return scmutil.addremove(self._repo, m,
os.path.join(prefix, self._path), opts,
dry_run, similarity)
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Matt Harbison
subrepo: drop the 'ui' parameter to cat()...
r23576 def cat(self, match, prefix, **opts):
Matt Harbison
cat: support cat with explicit paths in subrepos...
r21041 rev = self._state[1]
ctx = self._repo[rev]
Matt Harbison
subrepo: drop the 'ui' parameter to cat()...
r23576 return cmdutil.cat(self.ui, self._repo, ctx, match, prefix, **opts)
Matt Harbison
cat: support cat with explicit paths in subrepos...
r21041
@annotatesubrepoerror
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:
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
% (inst, subrelpath(self)))
Martin von Zweigbergk
status: update various other methods to return new class
r22914 return scmutil.status([], [], [], [], [], [], [])
Martin Geisler
status: recurse into subrepositories with --subrepos/-S flag
r12166
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
FUJIWARA Katsunori
subrepo: add argument to "diff()" to pass "ui" of caller side (issue3712) (API)...
r18006 def diff(self, ui, diffopts, node2, match, prefix, **opts):
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 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)
FUJIWARA Katsunori
subrepo: add argument to "diff()" to pass "ui" of caller side (issue3712) (API)...
r18006 cmdutil.diffordiffstat(ui, self._repo, diffopts,
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 node1, node2, match,
Bryan O'Sullivan
subrepo: use posixpath when diffing, for consistent paths...
r17968 prefix=posixpath.join(prefix, self._path),
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 listsubrepos=True, **opts)
except error.RepoLookupError, inst:
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
% (inst, subrelpath(self)))
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Matt Harbison
subrepo: drop the 'ui' parameter to archive()...
r23575 def archive(self, archiver, prefix, match=None):
Martin Geisler
subrepo: pull revisions on demand when archiving hg subrepos...
r15286 self._get(self._state + ('hg',))
Matt Harbison
subrepo: drop the 'ui' parameter to archive()...
r23575 total = abstractsubrepo.archive(self, archiver, prefix, match)
Martin Geisler
subrepo: add support for 'hg archive'
r12323 rev = self._state[1]
ctx = self._repo[rev]
for subpath in ctx.substate:
s = subrepo(ctx, subpath)
Matt Harbison
subrepo: propagate matcher to subrepos when archiving...
r17108 submatch = matchmod.narrowmatcher(subpath, match)
Angel Ezquerra
archive: raise error.Abort if the file pattern matches no files...
r18967 total += s.archive(
Matt Harbison
subrepo: drop the 'ui' parameter to archive()...
r23575 archiver, os.path.join(prefix, self._path), submatch)
Angel Ezquerra
archive: raise error.Abort if the file pattern matches no files...
r18967 return total
Martin Geisler
subrepo: add support for 'hg archive'
r12323
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Kevin Bullock
mq: update .hgsubstate if subrepos are clean (issue2499)...
r13174 def dirty(self, ignoreupdate=False):
Matt Mackall
commit: recurse into subrepositories
r8813 r = self._state[1]
Kevin Bullock
mq: update .hgsubstate if subrepos are clean (issue2499)...
r13174 if r == '' and not ignoreupdate: # no state recorded
Matt Mackall
commit: recurse into subrepositories
r8813 return True
w = self._repo[None]
Matt Mackall
extensions: drop maxlength from enabled and disabled...
r14316 if r != w.p1().hex() and not ignoreupdate:
Kevin Bullock
subrepo: clarify comments in dirty() methods...
r13325 # different version checked out
Matt Mackall
commit: recurse into subrepositories
r8813 return True
return w.dirty() # working directory changed
Matt Mackall
subrepo: add basestate method...
r16072 def basestate(self):
return self._repo['.'].hex()
Martin Geisler
localrepo: add auditor attribute which knows about subrepos
r12162 def checknested(self, path):
return self._repo._checknested(self._repo.wjoin(path))
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Matt Mackall
commit: recurse into subrepositories
r8813 def commit(self, text, user, date):
Kevin Bullock
subrepo: don't commit in subrepo if it's clean...
r14898 # don't bother committing in the subrepo if it's only been
# updated
if not self.dirty(True):
return self._repo['.'].hex()
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.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
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
FUJIWARA Katsunori
subrepo: check phase of state in each subrepositories before committing...
r20176 def phase(self, state):
return self._repo[state].phase()
@annotatesubrepoerror
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
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.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
Angel Ezquerra
subrepo: do not try to get hidden revisions...
r20317 if revision in self._repo.unfiltered():
Angel Ezquerra
subrepo: make it possible to update to hidden subrepo revisions...
r20319 return True
Angel Ezquerra
subrepo: remove unnecessary else clause in hgsubrepo._get...
r20318 self._repo._subsource = source
srcurl = _abssource(self._repo)
other = hg.peer(self._repo, {}, srcurl)
if len(self._repo) == 0:
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.status(_('cloning subrepo %s from %s\n')
% (subrelpath(self), srcurl))
Angel Ezquerra
subrepo: remove unnecessary else clause in hgsubrepo._get...
r20318 parentrepo = self._repo._subparent
shutil.rmtree(self._repo.path)
other, cloned = hg.clone(self._repo._subparent.baseui, {},
other, self._repo.root,
update=False)
self._repo = cloned.local()
self._initrepo(parentrepo, source, create=True)
self._cachestorehash(srcurl)
Angel Ezquerra
subrepo: do not try to get hidden revisions...
r20317 else:
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.status(_('pulling subrepo %s from %s\n')
% (subrelpath(self), srcurl))
Angel Ezquerra
subrepo: remove unnecessary else clause in hgsubrepo._get...
r20318 cleansub = self.storeclean(srcurl)
Pierre-Yves David
subrepo: use exchange.pull...
r22695 exchange.pull(self._repo, other)
Angel Ezquerra
subrepo: remove unnecessary else clause in hgsubrepo._get...
r20318 if cleansub:
# keep the repo clean after pull
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 self._cachestorehash(srcurl)
Angel Ezquerra
subrepo: make it possible to update to hidden subrepo revisions...
r20319 return False
Matt Mackall
subrepo: add update/merge logic
r8814
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 def get(self, state, overwrite=False):
Angel Ezquerra
subrepo: make it possible to update to hidden subrepo revisions...
r20319 inrepo = self._get(state)
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 source, revision, kind = state
Angel Ezquerra
subrepo: make it possible to update to hidden subrepo revisions...
r20319 repo = self._repo
repo.ui.debug("getting subrepo %s\n" % self._path)
if inrepo:
urepo = repo.unfiltered()
ctx = urepo[revision]
if ctx.hidden():
urepo.ui.warn(
_('revision %s in subrepo %s is hidden\n') \
% (revision[0:12], self._path))
repo = urepo
hg.updaterepo(repo, revision, overwrite)
Matt Mackall
subrepo: add update/merge logic
r8814
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Matt Mackall
subrepo: add update/merge logic
r8814 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)
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417
def mergefunc():
Friedrich Kastner-Masilko
subrepo: fix for merge inconsistencies...
r16196 if anc == cur and dst.branch() == cur.branch():
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.debug("updating subrepo %s\n" % subrelpath(self))
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 hg.update(self._repo, state[1])
elif anc == dst:
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.debug("skipping subrepo %s\n" % subrelpath(self))
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 else:
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.debug("merging subrepo %s\n" % subrelpath(self))
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 hg.merge(self._repo, state[1], remind=False)
wctx = self._repo[None]
if self.dirty():
if anc != dst:
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 if _updateprompt(self.ui, self, wctx.dirty(), cur, dst):
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 mergefunc()
else:
mergefunc()
Matt Mackall
subrepo: do a linear update when appropriate
r9781 else:
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 mergefunc()
Matt Mackall
subrepo: basic push support
r8815
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Angel Ezquerra
push: propagate --new-branch and --ssh options when pushing subrepos...
r15708 def push(self, opts):
force = opts.get('force')
newbranch = opts.get('new_branch')
ssh = opts.get('ssh')
Matt Mackall
subrepo: basic push support
r8815 # 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
push: more precise failure check on subrepo push...
r16022 if c.sub(s).push(opts) == 0:
Matt Mackall
subrepo: propagate and catch push failures
r11067 return False
Matt Mackall
subrepo: basic push support
r8815
dsturl = _abssource(self._repo, True)
Angel Ezquerra
subrepo: do not push mercurial subrepos whose store is clean...
r18940 if not force:
if self.storeclean(dsturl):
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.status(
Angel Ezquerra
subrepo: do not push mercurial subrepos whose store is clean...
r18940 _('no changes made to subrepo %s since last push to %s\n')
% (subrelpath(self), dsturl))
return None
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 self.ui.status(_('pushing subrepo %s to %s\n') %
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 (subrelpath(self), dsturl))
Simon Heimberg
peer: subrepo isolation, pass repo instead of repo.ui to hg.peer...
r17874 other = hg.peer(self._repo, {'ssh': ssh}, dsturl)
Pierre-Yves David
push: `exchange.push` instead of `localrepo.push`...
r22619 res = exchange.push(self._repo, other, force, newbranch=newbranch)
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939
# the repo is now clean
self._cachestorehash(dsturl)
Pierre-Yves David
push: `exchange.push` instead of `localrepo.push`...
r22619 return res.cgresult
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
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)
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
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)
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Martin Geisler
subrepo: introduce files and filedata methods for subrepo classes
r12322 def files(self):
rev = self._state[1]
ctx = self._repo[rev]
Matt Harbison
subrepo: return only the manifest keys from hgsubrepo.files()...
r24173 return ctx.manifest().keys()
Martin Geisler
subrepo: introduce files and filedata methods for subrepo classes
r12322
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)
Matt Harbison
subrepo: add basic support to hgsubrepo for the files command...
r24413 @annotatesubrepoerror
def printfiles(self, ui, m, fm, fmt):
# If the parent context is a workingctx, use the workingctx here for
# consistency.
if self._ctx.rev() is None:
ctx = self._repo[None]
else:
rev = self._state[1]
ctx = self._repo[rev]
return cmdutil.files(ui, ctx, m, fm, fmt, True)
David M. Carr
add: support adding explicit files in subrepos...
r15410 def walk(self, match):
ctx = self._repo[None]
return ctx.walk(match)
Martin Geisler
subrepo: introduce files and filedata methods for subrepo classes
r12322
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Matt Harbison
subrepo: drop the 'ui' parameter to forget()...
r23577 def forget(self, match, prefix):
return cmdutil.forget(self.ui, self._repo, match,
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 os.path.join(prefix, self._path), True)
Martin Geisler
subrepo: introduce files and filedata methods for subrepo classes
r12322
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Matt Harbison
subrepo: drop the 'ui' parameter to removefiles()...
r23578 def removefiles(self, matcher, prefix, after, force, subrepos):
return cmdutil.remove(self.ui, self._repo, matcher,
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325 os.path.join(prefix, self._path), after, force,
subrepos)
@annotatesubrepoerror
Matt Harbison
subrepo: drop the 'ui' parameter to revert()...
r23579 def revert(self, substate, *pats, **opts):
Angel Ezquerra
revert: add support for reverting subrepos without --no-backup and/or --all...
r16430 # reverting a subrepo is a 2 step process:
# 1. if the no_backup is not set, revert all modified
# files inside the subrepo
# 2. update the subrepo to the revision specified in
# the corresponding substate dictionary
Matt Harbison
subrepo: drop the 'ui' parameter to revert()...
r23579 self.ui.status(_('reverting subrepo %s\n') % substate[0])
Angel Ezquerra
revert: add support for reverting subrepos without --no-backup and/or --all...
r16430 if not opts.get('no_backup'):
# Revert all files on the subrepo, creating backups
# Note that this will not recursively revert subrepos
# We could do it if there was a set:subrepos() predicate
opts = opts.copy()
opts['date'] = None
opts['rev'] = substate[1]
Matt Harbison
subrepo: drop the 'ui' parameter to revert()...
r23579 self.filerevert(*pats, **opts)
Angel Ezquerra
revert: add support for reverting subrepos...
r16429
# Update the repo to the revision specified in the given substate
Matt Harbison
revert: display full subrepo output with --dry-run...
r24134 if not opts.get('dry_run'):
self.get(substate, overwrite=True)
Angel Ezquerra
revert: add support for reverting subrepos...
r16429
Matt Harbison
subrepo: drop the 'ui' parameter to revert()...
r23579 def filerevert(self, *pats, **opts):
Angel Ezquerra
revert: add support for reverting subrepos without --no-backup and/or --all...
r16430 ctx = self._repo[opts['rev']]
parents = self._repo.dirstate.parents()
Yuya Nishihara
subrepo: fix exception on revert when "all" option is omitted...
r18943 if opts.get('all'):
Angel Ezquerra
revert: add support for reverting subrepos without --no-backup and/or --all...
r16430 pats = ['set:modified()']
else:
pats = []
Matt Harbison
subrepo: drop the 'ui' parameter to revert()...
r23579 cmdutil.revert(self.ui, self._repo, ctx, parents, *pats, **opts)
Angel Ezquerra
revert: add support for reverting subrepos without --no-backup and/or --all...
r16430
Angel Ezquerra
subrepo: add shortid() method to subrepo classes...
r21400 def shortid(self, revid):
return revid[:12]
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):
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 super(svnsubrepo, self).__init__(ctx.repo().ui)
Augie Fackler
subrepo: Subversion support
r10178 self._path = path
self._state = state
self._ctx = ctx
Matt Mackall
subrepo: improve error message when svn isn't found...
r15190 self._exe = util.findexe('svn')
if not self._exe:
raise util.Abort(_("'svn' executable not found for subrepo '%s'")
% self._path)
Augie Fackler
subrepo: Subversion support
r10178
Augie Fackler
svn subrepos: work around checkout obstructions (issue2752)...
r14664 def _svncommand(self, commands, filename='', failok=False):
Matt Mackall
subrepo: improve error message when svn isn't found...
r15190 cmd = [self._exe]
Augie Fackler
subrepo: make stdin for svn a pipe for non-interactive use (issue2759)...
r14506 extrakw = {}
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 if not self.ui.interactive():
Augie Fackler
subrepo: make stdin for svn a pipe for non-interactive use (issue2759)...
r14506 # Making stdin be a pipe should prevent svn from behaving
# interactively even if we can't pass --non-interactive.
extrakw['stdin'] = subprocess.PIPE
# Starting in svn 1.5 --non-interactive is a global flag
# instead of being per-command, but we need to support 1.4 so
# we have to be intelligent about what commands take
# --non-interactive.
if commands[0] in ('update', 'checkout', 'commit'):
cmd.append('--non-interactive')
Augie Fackler
subrepo: tell Subversion when we are non-interactive (issue2759)...
r14025 cmd.extend(commands)
Patrick Mezard
subrepo: handle svn tracked/unknown directory collisions...
r14050 if filename is not None:
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 path = os.path.join(self._ctx.repo().origroot, self._path, filename)
Patrick Mezard
subrepo: handle svn tracked/unknown directory collisions...
r14050 cmd.append(path)
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.
Thomas Arendsen Hein
subrepo: setting LC_MESSAGES only works if LC_ALL is empty or unset...
r17705 lc_all = env.get('LC_ALL')
if lc_all:
env['LANG'] = lc_all
del env['LC_ALL']
Patrick Mezard
subrepo: make svn use C locale for portability...
r10271 env['LC_MESSAGES'] = 'C'
Eric Eisner
subrepo: use subprocess.Popen without the shell...
r13108 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
Patrick Mezard
subrepo: use subprocess directly to avoid python 2.6 bug...
r13014 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
Augie Fackler
subrepo: make stdin for svn a pipe for non-interactive use (issue2759)...
r14506 universal_newlines=True, env=env, **extrakw)
Patrick Mezard
subrepo: use subprocess directly to avoid python 2.6 bug...
r13014 stdout, stderr = p.communicate()
stderr = stderr.strip()
Augie Fackler
svn subrepos: work around checkout obstructions (issue2752)...
r14664 if not failok:
if p.returncode:
raise util.Abort(stderr or 'exited with code %d' % p.returncode)
if stderr:
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.warn(stderr + '\n')
Augie Fackler
svn subrepos: work around checkout obstructions (issue2752)...
r14664 return stdout, stderr
Augie Fackler
subrepo: Subversion support
r10178
Patrick Mezard
subrepo: handle svn tracked/unknown directory collisions...
r14050 @propertycache
def _svnversion(self):
Thomas Arendsen Hein
subrepo, hghave: use "svn --version --quiet" to determine version number...
r17707 output, err = self._svncommand(['--version', '--quiet'], filename=None)
m = re.search(r'^(\d+)\.(\d+)', output)
Patrick Mezard
subrepo: handle svn tracked/unknown directory collisions...
r14050 if not m:
raise util.Abort(_('cannot retrieve svn tool version'))
return (int(m.group(1)), int(m.group(2)))
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.
Augie Fackler
svn subrepos: work around checkout obstructions (issue2752)...
r14664 output, err = self._svncommand(['info', '--xml'])
Patrick Mezard
subrepo: svn xml output is much easier to parse...
r10272 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):
Patrick Mezard
subrepo/svn: improve error message on missing files...
r16530 """Return (changes, extchanges, missing) where changes is True
if the working directory was changed, extchanges is
True if any of these changes concern an external entry and missing
is True if any change is a missing entry.
Patrick Mezard
subrepo: handle svn externals and meta changes (issue1982)...
r10273 """
Augie Fackler
svn subrepos: work around checkout obstructions (issue2752)...
r14664 output, err = self._svncommand(['status', '--xml'])
Patrick Mezard
subrepo/svn: improve error message on missing files...
r16530 externals, changes, missing = [], [], []
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)
Patrick Mezard
subrepo/svn: improve error message on missing files...
r16530 elif item == 'missing':
missing.append(path)
Patrick Mezard
subrepo: handle svn externals and meta changes (issue1982)...
r10273 if (item not in ('', 'normal', 'unversioned', 'external')
Vasily Titskiy
subrepo: handle adding svn subrepo with a svn:external file in it (issue2931)
r14994 or props not in ('', 'none', 'normal')):
Patrick Mezard
subrepo: handle svn externals and meta changes (issue1982)...
r10273 changes.append(path)
for path in changes:
for ext in externals:
if path == ext or path.startswith(ext + os.sep):
Patrick Mezard
subrepo/svn: improve error message on missing files...
r16530 return True, True, bool(missing)
return bool(changes), False, bool(missing)
Augie Fackler
subrepo: Subversion support
r10178
Kevin Bullock
mq: update .hgsubstate if subrepos are clean (issue2499)...
r13174 def dirty(self, ignoreupdate=False):
if not self._wcchanged()[0]:
Patrick Mezard
Merge with stable
r13288 if self._state[1] in self._wcrevs() or ignoreupdate:
Kevin Bullock
mq: update .hgsubstate if subrepos are clean (issue2499)...
r13174 return False
Augie Fackler
subrepo: Subversion support
r10178 return True
Matt Mackall
subrepo: add basestate method...
r16072 def basestate(self):
Patrick Mezard
subrepo/svn: fix checked out rev number retrieval (issue2968)...
r16554 lastrev, rev = self._wcrevs()
if lastrev != rev:
# Last committed rev is not the same than rev. We would
# like to take lastrev but we do not know if the subrepo
# URL exists at lastrev. Test it and fallback to rev it
# is not there.
try:
Thomas Arendsen Hein
subrepo/svn: make rev number retrieval compatible with svn 1.5 (issue2968)...
r17035 self._svncommand(['list', '%s@%s' % (self._state[0], lastrev)])
Patrick Mezard
subrepo/svn: fix checked out rev number retrieval (issue2968)...
r16554 return lastrev
except error.Abort:
pass
return rev
Matt Mackall
subrepo: add basestate method...
r16072
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Augie Fackler
subrepo: Subversion support
r10178 def commit(self, text, user, date):
# user and date are out of our hands since svn is centralized
Patrick Mezard
subrepo/svn: improve error message on missing files...
r16530 changed, extchanged, missing = self._wcchanged()
Patrick Mezard
subrepo: handle svn externals and meta changes (issue1982)...
r10273 if not changed:
Patrick Mezard
subrepo/svn: fix checked out rev number retrieval (issue2968)...
r16554 return self.basestate()
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'))
Patrick Mezard
subrepo/svn: improve error message on missing files...
r16530 if missing:
# svn can commit with missing entries but aborting like hg
# seems a better approach.
raise util.Abort(_('cannot commit missing svn entries'))
Augie Fackler
svn subrepos: work around checkout obstructions (issue2752)...
r14664 commitinfo, err = self._svncommand(['commit', '-m', text])
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 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:
Patrick Mezard
subrepo/svn: abort on commit with missing file (issue3029)...
r16529 if not commitinfo.strip():
# Sometimes, our definition of "changed" differs from
# svn one. For instance, svn ignores missing files
# when committing. If there are only missing files, no
# commit is made, no output and no error code.
raise util.Abort(_('failed to commit svn changes'))
Augie Fackler
subrepo: Subversion support
r10178 raise util.Abort(commitinfo.splitlines()[-1])
newrev = newrev.groups()[0]
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.status(self._svncommand(['update', '-r', newrev])[0])
Augie Fackler
subrepo: Subversion support
r10178 return newrev
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Augie Fackler
subrepo: Subversion support
r10178 def remove(self):
if self.dirty():
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.warn(_('not removing repo %s because '
'it has changes.\n') % self._path)
Augie Fackler
subrepo: Subversion support
r10178 return
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 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)
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 path = self._ctx.repo().wjoin(self._path)
Patrick Mezard
subrepo: prune empty directories when removing svn subrepo
r13015 shutil.rmtree(path, onerror=onerror)
try:
os.removedirs(os.path.dirname(path))
except OSError:
pass
Augie Fackler
subrepo: Subversion support
r10178
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 def get(self, state, overwrite=False):
if overwrite:
Patrick Mezard
subrepo: fix update -C with svn subrepos when cwd != repo.root
r13332 self._svncommand(['revert', '--recursive'])
Patrick Mezard
subrepo: handle svn tracked/unknown directory collisions...
r14050 args = ['checkout']
if self._svnversion >= (1, 5):
args.append('--force')
Eli Carter
subrepo: correct revision in svn checkout...
r14820 # The revision must be specified at the end of the URL to properly
# update to a directory which has since been deleted and recreated.
args.append('%s@%s' % (state[0], state[1]))
Augie Fackler
svn subrepos: work around checkout obstructions (issue2752)...
r14664 status, err = self._svncommand(args, failok=True)
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 _sanitize(self.ui, self._ctx.repo().wjoin(self._path), '.svn')
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
svn subrepos: work around checkout obstructions (issue2752)...
r14664 if ('is already a working copy for a different URL' in err
Patrick Mezard
subrepo/svn: improve error message on missing files...
r16530 and (self._wcchanged()[:2] == (False, False))):
Augie Fackler
svn subrepos: work around checkout obstructions (issue2752)...
r14664 # obstructed but clean working copy, so just blow it away.
self.remove()
self.get(state, overwrite=False)
return
raise util.Abort((status or err).splitlines()[-1])
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.status(status)
Augie Fackler
subrepo: Subversion support
r10178
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Augie Fackler
subrepo: Subversion support
r10178 def merge(self, state):
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 old = self._state[1]
new = state[1]
Patrick Mezard
subrepo/svn: cache _wcrev() value in merge()
r16555 wcrev = self._wcrev()
if new != wcrev:
dirty = old == wcrev or self._wcchanged()[0]
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 if _updateprompt(self.ui, self, dirty, wcrev, new):
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 self.get(state, False)
Augie Fackler
subrepo: Subversion support
r10178
Angel Ezquerra
push: propagate --new-branch and --ssh options when pushing subrepos...
r15708 def push(self, opts):
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
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Martin Geisler
subrepo: introduce files and filedata methods for subrepo classes
r12322 def files(self):
Patrick Mezard
archive: make it work with svn subrepos (issue3308)...
r16450 output = self._svncommand(['list', '--recursive', '--xml'])[0]
doc = xml.dom.minidom.parseString(output)
paths = []
for e in doc.getElementsByTagName('entry'):
kind = str(e.getAttribute('kind'))
if kind != 'file':
continue
name = ''.join(c.data for c
in e.getElementsByTagName('name')[0].childNodes
if c.nodeType == c.TEXT_NODE)
Bryan O'Sullivan
subrepo: encode unicode path names (issue3610)...
r17441 paths.append(name.encode('utf-8'))
Patrick Mezard
archive: make it work with svn subrepos (issue3308)...
r16450 return paths
Martin Geisler
subrepo: introduce files and filedata methods for subrepo classes
r12322
def filedata(self, name):
Patrick Mezard
archive: make it work with svn subrepos (issue3308)...
r16450 return self._svncommand(['cat'], name)[0]
Martin Geisler
subrepo: introduce files and filedata methods for subrepo classes
r12322
Eric Eisner
subrepo: gitsubrepo should inherit from abstractsubrepo
r13106 class gitsubrepo(abstractsubrepo):
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 def __init__(self, ctx, path, state):
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 super(gitsubrepo, self).__init__(ctx.repo().ui)
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 self._state = state
self._ctx = ctx
Eric Eisner
subrepo: fix subrelpath for git subrepos...
r13181 self._path = path
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 self._relpath = os.path.join(reporelpath(ctx.repo()), path)
self._abspath = ctx.repo().wjoin(path)
self._subparent = ctx.repo()
Benjamin Pollack
subrepo: warn user if Git is not version 1.6.0 or higher
r17024 self._ensuregit()
def _ensuregit(self):
Benjamin Pollack
subrepo: support Git being named "git.cmd" on Windows (issue3173)...
r17025 try:
self._gitexecutable = 'git'
out, err = self._gitnodir(['--version'])
except OSError, e:
if e.errno != 2 or os.name != 'nt':
raise
self._gitexecutable = 'git.cmd'
out, err = self._gitnodir(['--version'])
Siddharth Agarwal
subrepo: factor out Git version check to add doctests...
r20840 versionstatus = self._checkversion(out)
if versionstatus == 'unknown':
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.warn(_('cannot retrieve git version\n'))
Siddharth Agarwal
subrepo: factor out Git version check to add doctests...
r20840 elif versionstatus == 'abort':
raise util.Abort(_('git subrepo requires at least 1.6.0 or later'))
elif versionstatus == 'warning':
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.warn(_('git subrepo requires at least 1.6.0 or later\n'))
Siddharth Agarwal
subrepo: factor out Git version check to add doctests...
r20840
@staticmethod
Mathias De Maré
subrepo: move git version check into a separate method...
r23521 def _gitversion(out):
Mathias De Maré
subrepo: extend git version check to 3 digits...
r23522 m = re.search(r'^git version (\d+)\.(\d+)\.(\d+)', out)
if m:
return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
Mathias De Maré
subrepo: move git version check into a separate method...
r23521 m = re.search(r'^git version (\d+)\.(\d+)', out)
if m:
Mathias De Maré
subrepo: extend git version check to 3 digits...
r23522 return (int(m.group(1)), int(m.group(2)), 0)
Mathias De Maré
subrepo: move git version check into a separate method...
r23521
return -1
@staticmethod
Siddharth Agarwal
subrepo: factor out Git version check to add doctests...
r20840 def _checkversion(out):
'''ensure git version is new enough
>>> _checkversion = gitsubrepo._checkversion
>>> _checkversion('git version 1.6.0')
'ok'
>>> _checkversion('git version 1.8.5')
'ok'
>>> _checkversion('git version 1.4.0')
'abort'
>>> _checkversion('git version 1.5.0')
'warning'
>>> _checkversion('git version 1.9-rc0')
'ok'
>>> _checkversion('git version 1.9.0.265.g81cdec2')
'ok'
>>> _checkversion('git version 1.9.0.GIT')
'ok'
>>> _checkversion('git version 12345')
'unknown'
>>> _checkversion('no')
'unknown'
'''
Mathias De Maré
subrepo: move git version check into a separate method...
r23521 version = gitsubrepo._gitversion(out)
Benjamin Pollack
subrepo: warn user if Git is not version 1.6.0 or higher
r17024 # git 1.4.0 can't work at all, but 1.5.X can in at least some cases,
# despite the docstring comment. For now, error on 1.4.0, warn on
# 1.5.0 but attempt to continue.
Mathias De Maré
subrepo: move git version check into a separate method...
r23521 if version == -1:
return 'unknown'
Mathias De Maré
subrepo: extend git version check to 3 digits...
r23522 if version < (1, 5, 0):
Siddharth Agarwal
subrepo: factor out Git version check to add doctests...
r20840 return 'abort'
Mathias De Maré
subrepo: extend git version check to 3 digits...
r23522 elif version < (1, 6, 0):
Siddharth Agarwal
subrepo: factor out Git version check to add doctests...
r20840 return 'warning'
return 'ok'
Eric Eisner
subrepo: support for adding a git subrepo...
r12992
Eric Eisner
subrepo: use environment variable instead of git commit's --date...
r13095 def _gitcommand(self, commands, env=None, stream=False):
return self._gitdir(commands, env=env, stream=stream)[0]
Eric Eisner
subrepo: support for adding a git subrepo...
r12992
Eric Eisner
subrepo: use environment variable instead of git commit's --date...
r13095 def _gitdir(self, commands, env=None, stream=False):
Eric Eisner
subrepo: fix subrelpath for git subrepos...
r13181 return self._gitnodir(commands, env=env, stream=stream,
cwd=self._abspath)
Eric Eisner
subrepo: support for adding a git subrepo...
r12992
Eric Eisner
subrepo: use environment variable instead of git commit's --date...
r13095 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 """Calls the git command
Mads Kiilerich
fix trivial spelling errors
r17424 The methods tries to call the git command. versions prior to 1.6.0
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 are not supported and very probably fail.
"""
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
Eric Eisner
subrepo: silence git output when ui.quiet is set
r13111 # unless ui.quiet is set, print git's stderr,
# which is mostly progress and useful info
errpipe = None
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 if self.ui.quiet:
Eric Eisner
subrepo: silence git output when ui.quiet is set
r13111 errpipe = open(os.devnull, 'w')
Benjamin Pollack
subrepo: support Git being named "git.cmd" on Windows (issue3173)...
r17025 p = subprocess.Popen([self._gitexecutable] + commands, bufsize=-1,
cwd=cwd, env=env, close_fds=util.closefds,
Eric Eisner
subrepo: silence git output when ui.quiet is set
r13111 stdout=subprocess.PIPE, stderr=errpipe)
Eric Eisner
subrepo: archive git subrepos
r13027 if stream:
return p.stdout, None
Eric Eisner
subrepo: strip gitcommand output
r13085 retdata = p.stdout.read().strip()
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 # wait for the child to exit to avoid race condition.
p.wait()
Eric Eisner
subrepo: treat git error code 1 as success...
r13107 if p.returncode != 0 and p.returncode != 1:
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 # there are certain error codes that are ok
Eric Eisner
subrepo: show git command with --debug...
r13110 command = commands[0]
Eric Eisner
subrepo: use low-level git-for-each-ref command in branchmap...
r13150 if command in ('cat-file', 'symbolic-ref'):
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 return retdata, p.returncode
# for all others, abort
Eric Eisner
subrepo: show git command with --debug...
r13110 raise util.Abort('git %s error %d in %s' %
(command, p.returncode, self._relpath))
Eric Eisner
subrepo: support for adding a git subrepo...
r12992
return retdata, p.returncode
Eric Eisner
subrepo: don't crash when git repo is missing
r13553 def _gitmissing(self):
return not os.path.exists(os.path.join(self._abspath, '.git'))
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 def _gitstate(self):
Eric Eisner
subrepo: strip gitcommand output
r13085 return self._gitcommand(['rev-parse', 'HEAD'])
Eric Eisner
subrepo: support for adding a git subrepo...
r12992
Eric Eisner
subrepo: defer determination of git's current branch
r13152 def _gitcurrentbranch(self):
current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
if err:
current = None
return current
Eric Eisner
subrepo: show the source that git pulls
r13569 def _gitremote(self, remote):
out = self._gitcommand(['remote', 'show', '-n', remote])
line = out.split('\n')[1]
i = line.index('URL: ') + len('URL: ')
return line[i:]
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 def _githavelocally(self, revision):
out, code = self._gitdir(['cat-file', '-e', revision])
return code == 0
Eric Eisner
subrepo: lazier git push logic...
r13029 def _gitisancestor(self, r1, r2):
Eric Eisner
subrepo: strip gitcommand output
r13085 base = self._gitcommand(['merge-base', r1, r2])
Eric Eisner
subrepo: lazier git push logic...
r13029 return base == r1
Paul Molodowitch
subrepo: bare git repos considered dirty...
r14440 def _gitisbare(self):
return self._gitcommand(['config', '--bool', 'core.bare']) == 'true'
Eric Roshan Eisner
subrepo: fix git status false positive (issue3109)...
r15531 def _gitupdatestat(self):
"""This must be run before git diff-index.
diff-index only looks at changes to file stat;
this command looks at file contents and updates the stat."""
self._gitcommand(['update-index', '-q', '--refresh'])
Eric Eisner
subrepo: update and merge works with any git branch
r12995 def _gitbranchmap(self):
Eric Eisner
subrepo: backout 519ac79d680b...
r13178 '''returns 2 things:
Eric Eisner
subrepo: return both mapping directions from gitbranchmap
r13086 a map from git branch to revision
Eric Eisner
subrepo: backout 519ac79d680b...
r13178 a map from revision to branches'''
Eric Eisner
subrepo: return both mapping directions from gitbranchmap
r13086 branch2rev = {}
rev2branch = {}
Eric Eisner
subrepo: backout 519ac79d680b...
r13178
Eric Eisner
subrepo: use low-level git-for-each-ref command in branchmap...
r13150 out = self._gitcommand(['for-each-ref', '--format',
Eric Eisner
subrepo: backout 519ac79d680b...
r13178 '%(objectname) %(refname)'])
Eric Eisner
subrepo: update and merge works with any git branch
r12995 for line in out.split('\n'):
Eric Eisner
subrepo: backout 519ac79d680b...
r13178 revision, ref = line.split(' ')
Eric Eisner
subrepo: disallow all unknown git ref types
r13465 if (not ref.startswith('refs/heads/') and
not ref.startswith('refs/remotes/')):
Eric Eisner
subrepo: update and merge works with any git branch
r12995 continue
Eric Eisner
subrepo: use low-level git-for-each-ref command in branchmap...
r13150 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
Eric Eisner
subrepo: update and merge works with any git branch
r12995 continue # ignore remote/HEAD redirects
Eric Eisner
subrepo: use low-level git-for-each-ref command in branchmap...
r13150 branch2rev[ref] = revision
rev2branch.setdefault(revision, []).append(ref)
Eric Eisner
subrepo: backout 519ac79d680b...
r13178 return branch2rev, rev2branch
def _gittracking(self, branches):
'return map of remote branch to local tracking branch'
# assumes no more than one local tracking branch for each remote
tracking = {}
for b in branches:
if b.startswith('refs/remotes/'):
continue
Eric Roshan Eisner
subrepo: fix git branch tracking logic (issue2920)
r15234 bname = b.split('/', 2)[2]
remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
Eric Eisner
subrepo: backout 519ac79d680b...
r13178 if remote:
Eric Roshan Eisner
subrepo: fix git branch tracking logic (issue2920)
r15234 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
Eric Eisner
subrepo: backout 519ac79d680b...
r13178 tracking['refs/remotes/%s/%s' %
(remote, ref.split('/', 2)[2])] = b
return tracking
Eric Eisner
subrepo: lazily update git's local tracking branches...
r13087
Eric Eisner
subrepo: expand relative sources for git subrepos
r13460 def _abssource(self, source):
Eric Eisner
subrepo: recognize scp-style paths as git URLs
r13692 if '://' not in source:
# recognize the scp syntax as an absolute source
colon = source.find(':')
if colon != -1 and '/' not in source[:colon]:
return source
Eric Eisner
subrepo: expand relative sources for git subrepos
r13460 self._subsource = source
return _abssource(self)
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993 def _fetch(self, source, revision):
Eric Eisner
subrepo: don't crash when git repo is missing
r13553 if self._gitmissing():
Eric Eisner
subrepo: show the source that git clones
r13525 source = self._abssource(source)
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.status(_('cloning subrepo %s from %s\n') %
Eric Eisner
subrepo: show the source that git clones
r13525 (self._relpath, source))
self._gitnodir(['clone', source, self._abspath])
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993 if self._githavelocally(revision):
return
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.status(_('pulling subrepo %s from %s\n') %
Eric Eisner
subrepo: show the source that git pulls
r13569 (self._relpath, self._gitremote('origin')))
Eric Eisner
subrepo: only attempt pulling from git's origin...
r13466 # try only origin: the originally cloned repo
Eric Eisner
subrepo: drop arguments unsupported by old git
r13097 self._gitcommand(['fetch'])
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993 if not self._githavelocally(revision):
raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
Eric Eisner
subrepo: fix subrelpath for git subrepos...
r13181 (revision, self._relpath))
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Eric Eisner
subrepo: support ignoreupdate in gitsubrepo's dirty()
r13179 def dirty(self, ignoreupdate=False):
Eric Eisner
subrepo: don't crash when git repo is missing
r13553 if self._gitmissing():
Eric Eisner
subrepo: don't crash when git .hgsubstate is empty (issue2716)
r14469 return self._state[1] != ''
Paul Molodowitch
subrepo: bare git repos considered dirty...
r14440 if self._gitisbare():
return True
Eric Eisner
subrepo: support ignoreupdate in gitsubrepo's dirty()
r13179 if not ignoreupdate and self._state[1] != self._gitstate():
Kevin Bullock
subrepo: clarify comments in dirty() methods...
r13325 # different version checked out
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 return True
# check for staged changes or modified files; ignore untracked files
Eric Roshan Eisner
subrepo: fix git status false positive (issue3109)...
r15531 self._gitupdatestat()
Eric Eisner
subrepo: use low-level git-diff-index for dirty()...
r13153 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
return code == 1
Eric Eisner
subrepo: support for adding a git subrepo...
r12992
Matt Mackall
subrepo: add basestate method...
r16072 def basestate(self):
return self._gitstate()
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Martin Geisler
merge with stable
r13323 def get(self, state, overwrite=False):
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993 source, revision, kind = state
Eric Eisner
subrepo: don't crash when git .hgsubstate is empty (issue2716)
r14469 if not revision:
self.remove()
return
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993 self._fetch(source, revision)
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996 # if the repo was set to be bare, unbare it
Paul Molodowitch
subrepo: bare git repos considered dirty...
r14440 if self._gitisbare():
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996 self._gitcommand(['config', 'core.bare', 'false'])
if self._gitstate() == revision:
self._gitcommand(['reset', '--hard', 'HEAD'])
return
elif self._gitstate() == revision:
Erik Zielke
subrepo: make update -C clean the working directory for git subrepos...
r13324 if overwrite:
Augie Fackler
subrepo: trailing whitespace cleanup
r13927 # first reset the index to unmark new files for commit, because
Erik Zielke
subrepo: make update -C clean the working directory for git subrepos...
r13324 # reset --hard will otherwise throw away files added for commit,
# not just unmark them.
self._gitcommand(['reset', 'HEAD'])
self._gitcommand(['reset', '--hard', 'HEAD'])
Eric Eisner
subrepo: update and merge works with any git branch
r12995 return
Eric Eisner
subrepo: backout 519ac79d680b...
r13178 branch2rev, rev2branch = self._gitbranchmap()
Eric Eisner
subrepo: lazily update git's local tracking branches...
r13087
Erik Zielke
subrepo: make update -C clean the working directory for git subrepos...
r13324 def checkout(args):
cmd = ['checkout']
if overwrite:
# first reset the index to unmark new files for commit, because
# the -f option will otherwise throw away files added for
# commit, not just unmark them.
self._gitcommand(['reset', 'HEAD'])
cmd.append('-f')
self._gitcommand(cmd + args)
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 _sanitize(self.ui, self._abspath, '.git')
Erik Zielke
subrepo: make update -C clean the working directory for git subrepos...
r13324
Eric Eisner
subrepo: lazily update git's local tracking branches...
r13087 def rawcheckout():
Eric Eisner
subrepo: update and merge works with any git branch
r12995 # no branch to checkout, check it out with no branch
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.warn(_('checking out detached HEAD in subrepo %s\n') %
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993 self._relpath)
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.warn(_('check out a git branch if you intend '
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993 'to make changes\n'))
Erik Zielke
subrepo: make update -C clean the working directory for git subrepos...
r13324 checkout(['-q', revision])
Eric Eisner
subrepo: lazily update git's local tracking branches...
r13087
if revision not in rev2branch:
rawcheckout()
Eric Eisner
subrepo: update and merge works with any git branch
r12995 return
Eric Eisner
subrepo: return both mapping directions from gitbranchmap
r13086 branches = rev2branch[revision]
Eric Eisner
subrepo: update and merge works with any git branch
r12995 firstlocalbranch = None
for b in branches:
Eric Eisner
subrepo: use low-level git-for-each-ref command in branchmap...
r13150 if b == 'refs/heads/master':
Eric Eisner
subrepo: update and merge works with any git branch
r12995 # master trumps all other branches
Erik Zielke
subrepo: make update -C clean the working directory for git subrepos...
r13324 checkout(['refs/heads/master'])
Eric Eisner
subrepo: update and merge works with any git branch
r12995 return
Eric Eisner
subrepo: use low-level git-for-each-ref command in branchmap...
r13150 if not firstlocalbranch and not b.startswith('refs/remotes/'):
Eric Eisner
subrepo: update and merge works with any git branch
r12995 firstlocalbranch = b
if firstlocalbranch:
Erik Zielke
subrepo: make update -C clean the working directory for git subrepos...
r13324 checkout([firstlocalbranch])
Eric Eisner
subrepo: lazily update git's local tracking branches...
r13087 return
Eric Eisner
subrepo: backout 519ac79d680b...
r13178 tracking = self._gittracking(branch2rev.keys())
Eric Eisner
subrepo: lazily update git's local tracking branches...
r13087 # choose a remote branch already tracked if possible
remote = branches[0]
if remote not in tracking:
for b in branches:
if b in tracking:
remote = b
break
if remote not in tracking:
# create a new local tracking branch
pozheg
subrepo: clone of git sub-repository creates incorrect git branch (issue3870)...
r19012 local = remote.split('/', 3)[3]
Erik Zielke
subrepo: make update -C clean the working directory for git subrepos...
r13324 checkout(['-b', local, remote])
Eric Eisner
subrepo: lazily update git's local tracking branches...
r13087 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
# When updating to a tracked remote branch,
# if the local tracking branch is downstream of it,
# a normal `git pull` would have performed a "fast-forward merge"
# which is equivalent to updating the local branch to the remote.
# Since we are only looking at branching at update, we need to
# detect this situation and perform this action lazily.
Eric Eisner
subrepo: defer determination of git's current branch
r13152 if tracking[remote] != self._gitcurrentbranch():
Erik Zielke
subrepo: make update -C clean the working directory for git subrepos...
r13324 checkout([tracking[remote]])
Eric Eisner
subrepo: lazily update git's local tracking branches...
r13087 self._gitcommand(['merge', '--ff', remote])
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 _sanitize(self.ui, self._abspath, '.git')
Eric Eisner
subrepo: lazily update git's local tracking branches...
r13087 else:
# a real merge would be required, just checkout the revision
rawcheckout()
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 def commit(self, text, user, date):
Eric Eisner
subrepo: don't crash when git repo is missing
r13553 if self._gitmissing():
raise util.Abort(_("subrepo %s is missing") % self._relpath)
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 cmd = ['commit', '-a', '-m', text]
Eric Eisner
subrepo: use environment variable instead of git commit's --date...
r13095 env = os.environ.copy()
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 if user:
cmd += ['--author', user]
if date:
# git's date parser silently ignores when seconds < 1e9
# convert to ISO8601
Eric Eisner
subrepo: use environment variable instead of git commit's --date...
r13095 env['GIT_AUTHOR_DATE'] = util.datestr(date,
'%Y-%m-%dT%H:%M:%S %1%2')
self._gitcommand(cmd, env=env)
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 # make sure commit works otherwise HEAD might not exist under certain
# circumstances
return self._gitstate()
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Eric Eisner
subrepo: allow git subrepos to push and merge...
r12994 def merge(self, state):
source, revision, kind = state
self._fetch(source, revision)
Eric Eisner
subrepo: strip gitcommand output
r13085 base = self._gitcommand(['merge-base', revision, self._state[1]])
Eric Roshan Eisner
subrepo: fix git status false positive (issue3109)...
r15531 self._gitupdatestat()
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
def mergefunc():
if base == revision:
self.get(state) # fast forward merge
elif base != self._state[1]:
self._gitcommand(['merge', '--no-commit', revision])
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 _sanitize(self.ui, self._abspath, '.git')
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417
if self.dirty():
if self._gitstate() != revision:
dirty = self._gitstate() == self._state[1] or code != 0
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 if _updateprompt(self.ui, self, dirty,
Martin Geisler
subrepo: break long line found by check-code
r13432 self._state[1][:7], revision[:7]):
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 mergefunc()
else:
mergefunc()
Eric Eisner
subrepo: allow git subrepos to push and merge...
r12994
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Angel Ezquerra
push: propagate --new-branch and --ssh options when pushing subrepos...
r15708 def push(self, opts):
force = opts.get('force')
Eric Eisner
subrepo: don't crash when git .hgsubstate is empty (issue2716)
r14469 if not self._state[1]:
return True
Eric Eisner
subrepo: don't crash when git repo is missing
r13553 if self._gitmissing():
raise util.Abort(_("subrepo %s is missing") % self._relpath)
Eric Eisner
subrepo: lazier git push logic...
r13029 # if a branch in origin contains the revision, nothing to do
Eric Eisner
subrepo: backout 519ac79d680b...
r13178 branch2rev, rev2branch = self._gitbranchmap()
Eric Eisner
subrepo: speed up git push logic...
r13109 if self._state[1] in rev2branch:
for b in rev2branch[self._state[1]]:
Eric Eisner
subrepo: use low-level git-for-each-ref command in branchmap...
r13150 if b.startswith('refs/remotes/origin/'):
Eric Eisner
subrepo: speed up git push logic...
r13109 return True
Eric Eisner
subrepo: return both mapping directions from gitbranchmap
r13086 for b, revision in branch2rev.iteritems():
Eric Eisner
subrepo: use low-level git-for-each-ref command in branchmap...
r13150 if b.startswith('refs/remotes/origin/'):
Eric Eisner
subrepo: return both mapping directions from gitbranchmap
r13086 if self._gitisancestor(self._state[1], revision):
return True
Eric Eisner
subrepo: lazier git push logic...
r13029 # otherwise, try to push the currently checked out branch
Eric Eisner
subrepo: allow git subrepos to push and merge...
r12994 cmd = ['push']
if force:
cmd.append('--force')
Eric Eisner
subrepo: defer determination of git's current branch
r13152
current = self._gitcurrentbranch()
Eric Eisner
subrepo: update and merge works with any git branch
r12995 if current:
Eric Eisner
subrepo: lazier git push logic...
r13029 # determine if the current branch is even useful
if not self._gitisancestor(self._state[1], current):
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.warn(_('unrelated git branch checked out '
Eric Eisner
subrepo: lazier git push logic...
r13029 'in subrepo %s\n') % self._relpath)
return False
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.status(_('pushing branch %s of subrepo %s\n') %
(current.split('/', 2)[2], self._relpath))
Matt Mackall
subrepo: check return code for git push (issue4223)
r20970 ret = self._gitdir(cmd + ['origin', current])
return ret[1] == 0
Eric Eisner
subrepo: update and merge works with any git branch
r12995 else:
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.warn(_('no branch checked out in subrepo %s\n'
'cannot push revision %s\n') %
Eric Eisner
subrepo: lazier git push logic...
r13029 (self._relpath, self._state[1]))
Eric Eisner
subrepo: update and merge works with any git branch
r12995 return False
Eric Eisner
subrepo: allow git subrepos to push and merge...
r12994
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Mathias De Maré
subrepos: support adding files in git subrepos...
r24174 def add(self, ui, match, prefix, explicitonly, **opts):
if self._gitmissing():
return []
Matt Harbison
subrepo: don't exclude files in .hgignore when adding to git...
r24182
(modified, added, removed,
Matt Harbison
subrepo: explicitly request clean and unknown files in status for git's add...
r24209 deleted, unknown, ignored, clean) = self.status(None, unknown=True,
clean=True)
Mathias De Maré
subrepos: support adding files in git subrepos...
r24174
Matt Harbison
subrepo: warn when adding already tracked files in gitsubrepo...
r24183 tracked = set()
# dirstates 'amn' warn, 'r' is added again
for l in (modified, added, deleted, clean):
tracked.update(l)
Matt Harbison
subrepo: don't exclude files in .hgignore when adding to git...
r24182 # Unknown files not of interest will be rejected by the matcher
files = unknown
files.extend(match.files())
Matt Harbison
subrepo: warn when adding already tracked files in gitsubrepo...
r24183 rejected = []
Matt Harbison
subrepo: don't exclude files in .hgignore when adding to git...
r24182 files = [f for f in sorted(set(files)) if match(f)]
Mathias De Maré
subrepos: support adding files in git subrepos...
r24174 for f in files:
exact = match.exact(f)
command = ["add"]
if exact:
command.append("-f") #should be added, even if ignored
if ui.verbose or not exact:
ui.status(_('adding %s\n') % match.rel(f))
Matt Harbison
subrepo: warn when adding already tracked files in gitsubrepo...
r24183
if f in tracked: # hg prints 'adding' even if already tracked
if exact:
rejected.append(f)
continue
Mathias De Maré
subrepos: support adding files in git subrepos...
r24174 if not opts.get('dry_run'):
self._gitcommand(command + [f])
Matt Harbison
subrepo: warn when adding already tracked files in gitsubrepo...
r24183
for f in rejected:
ui.warn(_("%s already tracked!\n") % match.abs(f))
return rejected
Mathias De Maré
subrepos: support adding files in git subrepos...
r24174
@annotatesubrepoerror
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996 def remove(self):
Eric Eisner
subrepo: don't crash when git repo is missing
r13553 if self._gitmissing():
return
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996 if self.dirty():
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.warn(_('not removing repo %s because '
'it has changes.\n') % self._relpath)
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996 return
# we can't fully delete the repository as it may contain
# local-only history
Matt Harbison
subrepo: rename the '_ui' member to 'ui'...
r23572 self.ui.note(_('removing subrepo %s\n') % self._relpath)
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996 self._gitcommand(['config', 'core.bare', 'true'])
Eric Eisner
subrepo: fix subrelpath for git subrepos...
r13181 for f in os.listdir(self._abspath):
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996 if f == '.git':
continue
Eric Eisner
subrepo: fix subrelpath for git subrepos...
r13181 path = os.path.join(self._abspath, f)
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996 if os.path.isdir(path) and not os.path.islink(path):
shutil.rmtree(path)
else:
os.remove(path)
Matt Harbison
subrepo: drop the 'ui' parameter to archive()...
r23575 def archive(self, archiver, prefix, match=None):
Angel Ezquerra
archive: raise error.Abort if the file pattern matches no files...
r18967 total = 0
Eric Eisner
subrepo: archive git subrepos
r13027 source, revision = self._state
Eric Eisner
subrepo: don't crash when git .hgsubstate is empty (issue2716)
r14469 if not revision:
Angel Ezquerra
archive: raise error.Abort if the file pattern matches no files...
r18967 return total
Eric Eisner
subrepo: archive git subrepos
r13027 self._fetch(source, revision)
# Parse git's native archive command.
# This should be much faster than manually traversing the trees
# and objects with many subprocess calls.
tarstream = self._gitcommand(['archive', revision], stream=True)
tar = tarfile.open(fileobj=tarstream, mode='r|')
Martin Geisler
subrepo: add progress bar support to archive
r13144 relpath = subrelpath(self)
Matt Harbison
subrepo: drop the 'ui' parameter to archive()...
r23575 self.ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
Martin Geisler
subrepo: add progress bar support to archive
r13144 for i, info in enumerate(tar):
Eric Eisner
subrepo: fix git archive parsing of directories and symfiles
r13180 if info.isdir():
continue
Matt Harbison
subrepo: propagate matcher to subrepos when archiving...
r17108 if match and not match(info.name):
continue
Eric Eisner
subrepo: fix git archive parsing of directories and symfiles
r13180 if info.issym():
data = info.linkname
else:
data = tar.extractfile(info).read()
Eric Eisner
subrepo: fix subrelpath for git subrepos...
r13181 archiver.addfile(os.path.join(prefix, self._path, info.name),
Eric Eisner
subrepo: fix git archive parsing of directories and symfiles
r13180 info.mode, info.issym(), data)
Angel Ezquerra
archive: raise error.Abort if the file pattern matches no files...
r18967 total += 1
Matt Harbison
subrepo: drop the 'ui' parameter to archive()...
r23575 self.ui.progress(_('archiving (%s)') % relpath, i + 1,
unit=_('files'))
self.ui.progress(_('archiving (%s)') % relpath, None)
Angel Ezquerra
archive: raise error.Abort if the file pattern matches no files...
r18967 return total
Martin Geisler
subrepo: add progress bar support to archive
r13144
Eric Eisner
subrepo: archive git subrepos
r13027
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Mathias De Maré
subrepo: add 'cat' support for git subrepos...
r23991 def cat(self, match, prefix, **opts):
rev = self._state[1]
if match.anypats():
return 1 #No support for include/exclude yet
if not match.files():
return 1
for f in match.files():
output = self._gitcommand(["show", "%s:%s" % (rev, f)])
fp = cmdutil.makefileobj(self._subparent, opts.get('output'),
self._ctx.node(),
pathname=os.path.join(prefix, f))
fp.write(output)
fp.close()
return 0
@annotatesubrepoerror
Eric Eisner
subrepo: basic support for status of git subrepos
r13182 def status(self, rev2, **opts):
Eric Eisner
subrepo: don't crash when git .hgsubstate is empty (issue2716)
r14469 rev1 = self._state[1]
if self._gitmissing() or not rev1:
Eric Eisner
subrepo: don't crash when git repo is missing
r13553 # if the repo is missing, return no results
Matt Harbison
subrepo: always return scmutil.status() from gitsubrepo.status()...
r24210 return scmutil.status([], [], [], [], [], [], [])
Eric Eisner
subrepo: basic support for status of git subrepos
r13182 modified, added, removed = [], [], []
Eric Roshan Eisner
subrepo: fix git status false positive (issue3109)...
r15531 self._gitupdatestat()
Eric Eisner
subrepo: basic support for status of git subrepos
r13182 if rev2:
command = ['diff-tree', rev1, rev2]
else:
command = ['diff-index', rev1]
out = self._gitcommand(command)
for line in out.split('\n'):
tab = line.find('\t')
if tab == -1:
continue
status, f = line[tab - 1], line[tab + 1:]
if status == 'M':
modified.append(f)
elif status == 'A':
added.append(f)
elif status == 'D':
removed.append(f)
Martin von Zweigbergk
subrepo: use separate instances of empty lists in status...
r22927 deleted, unknown, ignored, clean = [], [], [], []
Mathias De Maré
subrepo: add status support for ignored files in git subrepos...
r23411
Mathias De Maré
subrepo: add status support for ignored and clean files in git subrepos
r24256 command = ['status', '--porcelain', '-z']
Matt Harbison
subrepo: only fetch unknown files from git when explicitly requested
r24211 if opts.get('unknown'):
Mathias De Maré
subrepo: add status support for ignored and clean files in git subrepos
r24256 command += ['--untracked-files=all']
if opts.get('ignored'):
command += ['--ignored']
out = self._gitcommand(command)
changedfiles = set()
changedfiles.update(modified)
changedfiles.update(added)
changedfiles.update(removed)
for line in out.split('\0'):
if not line:
continue
st = line[0:2]
#moves and copies show 2 files on one line
if line.find('\0') >= 0:
filename1, filename2 = line[3:].split('\0')
else:
filename1 = line[3:]
filename2 = None
changedfiles.add(filename1)
if filename2:
changedfiles.add(filename2)
if st == '??':
unknown.append(filename1)
elif st == '!!':
ignored.append(filename1)
if opts.get('clean'):
out = self._gitcommand(['ls-files'])
for f in out.split('\n'):
if not f in changedfiles:
clean.append(f)
Mathias De Maré
subrepo: add status support for ignored files in git subrepos...
r23411
Martin von Zweigbergk
status: update various other methods to return new class
r22914 return scmutil.status(modified, added, removed, deleted,
unknown, ignored, clean)
Eric Eisner
subrepo: basic support for status of git subrepos
r13182
Mathias De Maré
subrepo: add partial diff support for git subrepos...
r23523 @annotatesubrepoerror
def diff(self, ui, diffopts, node2, match, prefix, **opts):
node1 = self._state[1]
cmd = ['diff']
if opts['stat']:
cmd.append('--stat')
else:
# for Git, this also implies '-p'
cmd.append('-U%d' % diffopts.context)
gitprefix = os.path.join(prefix, self._path)
if diffopts.noprefix:
cmd.extend(['--src-prefix=%s/' % gitprefix,
'--dst-prefix=%s/' % gitprefix])
else:
cmd.extend(['--src-prefix=a/%s/' % gitprefix,
'--dst-prefix=b/%s/' % gitprefix])
if diffopts.ignorews:
cmd.append('--ignore-all-space')
if diffopts.ignorewsamount:
cmd.append('--ignore-space-change')
if self._gitversion(self._gitcommand(['--version'])) >= (1, 8, 4) \
and diffopts.ignoreblanklines:
cmd.append('--ignore-blank-lines')
cmd.append(node1)
if node2:
cmd.append(node2)
if match.anypats():
return #No support for include/exclude yet
Mathias De Maré
subrepo: correctly add newline for git subrepo diffs...
r23938 output = ""
Mathias De Maré
subrepo: add partial diff support for git subrepos...
r23523 if match.always():
Mathias De Maré
subrepo: correctly add newline for git subrepo diffs...
r23938 output += self._gitcommand(cmd) + '\n'
Mathias De Maré
subrepo: add partial diff support for git subrepos...
r23523 elif match.files():
for f in match.files():
Mathias De Maré
subrepo: correctly add newline for git subrepo diffs...
r23938 output += self._gitcommand(cmd + [f]) + '\n'
Mathias De Maré
subrepo: add partial diff support for git subrepos...
r23523 elif match(gitprefix): #Subrepo is matched
Mathias De Maré
subrepo: correctly add newline for git subrepo diffs...
r23938 output += self._gitcommand(cmd) + '\n'
if output.strip():
ui.write(output)
Mathias De Maré
subrepo: add partial diff support for git subrepos...
r23523
Mathias De Maré
subrepo: add forgotten annotation for reverting git subrepos...
r23679 @annotatesubrepoerror
Matt Mackall
subrepo: fix git subrepo ui argument
r23580 def revert(self, substate, *pats, **opts):
self.ui.status(_('reverting subrepo %s\n') % substate[0])
Mathias De Maré
subrepo: add revert support without backup for git subrepos...
r23550 if not opts.get('no_backup'):
Mathias De Maré
subrepo: add full revert support for git subrepos...
r23678 status = self.status(None)
names = status.modified
for name in names:
bakname = "%s.orig" % name
self.ui.note(_('saving current version of %s as %s\n') %
(name, bakname))
util.rename(os.path.join(self._abspath, name),
os.path.join(self._abspath, bakname))
Mathias De Maré
subrepo: add revert support without backup for git subrepos...
r23550
Matt Harbison
revert: display full subrepo output with --dry-run...
r24134 if not opts.get('dry_run'):
self.get(substate, overwrite=True)
Mathias De Maré
subrepo: add revert support without backup for git subrepos...
r23550 return []
Angel Ezquerra
subrepo: add shortid() method to subrepo classes...
r21400 def shortid(self, revid):
return revid[:7]
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 types = {
'hg': hgsubrepo,
Augie Fackler
subrepo: Subversion support
r10178 'svn': svnsubrepo,
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 'git': gitsubrepo,
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 }