--- a/hgext/largefiles/overrides.py Sat Oct 05 10:29:34 2019 -0400
+++ b/hgext/largefiles/overrides.py Sun Oct 06 09:45:02 2019 -0400
@@ -14,9 +14,7 @@
from mercurial.i18n import _
-from mercurial.hgweb import (
- webcommands,
-)
+from mercurial.hgweb import webcommands
from mercurial import (
archival,
@@ -51,6 +49,7 @@
# -- Utility functions: commonly/repeatedly needed functionality ---------------
+
def composelargefilematcher(match, manifest):
'''create a matcher that matches only the largefiles in the original
matcher'''
@@ -63,14 +62,16 @@
m.matchfn = lambda f: lfile(f) and origmatchfn(f)
return m
+
def composenormalfilematcher(match, manifest, exclude=None):
excluded = set()
if exclude is not None:
excluded.update(exclude)
m = copy.copy(match)
- notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
- manifest or f in excluded)
+ notlfile = lambda f: not (
+ lfutil.isstandin(f) or lfutil.standin(f) in manifest or f in excluded
+ )
m._files = [lf for lf in m._files if notlfile(lf)]
m._fileset = set(m._files)
m.always = lambda: False
@@ -78,10 +79,12 @@
m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
return m
+
def addlargefiles(ui, repo, isaddremove, matcher, uipathfn, **opts):
large = opts.get(r'large')
lfsize = lfutil.getminsize(
- ui, lfutil.islfilesrepo(repo), opts.get(r'lfsize'))
+ ui, lfutil.islfilesrepo(repo), opts.get(r'lfsize')
+ )
lfmatcher = None
if lfutil.islfilesrepo(repo):
@@ -112,8 +115,9 @@
if not repo.wvfs.exists(f):
continue
- abovemin = (lfsize and
- repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024)
+ abovemin = (
+ lfsize and repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024
+ )
if large or abovemin or (lfmatcher and lfmatcher(f)):
lfnames.append(f)
if ui.verbose or not exact:
@@ -129,21 +133,28 @@
lfdirstate = lfutil.openlfdirstate(ui, repo)
for f in lfnames:
standinname = lfutil.standin(f)
- lfutil.writestandin(repo, standinname, hash='',
- executable=lfutil.getexecutable(repo.wjoin(f)))
+ lfutil.writestandin(
+ repo,
+ standinname,
+ hash='',
+ executable=lfutil.getexecutable(repo.wjoin(f)),
+ )
standins.append(standinname)
if lfdirstate[f] == 'r':
lfdirstate.normallookup(f)
else:
lfdirstate.add(f)
lfdirstate.write()
- bad += [lfutil.splitstandin(f)
- for f in repo[None].add(standins)
- if f in m.files()]
+ bad += [
+ lfutil.splitstandin(f)
+ for f in repo[None].add(standins)
+ if f in m.files()
+ ]
added = [f for f in lfnames if f not in bad]
return added, bad
+
def removelargefiles(ui, repo, isaddremove, matcher, uipathfn, dryrun, **opts):
after = opts.get(r'after')
m = composelargefilematcher(matcher, repo[None].manifest())
@@ -153,10 +164,10 @@
finally:
repo.lfstatus = False
manifest = repo[None].manifest()
- modified, added, deleted, clean = [[f for f in list
- if lfutil.standin(f) in manifest]
- for list in (s.modified, s.added,
- s.deleted, s.clean)]
+ modified, added, deleted, clean = [
+ [f for f in list if lfutil.standin(f) in manifest]
+ for list in (s.modified, s.added, s.deleted, s.clean)
+ ]
def warn(files, msg):
for f in files:
@@ -165,14 +176,28 @@
if after:
remove = deleted
- result = warn(modified + added + clean,
- _('not removing %s: file still exists\n'))
+ result = warn(
+ modified + added + clean, _('not removing %s: file still exists\n')
+ )
else:
remove = deleted + clean
- result = warn(modified, _('not removing %s: file is modified (use -f'
- ' to force removal)\n'))
- result = warn(added, _('not removing %s: file has been marked for add'
- ' (use forget to undo)\n')) or result
+ result = warn(
+ modified,
+ _(
+ 'not removing %s: file is modified (use -f'
+ ' to force removal)\n'
+ ),
+ )
+ result = (
+ warn(
+ added,
+ _(
+ 'not removing %s: file has been marked for add'
+ ' (use forget to undo)\n'
+ ),
+ )
+ or result
+ )
# Need to lock because standin files are deleted then removed from the
# repository and we could race in-between.
@@ -198,31 +223,47 @@
repo[None].forget(remove)
for f in remove:
- lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f),
- False)
+ lfutil.synclfdirstate(
+ repo, lfdirstate, lfutil.splitstandin(f), False
+ )
lfdirstate.write()
return result
+
# For overriding mercurial.hgweb.webcommands so that largefiles will
# appear at their right place in the manifests.
@eh.wrapfunction(webcommands, 'decodepath')
def decodepath(orig, path):
return lfutil.splitstandin(path) or path
+
# -- Wrappers: modify existing commands --------------------------------
-@eh.wrapcommand('add',
- opts=[('', 'large', None, _('add as largefile')),
- ('', 'normal', None, _('add as normal file')),
- ('', 'lfsize', '', _('add all files above this size (in megabytes) '
- 'as largefiles (default: 10)'))])
+
+@eh.wrapcommand(
+ 'add',
+ opts=[
+ ('', 'large', None, _('add as largefile')),
+ ('', 'normal', None, _('add as normal file')),
+ (
+ '',
+ 'lfsize',
+ '',
+ _(
+ 'add all files above this size (in megabytes) '
+ 'as largefiles (default: 10)'
+ ),
+ ),
+ ],
+)
def overrideadd(orig, ui, repo, *pats, **opts):
if opts.get(r'normal') and opts.get(r'large'):
raise error.Abort(_('--normal cannot be used with --large'))
return orig(ui, repo, *pats, **opts)
+
@eh.wrapfunction(cmdutil, 'add')
def cmdutiladd(orig, ui, repo, matcher, prefix, uipathfn, explicitonly, **opts):
# The --normal flag short circuits this override
@@ -230,21 +271,38 @@
return orig(ui, repo, matcher, prefix, uipathfn, explicitonly, **opts)
ladded, lbad = addlargefiles(ui, repo, False, matcher, uipathfn, **opts)
- normalmatcher = composenormalfilematcher(matcher, repo[None].manifest(),
- ladded)
+ normalmatcher = composenormalfilematcher(
+ matcher, repo[None].manifest(), ladded
+ )
bad = orig(ui, repo, normalmatcher, prefix, uipathfn, explicitonly, **opts)
bad.extend(f for f in lbad)
return bad
+
@eh.wrapfunction(cmdutil, 'remove')
-def cmdutilremove(orig, ui, repo, matcher, prefix, uipathfn, after, force,
- subrepos, dryrun):
+def cmdutilremove(
+ orig, ui, repo, matcher, prefix, uipathfn, after, force, subrepos, dryrun
+):
normalmatcher = composenormalfilematcher(matcher, repo[None].manifest())
- result = orig(ui, repo, normalmatcher, prefix, uipathfn, after, force,
- subrepos, dryrun)
- return removelargefiles(ui, repo, False, matcher, uipathfn, dryrun,
- after=after, force=force) or result
+ result = orig(
+ ui,
+ repo,
+ normalmatcher,
+ prefix,
+ uipathfn,
+ after,
+ force,
+ subrepos,
+ dryrun,
+ )
+ return (
+ removelargefiles(
+ ui, repo, False, matcher, uipathfn, dryrun, after=after, force=force
+ )
+ or result
+ )
+
@eh.wrapfunction(subrepo.hgsubrepo, 'status')
def overridestatusfn(orig, repo, rev2, **opts):
@@ -254,6 +312,7 @@
finally:
repo._repo.lfstatus = False
+
@eh.wrapcommand('status')
def overridestatus(orig, ui, repo, *pats, **opts):
try:
@@ -262,6 +321,7 @@
finally:
repo.lfstatus = False
+
@eh.wrapfunction(subrepo.hgsubrepo, 'dirty')
def overridedirty(orig, repo, ignoreupdate=False, missing=False):
try:
@@ -270,10 +330,18 @@
finally:
repo._repo.lfstatus = False
+
@eh.wrapcommand('log')
def overridelog(orig, ui, repo, *pats, **opts):
- def overridematchandpats(orig, ctx, pats=(), opts=None, globbed=False,
- default='relpath', badfn=None):
+ def overridematchandpats(
+ orig,
+ ctx,
+ pats=(),
+ opts=None,
+ globbed=False,
+ default='relpath',
+ badfn=None,
+ ):
"""Matcher that merges root directory with .hglf, suitable for log.
It is still possible to match .hglf directly.
For any listed files run log on the standin too.
@@ -304,13 +372,13 @@
cwd = repo.getcwd()
if cwd:
hglf = lfutil.shortname
- back = util.pconvert(repo.pathto(hglf)[:-len(hglf)])
+ back = util.pconvert(repo.pathto(hglf)[: -len(hglf)])
def tostandin(f):
# The file may already be a standin, so truncate the back
# prefix and test before mangling it. This avoids turning
# 'glob:../.hglf/foo*' into 'glob:../.hglf/../.hglf/foo*'.
- if f.startswith(back) and lfutil.splitstandin(f[len(back):]):
+ if f.startswith(back) and lfutil.splitstandin(f[len(back) :]):
return f
# An absolute path is from outside the repo, so truncate the
@@ -318,15 +386,18 @@
# is somewhere in the repo, relative to root, and needs to be
# prepended before building the standin.
if os.path.isabs(cwd):
- f = f[len(back):]
+ f = f[len(back) :]
else:
f = cwd + '/' + f
return back + lfutil.standin(f)
+
else:
+
def tostandin(f):
if lfutil.isstandin(f):
return f
return lfutil.standin(f)
+
pats.update(fixpats(f, tostandin) for f in p)
for i in range(0, len(m._files)):
@@ -346,12 +417,14 @@
m._fileset = set(m._files)
m.always = lambda: False
origmatchfn = m.matchfn
+
def lfmatchfn(f):
lf = lfutil.splitstandin(f)
if lf is not None and origmatchfn(lf):
return True
r = origmatchfn(f)
return r
+
m.matchfn = lfmatchfn
ui.debug('updated patterns: %s\n' % ', '.join(sorted(pats)))
@@ -363,25 +436,45 @@
# The magic matchandpats override should be used for case (1) but not for
# case (2).
oldmatchandpats = scmutil.matchandpats
+
def overridemakefilematcher(orig, repo, pats, opts, badfn=None):
wctx = repo[None]
match, pats = oldmatchandpats(wctx, pats, opts, badfn=badfn)
return lambda ctx: match
- wrappedmatchandpats = extensions.wrappedfunction(scmutil, 'matchandpats',
- overridematchandpats)
+ wrappedmatchandpats = extensions.wrappedfunction(
+ scmutil, 'matchandpats', overridematchandpats
+ )
wrappedmakefilematcher = extensions.wrappedfunction(
- logcmdutil, '_makenofollowfilematcher', overridemakefilematcher)
+ logcmdutil, '_makenofollowfilematcher', overridemakefilematcher
+ )
with wrappedmatchandpats, wrappedmakefilematcher:
return orig(ui, repo, *pats, **opts)
-@eh.wrapcommand('verify',
- opts=[('', 'large', None,
- _('verify that all largefiles in current revision exists')),
- ('', 'lfa', None,
- _('verify largefiles in all revisions, not just current')),
- ('', 'lfc', None,
- _('verify local largefile contents, not just existence'))])
+
+@eh.wrapcommand(
+ 'verify',
+ opts=[
+ (
+ '',
+ 'large',
+ None,
+ _('verify that all largefiles in current revision exists'),
+ ),
+ (
+ '',
+ 'lfa',
+ None,
+ _('verify largefiles in all revisions, not just current'),
+ ),
+ (
+ '',
+ 'lfc',
+ None,
+ _('verify local largefile contents, not just existence'),
+ ),
+ ],
+)
def overrideverify(orig, ui, repo, *pats, **opts):
large = opts.pop(r'large', False)
all = opts.pop(r'lfa', False)
@@ -392,17 +485,22 @@
result = result or lfcommands.verifylfiles(ui, repo, all, contents)
return result
-@eh.wrapcommand('debugstate',
- opts=[('', 'large', None, _('display largefiles dirstate'))])
+
+@eh.wrapcommand(
+ 'debugstate', opts=[('', 'large', None, _('display largefiles dirstate'))]
+)
def overridedebugstate(orig, ui, repo, *pats, **opts):
large = opts.pop(r'large', False)
if large:
+
class fakerepo(object):
dirstate = lfutil.openlfdirstate(ui, repo)
+
orig(ui, fakerepo, *pats, **opts)
else:
orig(ui, repo, *pats, **opts)
+
# Before starting the manifest merge, merge.updates will call
# _checkunknownfile to check if there are any files in the merged-in
# changeset that collide with unknown files in the working copy.
@@ -419,6 +517,7 @@
return False
return origfn(repo, wctx, mctx, f, f2)
+
# The manifest merge handles conflicts on the manifest level. We want
# to handle changes in largefile-ness of files at this level too.
#
@@ -446,11 +545,13 @@
# writing the files into the working copy and lfcommands.updatelfiles
# will update the largefiles.
@eh.wrapfunction(merge, 'calculateupdates')
-def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
- acceptremote, *args, **kwargs):
+def overridecalculateupdates(
+ origfn, repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs
+):
overwrite = force and not branchmerge
actions, diverge, renamedelete = origfn(
- repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs)
+ repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs
+ )
if overwrite:
return actions, diverge, renamedelete
@@ -474,13 +575,18 @@
sargs = (p2[f2].flags(), False)
# Case 1: normal file in the working copy, largefile in
# the second parent
- usermsg = _('remote turned local normal file %s into a largefile\n'
- 'use (l)argefile or keep (n)ormal file?'
- '$$ &Largefile $$ &Normal file') % lfile
- if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
+ usermsg = (
+ _(
+ 'remote turned local normal file %s into a largefile\n'
+ 'use (l)argefile or keep (n)ormal file?'
+ '$$ &Largefile $$ &Normal file'
+ )
+ % lfile
+ )
+ if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
actions[lfile] = ('r', None, 'replaced by standin')
actions[standin] = ('g', sargs, 'replaces standin')
- else: # keep local normal file
+ else: # keep local normal file
actions[lfile] = ('k', None, 'replaces standin')
if branchmerge:
actions[standin] = ('k', None, 'replaced by non-standin')
@@ -492,10 +598,15 @@
largs = (p2[f2].flags(), False)
# Case 2: largefile in the working copy, normal file in
# the second parent
- usermsg = _('remote turned local largefile %s into a normal file\n'
+ usermsg = (
+ _(
+ 'remote turned local largefile %s into a normal file\n'
'keep (l)argefile or use (n)ormal file?'
- '$$ &Largefile $$ &Normal file') % lfile
- if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
+ '$$ &Largefile $$ &Normal file'
+ )
+ % lfile
+ )
+ if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
if branchmerge:
# largefile can be restored from standin safely
actions[lfile] = ('k', None, 'replaced by standin')
@@ -503,17 +614,21 @@
else:
# "lfile" should be marked as "removed" without
# removal of itself
- actions[lfile] = ('lfmr', None,
- 'forget non-standin largefile')
+ actions[lfile] = (
+ 'lfmr',
+ None,
+ 'forget non-standin largefile',
+ )
# linear-merge should treat this largefile as 're-added'
actions[standin] = ('a', None, 'keep standin')
- else: # pick remote normal file
+ else: # pick remote normal file
actions[lfile] = ('g', largs, 'replaces standin')
actions[standin] = ('r', None, 'replaced by non-standin')
return actions, diverge, renamedelete
+
@eh.wrapfunction(merge, 'recordupdates')
def mergerecordupdates(orig, repo, actions, branchmerge, getfiledata):
if 'lfmr' in actions:
@@ -528,31 +643,43 @@
return orig(repo, actions, branchmerge, getfiledata)
+
# Override filemerge to prompt the user about how they wish to merge
# largefiles. This will handle identical edits without prompting the user.
@eh.wrapfunction(filemerge, '_filemerge')
-def overridefilemerge(origfn, premerge, repo, wctx, mynode, orig, fcd, fco, fca,
- labels=None):
+def overridefilemerge(
+ origfn, premerge, repo, wctx, mynode, orig, fcd, fco, fca, labels=None
+):
if not lfutil.isstandin(orig) or fcd.isabsent() or fco.isabsent():
- return origfn(premerge, repo, wctx, mynode, orig, fcd, fco, fca,
- labels=labels)
+ return origfn(
+ premerge, repo, wctx, mynode, orig, fcd, fco, fca, labels=labels
+ )
ahash = lfutil.readasstandin(fca).lower()
dhash = lfutil.readasstandin(fcd).lower()
ohash = lfutil.readasstandin(fco).lower()
- if (ohash != ahash and
- ohash != dhash and
- (dhash == ahash or
- repo.ui.promptchoice(
- _('largefile %s has a merge conflict\nancestor was %s\n'
- 'you can keep (l)ocal %s or take (o)ther %s.\n'
- 'what do you want to do?'
- '$$ &Local $$ &Other') %
- (lfutil.splitstandin(orig), ahash, dhash, ohash),
- 0) == 1)):
+ if (
+ ohash != ahash
+ and ohash != dhash
+ and (
+ dhash == ahash
+ or repo.ui.promptchoice(
+ _(
+ 'largefile %s has a merge conflict\nancestor was %s\n'
+ 'you can keep (l)ocal %s or take (o)ther %s.\n'
+ 'what do you want to do?'
+ '$$ &Local $$ &Other'
+ )
+ % (lfutil.splitstandin(orig), ahash, dhash, ohash),
+ 0,
+ )
+ == 1
+ )
+ ):
repo.wwrite(fcd.path(), fco.data(), fco.flags())
return True, 0, False
+
@eh.wrapfunction(copiesmod, 'pathcopies')
def copiespathcopies(orig, ctx1, ctx2, match=None):
copies = orig(ctx1, ctx2, match=match)
@@ -563,6 +690,7 @@
return updated
+
# Copy first changes the matchers to match standins instead of
# largefiles. Then it overrides util.copyfile in that function it
# checks if the destination largefile already exists. It also keeps a
@@ -582,12 +710,21 @@
nonormalfiles = False
nolfiles = False
manifest = repo[None].manifest()
- def normalfilesmatchfn(orig, ctx, pats=(), opts=None, globbed=False,
- default='relpath', badfn=None):
+
+ def normalfilesmatchfn(
+ orig,
+ ctx,
+ pats=(),
+ opts=None,
+ globbed=False,
+ default='relpath',
+ badfn=None,
+ ):
if opts is None:
opts = {}
match = orig(ctx, pats, opts, globbed, default, badfn=badfn)
return composenormalfilematcher(match, manifest)
+
with extensions.wrappedfunction(scmutil, 'match', normalfilesmatchfn):
try:
result = orig(ui, repo, pats, opts, rename)
@@ -622,8 +759,16 @@
wlock = repo.wlock()
manifest = repo[None].manifest()
- def overridematch(orig, ctx, pats=(), opts=None, globbed=False,
- default='relpath', badfn=None):
+
+ def overridematch(
+ orig,
+ ctx,
+ pats=(),
+ opts=None,
+ globbed=False,
+ default='relpath',
+ badfn=None,
+ ):
if opts is None:
opts = {}
newpats = []
@@ -640,14 +785,19 @@
m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
m._fileset = set(m._files)
origmatchfn = m.matchfn
+
def matchfn(f):
lfile = lfutil.splitstandin(f)
- return (lfile is not None and
- (f in manifest) and
- origmatchfn(lfile) or
- None)
+ return (
+ lfile is not None
+ and (f in manifest)
+ and origmatchfn(lfile)
+ or None
+ )
+
m.matchfn = matchfn
return m
+
listpats = []
for pat in pats:
if matchmod.patkind(pat) is not None:
@@ -656,23 +806,26 @@
listpats.append(makestandin(pat))
copiedfiles = []
+
def overridecopyfile(orig, src, dest, *args, **kwargs):
- if (lfutil.shortname in src and
- dest.startswith(repo.wjoin(lfutil.shortname))):
+ if lfutil.shortname in src and dest.startswith(
+ repo.wjoin(lfutil.shortname)
+ ):
destlfile = dest.replace(lfutil.shortname, '')
if not opts['force'] and os.path.exists(destlfile):
- raise IOError('',
- _('destination largefile already exists'))
+ raise IOError('', _('destination largefile already exists'))
copiedfiles.append((src, dest))
orig(src, dest, *args, **kwargs)
+
with extensions.wrappedfunction(util, 'copyfile', overridecopyfile):
with extensions.wrappedfunction(scmutil, 'match', overridematch):
result += orig(ui, repo, listpats, opts, rename)
lfdirstate = lfutil.openlfdirstate(ui, repo)
for (src, dest) in copiedfiles:
- if (lfutil.shortname in src and
- dest.startswith(repo.wjoin(lfutil.shortname))):
+ if lfutil.shortname in src and dest.startswith(
+ repo.wjoin(lfutil.shortname)
+ ):
srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
destlfiledir = repo.wvfs.dirname(repo.wjoin(destlfile)) or '.'
@@ -686,8 +839,7 @@
repo.wvfs.unlinkpath(srclfile, ignoremissing=True)
lfdirstate.remove(srclfile)
else:
- util.copyfile(repo.wjoin(srclfile),
- repo.wjoin(destlfile))
+ util.copyfile(repo.wjoin(srclfile), repo.wjoin(destlfile))
lfdirstate.add(destlfile)
lfdirstate.write()
@@ -704,6 +856,7 @@
return result
+
# When the user calls revert, we have to be careful to not revert any
# changes to other largefiles accidentally. This means we have to keep
# track of the largefiles that are being reverted so we only pull down
@@ -726,13 +879,20 @@
lfutil.updatestandin(repo, lfile, lfutil.standin(lfile))
for lfile in s.deleted:
fstandin = lfutil.standin(lfile)
- if (repo.wvfs.exists(fstandin)):
+ if repo.wvfs.exists(fstandin):
repo.wvfs.unlink(fstandin)
oldstandins = lfutil.getstandinsstate(repo)
- def overridematch(orig, mctx, pats=(), opts=None, globbed=False,
- default='relpath', badfn=None):
+ def overridematch(
+ orig,
+ mctx,
+ pats=(),
+ opts=None,
+ globbed=False,
+ default='relpath',
+ badfn=None,
+ ):
if opts is None:
opts = {}
match = orig(mctx, pats, opts, globbed, default, badfn=badfn)
@@ -742,8 +902,9 @@
# currently doesn't work correctly in that case, this match is
# called, so the lfdirstate above may not be the correct one for
# this invocation of match.
- lfdirstate = lfutil.openlfdirstate(mctx.repo().ui, mctx.repo(),
- False)
+ lfdirstate = lfutil.openlfdirstate(
+ mctx.repo().ui, mctx.repo(), False
+ )
wctx = repo[None]
matchfiles = []
@@ -758,14 +919,16 @@
m._files = matchfiles
m._fileset = set(m._files)
origmatchfn = m.matchfn
+
def matchfn(f):
lfile = lfutil.splitstandin(f)
if lfile is not None:
- return (origmatchfn(lfile) and
- (f in ctx or f in mctx))
+ return origmatchfn(lfile) and (f in ctx or f in mctx)
return origmatchfn(f)
+
m.matchfn = matchfn
return m
+
with extensions.wrappedfunction(scmutil, 'match', overridematch):
orig(ui, repo, ctx, parents, *pats, **opts)
@@ -776,16 +939,31 @@
# when target revision is explicitly specified: in such case,
# 'n' and valid timestamp in dirstate doesn't ensure 'clean'
# of target (standin) file.
- lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
- normallookup=True)
+ lfcommands.updatelfiles(
+ ui, repo, filelist, printmessage=False, normallookup=True
+ )
+
# after pulling changesets, we need to take some extra care to get
# largefiles updated remotely
-@eh.wrapcommand('pull',
- opts=[('', 'all-largefiles', None,
- _('download all pulled versions of largefiles (DEPRECATED)')),
- ('', 'lfrev', [],
- _('download largefiles for these revisions'), _('REV'))])
+@eh.wrapcommand(
+ 'pull',
+ opts=[
+ (
+ '',
+ 'all-largefiles',
+ None,
+ _('download all pulled versions of largefiles (DEPRECATED)'),
+ ),
+ (
+ '',
+ 'lfrev',
+ [],
+ _('download largefiles for these revisions'),
+ _('REV'),
+ ),
+ ],
+)
def overridepull(orig, ui, repo, source=None, **opts):
revsprepull = len(repo)
if not source:
@@ -798,7 +976,7 @@
lfrevs.append('pulled()')
if lfrevs and revspostpull > revsprepull:
numcached = 0
- repo.firstpulled = revsprepull # for pulled() revset expression
+ repo.firstpulled = revsprepull # for pulled() revset expression
try:
for rev in scmutil.revrange(repo, lfrevs):
ui.note(_('pulling largefiles for revision %d\n') % rev)
@@ -809,9 +987,13 @@
ui.status(_("%d largefiles cached\n") % numcached)
return result
-@eh.wrapcommand('push',
- opts=[('', 'lfrev', [],
- _('upload largefiles for these revisions'), _('REV'))])
+
+@eh.wrapcommand(
+ 'push',
+ opts=[
+ ('', 'lfrev', [], _('upload largefiles for these revisions'), _('REV'))
+ ],
+)
def overridepush(orig, ui, repo, *args, **kwargs):
"""Override push command and store --lfrev parameters in opargs"""
lfrevs = kwargs.pop(r'lfrev', None)
@@ -820,6 +1002,7 @@
opargs['lfrevs'] = scmutil.revrange(repo, lfrevs)
return orig(ui, repo, *args, **kwargs)
+
@eh.wrapfunction(exchange, 'pushoperation')
def exchangepushoperation(orig, *args, **kwargs):
"""Override pushoperation constructor and store lfrevs parameter"""
@@ -828,6 +1011,7 @@
pushop.lfrevs = lfrevs
return pushop
+
@eh.revsetpredicate('pulled()')
def pulledrevsetsymbol(repo, subset, x):
"""Changesets that just has been pulled.
@@ -854,20 +1038,31 @@
raise error.Abort(_("pulled() only available in --lfrev"))
return smartset.baseset([r for r in subset if r >= firstpulled])
-@eh.wrapcommand('clone',
- opts=[('', 'all-largefiles', None,
- _('download all versions of all largefiles'))])
+
+@eh.wrapcommand(
+ 'clone',
+ opts=[
+ (
+ '',
+ 'all-largefiles',
+ None,
+ _('download all versions of all largefiles'),
+ )
+ ],
+)
def overrideclone(orig, ui, source, dest=None, **opts):
d = dest
if d is None:
d = hg.defaultdest(source)
if opts.get(r'all_largefiles') and not hg.islocal(d):
- raise error.Abort(_(
- '--all-largefiles is incompatible with non-local destination %s') %
- d)
+ raise error.Abort(
+ _('--all-largefiles is incompatible with non-local destination %s')
+ % d
+ )
return orig(ui, source, dest, **opts)
+
@eh.wrapfunction(hg, 'clone')
def hgclone(orig, ui, opts, *args, **kwargs):
result = orig(ui, opts, *args, **kwargs)
@@ -893,6 +1088,7 @@
return result
+
@eh.wrapcommand('rebase', extension='rebase')
def overriderebase(orig, ui, repo, **opts):
if not util.safehasattr(repo, '_largefilesenabled'):
@@ -907,6 +1103,7 @@
repo._lfstatuswriters.pop()
repo._lfcommithooks.pop()
+
@eh.wrapcommand('archive')
def overridearchivecmd(orig, ui, repo, dest, **opts):
repo.unfiltered().lfstatus = True
@@ -916,6 +1113,7 @@
finally:
repo.unfiltered().lfstatus = False
+
@eh.wrapfunction(webcommands, 'archive')
def hgwebarchive(orig, web):
web.repo.lfstatus = True
@@ -925,14 +1123,26 @@
finally:
web.repo.lfstatus = False
+
@eh.wrapfunction(archival, 'archive')
-def overridearchive(orig, repo, dest, node, kind, decode=True, match=None,
- prefix='', mtime=None, subrepos=None):
+def overridearchive(
+ orig,
+ repo,
+ dest,
+ node,
+ kind,
+ decode=True,
+ match=None,
+ prefix='',
+ mtime=None,
+ subrepos=None,
+):
# For some reason setting repo.lfstatus in hgwebarchive only changes the
# unfiltered repo's attr, so check that as well.
if not repo.lfstatus and not repo.unfiltered().lfstatus:
- return orig(repo, dest, node, kind, decode, match, prefix, mtime,
- subrepos)
+ return orig(
+ repo, dest, node, kind, decode, match, prefix, mtime, subrepos
+ )
# No need to lock because we are only reading history and
# largefile caches, neither of which are modified.
@@ -946,8 +1156,7 @@
if kind == 'files':
if prefix:
- raise error.Abort(
- _('cannot give prefix when archiving to files'))
+ raise error.Abort(_('cannot give prefix when archiving to files'))
else:
prefix = archival.tidyprefix(dest, kind, prefix)
@@ -962,8 +1171,12 @@
archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
if repo.ui.configbool("ui", "archivemeta"):
- write('.hg_archival.txt', 0o644, False,
- lambda: archival.buildmetadata(ctx))
+ write(
+ '.hg_archival.txt',
+ 0o644,
+ False,
+ lambda: archival.buildmetadata(ctx),
+ )
for f in ctx:
ff = ctx.flags(f)
@@ -975,8 +1188,11 @@
if path is None:
raise error.Abort(
- _('largefile %s not found in repo store or system cache')
- % lfile)
+ _(
+ 'largefile %s not found in repo store or system cache'
+ )
+ % lfile
+ )
else:
path = lfile
@@ -995,6 +1211,7 @@
archiver.done()
+
@eh.wrapfunction(subrepo.hgsubrepo, 'archive')
def hgsubrepoarchive(orig, repo, archiver, prefix, match=None, decode=True):
lfenabled = util.safehasattr(repo._repo, '_largefilesenabled')
@@ -1029,8 +1246,11 @@
if path is None:
raise error.Abort(
- _('largefile %s not found in repo store or system cache')
- % lfile)
+ _(
+ 'largefile %s not found in repo store or system cache'
+ )
+ % lfile
+ )
else:
path = lfile
@@ -1047,6 +1267,7 @@
sub._repo.lfstatus = True
sub.archive(archiver, subprefix, submatch, decode)
+
# If a largefile is modified, the change is not reflected in its
# standin until a commit. cmdutil.bailifchanged() raises an exception
# if the repo has uncommitted changes. Wrap it to also check if
@@ -1060,6 +1281,7 @@
if s.modified or s.added or s.removed or s.deleted:
raise error.Abort(_('uncommitted changes'))
+
@eh.wrapfunction(cmdutil, 'postcommitstatus')
def postcommitstatus(orig, repo, *args, **kwargs):
repo.lfstatus = True
@@ -1068,12 +1290,22 @@
finally:
repo.lfstatus = False
+
@eh.wrapfunction(cmdutil, 'forget')
-def cmdutilforget(orig, ui, repo, match, prefix, uipathfn, explicitonly, dryrun,
- interactive):
+def cmdutilforget(
+ orig, ui, repo, match, prefix, uipathfn, explicitonly, dryrun, interactive
+):
normalmatcher = composenormalfilematcher(match, repo[None].manifest())
- bad, forgot = orig(ui, repo, normalmatcher, prefix, uipathfn, explicitonly,
- dryrun, interactive)
+ bad, forgot = orig(
+ ui,
+ repo,
+ normalmatcher,
+ prefix,
+ uipathfn,
+ explicitonly,
+ dryrun,
+ interactive,
+ )
m = composelargefilematcher(match, repo[None].manifest())
try:
@@ -1088,8 +1320,9 @@
for f in forget:
fstandin = lfutil.standin(f)
if fstandin not in repo.dirstate and not repo.wvfs.isdir(fstandin):
- ui.warn(_('not removing %s: file is already untracked\n')
- % uipathfn(f))
+ ui.warn(
+ _('not removing %s: file is already untracked\n') % uipathfn(f)
+ )
bad.append(f)
for f in forget:
@@ -1115,6 +1348,7 @@
forgot.extend(f for f in forget if f not in rejected)
return bad, forgot
+
def _getoutgoings(repo, other, missing, addfunc):
"""get pairs of filename and largefile hash in outgoing revisions
in 'missing'.
@@ -1126,62 +1360,75 @@
"""
knowns = set()
lfhashes = set()
+
def dedup(fn, lfhash):
k = (fn, lfhash)
if k not in knowns:
knowns.add(k)
lfhashes.add(lfhash)
+
lfutil.getlfilestoupload(repo, missing, dedup)
if lfhashes:
lfexists = storefactory.openstore(repo, other).exists(lfhashes)
for fn, lfhash in knowns:
- if not lfexists[lfhash]: # lfhash doesn't exist on "other"
+ if not lfexists[lfhash]: # lfhash doesn't exist on "other"
addfunc(fn, lfhash)
+
def outgoinghook(ui, repo, other, opts, missing):
if opts.pop('large', None):
lfhashes = set()
if ui.debugflag:
toupload = {}
+
def addfunc(fn, lfhash):
if fn not in toupload:
toupload[fn] = []
toupload[fn].append(lfhash)
lfhashes.add(lfhash)
+
def showhashes(fn):
for lfhash in sorted(toupload[fn]):
- ui.debug(' %s\n' % (lfhash))
+ ui.debug(' %s\n' % lfhash)
+
else:
toupload = set()
+
def addfunc(fn, lfhash):
toupload.add(fn)
lfhashes.add(lfhash)
+
def showhashes(fn):
pass
+
_getoutgoings(repo, other, missing, addfunc)
if not toupload:
ui.status(_('largefiles: no files to upload\n'))
else:
- ui.status(_('largefiles to upload (%d entities):\n')
- % (len(lfhashes)))
+ ui.status(
+ _('largefiles to upload (%d entities):\n') % (len(lfhashes))
+ )
for file in sorted(toupload):
ui.status(lfutil.splitstandin(file) + '\n')
showhashes(file)
ui.status('\n')
-@eh.wrapcommand('outgoing',
- opts=[('', 'large', None, _('display outgoing largefiles'))])
+
+@eh.wrapcommand(
+ 'outgoing', opts=[('', 'large', None, _('display outgoing largefiles'))]
+)
def _outgoingcmd(orig, *args, **kwargs):
# Nothing to do here other than add the extra help option- the hook above
# processes it.
return orig(*args, **kwargs)
+
def summaryremotehook(ui, repo, opts, changes):
largeopt = opts.get('large', False)
if changes is None:
if largeopt:
- return (False, True) # only outgoing check is needed
+ return (False, True) # only outgoing check is needed
else:
return (False, False)
elif largeopt:
@@ -1193,9 +1440,11 @@
toupload = set()
lfhashes = set()
+
def addfunc(fn, lfhash):
toupload.add(fn)
lfhashes.add(lfhash)
+
_getoutgoings(repo, peer, outgoing.missing, addfunc)
if not toupload:
@@ -1203,11 +1452,15 @@
ui.status(_('largefiles: (no files to upload)\n'))
else:
# i18n: column positioning for "hg summary"
- ui.status(_('largefiles: %d entities for %d files to upload\n')
- % (len(lfhashes), len(toupload)))
+ ui.status(
+ _('largefiles: %d entities for %d files to upload\n')
+ % (len(lfhashes), len(toupload))
+ )
-@eh.wrapcommand('summary',
- opts=[('', 'large', None, _('display outgoing largefiles'))])
+
+@eh.wrapcommand(
+ 'summary', opts=[('', 'large', None, _('display outgoing largefiles'))]
+)
def overridesummary(orig, ui, repo, *pats, **opts):
try:
repo.lfstatus = True
@@ -1215,6 +1468,7 @@
finally:
repo.lfstatus = False
+
@eh.wrapfunction(scmutil, 'addremove')
def scmutiladdremove(orig, repo, matcher, prefix, uipathfn, opts=None):
if opts is None:
@@ -1223,8 +1477,13 @@
return orig(repo, matcher, prefix, uipathfn, opts)
# Get the list of missing largefiles so we can remove them
lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
- unsure, s = lfdirstate.status(matchmod.always(), subrepos=[],
- ignored=False, clean=False, unknown=False)
+ unsure, s = lfdirstate.status(
+ matchmod.always(),
+ subrepos=[],
+ ignored=False,
+ clean=False,
+ unknown=False,
+ )
# Call into the normal remove code, but the removing of the standin, we want
# to have handled by original addremove. Monkey patching here makes sure
@@ -1240,18 +1499,27 @@
matchfn = m.matchfn
m.matchfn = lambda f: f in s.deleted and matchfn(f)
- removelargefiles(repo.ui, repo, True, m, uipathfn, opts.get('dry_run'),
- **pycompat.strkwargs(opts))
+ removelargefiles(
+ repo.ui,
+ repo,
+ True,
+ m,
+ uipathfn,
+ opts.get('dry_run'),
+ **pycompat.strkwargs(opts)
+ )
# Call into the normal add code, and any files that *should* be added as
# largefiles will be
- added, bad = addlargefiles(repo.ui, repo, True, matcher, uipathfn,
- **pycompat.strkwargs(opts))
+ added, bad = addlargefiles(
+ repo.ui, repo, True, matcher, uipathfn, **pycompat.strkwargs(opts)
+ )
# Now that we've handled largefiles, hand off to the original addremove
# function to take care of the rest. Make sure it doesn't do anything with
# largefiles by passing a matcher that will ignore them.
matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
return orig(repo, matcher, prefix, uipathfn, opts)
+
# Calling purge with --all will cause the largefiles to be deleted.
# Override repo.status to prevent this from happening.
@eh.wrapcommand('purge', extension='purge')
@@ -1267,29 +1535,44 @@
# cleaner instead.
repo = repo.unfiltered()
oldstatus = repo.status
- def overridestatus(node1='.', node2=None, match=None, ignored=False,
- clean=False, unknown=False, listsubrepos=False):
- r = oldstatus(node1, node2, match, ignored, clean, unknown,
- listsubrepos)
+
+ def overridestatus(
+ node1='.',
+ node2=None,
+ match=None,
+ ignored=False,
+ clean=False,
+ unknown=False,
+ listsubrepos=False,
+ ):
+ r = oldstatus(
+ node1, node2, match, ignored, clean, unknown, listsubrepos
+ )
lfdirstate = lfutil.openlfdirstate(ui, repo)
unknown = [f for f in r.unknown if lfdirstate[f] == '?']
ignored = [f for f in r.ignored if lfdirstate[f] == '?']
- return scmutil.status(r.modified, r.added, r.removed, r.deleted,
- unknown, ignored, r.clean)
+ return scmutil.status(
+ r.modified, r.added, r.removed, r.deleted, unknown, ignored, r.clean
+ )
+
repo.status = overridestatus
orig(ui, repo, *dirs, **opts)
repo.status = oldstatus
+
@eh.wrapcommand('rollback')
def overriderollback(orig, ui, repo, **opts):
with repo.wlock():
before = repo.dirstate.parents()
- orphans = set(f for f in repo.dirstate
- if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
+ orphans = set(
+ f
+ for f in repo.dirstate
+ if lfutil.isstandin(f) and repo.dirstate[f] != 'r'
+ )
result = orig(ui, repo, **opts)
after = repo.dirstate.parents()
if before == after:
- return result # no need to restore standins
+ return result # no need to restore standins
pctx = repo['.']
for f in repo.dirstate:
@@ -1318,6 +1601,7 @@
lfdirstate.write()
return result
+
@eh.wrapcommand('transplant', extension='transplant')
def overridetransplant(orig, ui, repo, *revs, **opts):
resuming = opts.get(r'continue')
@@ -1330,6 +1614,7 @@
repo._lfcommithooks.pop()
return result
+
@eh.wrapcommand('cat')
def overridecat(orig, ui, repo, file1, *pats, **opts):
opts = pycompat.byteskwargs(opts)
@@ -1338,6 +1623,7 @@
notbad = set()
m = scmutil.match(ctx, (file1,) + pats, opts)
origmatchfn = m.matchfn
+
def lfmatchfn(f):
if origmatchfn(f):
return True
@@ -1346,14 +1632,18 @@
return False
notbad.add(lf)
return origmatchfn(lf)
+
m.matchfn = lfmatchfn
origbadfn = m.bad
+
def lfbadfn(f, msg):
if not f in notbad:
origbadfn(f, msg)
+
m.bad = lfbadfn
origvisitdirfn = m.visitdir
+
def lfvisitdirfn(dir):
if dir == lfutil.shortname:
return True
@@ -1364,6 +1654,7 @@
if lf is None:
return False
return origvisitdirfn(lf)
+
m.visitdir = lfvisitdirfn
for f in ctx.walk(m):
@@ -1382,8 +1673,12 @@
success, missing = store.get([(lf, hash)])
if len(success) != 1:
raise error.Abort(
- _('largefile %s is not in cache and could not be '
- 'downloaded') % lf)
+ _(
+ 'largefile %s is not in cache and could not be '
+ 'downloaded'
+ )
+ % lf
+ )
path = lfutil.usercachepath(repo.ui, hash)
with open(path, "rb") as fpin:
for chunk in util.filechunkiter(fpin):
@@ -1391,9 +1686,9 @@
err = 0
return err
+
@eh.wrapfunction(merge, 'update')
-def mergeupdate(orig, repo, node, branchmerge, force,
- *args, **kwargs):
+def mergeupdate(orig, repo, node, branchmerge, force, *args, **kwargs):
matcher = kwargs.get(r'matcher', None)
# note if this is a partial update
partial = matcher and not matcher.always()
@@ -1414,8 +1709,13 @@
# (*1) deprecated, but used internally (e.g: "rebase --collapse")
lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
- unsure, s = lfdirstate.status(matchmod.always(), subrepos=[],
- ignored=False, clean=True, unknown=False)
+ unsure, s = lfdirstate.status(
+ matchmod.always(),
+ subrepos=[],
+ ignored=False,
+ clean=True,
+ unknown=False,
+ )
oldclean = set(s.clean)
pctx = repo['.']
dctx = repo[node]
@@ -1425,10 +1725,12 @@
continue
lfhash = lfutil.hashfile(lfileabs)
standin = lfutil.standin(lfile)
- lfutil.writestandin(repo, standin, lfhash,
- lfutil.getexecutable(lfileabs))
- if (standin in pctx and
- lfhash == lfutil.readasstandin(pctx[standin])):
+ lfutil.writestandin(
+ repo, standin, lfhash, lfutil.getexecutable(lfileabs)
+ )
+ if standin in pctx and lfhash == lfutil.readasstandin(
+ pctx[standin]
+ ):
oldclean.add(lfile)
for lfile in s.added:
fstandin = lfutil.standin(lfile)
@@ -1462,11 +1764,13 @@
if branchmerge or force or partial:
filelist.extend(s.deleted + s.removed)
- lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
- normallookup=partial)
+ lfcommands.updatelfiles(
+ repo.ui, repo, filelist=filelist, normallookup=partial
+ )
return result
+
@eh.wrapfunction(scmutil, 'marktouched')
def scmutilmarktouched(orig, repo, files, *args, **kwargs):
result = orig(repo, files, *args, **kwargs)
@@ -1477,11 +1781,17 @@
if lf is not None:
filelist.append(lf)
if filelist:
- lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
- printmessage=False, normallookup=True)
+ lfcommands.updatelfiles(
+ repo.ui,
+ repo,
+ filelist=filelist,
+ printmessage=False,
+ normallookup=True,
+ )
return result
+
@eh.wrapfunction(upgrade, 'preservedrequirements')
@eh.wrapfunction(upgrade, 'supporteddestrequirements')
def upgraderequirements(orig, repo):
@@ -1490,15 +1800,17 @@
reqs.add('largefiles')
return reqs
+
_lfscheme = 'largefile://'
+
@eh.wrapfunction(urlmod, 'open')
def openlargefile(orig, ui, url_, data=None):
if url_.startswith(_lfscheme):
if data:
msg = "cannot use data on a 'largefile://' url"
raise error.ProgrammingError(msg)
- lfid = url_[len(_lfscheme):]
+ lfid = url_[len(_lfscheme) :]
return storefactory.getlfile(ui, lfid)
else:
return orig(ui, url_, data=data)