##// END OF EJS Templates
rebase: provide detailed hint to abort message if working dir is not clean...
rebase: provide detailed hint to abort message if working dir is not clean Detailed hint message is now provided when 'pull --rebase' operation detects unclean working dir, for example: abort: uncommitted changes (cannot pull with rebase: please commit or shelve your changes first) Added tests for uncommitted merge, and for subrepo support verifying that same hint is also passed to subrepo state check.

File last commit:

r30755:0fbb3a5c default
r30755:0fbb3a5c default
Show More
subrepo.py
1960 lines | 71.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
Gregory Szorc
subrepo: use absolute_import
r25980 from __future__ import absolute_import
Matt Harbison
addremove: automatically process a subrepository's subrepos...
r23540 import copy
Gregory Szorc
subrepo: use absolute_import
r25980 import errno
Augie Fackler
cleanup: replace uses of util.(md5|sha1|sha256|sha512) with hashlib.\1...
r29341 import hashlib
Gregory Szorc
subrepo: use absolute_import
r25980 import os
import posixpath
import re
import stat
import subprocess
import sys
import tarfile
Augie Fackler
subrepo: move import of xml.minidom.dom to its own line for check-code
r19788 import xml.dom.minidom
Gregory Szorc
subrepo: use absolute_import
r25980
from .i18n import _
from . import (
cmdutil,
config,
Pulkit Goyal
py3: replace os.environ with encoding.environ (part 2 of 5)
r30635 encoding,
Gregory Szorc
subrepo: use absolute_import
r25980 error,
exchange,
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 filemerge,
Gregory Szorc
subrepo: use absolute_import
r25980 match as matchmod,
node,
pathutil,
phases,
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 3 of 4)
r30615 pycompat,
Gregory Szorc
subrepo: use absolute_import
r25980 scmutil,
util,
)
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'''
Augie Fackler
cleanup: replace uses of util.(md5|sha1|sha256|sha512) with hashlib.\1...
r29341 return hashlib.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):
Yuya Nishihara
error: make hintable exceptions reject unknown keyword arguments (API)...
r29510 self.subrepo = kw.pop('subrepo', None)
self.cause = kw.pop('cause', None)
Brendan Cully
subrepo: fix python2.4 compatibility after 9aa6bee6e9f9...
r18296 error.Abort.__init__(self, *args, **kw)
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)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except SubrepoAbort as ex:
Angel Ezquerra
subrepo: append subrepo path to subrepo error messages...
r18109 # This exception has already been handled
raise ex
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.Abort as 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()
FUJIWARA Katsunori
subrepo: prefetch ctx.repo() for efficiency and centralization...
r25768 repo = ctx.repo()
Matt Mackall
subrepo: introduce basic state parsing
r8812 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()
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as err:
Patrick Mezard
subrepo: handle missing subrepo spec file as removed...
r13017 if err.errno != errno.ENOENT:
raise
# handle missing subrepo spec files as removed
Matt Harbison
subrepo: precisely identify the missing subrepo spec file...
r24645 ui.warn(_("warning: subrepo spec file \'%s\' not found\n") %
FUJIWARA Katsunori
subrepo: use repo.pathto instead of util.pathto to simplify invocation...
r25769 repo.pathto(f))
Patrick Mezard
subrepo: handle missing subrepo spec file as removed...
r13017 return
p.parse(f, data, sections, remap, read)
Matt Mackall
subrepo: fix includes support in .hgsub
r10174 else:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("subrepo spec file \'%s\' not found") %
FUJIWARA Katsunori
subrepo: use repo.pathto instead of util.pathto to simplify invocation...
r25769 repo.pathto(f))
Matt Mackall
subrepo: fix includes support in .hgsub
r10174 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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("invalid subrepository revision "
Matt Harbison
subrepo: precisely identify the missing subrepo spec file...
r24645 "specifier in \'%s\' line %d")
FUJIWARA Katsunori
subrepo: use repo.pathto instead of util.pathto to simplify invocation...
r25769 % (repo.pathto('.hgsubstate'), (i + 1)))
Matt Mackall
subrepo: introduce basic state parsing
r8812 rev[path] = revision
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as err:
Matt Mackall
subrepo: introduce basic state parsing
r8812 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)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except re.error as e:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("bad subrepository pattern in %s: %s")
Martin Geisler
subrepos: support remapping of .hgsub source paths...
r11775 % (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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('missing ] in subrepo source'))
Martin Geisler
subrepo: refactor state function
r15149 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():
FUJIWARA Katsunori
subrepo: prefetch ctx.repo() for efficiency and centralization...
r25768 parent = _abssource(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"""
Matt Harbison
subrepo: don't write .hgsubstate lines with empty subrepo state (issue4622)...
r24858 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)
if state[s][1] != nullstate[1]]
Martin Geisler
subrepo: refactor writestate for clarity
r14443 repo.wwrite('.hgsubstate', ''.join(lines), '')
Matt Mackall
commit: recurse into subrepositories
r8813
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 def submerge(repo, wctx, mctx, actx, overwrite, labels=None):
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:
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 prompts = filemerge.partextras(labels)
prompts['s'] = s
Matt Mackall
subrepo: add update/merge logic
r8814 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 Farnsworth
merge: use labels in subrepo merge...
r30060 prompts['lo'] = l[0]
prompts['ro'] = r[0]
Simon Heimberg
ui: extract choice from prompt...
r9048 if repo.ui.promptchoice(
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 _(' subrepository sources for %(s)s differ\n'
'use (l)ocal%(l)s source (%(lo)s)'
' or (r)emote%(o)s source (%(ro)s)?'
'$$ &Local $$ &Remote') % prompts, 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)
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 prompts['sl'] = srepo.shortid(l[1])
prompts['sr'] = srepo.shortid(r[1])
Angel Ezquerra
merge: let the user choose to merge, keep local or keep remote subrepo revisions...
r19811 option = repo.ui.promptchoice(
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 _(' subrepository %(s)s diverged (local revision: %(sl)s, '
'remote revision: %(sr)s)\n'
'(M)erge, keep (l)ocal%(l)s or keep (r)emote%(o)s?'
Angel Ezquerra
merge: let the user choose to merge, keep local or keep remote subrepo revisions...
r19811 '$$ &Merge $$ &Local $$ &Remote')
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 % prompts, 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(
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 _(' local%(l)s changed subrepository %(s)s'
' which remote%(o)s removed\n'
Matt Mackall
ui: merge prompt text components into a singe string...
r19226 'use (c)hanged version or (d)elete?'
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 '$$ &Changed $$ &Delete') % prompts, 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(
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 _(' remote%(o)s changed subrepository %(s)s'
' which local%(l)s removed\n'
Matt Mackall
ui: merge prompt text components into a singe string...
r19226 'use (c)hanged version or (d)elete?'
Simon Farnsworth
merge: use labels in subrepo merge...
r30060 '$$ &Changed $$ &Delete') % prompts, 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
Matt Harbison
subrepo: backout 93b0e0db7929 to restore reporelpath()...
r24785 def reporelpath(repo):
"""return path to this (sub)repo as seen from outermost repo"""
parent = repo
while util.safehasattr(parent, '_subparent'):
parent = parent._subparent
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"""
FUJIWARA Katsunori
subrepo: add _relpath field to centralize subrelpath logic...
r24673 return sub._relpath
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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("default path for subrepository not found"))
Matt Mackall
subrepo: add update/merge logic
r8814
FUJIWARA Katsunori
subrepo: pass wvfs to _sanitize instead of absolute path to a subrepository...
r24724 def _sanitize(ui, vfs, ignore):
FUJIWARA Katsunori
subrepo: use vfs.walk instead of os.walk...
r24726 for dirname, dirs, names in vfs.walk():
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
FUJIWARA Katsunori
subrepo: use vfs.basename instead of os.path.basename
r25771 if vfs.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' "
FUJIWARA Katsunori
subrepo: use vfs.walk instead of os.walk...
r24726 "in '%s'\n") % vfs.join(dirname))
vfs.unlink(vfs.reljoin(dirname, f))
Matt Mackall
subrepo: sanitize non-hg subrepos
r20104
Matt Harbison
verify: don't init subrepo when missing one is referenced (issue5128) (API)...
r29021 def subrepo(ctx, path, allowwdir=False, allowcreate=True):
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
Gregory Szorc
subrepo: use absolute_import
r25980 from . 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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('unknown subrepo type %s') % state[2])
Matt Harbison
subrepo: allow a representation of the working directory subrepo...
r25600 if allowwdir:
state = (state[0], ctx.subrev(path), state[2])
Matt Harbison
verify: don't init subrepo when missing one is referenced (issue5128) (API)...
r29021 return types[state[2]](ctx, path, state[:2], allowcreate)
Matt Mackall
commit: recurse into subrepositories
r8813
Matt Harbison
subrepo: introduce the nullsubrepo() method...
r25416 def nullsubrepo(ctx, path, pctx):
"""return an empty subrepo in pctx for the extant subrepo in ctx"""
# 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
global hg
Gregory Szorc
subrepo: use absolute_import
r25980 from . import hg as h
Matt Harbison
subrepo: introduce the nullsubrepo() method...
r25416 hg = h
pathutil.pathauditor(ctx.repo().root)(path)
state = ctx.substate[path]
if state[2] not in types:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('unknown subrepo type %s') % state[2])
Matt Harbison
subrepo: introduce the nullsubrepo() method...
r25416 subrev = ''
if state[2] == 'hg':
subrev = "0" * 40
Matt Harbison
verify: don't init subrepo when missing one is referenced (issue5128) (API)...
r29021 return types[state[2]](pctx, path, (state[0], subrev), True)
Matt Harbison
subrepo: introduce the nullsubrepo() method...
r25416
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'):
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('invalid phases.checksubrepos configuration: %s')
FUJIWARA Katsunori
subrepo: check phase of state in each subrepositories before committing...
r20176 % (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':
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("can't commit in %s phase"
FUJIWARA Katsunori
subrepo: check phase of state in each subrepositories before committing...
r20176 " 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):
FUJIWARA Katsunori
subrepo: change arguments of abstractsubrepo.__init__ (API)...
r24671 def __init__(self, ctx, path):
"""Initialize abstractsubrepo part
``ctx`` is the context referring this subrepository in the
parent repository.
Mads Kiilerich
spelling: trivial spell checking
r26781 ``path`` is the path to this subrepository as seen from
FUJIWARA Katsunori
subrepo: change arguments of abstractsubrepo.__init__ (API)...
r24671 innermost repository.
"""
self.ui = ctx.repo().ui
self._ctx = ctx
self._path = path
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)
Valters Vingolds
rebase: provide detailed hint to abort message if working dir is not clean...
r30755 def bailifchanged(self, ignoreupdate=False, hint=None):
FUJIWARA Katsunori
subrepo: add bailifchanged to centralize raising Abort if subrepo is dirty...
r24471 """raise Abort if subrepository is ``dirty()``
"""
dirtyreason = self.dirtyreason(ignoreupdate=ignoreupdate)
if dirtyreason:
Valters Vingolds
rebase: provide detailed hint to abort message if working dir is not clean...
r30755 raise error.Abort(dirtyreason, hint=hint)
FUJIWARA Katsunori
subrepo: add bailifchanged to centralize raising Abort if subrepo is dirty...
r24471
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: introduce getfileset()...
r25121 def getfileset(self, expr):
"""Resolve the fileset expression for this repo"""
return set()
Matt Harbison
files: recurse into subrepos automatically with an explicit path
r25228 def printfiles(self, ui, m, fm, fmt, subrepos):
Matt Harbison
subrepo: add basic support to hgsubrepo for the files command...
r24413 """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)
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 mode = 'x' in flags and 0o755 or 0o644
Martin Geisler
subrepo: add support for 'hg archive'
r12323 symlink = 'l' in flags
Matt Harbison
archive: always use portable path component separators with subrepos...
r24924 archiver.addfile(prefix + self._path + '/' + name,
Martin Geisler
subrepo: add support for 'hg archive'
r12323 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
timeless
remove: queue warnings until after status messages (issue5140) (API)...
r28607 def removefiles(self, matcher, prefix, after, force, subrepos, warnings):
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.
"""
timeless
remove: queue warnings until after status messages (issue5140) (API)...
r28607 warnings.append(_("warning: removefiles not implemented (%s)")
% self._path)
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325 return 1
Matt Harbison
subrepo: drop the 'ui' parameter to revert()...
r23579 def revert(self, substate, *pats, **opts):
FUJIWARA Katsunori
subrepo: make a message translatable...
r29243 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
Matt Harbison
verify: check the subrepository references in .hgsubstate...
r25591 def verify(self):
'''verify the integrity of the repository. Return 0 on success or
warning, 1 on any error.
'''
return 0
FUJIWARA Katsunori
subrepo: add wvfs field to access the working directory via vfs...
r24672 @propertycache
def wvfs(self):
"""return vfs to access the working directory of this subrepository
"""
return scmutil.vfs(self._ctx.repo().wvfs.join(self._path))
FUJIWARA Katsunori
subrepo: add _relpath field to centralize subrelpath logic...
r24673 @propertycache
def _relpath(self):
"""return path to this subrepository as seen from outermost repository
"""
Matt Harbison
subrepo: backout 93b0e0db7929 to restore reporelpath()...
r24785 return self.wvfs.reljoin(reporelpath(self._ctx.repo()), self._path)
FUJIWARA Katsunori
subrepo: add _relpath field to centralize subrelpath logic...
r24673
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 class hgsubrepo(abstractsubrepo):
Matt Harbison
verify: don't init subrepo when missing one is referenced (issue5128) (API)...
r29021 def __init__(self, ctx, path, state, allowcreate):
FUJIWARA Katsunori
subrepo: change arguments of abstractsubrepo.__init__ (API)...
r24671 super(hgsubrepo, self).__init__(ctx, path)
Matt Mackall
commit: recurse into subrepositories
r8813 self._state = state
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 r = ctx.repo()
Matt Mackall
commit: recurse into subrepositories
r8813 root = r.wjoin(path)
Matt Harbison
verify: don't init subrepo when missing one is referenced (issue5128) (API)...
r29021 create = allowcreate and 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: propagate the --hidden option to hg subrepositories...
r24877
# Propagate the parent's --hidden option
if r is r.unfiltered():
self._repo = self._repo.unfiltered()
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')
Matt Mackall
subrepo: mark internal-only option
r25848 # internal config: ui._usedassubrepo
Matt Harbison
subrepo: use 'self.ui' instead of 'self._repo.ui'...
r23574 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):
Bryan O'Sullivan
with: use context manager in subrepo storeclean
r27844 with self._repo.lock():
FUJIWARA Katsunori
subrepo: ensure "lock.release()" execution at the end of "storeclean()"...
r21885 return self._storeclean(path)
def _storeclean(self, path):
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 clean = True
itercache = self._calcstorehash(path)
Pierre-Yves David
subrepo: further replacement of try/except with 'next'...
r25172 for filehash in self._readstorehashcache(path):
if filehash != next(itercache, None):
clean = False
break
if clean:
# if not empty:
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 # the cached and current pull states have a different size
Pierre-Yves David
subrepo: further replacement of try/except with 'next'...
r25172 clean = next(itercache, None) is None
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939 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:
Augie Fackler
cleanup: replace uses of util.(md5|sha1|sha256|sha512) with hashlib.\1...
r29341 filehash = hashlib.sha1(vfs.tryread(relname)).hexdigest()
FUJIWARA Katsunori
subrepo: replace "_calcfilehash" invocation by "vfs.tryread"...
r23365 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)
Bryan O'Sullivan
with: use context manager in subrepo _cachestorehash
r27843 with self._repo.lock():
FUJIWARA Katsunori
subrepo: ensure "lock.release()" execution at the end of "_cachestorehash()"...
r21886 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)
Angel Ezquerra
subrepo: implement "storeclean" method for mercurial subrepos...
r18939
Matt Harbison
subrepo: introduce hgsubrepo._getctx()...
r25572 def _getctx(self):
'''fetch the context for this subrepo revision, possibly a workingctx
'''
if self._ctx.rev() is None:
return self._repo[None] # workingctx if parent is workingctx
else:
rev = self._state[1]
return self._repo[rev]
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,
FUJIWARA Katsunori
subrepo: use vfs.reljoin instead of os.path.join
r24675 self.wvfs.reljoin(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,
FUJIWARA Katsunori
subrepo: use vfs.reljoin instead of os.path.join
r24675 self.wvfs.reljoin(prefix, self._path), opts,
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537 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)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.RepoLookupError as 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)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.RepoLookupError as 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:
Matt Harbison
archive: support 'wdir()'...
r25601 s = subrepo(ctx, subpath, True)
Martin von Zweigbergk
match: rename "narrowmatcher" to "subdirmatcher" (API)...
r28017 submatch = matchmod.subdirmatcher(subpath, match)
Matt Harbison
archive: always use portable path component separators with subrepos...
r24924 total += s.archive(archiver, 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
FUJIWARA Katsunori
subrepo: use vfs.rmtree instead of shutil.rmtree...
r24690 # use self._repo.vfs instead of self.wvfs to remove .hg only
self._repo.vfs.rmtree()
Angel Ezquerra
subrepo: remove unnecessary else clause in hgsubrepo._get...
r20318 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):
Matt Harbison
subrepo: don't pass the outer repo's --rev or --branch to subrepo outgoing()...
r24875 if 'rev' in opts or 'branch' in opts:
opts = copy.copy(opts)
opts.pop('rev', None)
opts.pop('branch', None)
Martin Geisler
outgoing: recurse into subrepositories with --subrepos/-S flag...
r12272 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):
Matt Harbison
subrepo: don't pass the outer repo's --rev or --branch to subrepo incoming()...
r24876 if 'rev' in opts or 'branch' in opts:
opts = copy.copy(opts)
opts.pop('rev', None)
opts.pop('branch', None)
Martin Geisler
incoming: recurse into subrepositories with --subrepos/-S flag...
r12274 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
Matt Harbison
files: recurse into subrepos automatically with an explicit path
r25228 def printfiles(self, ui, m, fm, fmt, subrepos):
Matt Harbison
subrepo: add basic support to hgsubrepo for the files command...
r24413 # 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]
Matt Harbison
files: recurse into subrepos automatically with an explicit path
r25228 return cmdutil.files(ui, ctx, m, fm, fmt, subrepos)
Matt Harbison
subrepo: add basic support to hgsubrepo for the files command...
r24413
Matt Harbison
subrepo: introduce getfileset()...
r25121 @annotatesubrepoerror
def getfileset(self, expr):
if self._ctx.rev() is None:
ctx = self._repo[None]
else:
rev = self._state[1]
ctx = self._repo[rev]
files = ctx.getfileset(expr)
for subpath in ctx.substate:
sub = ctx.sub(subpath)
try:
files.extend(subpath + '/' + f for f in sub.getfileset(expr))
except error.LookupError:
self.ui.status(_("skipping missing subrepository: %s\n")
% self.wvfs.reljoin(reporelpath(self), subpath))
return files
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,
FUJIWARA Katsunori
subrepo: use vfs.reljoin instead of os.path.join
r24675 self.wvfs.reljoin(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
timeless
remove: queue warnings until after status messages (issue5140) (API)...
r28607 def removefiles(self, matcher, prefix, after, force, subrepos, warnings):
Matt Harbison
subrepo: drop the 'ui' parameter to removefiles()...
r23578 return cmdutil.remove(self.ui, self._repo, matcher,
FUJIWARA Katsunori
subrepo: use vfs.reljoin instead of os.path.join
r24675 self.wvfs.reljoin(prefix, self._path),
after, force, subrepos)
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325
@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]
Matt Harbison
verify: check the subrepository references in .hgsubstate...
r25591 def verify(self):
try:
rev = self._state[1]
ctx = self._repo.unfiltered()[rev]
if ctx.hidden():
# Since hidden revisions aren't pushed/pulled, it seems worth an
# explicit warning.
ui = self._repo.ui
ui.warn(_("subrepo '%s' is hidden in revision %s\n") %
(self._relpath, node.short(self._ctx.node())))
return 0
except error.RepoLookupError:
# A missing subrepo revision may be a case of needing to pull it, so
# don't treat this as an error.
self._repo.ui.warn(_("subrepo '%s' not found in revision %s\n") %
(self._relpath, node.short(self._ctx.node())))
return 0
FUJIWARA Katsunori
subrepo: add wvfs field to access the working directory via vfs...
r24672 @propertycache
def wvfs(self):
Mads Kiilerich
spelling: trivial spell checking
r26781 """return own wvfs for efficiency and consistency
FUJIWARA Katsunori
subrepo: add wvfs field to access the working directory via vfs...
r24672 """
return self._repo.wvfs
Matt Harbison
subrepo: calculate _relpath for hgsubrepo based on self instead of parent...
r24786 @propertycache
def _relpath(self):
"""return path to this subrepository as seen from outermost repository
"""
# Keep consistent dir separators by avoiding vfs.join(self._path)
return reporelpath(self._repo)
Martin Geisler
subrepo: add abstract superclass for subrepo classes
r11559 class svnsubrepo(abstractsubrepo):
Matt Harbison
verify: don't init subrepo when missing one is referenced (issue5128) (API)...
r29021 def __init__(self, ctx, path, state, allowcreate):
FUJIWARA Katsunori
subrepo: change arguments of abstractsubrepo.__init__ (API)...
r24671 super(svnsubrepo, self).__init__(ctx, path)
Augie Fackler
subrepo: Subversion support
r10178 self._state = state
Matt Mackall
subrepo: improve error message when svn isn't found...
r15190 self._exe = util.findexe('svn')
if not self._exe:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("'svn' executable not found for subrepo '%s'")
Matt Mackall
subrepo: improve error message when svn isn't found...
r15190 % 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:
FUJIWARA Katsunori
subrepo: use vfs.reljoin instead of os.path.join
r24675 path = self.wvfs.reljoin(self._ctx.repo().origroot,
self._path, filename)
Patrick Mezard
subrepo: handle svn tracked/unknown directory collisions...
r14050 cmd.append(path)
Pulkit Goyal
py3: replace os.environ with encoding.environ (part 2 of 5)
r30635 env = dict(encoding.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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(stderr or 'exited with code %d'
% p.returncode)
Augie Fackler
svn subrepos: work around checkout obstructions (issue2752)...
r14664 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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('cannot retrieve svn tool version'))
Patrick Mezard
subrepo: handle svn tracked/unknown directory collisions...
r14050 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:
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 3 of 4)
r30615 if path == ext or path.startswith(ext + pycompat.ossep):
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
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.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.
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.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.
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('failed to commit svn changes'))
raise error.Abort(commitinfo.splitlines()[-1])
Augie Fackler
subrepo: Subversion support
r10178 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
FUJIWARA Katsunori
subrepo: use vfs.rmtree instead of shutil.rmtree...
r24690 self.wvfs.rmtree(forcibly=True)
Patrick Mezard
subrepo: prune empty directories when removing svn subrepo
r13015 try:
FUJIWARA Katsunori
subrepo: use vfs.dirname instead of os.path.dirname...
r25773 pwvfs = self._ctx.repo().wvfs
pwvfs.removedirs(pwvfs.dirname(self._path))
Patrick Mezard
subrepo: prune empty directories when removing svn subrepo
r13015 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)
FUJIWARA Katsunori
subrepo: pass wvfs to _sanitize instead of absolute path to a subrepository...
r24724 _sanitize(self.ui, self.wvfs, '.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
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.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):
Matt Harbison
verify: don't init subrepo when missing one is referenced (issue5128) (API)...
r29021 def __init__(self, ctx, path, state, allowcreate):
FUJIWARA Katsunori
subrepo: change arguments of abstractsubrepo.__init__ (API)...
r24671 super(gitsubrepo, self).__init__(ctx, path)
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 self._state = state
Matt Harbison
subrepo: replace 'ctx._repo' with 'ctx.repo()'
r24302 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'])
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as e:
Mason Malone
subrepo: better error messages in _ensuregit...
r27935 genericerror = _("error executing git for subrepo '%s': %s")
notfoundhint = _("check git is installed and in your PATH")
if e.errno != errno.ENOENT:
raise error.Abort(genericerror % (self._path, e.strerror))
Pulkit Goyal
py3: replace os.name with pycompat.osname (part 1 of 2)...
r30639 elif pycompat.osname == 'nt':
Mason Malone
subrepo: better error messages in _ensuregit...
r27935 try:
self._gitexecutable = 'git.cmd'
out, err = self._gitnodir(['--version'])
except OSError as e2:
if e2.errno == errno.ENOENT:
raise error.Abort(_("couldn't find 'git' or 'git.cmd'"
" for subrepo '%s'") % self._path,
hint=notfoundhint)
else:
raise error.Abort(genericerror % (self._path,
e2.strerror))
else:
raise error.Abort(_("couldn't find git for subrepo '%s'")
% self._path, hint=notfoundhint)
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':
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('git subrepo requires at least 1.6.0 or later'))
Siddharth Agarwal
subrepo: factor out Git version check to add doctests...
r20840 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)))
Mateusz Kwapich
subrepo: set GIT_ALLOW_PROTOCOL to limit git clone protocols (SEC)...
r28658 if env is None:
Pulkit Goyal
py3: replace os.environ with encoding.environ (part 2 of 5)
r30635 env = encoding.environ.copy()
Matt Mackall
subrepo: disable localizations when calling Git (issue5176)...
r28949 # disable localization for Git output (issue5176)
env['LC_ALL'] = 'C'
Mateusz Kwapich
subrepo: set GIT_ALLOW_PROTOCOL to limit git clone protocols (SEC)...
r28658 # fix for Git CVE-2015-7545
if 'GIT_ALLOW_PROTOCOL' not in env:
env['GIT_ALLOW_PROTOCOL'] = 'file:git:http:https:ssh'
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
liscju
i18n: translate abort messages...
r29389 raise error.Abort(_('git %s error %d in %s') %
Eric Eisner
subrepo: show git command with --debug...
r13110 (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):
Matt Harbison
subrepo: convert the os.path references in git to vfs...
r24695 return not self.wvfs.exists('.git')
Eric Eisner
subrepo: don't crash when git repo is missing
r13553
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):
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.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)
FUJIWARA Katsunori
subrepo: pass wvfs to _sanitize instead of absolute path to a subrepository...
r24724 _sanitize(self.ui, self.wvfs, '.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])
FUJIWARA Katsunori
subrepo: pass wvfs to _sanitize instead of absolute path to a subrepository...
r24724 _sanitize(self.ui, self.wvfs, '.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():
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("subrepo %s is missing") % self._relpath)
Eric Eisner
subrepo: support for adding a git subrepo...
r12992 cmd = ['commit', '-a', '-m', text]
Pulkit Goyal
py3: replace os.environ with encoding.environ (part 2 of 5)
r30635 env = encoding.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])
FUJIWARA Katsunori
subrepo: pass wvfs to _sanitize instead of absolute path to a subrepository...
r24724 _sanitize(self.ui, self.wvfs, '.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():
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.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'])
FUJIWARA Katsunori
subrepo: use vfs.readdir instead of os.listdir to avoid expensive stat calls...
r24688 for f, kind in self.wvfs.readdir():
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996 if f == '.git':
continue
FUJIWARA Katsunori
subrepo: use vfs.readdir instead of os.listdir to avoid expensive stat calls...
r24688 if kind == stat.S_IFDIR:
FUJIWARA Katsunori
subrepo: use vfs.rmtree instead of shutil.rmtree...
r24690 self.wvfs.rmtree(f)
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996 else:
FUJIWARA Katsunori
subrepo: use vfs.unlink instead of os.remove...
r24691 self.wvfs.unlink(f)
Eric Eisner
subrepo: removing (and restoring) git subrepo state
r12996
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()
Matt Harbison
archive: always use portable path component separators with subrepos...
r24924 archiver.addfile(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(),
FUJIWARA Katsunori
subrepo: use vfs.reljoin instead of os.path.join
r24675 pathname=self.wvfs.reljoin(prefix, f))
Mathias De Maré
subrepo: add 'cat' support for git subrepos...
r23991 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:
Martin von Zweigbergk
subrepo: adapt to git's recent renames-by-default...
r28618 command = ['diff-tree', '--no-renames', '-r', rev1, rev2]
Eric Eisner
subrepo: basic support for status of git subrepos
r13182 else:
Martin von Zweigbergk
subrepo: adapt to git's recent renames-by-default...
r28618 command = ['diff-index', '--no-renames', rev1]
Eric Eisner
subrepo: basic support for status of git subrepos
r13182 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]
Martin von Zweigbergk
subrepo: adapt to git's recent renames-by-default...
r28618 cmd = ['diff', '--no-renames']
Mathias De Maré
subrepo: add partial diff support for git subrepos...
r23523 if opts['stat']:
cmd.append('--stat')
else:
# for Git, this also implies '-p'
cmd.append('-U%d' % diffopts.context)
FUJIWARA Katsunori
subrepo: use vfs.reljoin instead of os.path.join
r24675 gitprefix = self.wvfs.reljoin(prefix, self._path)
Mathias De Maré
subrepo: add partial diff support for git subrepos...
r23523
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)
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 include/exclude support for diffing git subrepos...
r24778 else:
st = self.status(node2)[:3]
files = [f for sublist in st for f in sublist]
for f in files:
if match(f):
output += self._gitcommand(cmd + ['--', f]) + '\n'
Mathias De Maré
subrepo: correctly add newline for git subrepo diffs...
r23938
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:
Siddharth Agarwal
origpath: move from cmdutil to scmutil...
r27651 bakname = scmutil.origpath(self.ui, self._subparent, name)
Mathias De Maré
subrepo: add full revert support for git subrepos...
r23678 self.ui.note(_('saving current version of %s as %s\n') %
(name, bakname))
Matt Harbison
subrepo: convert the os.path references in git to vfs...
r24695 self.wvfs.rename(name, 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 }