##// END OF EJS Templates
copies: refactor checkcopies() into a top level method...
copies: refactor checkcopies() into a top level method This moves checkcopies() out of mergecopies() and makes it a top level function in the copies module. This allows extensions to override it. For example, I'm developing a filelog replacement that doesn't have rev numbers so all the rev number dependent implementation here needs to be replaced by the extension. No logic is changed in this commit.

File last commit:

r19156:ed1a2121 stable
r19178:4327687c default
Show More
subrepo.py
1451 lines | 54.3 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
subrepo: chain the original exception to SubrepoAbort...
r18964 import errno, os, re, xml.dom.minidom, shutil, posixpath, sys
Eric Eisner
subrepo: archive git subrepos
r13027 import stat, subprocess, tarfile
Matt Mackall
subrepo: add update/merge logic
r8814 from i18n import _
Matt Harbison
subrepo: propagate matcher to subrepos when archiving...
r17108 import config, scmutil, util, node, error, cmdutil, bookmarks, match as matchmod
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
def _calcfilehash(filename):
data = ''
if os.path.exists(filename):
FUJIWARA Katsunori
subrepo: open files in 'rb' mode to read exact data in (issue3926)...
r19156 fd = open(filename, 'rb')
Angel Ezquerra
subrepo: introduce storeclean helper functions...
r18936 data = fd.read()
fd.close()
return util.sha1(data).hexdigest()
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():
parent = _abssource(ctx._repo, abort=False)
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'
Dongsheng Song
Fix warning: Seen unexpected token "%"
r8908 'use (l)ocal source (%s) or (r)emote source (%s)?')
Matt Mackall
subrepo: add update/merge logic
r8814 % (s, l[0], r[0]),
Simon Heimberg
ui: extract choice from prompt...
r9048 (_('&Local'), _('&Remote')), 0):
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "prompt changed, get", r)
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 wctx.sub(s).get(r, overwrite)
Matt Mackall
subrepo: add update/merge logic
r8814 sm[s] = r
Matt Mackall
subrepo: fix recording of + in .hgsubstate (issue2217)
r11463 elif ld[1] == a[1]: # local side is unchanged
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "other side changed, get", r)
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 wctx.sub(s).get(r, overwrite)
Matt Mackall
subrepo: add update/merge logic
r8814 sm[s] = r
else:
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "both sides changed, merge with", r)
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).merge(r)
sm[s] = l
Matt Mackall
subrepo: fix recording of + in .hgsubstate (issue2217)
r11463 elif ld == a: # remote removed, local unchanged
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "remote removed, remove")
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).remove()
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'
Dongsheng Song
Fix warning: Seen unexpected token "%"
r8908 'use (c)hanged version or (d)elete?') % s,
Martin Geisler
filemerge, subrepo: correct indention
r9049 (_('&Changed'), _('&Delete')), 0):
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "prompt remove")
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).remove()
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'
Dongsheng Song
Fix warning: Seen unexpected token "%"
r8908 'use (c)hanged version or (d)elete?') % s,
Martin Geisler
filemerge, subrepo: correct indention
r9049 (_('&Changed'), _('&Delete')), 0) == 0:
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 debug(s, "prompt recreate", r)
Matt Mackall
subrepo: add update/merge logic
r8814 wctx.sub(s).get(r)
sm[s] = r
# record merged .hgsubstate
writestate(repo, sm)
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'
'use (l)ocal source (%s) or (r)emote source (%s)?\n')
% (subrelpath(sub), local, remote))
else:
Brodie Rao
cleanup: eradicate long lines
r16683 msg = (_(' subrepository sources for %s differ (in checked out '
'version)\n'
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
% (subrelpath(sub), local, remote))
return ui.promptchoice(msg, (_('&Local'), _('&Remote')), 0)
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
Matt Mackall
subrepo: fix repo relative path calculation for root directories (issue3033)
r15191 p = parent.root.rstrip(os.sep)
return repo.root[len(p) + 1:]
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')
Matt Harbison
subrepo: use sharepath if available when locating the source repo...
r18510 if repo.sharedpath != repo.path:
# 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
Martin Geisler
subrepos: add function for iterating over ctx subrepos
r12176 def itersubrepos(ctx1, ctx2):
"""find subrepos in ctx1 or ctx2"""
# Create a (subpath, ctx) mapping where we prefer subpaths from
# ctx1. The subpaths from ctx2 are important when the .hgsub file
# has been modified (in ctx2) but not yet committed (in ctx1).
subpaths = dict.fromkeys(ctx2.substate, ctx2)
subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
for subpath, ctx in sorted(subpaths.iteritems()):
yield subpath, ctx.sub(subpath)
Matt Mackall
commit: recurse into subrepositories
r8813 def subrepo(ctx, path):
Mads Kiilerich
subrepo: docstrings
r11571 """return instance of the right subrepo class for subrepo in path"""
Matt Mackall
commit: recurse into subrepositories
r8813 # subrepo inherently violates our import layering rules
# because it wants to make repo objects from deep inside the stack
# so we manually delay the circular imports to not break
# scripts that don't use our demand-loading
Abderrahim Kitouni
subrepo: use hg.repository instead of creating localrepo directly...
r9092 global hg
import hg as h
Matt Mackall
subrepo: add update/merge logic
r8814 hg = h
Matt Mackall
commit: recurse into subrepositories
r8813
Adrian Buehlmann
rename path_auditor to pathauditor...
r14220 scmutil.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
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 # subrepo classes need to implement the following abstract class:
class abstractsubrepo(object):
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
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
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
David M. Carr
add: fix subrepo recursion for explicit path handling...
r15911 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 return []
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559
Martin Geisler
status: recurse into subrepositories with --subrepos/-S flag
r12166 def status(self, rev2, **opts):
return [], [], [], [], [], [], []
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: propagate matcher to subrepos when archiving...
r17108 def archive(self, ui, archiver, prefix, match=None):
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)
ui.progress(_('archiving (%s)') % relpath, 0,
unit=_('files'), total=total)
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))
Martin Geisler
subrepo: add progress bar support to archive
r13144 ui.progress(_('archiving (%s)') % relpath, i + 1,
unit=_('files'), total=total)
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
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 def forget(self, ui, match, prefix):
Patrick Mezard
subrepo: fix default implementation of forget() (issue3404)
r16527 return ([], [])
Martin Geisler
subrepo: add support for 'hg archive'
r12323
Angel Ezquerra
revert: add support for reverting subrepos...
r16429 def revert(self, ui, substate, *pats, **opts):
Angel Ezquerra
revert: show warning when reverting subrepos that do not support revert...
r16468 ui.warn('%s: reverting %s subrepos is unsupported\n' \
% (substate[0], substate[2]))
Angel Ezquerra
revert: add support for reverting subrepos...
r16429 return []
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 class hgsubrepo(abstractsubrepo):
Matt Mackall
commit: recurse into subrepositories
r8813 def __init__(self, ctx, path, state):
self._path = path
self._state = state
r = ctx._repo
root = r.wjoin(path)
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666 create = False
if not os.path.exists(os.path.join(root, '.hg')):
create = True
Matt Mackall
subrepo: add update/merge logic
r8814 util.makedirs(root)
FUJIWARA Katsunori
subrepo: isolate configuration between each repositories in subrepo tree...
r17873 self._repo = hg.repository(r.baseui, root, create=create)
for s, k in [('ui', 'commitsubrepos')]:
v = r.ui.config(s, k)
if v:
self._repo.ui.setconfig(s, k, v)
Pierre-Yves David
subrepo: allows to drop courtesy phase sync (issue3781)...
r18520 self._repo.ui.setconfig('ui', '_usedassubrepo', 'True')
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):
clean = True
lock = self._repo.lock()
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
lock.release()
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)
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 for relname in filelist:
absname = os.path.normpath(self._repo.join(relname))
Angel Ezquerra
subrepo: do not push mercurial subrepos whose store is clean...
r18940 yield '%s = %s\n' % (relname, _calcfilehash(absname))
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939
def _getstorehashcachepath(self, remotepath):
'''get a unique path for the store hash cache'''
return self._repo.join(os.path.join(
'cache', 'storehash', _getstorehashcachename(remotepath)))
def _readstorehashcache(self, remotepath):
'''read the store hash cache for a given remote repository'''
cachefile = self._getstorehashcachepath(remotepath)
if not os.path.exists(cachefile):
return ''
fd = open(cachefile, 'r')
pullstate = fd.readlines()
fd.close()
return pullstate
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
'''
cachefile = self._getstorehashcachepath(remotepath)
lock = self._repo.lock()
storehash = list(self._calcstorehash(remotepath))
cachedir = os.path.dirname(cachefile)
if not os.path.exists(cachedir):
util.makedirs(cachedir, notindexed=True)
fd = open(cachefile, 'w')
fd.writelines(storehash)
fd.close()
lock.release()
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:
fp = self._repo.opener("hgrc", "w", text=True)
fp.write('[paths]\n')
def addpathconfig(key, value):
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 if value:
fp.write('%s = %s\n' % (key, value))
self._repo.ui.setconfig('paths', key, value)
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666
Mads Kiilerich
subrepo: abort instead of pushing/pulling to the repo itself...
r12753 defpath = _abssource(self._repo, abort=False)
defpushpath = _abssource(self._repo, True, abort=False)
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666 addpathconfig('default', defpath)
Edouard Gomez
subrepo: fix hgrc paths section during subrepo pulling...
r10697 if defpath != defpushpath:
addpathconfig('default-push', defpushpath)
Benoit Boissinot
subrepo: keep ui and hgrc in sync when creating new repo
r10666 fp.close()
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
David M. Carr
add: fix subrepo recursion for explicit path handling...
r15911 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
return cmdutil.add(ui, self._repo, match, dryrun, listsubrepos,
os.path.join(prefix, self._path), explicitonly)
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @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:
Wagner Bruna
subrepo: improve lookup error messages
r12503 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 % (inst, subrelpath(self)))
Martin Geisler
status: recurse into subrepositories with --subrepos/-S flag
r12166 return [], [], [], [], [], [], []
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:
Wagner Bruna
subrepo: improve lookup error messages
r12503 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 % (inst, subrelpath(self)))
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @annotatesubrepoerror
Matt Harbison
subrepo: propagate matcher to subrepos when archiving...
r17108 def archive(self, ui, archiver, prefix, match=None):
Martin Geisler
subrepo: pull revisions on demand when archiving hg subrepos...
r15286 self._get(self._state + ('hg',))
Angel Ezquerra
archive: raise error.Abort if the file pattern matches no files...
r18967 total = abstractsubrepo.archive(self, ui, 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(
ui, archiver, os.path.join(prefix, self._path), submatch)
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()
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
Matt Mackall
commit: recurse into subrepositories
r8813 n = self._repo.commit(text, user, date)
if not n:
return self._repo['.'].hex() # different version checked out
return node.hex(n)
Matt Mackall
subrepo: add update/merge logic
r8814
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 @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
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
Matt Mackall
subrepo: add update/merge logic
r8814 hg.clean(self._repo, node.nullid, False)
Matt Mackall
subrepo: add auto-pull for merge
r9507 def _get(self, state):
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 source, revision, kind = state
Martin Geisler
subrepo: simplify hgsubrepo._get a little
r13753 if revision not in self._repo:
Matt Mackall
subrepo: add update/merge logic
r8814 self._repo._subsource = source
srcurl = _abssource(self._repo)
Simon Heimberg
peer: subrepo isolation, pass repo instead of repo.ui to hg.peer...
r17874 other = hg.peer(self._repo, {}, srcurl)
Martin Geisler
subrepo: create subrepos using clone instead of pull...
r14281 if len(self._repo) == 0:
self._repo.ui.status(_('cloning subrepo %s from %s\n')
% (subrelpath(self), srcurl))
parentrepo = self._repo._subparent
Martin Geisler
subrepo: abort in hgsubrepo._get if the destination is obstructed...
r15287 shutil.rmtree(self._repo.path)
Simon Heimberg
subrepo: subrepo isolation, pass baseui when cloning a new subrepo (issue2904)...
r17876 other, cloned = hg.clone(self._repo._subparent.baseui, {},
Sune Foldager
peer: introduce peer methods to prepare for peer classes...
r17191 other, self._repo.root,
update=False)
self._repo = cloned.local()
Martin Geisler
subrepo: create subrepos using clone instead of pull...
r14281 self._initrepo(parentrepo, source, create=True)
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 self._cachestorehash(srcurl)
Martin Geisler
subrepo: create subrepos using clone instead of pull...
r14281 else:
self._repo.ui.status(_('pulling subrepo %s from %s\n')
% (subrelpath(self), srcurl))
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 cleansub = self.storeclean(srcurl)
Siddharth Agarwal
pull: list bookmarks before pulling changesets (issue3873)...
r18851 remotebookmarks = other.listkeys('bookmarks')
Martin Geisler
subrepo: create subrepos using clone instead of pull...
r14281 self._repo.pull(other)
Siddharth Agarwal
pull: list bookmarks before pulling changesets (issue3873)...
r18851 bookmarks.updatefromremote(self._repo.ui, self._repo,
remotebookmarks, srcurl)
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 if cleansub:
# keep the repo clean after pull
self._cachestorehash(srcurl)
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):
Matt Mackall
subrepo: add auto-pull for merge
r9507 self._get(state)
Augie Fackler
subrepo: add table-based dispatch for subrepo types
r10177 source, revision, kind = state
Matt Mackall
subrepo: add more debugging output, lose _ markers
r9782 self._repo.ui.debug("getting subrepo %s\n" % self._path)
Simon Heimberg
subrepo: only do clean update when overwrite is set (issue3276)...
r17895 hg.updaterepo(self._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():
Erik Zielke
subrepos: prompt on conflicts on update with dirty subrepos...
r13417 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
hg.update(self._repo, state[1])
elif anc == dst:
self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
else:
self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
hg.merge(self._repo, state[1], remind=False)
wctx = self._repo[None]
if self.dirty():
if anc != dst:
if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
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):
self._repo.ui.status(
_('no changes made to subrepo %s since last push to %s\n')
% (subrelpath(self), dsturl))
return None
Edouard Gomez
subrepo: print pushing url
r11111 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
Mads Kiilerich
subrepo: rename relpath to subrelpath and introduce reporelpath
r12752 (subrelpath(self), dsturl))
Simon Heimberg
peer: subrepo isolation, pass repo instead of repo.ui to hg.peer...
r17874 other = hg.peer(self._repo, {'ssh': ssh}, dsturl)
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 res = self._repo.push(other, force, newbranch=newbranch)
# the repo is now clean
self._cachestorehash(dsturl)
return res
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]
return ctx.manifest()
def filedata(self, name):
rev = self._state[1]
return self._repo[rev][name].data()
def fileflags(self, name):
rev = self._state[1]
ctx = self._repo[rev]
return ctx.flags(name)
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
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 def forget(self, ui, match, prefix):
return cmdutil.forget(ui, self._repo, match,
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
Angel Ezquerra
revert: add support for reverting subrepos...
r16429 def revert(self, ui, 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
Angel Ezquerra
revert: add support for reverting subrepos...
r16429 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]
pats = []
Yuya Nishihara
subrepo: fix exception on revert when "all" option is omitted...
r18943 if not opts.get('all'):
Angel Ezquerra
revert: add support for reverting subrepos without --no-backup and/or --all...
r16430 pats = ['set:modified()']
self.filerevert(ui, *pats, **opts)
Angel Ezquerra
revert: add support for reverting subrepos...
r16429
# Update the repo to the revision specified in the given substate
self.get(substate, overwrite=True)
Angel Ezquerra
revert: add support for reverting subrepos without --no-backup and/or --all...
r16430 def filerevert(self, ui, *pats, **opts):
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 = []
cmdutil.revert(ui, self._repo, ctx, parents, *pats, **opts)
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 class svnsubrepo(abstractsubrepo):
Augie Fackler
subrepo: Subversion support
r10178 def __init__(self, ctx, path, state):
self._path = path
self._state = state
self._ctx = ctx
self._ui = ctx._repo.ui
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 = {}
if not self._ui.interactive():
# 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:
path = os.path.join(self._ctx._repo.origroot, self._path, filename)
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:
self._ui.warn(stderr + '\n')
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])
Augie Fackler
subrepo: Subversion support
r10178 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]
Augie Fackler
svn subrepos: work around checkout obstructions (issue2752)...
r14664 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():
Benoit Boissinot
subrepo: fix errors reported by pylint
r10299 self._ui.warn(_('not removing repo %s because '
'it has changes.\n' % self._path))
Augie Fackler
subrepo: Subversion support
r10178 return
Benoit Boissinot
i18n: mark more strings for translation
r10510 self._ui.note(_('removing subrepo %s\n') % self._path)
Patrick Mezard
subrepo: fix removing read-only svn files on Windows
r13013
def onerror(function, path, excinfo):
if function is not os.remove:
raise
# read-only files cannot be unlinked under Windows
s = os.stat(path)
if (s.st_mode & stat.S_IWRITE) != 0:
raise
os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
os.remove(path)
Patrick Mezard
subrepo: prune empty directories when removing svn subrepo
r13015 path = self._ctx._repo.wjoin(self._path)
shutil.rmtree(path, onerror=onerror)
try:
os.removedirs(os.path.dirname(path))
except OSError:
pass
Augie Fackler
subrepo: Subversion support
r10178
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)
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])
Augie Fackler
subrepo: Subversion support
r10178 self._ui.status(status)
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]
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):
self._state = state
self._ctx = ctx
Eric Eisner
subrepo: fix subrelpath for git subrepos...
r13181 self._path = path
self._relpath = os.path.join(reporelpath(ctx._repo), path)
self._abspath = ctx._repo.wjoin(path)
Eric Eisner
subrepo: expand relative sources for git subrepos
r13460 self._subparent = ctx._repo
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 self._ui = ctx._repo.ui
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'])
Benjamin Pollack
subrepo: warn user if Git is not version 1.6.0 or higher
r17024 m = re.search(r'^git version (\d+)\.(\d+)\.(\d+)', out)
if not m:
self._ui.warn(_('cannot retrieve git version'))
return
version = (int(m.group(1)), m.group(2), m.group(3))
# 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.
if version < (1, 5, 0):
raise util.Abort(_('git subrepo requires at least 1.6.0 or later'))
elif version < (1, 6, 0):
self._ui.warn(_('git subrepo requires at least 1.6.0 or later'))
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.
"""
Eric Eisner
subrepo: show git command with --debug...
r13110 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
if self._ui.quiet:
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)
self._ui.status(_('cloning subrepo %s from %s\n') %
(self._relpath, source))
self._gitnodir(['clone', source, self._abspath])
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993 if self._githavelocally(revision):
return
Eric Eisner
subrepo: show the source that git pulls
r13569 self._ui.status(_('pulling subrepo %s from %s\n') %
(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)
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
Eric Eisner
subrepo: cloning and updating of git subrepos...
r12993 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
self._relpath)
self._ui.warn(_('check out a git branch if you intend '
'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])
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])
if self.dirty():
if self._gitstate() != revision:
dirty = self._gitstate() == self._state[1] or code != 0
Martin Geisler
subrepo: break long line found by check-code
r13432 if _updateprompt(self._ui, self, dirty,
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):
self._ui.warn(_('unrelated git branch checked out '
'in subrepo %s\n') % self._relpath)
return False
self._ui.status(_('pushing branch %s of subrepo %s\n') %
Eric Eisner
subrepo: use low-level git-for-each-ref command in branchmap...
r13150 (current.split('/', 2)[2], self._relpath))
Eric Eisner
subrepo: drop arguments unsupported by old git
r13097 self._gitcommand(cmd + ['origin', current])
Eric Eisner
subrepo: update and merge works with any git branch
r12995 return True
else:
self._ui.warn(_('no branch checked out in subrepo %s\n'
Martin Geisler
subrepo: add missing newline in Git warning message
r17140 '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
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():
self._ui.warn(_('not removing repo %s because '
Eric Eisner
subrepo: fix subrelpath for git subrepos...
r13181 '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
Eric Eisner
subrepo: fix subrelpath for git subrepos...
r13181 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: propagate matcher to subrepos when archiving...
r17108 def archive(self, ui, 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)
ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
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
Martin Geisler
subrepo: add progress bar support to archive
r13144 ui.progress(_('archiving (%s)') % relpath, i + 1,
unit=_('files'))
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
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
return [], [], [], [], [], [], []
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)
deleted = unknown = ignored = clean = []
return modified, added, removed, deleted, unknown, ignored, clean
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 }