##// END OF EJS Templates
debugbackupbundle: introduce command to interact with strip backups...
debugbackupbundle: introduce command to interact with strip backups This vendors backups extension from hg-experimental. Listing backups and having some utility to apply them is nice. I know we have obsmarkers now, but this will help a lot of end users who still uses strip until we get evolve out of experimental. Differential Revision: https://phab.mercurial-scm.org/D7932

File last commit:

r44514:006e7821 default
r44915:f82d2d4e default
Show More
lfcommands.py
669 lines | 22.0 KiB | text/x-python | PythonLexer
various
hgext: add largefiles extension...
r15168 # Copyright 2009-2010 Gregory P. Ward
# Copyright 2009-2010 Intelerad Medical Systems Incorporated
# Copyright 2010-2011 Fog Creek Software
# Copyright 2010-2011 Unity Technologies
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Greg Ward
largefiles: improve comments, internal docstrings...
r15252 '''High-level command function for lfconvert, plus the cmdtable.'''
liscju
py3: make largefiles/lfcommands.py use absolute_import
r29308 from __future__ import absolute_import
various
hgext: add largefiles extension...
r15168
liscju
py3: make largefiles/lfcommands.py use absolute_import
r29308 import errno
import os
various
hgext: add largefiles extension...
r15168 import shutil
from mercurial.i18n import _
liscju
py3: make largefiles/lfcommands.py use absolute_import
r29308 from mercurial import (
cmdutil,
context,
error,
Matt Harbison
largefiles: port commands to exthelper...
r41091 exthelper,
liscju
py3: make largefiles/lfcommands.py use absolute_import
r29308 hg,
lock,
liscju
largefiles: rename match_ to matchmod import in lfcommands
r29317 match as matchmod,
liscju
py3: make largefiles/lfcommands.py use absolute_import
r29308 node,
Pulkit Goyal
py3: handle keyword arguments correctly in hgext/largefiles/...
r35349 pycompat,
liscju
py3: make largefiles/lfcommands.py use absolute_import
r29308 scmutil,
util,
)
Augie Fackler
hgext: replace references to hashlib.sha1 with hashutil.sha1...
r44519 from mercurial.utils import hashutil
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325
liscju
py3: make largefiles/lfcommands.py use absolute_import
r29308 from ..convert import (
convcmd,
filemap,
)
Augie Fackler
formatting: blacken the codebase...
r43346 from . import lfutil, storefactory
liscju
py3: make largefiles/lfcommands.py use absolute_import
r29308
release = lock.release
various
hgext: add largefiles extension...
r15168
# -- Commands ----------------------------------------------------------
Matt Harbison
largefiles: port commands to exthelper...
r41091 eh = exthelper.exthelper()
Gregory Szorc
largefiles: declare commands using decorator
r21242
Augie Fackler
formatting: blacken the codebase...
r43346
@eh.command(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'lfconvert',
Augie Fackler
formatting: blacken the codebase...
r43346 [
(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b's',
b'size',
b'',
_(b'minimum size (MB) for files to be converted as largefiles'),
b'SIZE',
Augie Fackler
formatting: blacken the codebase...
r43346 ),
(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'',
b'to-normal',
Augie Fackler
formatting: blacken the codebase...
r43346 False,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'convert from a largefiles repo to a normal repo'),
Augie Fackler
formatting: blacken the codebase...
r43346 ),
Gregory Szorc
largefiles: declare commands using decorator
r21242 ],
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'hg lfconvert SOURCE DEST [FILE ...]'),
Gregory Szorc
largefiles: define inferrepo in command decorator
r21785 norepo=True,
Augie Fackler
formatting: blacken the codebase...
r43346 inferrepo=True,
)
various
hgext: add largefiles extension...
r15168 def lfconvert(ui, src, dest, *pats, **opts):
Greg Ward
largefiles: improve help...
r15230 '''convert a normal repository to a largefiles repository
various
hgext: add largefiles extension...
r15168
Greg Ward
largefiles: improve help...
r15230 Convert repository SOURCE to a new repository DEST, identical to
SOURCE except that certain files will be converted as largefiles:
specifically, any file that matches any PATTERN *or* whose size is
above the minimum size threshold is converted as a largefile. The
size used to determine whether or not to track a file as a
largefile is the size of the first version of the file. The
minimum size can be specified either with --size or in
configuration as ``largefiles.size``.
After running this command you will need to make sure that
largefiles is enabled anywhere you intend to push the new
repository.
Greg Ward
largefiles: rename lfconvert --tonormal option to --to-normal
r15332 Use --to-normal to convert largefiles back to normal files; after
Greg Ward
largefiles: improve help...
r15230 this, the DEST repository can be used without largefiles at all.'''
various
hgext: add largefiles extension...
r15168
Pulkit Goyal
py3: handle keyword arguments correctly in hgext/largefiles/...
r35349 opts = pycompat.byteskwargs(opts)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts[b'to_normal']:
various
hgext: add largefiles extension...
r15168 tolfile = False
else:
tolfile = True
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 size = lfutil.getminsize(ui, True, opts.get(b'size'), default=None)
Greg Ward
largefiles: rearrange how lfconvert detects non-local repos...
r15340
if not hg.islocal(src):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'%s is not a local Mercurial repo') % src)
Greg Ward
largefiles: rearrange how lfconvert detects non-local repos...
r15340 if not hg.islocal(dest):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'%s is not a local Mercurial repo') % dest)
Greg Ward
largefiles: rearrange how lfconvert detects non-local repos...
r15340
Greg Ward
largefiles: test lfconvert error handling; remove redundant code
r15339 rsrc = hg.repository(ui, src)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b'initializing destination %s\n') % dest)
Greg Ward
largefiles: test lfconvert error handling; remove redundant code
r15339 rdst = hg.repository(ui, dest, create=True)
various
hgext: add largefiles extension...
r15168
Matt Mackall
largefiles: eliminate naked exceptions
r15171 success = False
Mads Kiilerich
largefiles: use wlock for lfconvert (issue3444)...
r16717 dstwlock = dstlock = None
various
hgext: add largefiles extension...
r15168 try:
# Get a list of all changesets in the source. The easy way to do this
Mads Kiilerich
fix trivial spelling errors
r17424 # is to simply walk the changelog, using changelog.nodesbetween().
various
hgext: add largefiles extension...
r15168 # Take a look at mercurial/revlog.py:639 for more details.
# Use a generator instead of a list to decrease memory usage
Augie Fackler
formatting: blacken the codebase...
r43346 ctxs = (
rsrc[ctx]
for ctx in rsrc.changelog.nodesbetween(None, rsrc.heads())[0]
)
various
hgext: add largefiles extension...
r15168 revmap = {node.nullid: node.nullid}
if tolfile:
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325 # Lock destination to prevent modification while it is converted to.
# Don't need to lock src because we are just reading from its
# history which can't change.
dstwlock = rdst.wlock()
dstlock = rdst.lock()
various
hgext: add largefiles extension...
r15168 lfiles = set()
normalfiles = set()
if not pats:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 pats = ui.configlist(lfutil.longname, b'patterns')
various
hgext: add largefiles extension...
r15168 if pats:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 matcher = matchmod.match(rsrc.root, b'', list(pats))
various
hgext: add largefiles extension...
r15168 else:
matcher = None
lfiletohash = {}
Augie Fackler
formatting: blacken the codebase...
r43346 with ui.makeprogress(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'converting revisions'),
unit=_(b'revisions'),
total=rsrc[b'tip'].rev(),
Augie Fackler
formatting: blacken the codebase...
r43346 ) as progress:
Matt Harbison
largefiles: use a context manager to control the progress bar lifetime
r39427 for ctx in ctxs:
progress.update(ctx.rev())
Augie Fackler
formatting: blacken the codebase...
r43346 _lfconvert_addchangeset(
rsrc,
rdst,
ctx,
revmap,
lfiles,
normalfiles,
matcher,
size,
lfiletohash,
)
various
hgext: add largefiles extension...
r15168
liscju
largefiles: replace invocation of os.path module by vfs in lfcommands.py
r28559 if rdst.wvfs.exists(lfutil.shortname):
rdst.wvfs.rmtree(lfutil.shortname)
various
hgext: add largefiles extension...
r15168
for f in lfiletohash.keys():
liscju
largefiles: replace invocation of os.path module by vfs in lfcommands.py
r28559 if rdst.wvfs.isfile(f):
rdst.wvfs.unlink(f)
various
hgext: add largefiles extension...
r15168 try:
liscju
largefiles: replace invocation of os.path module by vfs in lfcommands.py
r28559 rdst.wvfs.removedirs(rdst.wvfs.dirname(f))
Matt Mackall
largefiles: eliminate naked exceptions
r15171 except OSError:
various
hgext: add largefiles extension...
r15168 pass
Eli Carter
largefiles: include 'largefiles' in converted repository requirements
r15303 # If there were any files converted to largefiles, add largefiles
# to the destination repository's requirements.
if lfiles:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 rdst.requirements.add(b'largefiles')
Eli Carter
largefiles: include 'largefiles' in converted repository requirements
r15303 rdst._writerequirements()
various
hgext: add largefiles extension...
r15168 else:
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325 class lfsource(filemap.filemap_source):
def __init__(self, ui, source):
super(lfsource, self).__init__(ui, source, None)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.filemapper.rename[lfutil.shortname] = b'.'
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325
def getfile(self, name, rev):
realname, realrev = rev
f = super(lfsource, self).getfile(name, rev)
Augie Fackler
formatting: blacken the codebase...
r43346 if (
not realname.startswith(lfutil.shortnameslash)
or f[0] is None
):
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325 return f
# Substitute in the largefile data for the hash
hash = f[0].strip()
path = lfutil.findfile(rsrc, hash)
various
hgext: add largefiles extension...
r15168
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325 if path is None:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"missing largefile for '%s' in %s")
Augie Fackler
formatting: blacken the codebase...
r43346 % (realname, realrev)
)
Bryan O'Sullivan
largefiles: use util.readfile in lfconvert
r27774 return util.readfile(path), f[1]
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325
class converter(convcmd.converter):
def __init__(self, ui, source, dest, revmapfile, opts):
src = lfsource(ui, source)
Augie Fackler
formatting: blacken the codebase...
r43346 super(converter, self).__init__(
ui, src, dest, revmapfile, opts
)
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325
found, missing = downloadlfiles(ui, rsrc)
if missing != 0:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b"all largefiles must be present locally"))
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325
Matt Harbison
largefiles: restore the original converter class after lfconvert --to-normal...
r25560 orig = convcmd.converter
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325 convcmd.converter = converter
Matt Harbison
largefiles: restore the original converter class after lfconvert --to-normal...
r25560
try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 convcmd.convert(
ui, src, dest, source_type=b'hg', dest_type=b'hg'
)
Matt Harbison
largefiles: restore the original converter class after lfconvert --to-normal...
r25560 finally:
convcmd.converter = orig
Matt Mackall
largefiles: eliminate naked exceptions
r15171 success = True
various
hgext: add largefiles extension...
r15168 finally:
Matt Harbison
largefiles: use the convert extension for 'lfconvert --to-normal'...
r25325 if tolfile:
rdst.dirstate.clear()
release(dstlock, dstwlock)
Matt Mackall
largefiles: eliminate naked exceptions
r15171 if not success:
# we failed, remove the new directory
shutil.rmtree(rdst.root)
various
hgext: add largefiles extension...
r15168
Augie Fackler
formatting: blacken the codebase...
r43346
def _lfconvert_addchangeset(
rsrc, rdst, ctx, revmap, lfiles, normalfiles, matcher, size, lfiletohash
):
various
hgext: add largefiles extension...
r15168 # Convert src parents to dst parents
Levi Bard
largefiles: remove pasted code...
r15811 parents = _convertparents(ctx, revmap)
various
hgext: add largefiles extension...
r15168
# Generate list of changed files
Levi Bard
largefiles: remove pasted code...
r15811 files = _getchangedfiles(ctx, parents)
various
hgext: add largefiles extension...
r15168
dstfiles = []
for f in files:
if f not in lfiles and f not in normalfiles:
islfile = _islfile(f, ctx, matcher, size)
# If this file was renamed or copied then copy
Mads Kiilerich
fix trivial spelling errors
r17424 # the largefile-ness of its predecessor
various
hgext: add largefiles extension...
r15168 if f in ctx.manifest():
fctx = ctx.filectx(f)
Martin von Zweigbergk
largefiles: migrate to new method for getting copy info...
r41941 renamed = fctx.copysource()
Sean Farley
filectx: fix return of renamed...
r39746 if renamed is None:
# the code below assumes renamed to be a boolean or a list
# and won't quite work with the value None
renamed = False
Martin von Zweigbergk
largefiles: migrate to new method for getting copy info...
r41941 renamedlfile = renamed and renamed in lfiles
various
hgext: add largefiles extension...
r15168 islfile |= renamedlfile
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'l' in fctx.flags():
various
hgext: add largefiles extension...
r15168 if renamedlfile:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'renamed/copied largefile %s becomes symlink')
% f
Augie Fackler
formatting: blacken the codebase...
r43346 )
various
hgext: add largefiles extension...
r15168 islfile = False
if islfile:
lfiles.add(f)
else:
normalfiles.add(f)
if f in lfiles:
FUJIWARA Katsunori
largefiles: avoid redundant standin() invocations...
r31618 fstandin = lfutil.standin(f)
dstfiles.append(fstandin)
Greg Ward
largefiles: more work on cleaning up comments...
r15254 # largefile in manifest if it has not been removed/renamed
various
hgext: add largefiles extension...
r15168 if f in ctx.manifest():
Levi Bard
largefiles: don't reference uninitialized variable (issue3092)
r15808 fctx = ctx.filectx(f)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'l' in fctx.flags():
Martin von Zweigbergk
largefiles: migrate to new method for getting copy info...
r41941 renamed = fctx.copysource()
if renamed and renamed in lfiles:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(
_(b'largefile %s becomes symlink') % f
)
various
hgext: add largefiles extension...
r15168
Greg Ward
largefiles: more work on cleaning up comments...
r15254 # largefile was modified, update standins
Augie Fackler
hgext: replace references to hashlib.sha1 with hashutil.sha1...
r44519 m = hashutil.sha1(b'')
various
hgext: add largefiles extension...
r15168 m.update(ctx[f].data())
Pulkit Goyal
py3: use node.hex(m.digest()) instead of m.hexdigest()...
r40711 hash = node.hex(m.digest())
various
hgext: add largefiles extension...
r15168 if f not in lfiletohash or lfiletohash[f] != hash:
Mads Kiilerich
largefiles: use repo.wwrite for writing standins (issue3909)
r19089 rdst.wwrite(f, ctx[f].data(), ctx[f].flags())
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 executable = b'x' in ctx[f].flags()
Augie Fackler
formatting: blacken the codebase...
r43346 lfutil.writestandin(rdst, fstandin, hash, executable)
various
hgext: add largefiles extension...
r15168 lfiletohash[f] = hash
else:
# normal file
dstfiles.append(f)
def getfilectx(repo, memctx, f):
FUJIWARA Katsunori
largefiles: omit redundant isstandin() before splitstandin()...
r31613 srcfname = lfutil.splitstandin(f)
if srcfname is not None:
various
hgext: add largefiles extension...
r15168 # if the file isn't in the manifest then it was removed
FUJIWARA Katsunori
misc: update descriptions about removed file for filectxfn...
r31612 # or renamed, return None to indicate this
various
hgext: add largefiles extension...
r15168 try:
fctx = ctx.filectx(srcfname)
except error.LookupError:
Mads Kiilerich
convert: use None value for missing files instead of overloading IOError...
r22296 return None
Martin von Zweigbergk
largefiles: migrate to new method for getting copy info...
r41941 renamed = fctx.copysource()
various
hgext: add largefiles extension...
r15168 if renamed:
Greg Ward
largefiles: more work on cleaning up comments...
r15254 # standin is always a largefile because largefile-ness
various
hgext: add largefiles extension...
r15168 # doesn't change after rename or copy
Martin von Zweigbergk
largefiles: migrate to new method for getting copy info...
r41941 renamed = lfutil.standin(renamed)
various
hgext: add largefiles extension...
r15168
Augie Fackler
formatting: blacken the codebase...
r43346 return context.memfilectx(
repo,
memctx,
f,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 lfiletohash[srcfname] + b'\n',
b'l' in fctx.flags(),
b'x' in fctx.flags(),
Augie Fackler
formatting: blacken the codebase...
r43346 renamed,
)
various
hgext: add largefiles extension...
r15168 else:
Sean Farley
memfilectx: call super.__init__ instead of duplicating code...
r21689 return _getnormalcontext(repo, ctx, f, revmap)
various
hgext: add largefiles extension...
r15168
# Commit
Levi Bard
largefiles: remove pasted code...
r15811 _commitcontext(rdst, parents, ctx, dstfiles, getfilectx, revmap)
Augie Fackler
formatting: blacken the codebase...
r43346
Levi Bard
largefiles: remove pasted code...
r15811 def _commitcontext(rdst, parents, ctx, dstfiles, getfilectx, revmap):
Augie Fackler
formatting: blacken the codebase...
r43346 mctx = context.memctx(
rdst,
parents,
ctx.description(),
dstfiles,
getfilectx,
ctx.user(),
ctx.date(),
ctx.extra(),
)
various
hgext: add largefiles extension...
r15168 ret = rdst.commitctx(mctx)
FUJIWARA Katsunori
largefiles: move "copyalltostore" invocation into "markcommitted"...
r23276 lfutil.copyalltostore(rdst, ret)
Patrick Mezard
localrepo: add setparents() to adjust dirstate copies (issue3407)...
r16551 rdst.setparents(ret)
various
hgext: add largefiles extension...
r15168 revmap[ctx.node()] = rdst.changelog.tip()
Augie Fackler
formatting: blacken the codebase...
r43346
Levi Bard
largefiles: remove pasted code...
r15811 # Generate list of changed files
def _getchangedfiles(ctx, parents):
files = set(ctx.files())
if node.nullid not in parents:
mc = ctx.manifest()
Martin von Zweigbergk
largefiles: avoid walking full manifest...
r41445 for pctx in ctx.parents():
for fn in pctx.manifest().diff(mc):
files.add(fn)
Levi Bard
largefiles: remove pasted code...
r15811 return files
Augie Fackler
formatting: blacken the codebase...
r43346
Levi Bard
largefiles: remove pasted code...
r15811 # Convert src parents to dst parents
def _convertparents(ctx, revmap):
parents = []
for p in ctx.parents():
parents.append(revmap[p.node()])
while len(parents) < 2:
parents.append(node.nullid)
return parents
Augie Fackler
formatting: blacken the codebase...
r43346
Levi Bard
largefiles: remove pasted code...
r15811 # Get memfilectx for a normal file
Sean Farley
memfilectx: call super.__init__ instead of duplicating code...
r21689 def _getnormalcontext(repo, ctx, f, revmap):
Levi Bard
largefiles: remove pasted code...
r15811 try:
fctx = ctx.filectx(f)
except error.LookupError:
Mads Kiilerich
convert: use None value for missing files instead of overloading IOError...
r22296 return None
Martin von Zweigbergk
largefiles: migrate to new method for getting copy info...
r41941 renamed = fctx.copysource()
Levi Bard
largefiles: remove pasted code...
r15811
data = fctx.data()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if f == b'.hgtags':
Augie Fackler
formatting: blacken the codebase...
r43346 data = _converttags(repo.ui, revmap, data)
return context.memfilectx(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo, ctx, f, data, b'l' in fctx.flags(), b'x' in fctx.flags(), renamed
Augie Fackler
formatting: blacken the codebase...
r43346 )
Levi Bard
largefiles: remove pasted code...
r15811
# Remap tag data using a revision map
def _converttags(ui, revmap, data):
newdata = []
for line in data.splitlines():
try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 id, name = line.split(b' ', 1)
Levi Bard
largefiles: remove pasted code...
r15811 except ValueError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.warn(_(b'skipping incorrectly formatted tag %s\n') % line)
Levi Bard
largefiles: remove pasted code...
r15811 continue
try:
newid = node.bin(id)
except TypeError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.warn(_(b'skipping incorrectly formatted id %s\n') % id)
Levi Bard
largefiles: remove pasted code...
r15811 continue
try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 newdata.append(b'%s %s\n' % (node.hex(revmap[newid]), name))
Levi Bard
largefiles: remove pasted code...
r15811 except KeyError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.warn(_(b'no mapping for id %s\n') % id)
Levi Bard
largefiles: remove pasted code...
r15811 continue
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''.join(newdata)
Levi Bard
largefiles: remove pasted code...
r15811
Augie Fackler
formatting: blacken the codebase...
r43346
various
hgext: add largefiles extension...
r15168 def _islfile(file, ctx, matcher, size):
Greg Ward
largefiles: improve comments, internal docstrings...
r15252 '''Return true if file should be considered a largefile, i.e.
matcher matches it or it is larger than size.'''
# never store special .hg* files as largefiles
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if file == b'.hgtags' or file == b'.hgignore' or file == b'.hgsigs':
various
hgext: add largefiles extension...
r15168 return False
if matcher and matcher(file):
return True
try:
return ctx.filectx(file).size() >= size * 1024 * 1024
except error.LookupError:
return False
Augie Fackler
formatting: blacken the codebase...
r43346
various
hgext: add largefiles extension...
r15168 def uploadlfiles(ui, rsrc, rdst, files):
'''upload largefiles to the central store'''
Benjamin Pollack
largefiles: make the store primary, and the user cache secondary...
r15317 if not files:
various
hgext: add largefiles extension...
r15168 return
liscju
largefiles: make storefactory._openstore public...
r29355 store = storefactory.openstore(rsrc, rdst, put=True)
various
hgext: add largefiles extension...
r15168
at = 0
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.debug(b"sending statlfile command for %d largefiles\n" % len(files))
Na'Tosha Bard
largefiles: batch statlfile requests when pushing a largefiles repo (issue3386)...
r17127 retval = store.exists(files)
Augie Fackler
largfiles: replace filter() with listcomp when result needs to be a list...
r36329 files = [h for h in files if not retval[h]]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.debug(b"%d largefiles need to be uploaded\n" % len(files))
Na'Tosha Bard
largefiles: batch statlfile requests when pushing a largefiles repo (issue3386)...
r17127
Augie Fackler
formatting: blacken the codebase...
r43346 with ui.makeprogress(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'uploading largefiles'), unit=_(b'files'), total=len(files)
Augie Fackler
formatting: blacken the codebase...
r43346 ) as progress:
Matt Harbison
largefiles: use a context manager to control the progress bar lifetime
r39427 for hash in files:
progress.update(at)
source = lfutil.findfile(rsrc, hash)
if not source:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'largefile %s missing from store'
b' (needs to be uploaded)'
Augie Fackler
formatting: blacken the codebase...
r43346 )
% hash
)
Matt Harbison
largefiles: use a context manager to control the progress bar lifetime
r39427 # XXX check for errors here
store.put(source, hash)
at += 1
various
hgext: add largefiles extension...
r15168
Augie Fackler
formatting: blacken the codebase...
r43346
various
hgext: add largefiles extension...
r15168 def verifylfiles(ui, repo, all=False, contents=False):
Mads Kiilerich
largefiles: docstrings for verify methods
r18574 '''Verify that every largefile revision in the current changeset
various
hgext: add largefiles extension...
r15168 exists in the central store. With --contents, also verify that
Mads Kiilerich
largefiles: docstrings for verify methods
r18574 the contents of each local largefile file revision are correct (SHA-1 hash
various
hgext: add largefiles extension...
r15168 matches the revision ID). With --all, check every changeset in
this repository.'''
if all:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 revs = repo.revs(b'all()')
various
hgext: add largefiles extension...
r15168 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 revs = [b'.']
various
hgext: add largefiles extension...
r15168
liscju
largefiles: make storefactory._openstore public...
r29355 store = storefactory.openstore(repo)
various
hgext: add largefiles extension...
r15168 return store.verify(revs, contents=contents)
Augie Fackler
formatting: blacken the codebase...
r43346
Na'Tosha Bard
largefiles: optimize performance when updating (issue3440)...
r16700 def cachelfiles(ui, repo, node, filelist=None):
various
hgext: add largefiles extension...
r15168 '''cachelfiles ensures that all largefiles needed by the specified revision
are present in the repository's largefile cache.
returns a tuple (cached, missing). cached is the list of files downloaded
by this operation; missing is the list of files that were needed but could
not be found.'''
lfiles = lfutil.listlfiles(repo, node)
Na'Tosha Bard
largefiles: optimize performance when updating (issue3440)...
r16700 if filelist:
lfiles = set(lfiles) & set(filelist)
various
hgext: add largefiles extension...
r15168 toget = []
FUJIWARA Katsunori
largefiles: avoid redundant changectx looking up at each repetitions...
r31654 ctx = repo[node]
various
hgext: add largefiles extension...
r15168 for lfile in lfiles:
Mads Kiilerich
largefiles: simplify cachelfiles - don't spend a lot of time checking hashes...
r18728 try:
FUJIWARA Katsunori
largefiles: use readasstandin() to read hex hash directly from filectx...
r31740 expectedhash = lfutil.readasstandin(ctx[lfutil.standin(lfile)])
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as err:
Mads Kiilerich
largefiles: simplify cachelfiles - don't spend a lot of time checking hashes...
r18728 if err.errno == errno.ENOENT:
Augie Fackler
formatting: blacken the codebase...
r43346 continue # node must be None and standin wasn't found in wctx
Mads Kiilerich
largefiles: simplify cachelfiles - don't spend a lot of time checking hashes...
r18728 raise
if not lfutil.findfile(repo, expectedhash):
various
hgext: add largefiles extension...
r15168 toget.append((lfile, expectedhash))
if toget:
liscju
largefiles: make storefactory._openstore public...
r29355 store = storefactory.openstore(repo)
various
hgext: add largefiles extension...
r15168 ret = store.get(toget)
return ret
return ([], [])
Augie Fackler
formatting: blacken the codebase...
r43346
Na'Tosha Bard
largefiles: refactor downloading of all largefiles to generic function
r16691 def downloadlfiles(ui, repo, rev=None):
Martin von Zweigbergk
cleanup: rename "matchfn" to "match" where obviously a matcher...
r34085 match = scmutil.match(repo[None], [repo.wjoin(lfutil.shortname)], {})
Augie Fackler
formatting: blacken the codebase...
r43346
Na'Tosha Bard
largefiles: refactor downloading of all largefiles to generic function
r16691 def prepare(ctx, fns):
pass
Augie Fackler
formatting: blacken the codebase...
r43346
Na'Tosha Bard
largefiles: refactor downloading of all largefiles to generic function
r16691 totalsuccess = 0
totalmissing = 0
Augie Fackler
formatting: blacken the codebase...
r43346 if rev != []: # walkchangerevs on empty list would return all revs
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for ctx in cmdutil.walkchangerevs(repo, match, {b'rev': rev}, prepare):
Mads Kiilerich
largefiles: fix download of largefiles from an empty list of changesets...
r18722 success, missing = cachelfiles(ui, repo, ctx.node())
totalsuccess += len(success)
totalmissing += len(missing)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b"%d additional largefiles cached\n") % totalsuccess)
Na'Tosha Bard
largefiles: refactor downloading of all largefiles to generic function
r16691 if totalmissing > 0:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b"%d largefiles failed to download\n") % totalmissing)
Na'Tosha Bard
largefiles: refactor downloading of all largefiles to generic function
r16691 return totalsuccess, totalmissing
Augie Fackler
formatting: blacken the codebase...
r43346
def updatelfiles(
ui, repo, filelist=None, printmessage=None, normallookup=False
):
FUJIWARA Katsunori
largefiles: get function to write status messages via "getstatuswriter()"...
r23189 '''Update largefiles according to standins in the working directory
If ``printmessage`` is other than ``None``, it means "print (or
ignore, for false) message forcibly".
'''
statuswriter = lfutil.getstatuswriter(ui, repo, printmessage)
Bryan O'Sullivan
with: use context manager for wlock in updatelfiles
r27820 with repo.wlock():
various
hgext: add largefiles extension...
r15168 lfdirstate = lfutil.openlfdirstate(ui, repo)
lfiles = set(lfutil.listlfiles(repo)) | set(lfdirstate)
if filelist is not None:
FUJIWARA Katsunori
largefiles: update lfdirstate for unchanged largefiles during linear merging...
r22197 filelist = set(filelist)
various
hgext: add largefiles extension...
r15168 lfiles = [f for f in lfiles if f in filelist]
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063 update = {}
Matt Harbison
largefiles: pay attention to dropped standin files when updating largefiles...
r35175 dropped = set()
various
hgext: add largefiles extension...
r15168 updated, removed = 0, 0
liscju
largefiles: replace invocation of os.path module by vfs in lfcommands.py
r28559 wvfs = repo.wvfs
FUJIWARA Katsunori
largefiles: avoid redundant changectx looking up at each repetitions...
r31654 wctx = repo[None]
Mads Kiilerich
largefiles: inline _updatelfile, prepare for further refactorings
r20062 for lfile in lfiles:
Martin von Zweigbergk
largefiles: drop "rel" prefix from filename variables...
r41709 lfileorig = os.path.relpath(
Augie Fackler
formatting: blacken the codebase...
r43346 scmutil.backuppath(ui, repo, lfile), start=repo.root
)
Martin von Zweigbergk
largefiles: drop "rel" prefix from filename variables...
r41709 standin = lfutil.standin(lfile)
standinorig = os.path.relpath(
Augie Fackler
formatting: blacken the codebase...
r43346 scmutil.backuppath(ui, repo, standin), start=repo.root
)
Martin von Zweigbergk
largefiles: drop "rel" prefix from filename variables...
r41709 if wvfs.exists(standin):
Augie Fackler
formatting: blacken the codebase...
r43346 if wvfs.exists(standinorig) and wvfs.exists(lfile):
shutil.copyfile(wvfs.join(lfile), wvfs.join(lfileorig))
Martin von Zweigbergk
largefiles: drop "rel" prefix from filename variables...
r41709 wvfs.unlinkpath(standinorig)
expecthash = lfutil.readasstandin(wctx[standin])
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if expecthash != b'':
Augie Fackler
formatting: blacken the codebase...
r43346 if lfile not in wctx: # not switched to normal file
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if repo.dirstate[standin] != b'?':
Martin von Zweigbergk
largefiles: drop "rel" prefix from filename variables...
r41709 wvfs.unlinkpath(lfile, ignoremissing=True)
Matt Harbison
largefiles: pay attention to dropped standin files when updating largefiles...
r35175 else:
Martin von Zweigbergk
largefiles: drop "rel" prefix from filename variables...
r41709 dropped.add(lfile)
Matt Harbison
largefiles: pay attention to dropped standin files when updating largefiles...
r35175
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 # use normallookup() to allocate an entry in largefiles
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r24180 # dirstate to prevent lfilesrepo.status() from reporting
# missing files as removed.
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063 lfdirstate.normallookup(lfile)
update[lfile] = expecthash
Mads Kiilerich
largefiles: inline _updatelfile, prepare for further refactorings
r20062 else:
# Remove lfiles for which the standin is deleted, unless the
# lfile is added to the repository again. This happens when a
# largefile is converted back to a normal file: the standin
# disappears, but a new (normal) file appears as the lfile.
Augie Fackler
formatting: blacken the codebase...
r43346 if (
wvfs.exists(lfile)
and repo.dirstate.normalize(lfile) not in wctx
):
Martin von Zweigbergk
largefiles: drop "rel" prefix from filename variables...
r41709 wvfs.unlinkpath(lfile)
Mads Kiilerich
largefiles: inline _updatelfile, prepare for further refactorings
r20062 removed += 1
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063
# largefile processing might be slow and be interrupted - be prepared
lfdirstate.write()
if lfiles:
Matt Harbison
largefiles: pay attention to dropped standin files when updating largefiles...
r35175 lfiles = [f for f in lfiles if f not in dropped]
for f in dropped:
repo.wvfs.unlinkpath(lfutil.standin(f))
# This needs to happen for dropped files, otherwise they stay in
# the M state.
lfutil.synclfdirstate(repo, lfdirstate, f, normallookup)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 statuswriter(_(b'getting changed largefiles\n'))
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063 cachelfiles(ui, repo, None, lfiles)
for lfile in lfiles:
update1 = 0
expecthash = update.get(lfile)
if expecthash:
if not lfutil.copyfromcache(repo, expecthash, lfile):
# failed ... but already removed and set to normallookup
continue
# Synchronize largefile dirstate to the last modified
# time of the file
lfdirstate.normal(lfile)
update1 = 1
Mads Kiilerich
largefiles: clarify variable name holding file mode...
r30269 # copy the exec mode of largefile standin from the repository's
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063 # dirstate to its state in the lfdirstate.
Martin von Zweigbergk
largefiles: drop "rel" prefix from filename variables...
r41709 standin = lfutil.standin(lfile)
if wvfs.exists(standin):
Mads Kiilerich
largefiles: clarify variable name holding file mode...
r30269 # exec is decided by the users permissions using mask 0o100
Martin von Zweigbergk
largefiles: drop "rel" prefix from filename variables...
r41709 standinexec = wvfs.stat(standin).st_mode & 0o100
st = wvfs.stat(lfile)
Mads Kiilerich
largefiles: clarify variable name holding file mode...
r30269 mode = st.st_mode
if standinexec != mode & 0o100:
# first remove all X bits, then shift all R bits to X
mode &= ~0o111
Mads Kiilerich
largefiles: when setting/clearing x bit on largefiles, don't change other bits...
r30141 if standinexec:
Mads Kiilerich
largefiles: clarify variable name holding file mode...
r30269 mode |= (mode >> 2) & 0o111 & ~util.umask
Martin von Zweigbergk
largefiles: drop "rel" prefix from filename variables...
r41709 wvfs.chmod(lfile, mode)
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063 update1 = 1
updated += update1
FUJIWARA Katsunori
largefiles: factor out synchronization of lfdirstate for future use
r22095 lfutil.synclfdirstate(repo, lfdirstate, lfile, normallookup)
various
hgext: add largefiles extension...
r15168
lfdirstate.write()
FUJIWARA Katsunori
largefiles: get function to write status messages via "getstatuswriter()"...
r23189 if lfiles:
Augie Fackler
formatting: blacken the codebase...
r43346 statuswriter(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'%d largefiles updated, %d removed\n') % (updated, removed)
Augie Fackler
formatting: blacken the codebase...
r43346 )
various
hgext: add largefiles extension...
r15168
Augie Fackler
formatting: blacken the codebase...
r43346 @eh.command(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'lfpull',
[(b'r', b'rev', [], _(b'pull largefiles for these revisions'))]
Augie Fackler
formatting: blacken the codebase...
r43346 + cmdutil.remoteopts,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'-r REV... [-e CMD] [--remotecmd CMD] [SOURCE]'),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def lfpull(ui, repo, source=b"default", **opts):
Mads Kiilerich
largefiles: introduce lfpull command for pulling missing largefiles
r18976 """pull largefiles for the specified revisions from the specified source
Pull largefiles that are referenced from local changesets but missing
locally, pulling from a remote repository to the local cache.
If SOURCE is omitted, the 'default' path will be used.
See :hg:`help urls` for more information.
.. container:: verbose
Some examples:
- pull largefiles for all branch heads::
hg lfpull -r "head() and not closed()"
- pull largefiles on the default branch::
hg lfpull -r "branch(default)"
"""
repo.lfpullsource = source
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 revs = opts.get('rev', [])
Mads Kiilerich
largefiles: introduce lfpull command for pulling missing largefiles
r18976 if not revs:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'no revisions specified'))
Mads Kiilerich
largefiles: introduce lfpull command for pulling missing largefiles
r18976 revs = scmutil.revrange(repo, revs)
numcached = 0
for rev in revs:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.note(_(b'pulling largefiles for revision %d\n') % rev)
Mads Kiilerich
largefiles: introduce lfpull command for pulling missing largefiles
r18976 (cached, missing) = cachelfiles(ui, repo, rev)
numcached += len(cached)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b"%d largefiles cached\n") % numcached)
Boris Feld
largefiles: add a 'debuglfput' command to put largefile into the store...
r35579
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 @eh.command(b'debuglfput', [] + cmdutil.remoteopts, _(b'FILE'))
Boris Feld
largefiles: add a 'debuglfput' command to put largefile into the store...
r35579 def debuglfput(ui, repo, filepath, **kwargs):
hash = lfutil.hashfile(filepath)
storefactory.openstore(repo).put(filepath, hash)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.write(b'%s\n' % hash)
Boris Feld
largefiles: add a 'debuglfput' command to put largefile into the store...
r35579 return 0