##// END OF EJS Templates
largefiles: rely on main scoping for writing dirstate in `markcommitted`...
largefiles: rely on main scoping for writing dirstate in `markcommitted` Yeah, cleaner code.

File last commit:

r50914:eed104af default
r50945:22cd517b default
Show More
lfcommands.py
673 lines | 22.1 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.'''
various
hgext: add largefiles extension...
r15168
Manuel Jacob
node: stop converting binascii.Error to TypeError in bin()...
r50143 import binascii
liscju
py3: make largefiles/lfcommands.py use absolute_import
r29308 import os
various
hgext: add largefiles extension...
r15168 import shutil
from mercurial.i18n import _
Joerg Sonnenberger
node: import symbols explicitly...
r46729 from mercurial.node import (
bin,
hex,
)
various
hgext: add largefiles extension...
r15168
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,
Martin von Zweigbergk
errors: raise InputError on bad revset to revrange() iff provided by the user...
r48928 logcmdutil,
liscju
largefiles: rename match_ to matchmod import in lfcommands
r29317 match as matchmod,
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):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """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
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 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]
)
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 revmap = {rsrc.nullid: rdst.nullid}
various
hgext: add largefiles extension...
r15168 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')
Pulkit Goyal
scmutil: add writereporequirements() and route requires writing through it...
r45666 scmutil.writereporequirements(rdst)
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())
Joerg Sonnenberger
node: import symbols explicitly...
r46729 hash = 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())
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if ctx.repo().nullid not in parents:
Levi Bard
largefiles: remove pasted code...
r15811 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:
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 parents.append(ctx.repo().nullid)
Levi Bard
largefiles: remove pasted code...
r15811 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:
Joerg Sonnenberger
node: import symbols explicitly...
r46729 newid = bin(id)
Manuel Jacob
node: stop converting binascii.Error to TypeError in bin()...
r50143 except binascii.Error:
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:
Joerg Sonnenberger
node: import symbols explicitly...
r46729 newdata.append(b'%s %s\n' % (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):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Return true if file should be considered a largefile, i.e.
matcher matches it or it is larger than size."""
Greg Ward
largefiles: improve comments, internal docstrings...
r15252 # 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):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """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
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 this repository."""
various
hgext: add largefiles extension...
r15168 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):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """cachelfiles ensures that all largefiles needed by the specified revision
various
hgext: add largefiles extension...
r15168 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
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 not be found."""
various
hgext: add largefiles extension...
r15168 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)])
Manuel Jacob
py3: catch FileNotFoundError instead of checking errno == ENOENT
r50201 except FileNotFoundError:
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 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
Yuya Nishihara
largefiles: remove unused 'rev' parameter from downloadlfiles()...
r46025 def downloadlfiles(ui, repo):
Yuya Nishihara
largefiles: replace use of walkchangerevs() with simple revset query...
r46026 tonode = repo.changelog.node
Na'Tosha Bard
largefiles: refactor downloading of all largefiles to generic function
r16691 totalsuccess = 0
totalmissing = 0
Yuya Nishihara
largefiles: walk history in ascending order while downloading all lfiles...
r46027 for rev in repo.revs(b'file(%s)', b'path:' + lfutil.shortname):
Yuya Nishihara
largefiles: replace use of walkchangerevs() with simple revset query...
r46026 success, missing = cachelfiles(ui, repo, tonode(rev))
Yuya Nishihara
largefiles: remove unused 'rev' parameter from downloadlfiles()...
r46025 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
):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Update largefiles according to standins in the working directory
FUJIWARA Katsunori
largefiles: get function to write status messages via "getstatuswriter()"...
r23189
If ``printmessage`` is other than ``None``, it means "print (or
ignore, for false) message forcibly".
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
FUJIWARA Katsunori
largefiles: get function to write status messages via "getstatuswriter()"...
r23189 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]
largefiles: remove the first `changing_parents` in `updatelfiles`...
r50913 update = {}
dropped = set()
updated, removed = 0, 0
wvfs = repo.wvfs
wctx = repo[None]
for lfile in lfiles:
lfileorig = os.path.relpath(
scmutil.backuppath(ui, repo, lfile), start=repo.root
)
standin = lfutil.standin(lfile)
standinorig = os.path.relpath(
scmutil.backuppath(ui, repo, standin), start=repo.root
)
if wvfs.exists(standin):
if wvfs.exists(standinorig) and wvfs.exists(lfile):
shutil.copyfile(wvfs.join(lfile), wvfs.join(lfileorig))
wvfs.unlinkpath(standinorig)
expecthash = lfutil.readasstandin(wctx[standin])
if expecthash != b'':
if lfile not in wctx: # not switched to normal file
if repo.dirstate.get_entry(standin).any_tracked:
wvfs.unlinkpath(lfile, ignoremissing=True)
else:
dropped.add(lfile)
Matt Harbison
largefiles: pay attention to dropped standin files when updating largefiles...
r35175
largefiles: remove the first `changing_parents` in `updatelfiles`...
r50913 # allocate an entry in largefiles dirstate to prevent
# lfilesrepo.status() from reporting missing files as
# removed.
lfdirstate.hacky_extension_update_file(
lfile,
p1_tracked=True,
wc_tracked=True,
possibly_dirty=True,
)
update[lfile] = expecthash
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.
if (
wvfs.exists(lfile)
and repo.dirstate.normalize(lfile) not in wctx
):
wvfs.unlinkpath(lfile)
removed += 1
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063
# largefile processing might be slow and be interrupted - be prepared
Pulkit Goyal
largefiles: pass current transaction to `lfdirstate.write()`...
r48982 lfdirstate.write(repo.currenttransaction())
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063
Pulkit Goyal
largefiles: replace use of synclfdirstate with drop...
r48458 if lfiles:
lfiles = [f for f in lfiles if f not in dropped]
Matt Harbison
largefiles: pay attention to dropped standin files when updating largefiles...
r35175
Pulkit Goyal
largefiles: replace use of synclfdirstate with drop...
r48458 for f in dropped:
repo.wvfs.unlinkpath(lfutil.standin(f))
# This needs to happen for dropped files, otherwise they stay in
# the M state.
dirstate: use `reset_state` instead of `dropfile` in largefile...
r48815 lfdirstate._map.reset_state(f)
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063
Pulkit Goyal
largefiles: replace use of synclfdirstate with drop...
r48458 statuswriter(_(b'getting changed largefiles\n'))
cachelfiles(ui, repo, None, lfiles)
largefile: consider `updatelfiles` as a `parentchange`...
r48451
largefiles: remove the second `changing_parents` in `updatelfiles`...
r50914 for lfile in lfiles:
update1 = 0
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063
largefiles: remove the second `changing_parents` in `updatelfiles`...
r50914 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.hacky_extension_update_file(
lfile,
p1_tracked=True,
wc_tracked=True,
)
update1 = 1
# copy the exec mode of largefile standin from the repository's
# dirstate to its state in the lfdirstate.
standin = lfutil.standin(lfile)
if wvfs.exists(standin):
# exec is decided by the users permissions using mask 0o100
standinexec = wvfs.stat(standin).st_mode & 0o100
st = wvfs.stat(lfile)
mode = st.st_mode
if standinexec != mode & 0o100:
# first remove all X bits, then shift all R bits to X
mode &= ~0o111
if standinexec:
mode |= (mode >> 2) & 0o111 & ~util.umask
wvfs.chmod(lfile, mode)
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063 update1 = 1
largefiles: remove the second `changing_parents` in `updatelfiles`...
r50914 updated += update1
Mads Kiilerich
largefiles: update in two steps, handle interrupted updates better...
r20063
largefiles: remove the second `changing_parents` in `updatelfiles`...
r50914 lfutil.synclfdirstate(repo, lfdirstate, lfile, normallookup)
various
hgext: add largefiles extension...
r15168
Pulkit Goyal
largefiles: pass current transaction to `lfdirstate.write()`...
r48982 lfdirstate.write(repo.currenttransaction())
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'))
Martin von Zweigbergk
errors: raise InputError on bad revset to revrange() iff provided by the user...
r48928 revs = logcmdutil.revrange(repo, revs)
Mads Kiilerich
largefiles: introduce lfpull command for pulling missing largefiles
r18976
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