def push(self, remote, force=False, revs=None, newbranch=False): outgoing = discovery.findcommonoutgoing(repo, remote.peer(), force=force) if outgoing.missing: toupload = set() o = self.changelog.nodesbetween(outgoing.missing, revs)[0] for n in o: parents = [p for p in self.changelog.parents(n) if p != node_.nullid] ctx = self[n] files = set(ctx.files()) if len(parents) == 2: mc = ctx.manifest() mp1 = ctx.parents()[0].manifest() mp2 = ctx.parents()[1].manifest() for f in mp1: if f not in mc: files.add(f) for f in mp2: if f not in mc: files.add(f) for f in mc: if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None): files.add(f) toupload = toupload.union( set([ctx[f].data().strip() for f in files if lfutil.isstandin(f) and f in ctx])) lfcommands.uploadlfiles(ui, self, remote, toupload) return super(lfilesrepo, self).push(remote, force, revs, newbranch)
def push(self, remote, force=False, revs=None, newbranch=False): o = lfutil.findoutgoing(repo, remote, force) if o: toupload = set() o = repo.changelog.nodesbetween(o, revs)[0] for n in o: parents = [p for p in repo.changelog.parents(n) if p != node_.nullid] ctx = repo[n] files = set(ctx.files()) if len(parents) == 2: mc = ctx.manifest() mp1 = ctx.parents()[0].manifest() mp2 = ctx.parents()[1].manifest() for f in mp1: if f not in mc: files.add(f) for f in mp2: if f not in mc: files.add(f) for f in mc: if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None): files.add(f) toupload = toupload.union( set([ctx[f].data().strip() for f in files if lfutil.isstandin(f) and f in ctx])) lfcommands.uploadlfiles(ui, self, remote, toupload) return super(lfilesrepo, self).push(remote, force, revs, newbranch)
def _subdirlfs(self, files, lfiles): ''' Adjust matched file list If we pass a directory to commit whose only committable files are largefiles, the core commit code aborts before finding the largefiles. So we do the following: For directories that only have largefiles as matches, we explicitly add the largefiles to the match list and remove the directory. In other cases, we leave the match list unmodified. ''' actualfiles = [] dirs = [] regulars = [] for f in files: if lfutil.isstandin(f + '/'): raise error.Abort( _('file "%s" is a largefile standin') % f, hint=('commit the largefile itself instead')) # Scan directories if self.wvfs.isdir(f): dirs.append(f) else: regulars.append(f) for f in dirs: matcheddir = False d = self.dirstate.normalize(f) + '/' # Check for matched normal files for mf in regulars: if self.dirstate.normalize(mf).startswith(d): actualfiles.append(f) matcheddir = True break if not matcheddir: # If no normal match, manually append # any matching largefiles for lf in lfiles: if self.dirstate.normalize(lf).startswith(d): actualfiles.append(lf) if not matcheddir: # There may still be normal files in the dir, so # add a directory to the list, which # forces status/dirstate to walk all files and # call the match function on the matcher, even # on case sensitive filesystems. actualfiles.append('.') matcheddir = True # Nothing in dir, so readd it # and let commit reject it if not matcheddir: actualfiles.append(f) # Always add normal files actualfiles += regulars return actualfiles
def _subdirlfs(self, files, lfiles): ''' Adjust matched file list If we pass a directory to commit whose only committable files are largefiles, the core commit code aborts before finding the largefiles. So we do the following: For directories that only have largefiles as matches, we explicitly add the largefiles to the match list and remove the directory. In other cases, we leave the match list unmodified. ''' actualfiles = [] dirs = [] regulars = [] for f in files: if lfutil.isstandin(f + '/'): raise error.Abort( _('file "%s" is a largefile standin') % f, hint=('commit the largefile itself instead')) # Scan directories if os.path.isdir(self.wjoin(f)): dirs.append(f) else: regulars.append(f) for f in dirs: matcheddir = False d = self.dirstate.normalize(f) + '/' # Check for matched normal files for mf in regulars: if self.dirstate.normalize(mf).startswith(d): actualfiles.append(f) matcheddir = True break if not matcheddir: # If no normal match, manually append # any matching largefiles for lf in lfiles: if self.dirstate.normalize(lf).startswith(d): actualfiles.append(lf) if not matcheddir: # There may still be normal files in the dir, so # add a directory to the list, which # forces status/dirstate to walk all files and # call the match function on the matcher, even # on case sensitive filesystems. actualfiles.append('.') matcheddir = True # Nothing in dir, so readd it # and let commit reject it if not matcheddir: actualfiles.append(f) # Always add normal files actualfiles += regulars return actualfiles
def commitctx(self, *args, **kwargs): node = super(lfiles_repo, self).commitctx(*args, **kwargs) ctx = self[node] for filename in ctx.files(): if lfutil.isstandin(filename) and filename in ctx.manifest(): realfile = lfutil.splitstandin(filename) lfutil.copytostore(self, ctx.node(), realfile) return node
def override_match(ctx, pats=[], opts={}, globbed=False, default="relpath"): match = oldmatch(ctx, pats, opts, globbed, default) m = copy.copy(match) notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in manifest) m._files = filter(notlfile, m._files) m._fmap = set(m._files) orig_matchfn = m.matchfn m.matchfn = lambda f: notlfile(f) and orig_matchfn(f) or None return m
def overridematch(ctx, pats=[], opts={}, globbed=False, default='relpath'): match = oldmatch(ctx, pats, opts, globbed, default) m = copy.copy(match) notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in manifest) m._files = filter(notlfile, m._files) m._fmap = set(m._files) m._always = False origmatchfn = m.matchfn m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None return m
def _subdirlfs(self, files, lfiles): """ Adjust matched file list If we pass a directory to commit whose only commitable files are largefiles, the core commit code aborts before finding the largefiles. So we do the following: For directories that only have largefiles as matches, we explicitly add the largefiles to the match list and remove the directory. In other cases, we leave the match list unmodified. """ actualfiles = [] dirs = [] regulars = [] for f in files: if lfutil.isstandin(f + "/"): raise util.Abort( _('file "%s" is a largefile standin') % f, hint=("commit the largefile itself instead") ) # Scan directories if os.path.isdir(self.wjoin(f)): dirs.append(f) else: regulars.append(f) for f in dirs: matcheddir = False d = self.dirstate.normalize(f) + "/" # Check for matched normal files for mf in regulars: if self.dirstate.normalize(mf).startswith(d): actualfiles.append(f) matcheddir = True break if not matcheddir: # If no normal match, manually append # any matching largefiles for lf in lfiles: if self.dirstate.normalize(lf).startswith(d): actualfiles.append(lf) if not matcheddir: actualfiles.append(lfutil.standin(f)) matcheddir = True # Nothing in dir, so readd it # and let commit reject it if not matcheddir: actualfiles.append(f) # Always add normal files actualfiles += regulars return actualfiles
def _addchangeset(ui, rsrc, rdst, ctx, revmap): # Convert src parents to dst parents parents = _convertparents(ctx, revmap) # Generate list of changed files files = _getchangedfiles(ctx, parents) def getfilectx(repo, memctx, f): if lfutil.standin(f) in files: # if the file isn't in the manifest then it was removed # or renamed, raise IOError to indicate this try: fctx = ctx.filectx(lfutil.standin(f)) except error.LookupError: return None renamed = fctx.renamed() if renamed: renamed = lfutil.splitstandin(renamed[0]) hash = fctx.data().strip() path = lfutil.findfile(rsrc, hash) # If one file is missing, likely all files from this rev are if path is None: cachelfiles(ui, rsrc, ctx.node()) path = lfutil.findfile(rsrc, hash) if path is None: raise util.Abort( _("missing largefile \'%s\' from revision %s") % (f, node.hex(ctx.node()))) data = '' fd = None try: fd = open(path, 'rb') data = fd.read() finally: if fd: fd.close() return context.memfilectx(repo, f, data, 'l' in fctx.flags(), 'x' in fctx.flags(), renamed) else: return _getnormalcontext(repo, ctx, f, revmap) dstfiles = [] for file in files: if lfutil.isstandin(file): dstfiles.append(lfutil.splitstandin(file)) else: dstfiles.append(file) # Commit _commitcontext(rdst, parents, ctx, dstfiles, getfilectx, revmap)
def _addchangeset(ui, rsrc, rdst, ctx, revmap): # Convert src parents to dst parents parents = _convertparents(ctx, revmap) # Generate list of changed files files = _getchangedfiles(ctx, parents) def getfilectx(repo, memctx, f): if lfutil.standin(f) in files: # if the file isn't in the manifest then it was removed # or renamed, raise IOError to indicate this try: fctx = ctx.filectx(lfutil.standin(f)) except error.LookupError: raise IOError renamed = fctx.renamed() if renamed: renamed = lfutil.splitstandin(renamed[0]) hash = fctx.data().strip() path = lfutil.findfile(rsrc, hash) # If one file is missing, likely all files from this rev are if path is None: cachelfiles(ui, rsrc, ctx.node()) path = lfutil.findfile(rsrc, hash) if path is None: raise util.Abort( _("missing largefile \'%s\' from revision %s") % (f, node.hex(ctx.node()))) data = '' fd = None try: fd = open(path, 'rb') data = fd.read() finally: if fd: fd.close() return context.memfilectx(repo, f, data, 'l' in fctx.flags(), 'x' in fctx.flags(), renamed) else: return _getnormalcontext(repo, ctx, f, revmap) dstfiles = [] for file in files: if lfutil.isstandin(file): dstfiles.append(lfutil.splitstandin(file)) else: dstfiles.append(file) # Commit _commitcontext(rdst, parents, ctx, dstfiles, getfilectx, revmap)
def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca): if not lfutil.isstandin(orig): return origfn(repo, mynode, orig, fcd, fco, fca) ahash = fca.data().strip().lower() dhash = fcd.data().strip().lower() ohash = fco.data().strip().lower() if (ohash != ahash and ohash != dhash and (dhash == ahash or repo.ui.promptchoice( _('largefile %s has a merge conflict\nancestor was %s\n' 'keep (l)ocal %s or\ntake (o)ther %s?' '$$ &Local $$ &Other') % (lfutil.splitstandin(orig), ahash, dhash, ohash), 0) == 1)): repo.wwrite(fcd.path(), fco.data(), fco.flags()) return 0
def matchfn(f): if lfutil.isstandin(f): # We need to keep track of what largefiles are being # matched so we know which ones to update later -- # otherwise we accidentally revert changes to other # largefiles. This is repo-specific, so duckpunch the # repo object to keep the list of largefiles for us # later. if orig_matchfn(lfutil.splitstandin(f)) and (f in repo[None] or f in ctx): lfileslist = getattr(repo, "_lfilestoupdate", []) lfileslist.append(lfutil.splitstandin(f)) repo._lfilestoupdate = lfileslist return True else: return False return orig_matchfn(f)
def matchfn(f): if lfutil.isstandin(f): # We need to keep track of what largefiles are being # matched so we know which ones to update later -- # otherwise we accidentally revert changes to other # largefiles. This is repo-specific, so duckpunch the # repo object to keep the list of largefiles for us # later. if origmatchfn(lfutil.splitstandin(f)) and \ (f in repo[None] or f in ctx): lfileslist = getattr(repo, '_lfilestoupdate', []) lfileslist.append(lfutil.splitstandin(f)) repo._lfilestoupdate = lfileslist return True else: return False return origmatchfn(f)
def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None): repo._get(repo._state + ('hg', )) rev = repo._state[1] ctx = repo._repo[rev] lfcommands.cachelfiles(ui, repo._repo, ctx.node()) def write(name, mode, islink, getdata): # At this point, the standin has been replaced with the largefile name, # so the normal matcher works here without the lfutil variants. if match and not match(f): return data = getdata() archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data) for f in ctx: ff = ctx.flags(f) getdata = ctx[f].data if lfutil.isstandin(f): path = lfutil.findfile(repo._repo, getdata().strip()) if path is None: raise util.Abort( _('largefile %s not found in repo store or system cache') % lfutil.splitstandin(f)) f = lfutil.splitstandin(f) def getdatafn(): fd = None try: fd = open(os.path.join(prefix, path), 'rb') return fd.read() finally: if fd: fd.close() getdata = getdatafn write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata) for subpath in sorted(ctx.substate): sub = ctx.sub(subpath) submatch = match_.narrowmatcher(subpath, match) sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/', submatch)
def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None): repo._get(repo._state + ('hg',)) rev = repo._state[1] ctx = repo._repo[rev] lfcommands.cachelfiles(ui, repo._repo, ctx.node()) def write(name, mode, islink, getdata): # At this point, the standin has been replaced with the largefile name, # so the normal matcher works here without the lfutil variants. if match and not match(f): return data = getdata() archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data) for f in ctx: ff = ctx.flags(f) getdata = ctx[f].data if lfutil.isstandin(f): path = lfutil.findfile(repo._repo, getdata().strip()) if path is None: raise util.Abort( _('largefile %s not found in repo store or system cache') % lfutil.splitstandin(f)) f = lfutil.splitstandin(f) def getdatafn(): fd = None try: fd = open(os.path.join(prefix, path), 'rb') return fd.read() finally: if fd: fd.close() getdata = getdatafn write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata) for subpath in sorted(ctx.substate): sub = ctx.sub(subpath) submatch = match_.narrowmatcher(subpath, match) sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/', submatch)
def getfilectx(repo, memctx, f): if lfutil.isstandin(f): # if the file isn't in the manifest then it was removed # or renamed, raise IOError to indicate this srcfname = lfutil.splitstandin(f) try: fctx = ctx.filectx(srcfname) except error.LookupError: raise IOError() renamed = fctx.renamed() if renamed: # standin is always a largefile because largefile-ness # doesn't change after rename or copy renamed = lfutil.standin(renamed[0]) return context.memfilectx(f, lfiletohash[srcfname] + '\n', 'l' in fctx.flags(), 'x' in fctx.flags(), renamed) else: return _getnormalcontext(repo.ui, ctx, f, revmap)
def _addchangeset(ui, rsrc, rdst, ctx, revmap): # Convert src parents to dst parents parents = _convertparents(ctx, revmap) # Generate list of changed files files = _getchangedfiles(ctx, parents) def getfilectx(repo, memctx, f): if lfutil.standin(f) in files: # if the file isn't in the manifest then it was removed # or renamed, raise IOError to indicate this try: fctx = ctx.filectx(lfutil.standin(f)) except error.LookupError: raise IOError() renamed = fctx.renamed() if renamed: renamed = lfutil.splitstandin(renamed[0]) hash = fctx.data().strip() path = lfutil.findfile(rsrc, hash) ### TODO: What if the file is not cached? data = '' fd = None try: fd = open(path, 'rb') data = fd.read() finally: if fd: fd.close() return context.memfilectx(f, data, 'l' in fctx.flags(), 'x' in fctx.flags(), renamed) else: return _getnormalcontext(repo.ui, ctx, f, revmap) dstfiles = [] for file in files: if lfutil.isstandin(file): dstfiles.append(lfutil.splitstandin(file)) else: dstfiles.append(file) # Commit _commitcontext(rdst, parents, ctx, dstfiles, getfilectx, revmap)
def getfilectx(repo, memctx, f): if lfutil.isstandin(f): # if the file isn't in the manifest then it was removed # or renamed, raise IOError to indicate this srcfname = lfutil.splitstandin(f) try: fctx = ctx.filectx(srcfname) except error.LookupError: raise IOError renamed = fctx.renamed() if renamed: # standin is always a largefile because largefile-ness # doesn't change after rename or copy renamed = lfutil.standin(renamed[0]) return context.memfilectx(f, lfiletohash[srcfname] + '\n', 'l' in fctx.flags(), 'x' in fctx.flags(), renamed) else: return _getnormalcontext(repo.ui, ctx, f, revmap)
def push(self, remote, force=False, revs=None, newbranch=False): if remote.local(): missing = set(self.requirements) - remote.local().supported if missing: msg = _("required features are not" " supported in the destination:" " %s") % (', '.join(sorted(missing))) raise util.Abort(msg) outgoing = discovery.findcommonoutgoing(repo, remote.peer(), force=force) if outgoing.missing: toupload = set() o = self.changelog.nodesbetween(outgoing.missing, revs)[0] for n in o: parents = [p for p in self.changelog.parents(n) if p != node_.nullid] ctx = self[n] files = set(ctx.files()) if len(parents) == 2: mc = ctx.manifest() mp1 = ctx.parents()[0].manifest() mp2 = ctx.parents()[1].manifest() for f in mp1: if f not in mc: files.add(f) for f in mp2: if f not in mc: files.add(f) for f in mc: if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None): files.add(f) toupload = toupload.union( set([ctx[f].data().strip() for f in files if lfutil.isstandin(f) and f in ctx])) lfcommands.uploadlfiles(ui, self, remote, toupload) return super(lfilesrepo, self).push(remote, force, revs, newbranch)
def getoutgoinglfiles(ui, repo, dest=None, **opts): dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest, opts.get('branch')) revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev')) if revs: revs = [repo.lookup(rev) for rev in revs] remoteui = hg.remoteui try: remote = hg.repository(remoteui(repo, opts), dest) except error.RepoError: return None o = lfutil.findoutgoing(repo, remote, False) if not o: return None o = repo.changelog.nodesbetween(o, revs)[0] if opts.get('newest_first'): o.reverse() toupload = set() for n in o: parents = [p for p in repo.changelog.parents(n) if p != node.nullid] ctx = repo[n] files = set(ctx.files()) if len(parents) == 2: mc = ctx.manifest() mp1 = ctx.parents()[0].manifest() mp2 = ctx.parents()[1].manifest() for f in mp1: if f not in mc: files.add(f) for f in mp2: if f not in mc: files.add(f) for f in mc: if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None): files.add(f) toupload = toupload.union( set([f for f in files if lfutil.isstandin(f) and f in ctx])) return toupload
def override_match(ctx, pats=[], opts={}, globbed=False, default='relpath'): newpats = [] # The patterns were previously mangled to add the standin # directory; we need to remove that now for pat in pats: if match_.patkind(pat) is None and lfutil.shortname in pat: newpats.append(pat.replace(lfutil.shortname, '')) else: newpats.append(pat) match = oldmatch(ctx, newpats, opts, globbed, default) m = copy.copy(match) lfile = lambda f: lfutil.standin(f) in manifest m._files = [lfutil.standin(f) for f in m._files if lfile(f)] m._fmap = set(m._files) orig_matchfn = m.matchfn m.matchfn = lambda f: (lfutil.isstandin(f) and lfile(lfutil.splitstandin(f)) and orig_matchfn(lfutil.splitstandin(f)) or None) return m
def override_filemerge(origfn, repo, mynode, orig, fcd, fco, fca): # Use better variable names here. Because this is a wrapper we cannot # change the variable names in the function declaration. fcdest, fcother, fcancestor = fcd, fco, fca if not lfutil.isstandin(orig): return origfn(repo, mynode, orig, fcdest, fcother, fcancestor) else: if not fcother.cmp(fcdest): # files identical? return None # backwards, use working dir parent as ancestor if fcancestor == fcother: fcancestor = fcdest.parents()[0] if orig != fcother.path(): repo.ui.status( _("merging %s and %s to %s\n") % (lfutil.splitstandin(orig), lfutil.splitstandin(fcother.path()), lfutil.splitstandin(fcdest.path())) ) else: repo.ui.status(_("merging %s\n") % lfutil.splitstandin(fcdest.path())) if fcancestor.path() != fcother.path() and fcother.data() == fcancestor.data(): return 0 if fcancestor.path() != fcdest.path() and fcdest.data() == fcancestor.data(): repo.wwrite(fcdest.path(), fcother.data(), fcother.flags()) return 0 if ( repo.ui.promptchoice( _("largefile %s has a merge conflict\n" "keep (l)ocal or take (o)ther?") % lfutil.splitstandin(orig), (_("&Local"), _("&Other")), 0, ) == 0 ): return 0 else: repo.wwrite(fcdest.path(), fcother.data(), fcother.flags()) return 0
def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca): # Use better variable names here. Because this is a wrapper we cannot # change the variable names in the function declaration. fcdest, fcother, fcancestor = fcd, fco, fca if not lfutil.isstandin(orig): return origfn(repo, mynode, orig, fcdest, fcother, fcancestor) else: if not fcother.cmp(fcdest): # files identical? return None # backwards, use working dir parent as ancestor if fcancestor == fcother: fcancestor = fcdest.parents()[0] if orig != fcother.path(): repo.ui.status( _('merging %s and %s to %s\n') % (lfutil.splitstandin(orig), lfutil.splitstandin( fcother.path()), lfutil.splitstandin(fcdest.path()))) else: repo.ui.status( _('merging %s\n') % lfutil.splitstandin(fcdest.path())) if fcancestor.path() != fcother.path() and fcother.data() == \ fcancestor.data(): return 0 if fcancestor.path() != fcdest.path() and fcdest.data() == \ fcancestor.data(): repo.wwrite(fcdest.path(), fcother.data(), fcother.flags()) return 0 if repo.ui.promptchoice( _('largefile %s has a merge conflict\n' 'keep (l)ocal or take (o)ther?') % lfutil.splitstandin(orig), (_('&Local'), _('&Other')), 0) == 0: return 0 else: repo.wwrite(fcdest.path(), fcother.data(), fcother.flags()) return 0
def override_match(ctx, pats=[], opts={}, globbed=False, default='relpath'): newpats = [] # The patterns were previously mangled to add the standin # directory; we need to remove that now for pat in pats: if match_.patkind(pat) is None and lfutil.shortname in pat: newpats.append(pat.replace(lfutil.shortname, '')) else: newpats.append(pat) match = oldmatch(ctx, newpats, opts, globbed, default) m = copy.copy(match) lfile = lambda f: lfutil.standin(f) in manifest m._files = [lfutil.standin(f) for f in m._files if lfile(f)] m._fmap = set(m._files) orig_matchfn = m.matchfn m.matchfn = lambda f: (lfutil.isstandin(f) and lfile( lfutil.splitstandin(f)) and orig_matchfn( lfutil.splitstandin(f)) or None) return m
def getfilectx(repo, memctx, f): if lfutil.isstandin(f): # if the file isn't in the manifest then it was removed # or renamed, raise IOError to indicate this srcfname = lfutil.splitstandin(f) try: fctx = ctx.filectx(srcfname) except error.LookupError: raise IOError() renamed = fctx.renamed() if renamed: # standin is always a largefile because largefile-ness # doesn't change after rename or copy renamed = lfutil.standin(renamed[0]) return context.memfilectx(f, lfiletohash[srcfname] + '\n', 'l' in fctx.flags(), 'x' in fctx.flags(), renamed) else: try: fctx = ctx.filectx(f) except error.LookupError: raise IOError() renamed = fctx.renamed() if renamed: renamed = renamed[0] data = fctx.data() if f == '.hgtags': newdata = [] for line in data.splitlines(): id, name = line.split(' ', 1) newdata.append('%s %s\n' % (node.hex(revmap[node.bin(id)]), name)) data = ''.join(newdata) return context.memfilectx(f, data, 'l' in fctx.flags(), 'x' in fctx.flags(), renamed)
def status(self, node1='.', node2=None, match=None, ignored=False, clean=False, unknown=False, listsubrepos=False): listignored, listclean, listunknown = ignored, clean, unknown if not self.lfstatus: try: return super(lfiles_repo, self).status(node1, node2, match, listignored, listclean, listunknown, listsubrepos) except TypeError: return super(lfiles_repo, self).status(node1, node2, match, listignored, listclean, listunknown) else: # some calls in this function rely on the old version of status self.lfstatus = False if isinstance(node1, context.changectx): ctx1 = node1 else: ctx1 = repo[node1] if isinstance(node2, context.changectx): ctx2 = node2 else: ctx2 = repo[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] def inctx(file, ctx): try: if ctx.rev() is None: return file in ctx.manifest() ctx[file] return True except KeyError: return False if match is None: match = match_.always(self.root, self.getcwd()) # Create a copy of match that matches standins instead # of largefiles. def tostandin(file): if inctx(lfutil.standin(file), ctx2): return lfutil.standin(file) return file m = copy.copy(match) m._files = [tostandin(f) for f in m._files] # get ignored, clean, and unknown but remove them # later if they were not asked for try: result = super(lfiles_repo, self).status(node1, node2, m, True, True, True, listsubrepos) except TypeError: result = super(lfiles_repo, self).status(node1, node2, m, True, True, True) if working: # hold the wlock while we read largefiles and # update the lfdirstate wlock = repo.wlock() try: # Any non-largefiles that were explicitly listed must be # taken out or lfdirstate.status will report an error. # The status of these files was already computed using # super's status. lfdirstate = lfutil.openlfdirstate(ui, self) match._files = [ f for f in match._files if f in lfdirstate ] s = lfdirstate.status(match, [], listignored, listclean, listunknown) (unsure, modified, added, removed, missing, unknown, ignored, clean) = s if parentworking: for lfile in unsure: if ctx1[lfutil.standin(lfile)].data().strip() \ != lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) lfdirstate.normal(lfile) lfdirstate.write() else: tocheck = unsure + modified + added + clean modified, added, clean = [], [], [] for lfile in tocheck: standin = lfutil.standin(lfile) if inctx(standin, ctx1): if ctx1[standin].data().strip() != \ lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) else: added.append(lfile) finally: wlock.release() for standin in ctx1.manifest(): if not lfutil.isstandin(standin): continue lfile = lfutil.splitstandin(standin) if not match(lfile): continue if lfile not in lfdirstate: removed.append(lfile) # Handle unknown and ignored differently lfiles = (modified, added, removed, missing, [], [], clean) result = list(result) # Unknown files result[4] = [ f for f in unknown if (repo.dirstate[f] == '?' and not lfutil.isstandin(f) ) ] # Ignored files must be ignored by both the dirstate and # lfdirstate result[5] = set(ignored).intersection(set(result[5])) # combine normal files and largefiles normals = [[ fn for fn in filelist if not lfutil.isstandin(fn) ] for filelist in result] result = [ sorted(list1 + list2) for (list1, list2) in zip(normals, lfiles) ] else: def toname(f): if lfutil.isstandin(f): return lfutil.splitstandin(f) return f result = [[toname(f) for f in items] for items in result] if not listunknown: result[4] = [] if not listignored: result[5] = [] if not listclean: result[6] = [] self.lfstatus = True return result
def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None, prefix=None, mtime=None, subrepos=None): # No need to lock because we are only reading history and # largefile caches, neither of which are modified. lfcommands.cachelfiles(repo.ui, repo, node) if kind not in archival.archivers: raise util.Abort(_("unknown archive type '%s'") % kind) ctx = repo[node] if kind == 'files': if prefix: raise util.Abort( _('cannot give prefix when archiving to files')) else: prefix = archival.tidyprefix(dest, kind, prefix) def write(name, mode, islink, getdata): if matchfn and not matchfn(name): return data = getdata() if decode: data = repo.wwritedata(name, data) archiver.addfile(prefix + name, mode, islink, data) archiver = archival.archivers[kind](dest, mtime or ctx.date()[0]) if repo.ui.configbool("ui", "archivemeta", True): def metadata(): base = 'repo: %s\nnode: %s\nbranch: %s\n' % ( hex(repo.changelog.node(0)), hex(node), ctx.branch()) tags = ''.join('tag: %s\n' % t for t in ctx.tags() if repo.tagtype(t) == 'global') if not tags: repo.ui.pushbuffer() opts = {'template': '{latesttag}\n{latesttagdistance}', 'style': '', 'patch': None, 'git': None} cmdutil.show_changeset(repo.ui, repo, opts).show(ctx) ltags, dist = repo.ui.popbuffer().split('\n') tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':')) tags += 'latesttagdistance: %s\n' % dist return base + tags write('.hg_archival.txt', 0644, False, metadata) for f in ctx: ff = ctx.flags(f) getdata = ctx[f].data if lfutil.isstandin(f): path = lfutil.findfile(repo, getdata().strip()) if path is None: raise util.Abort( _('largefile %s not found in repo store or system cache') % lfutil.splitstandin(f)) f = lfutil.splitstandin(f) def getdatafn(): fd = None try: fd = open(path, 'rb') return fd.read() finally: if fd: fd.close() getdata = getdatafn write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata) if subrepos: for subpath in sorted(ctx.substate): sub = ctx.sub(subpath) submatch = match_.narrowmatcher(subpath, matchfn) sub.archive(repo.ui, archiver, prefix, submatch) archiver.done()
def addlargefiles(ui, repo, *pats, **opts): large = opts.pop('large', None) lfsize = lfutil.getminsize( ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None)) lfmatcher = None if lfutil.islfilesrepo(repo): lfpats = ui.configlist(lfutil.longname, 'patterns', default=[]) if lfpats: lfmatcher = match_.match(repo.root, '', list(lfpats)) lfnames = [] m = scmutil.match(repo[None], pats, opts) m.bad = lambda x, y: None wctx = repo[None] for f in repo.walk(m): exact = m.exact(f) lfile = lfutil.standin(f) in wctx nfile = f in wctx exists = lfile or nfile # Don't warn the user when they attempt to add a normal tracked file. # The normal add code will do that for us. if exact and exists: if lfile: ui.warn(_('%s already a largefile\n') % f) continue if (exact or not exists) and not lfutil.isstandin(f): wfile = repo.wjoin(f) # In case the file was removed previously, but not committed # (issue3507) if not os.path.exists(wfile): continue abovemin = (lfsize and os.lstat(wfile).st_size >= lfsize * 1024 * 1024) if large or abovemin or (lfmatcher and lfmatcher(f)): lfnames.append(f) if ui.verbose or not exact: ui.status(_('adding %s as a largefile\n') % m.rel(f)) bad = [] standins = [] # Need to lock, otherwise there could be a race condition between # when standins are created and added to the repo. wlock = repo.wlock() try: if not opts.get('dry_run'): lfdirstate = lfutil.openlfdirstate(ui, repo) for f in lfnames: standinname = lfutil.standin(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()] finally: wlock.release() return bad
def override_archive(orig, repo, dest, node, kind, decode=True, matchfn=None, prefix=None, mtime=None, subrepos=None): # No need to lock because we are only reading history and # largefile caches, neither of which are modified. lfcommands.cachelfiles(repo.ui, repo, node) if kind not in archival.archivers: raise util.Abort(_("unknown archive type '%s'") % kind) ctx = repo[node] if kind == "files": if prefix: raise util.Abort(_("cannot give prefix when archiving to files")) else: prefix = archival.tidyprefix(dest, kind, prefix) def write(name, mode, islink, getdata): if matchfn and not matchfn(name): return data = getdata() if decode: data = repo.wwritedata(name, data) archiver.addfile(prefix + name, mode, islink, data) archiver = archival.archivers[kind](dest, mtime or ctx.date()[0]) if repo.ui.configbool("ui", "archivemeta", True): def metadata(): base = "repo: %s\nnode: %s\nbranch: %s\n" % (hex(repo.changelog.node(0)), hex(node), ctx.branch()) tags = "".join("tag: %s\n" % t for t in ctx.tags() if repo.tagtype(t) == "global") if not tags: repo.ui.pushbuffer() opts = {"template": "{latesttag}\n{latesttagdistance}", "style": "", "patch": None, "git": None} cmdutil.show_changeset(repo.ui, repo, opts).show(ctx) ltags, dist = repo.ui.popbuffer().split("\n") tags = "".join("latesttag: %s\n" % t for t in ltags.split(":")) tags += "latesttagdistance: %s\n" % dist return base + tags write(".hg_archival.txt", 0644, False, metadata) for f in ctx: ff = ctx.flags(f) getdata = ctx[f].data if lfutil.isstandin(f): path = lfutil.findfile(repo, getdata().strip()) if path is None: raise util.Abort(_("largefile %s not found in repo store or system cache") % lfutil.splitstandin(f)) f = lfutil.splitstandin(f) def getdatafn(): fd = None try: fd = open(path, "rb") return fd.read() finally: if fd: fd.close() getdata = getdatafn write(f, "x" in ff and 0755 or 0644, "l" in ff, getdata) if subrepos: for subpath in ctx.substate: sub = ctx.sub(subpath) sub.archive(repo.ui, archiver, prefix) archiver.done()
def status(self, node1='.', node2=None, match=None, ignored=False, clean=False, unknown=False, listsubrepos=False): listignored, listclean, listunknown = ignored, clean, unknown if not self.lfstatus: try: return super(lfiles_repo, self).status(node1, node2, match, listignored, listclean, listunknown, listsubrepos) except TypeError: return super(lfiles_repo, self).status(node1, node2, match, listignored, listclean, listunknown) else: # some calls in this function rely on the old version of status self.lfstatus = False if isinstance(node1, context.changectx): ctx1 = node1 else: ctx1 = repo[node1] if isinstance(node2, context.changectx): ctx2 = node2 else: ctx2 = repo[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] def inctx(file, ctx): try: if ctx.rev() is None: return file in ctx.manifest() ctx[file] return True except KeyError: return False if match is None: match = match_.always(self.root, self.getcwd()) # Create a copy of match that matches standins instead # of largefiles. def tostandin(file): if inctx(lfutil.standin(file), ctx2): return lfutil.standin(file) return file m = copy.copy(match) m._files = [tostandin(f) for f in m._files] # get ignored, clean, and unknown but remove them # later if they were not asked for try: result = super(lfiles_repo, self).status(node1, node2, m, True, True, True, listsubrepos) except TypeError: result = super(lfiles_repo, self).status(node1, node2, m, True, True, True) if working: # hold the wlock while we read largefiles and # update the lfdirstate wlock = repo.wlock() try: # Any non-largefiles that were explicitly listed must be # taken out or lfdirstate.status will report an error. # The status of these files was already computed using # super's status. lfdirstate = lfutil.openlfdirstate(ui, self) match._files = [f for f in match._files if f in lfdirstate] s = lfdirstate.status(match, [], listignored, listclean, listunknown) (unsure, modified, added, removed, missing, unknown, ignored, clean) = s if parentworking: for lfile in unsure: if ctx1[lfutil.standin(lfile)].data().strip() \ != lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) lfdirstate.normal(lfile) lfdirstate.write() else: tocheck = unsure + modified + added + clean modified, added, clean = [], [], [] for lfile in tocheck: standin = lfutil.standin(lfile) if inctx(standin, ctx1): if ctx1[standin].data().strip() != \ lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) else: added.append(lfile) finally: wlock.release() for standin in ctx1.manifest(): if not lfutil.isstandin(standin): continue lfile = lfutil.splitstandin(standin) if not match(lfile): continue if lfile not in lfdirstate: removed.append(lfile) # Handle unknown and ignored differently lfiles = (modified, added, removed, missing, [], [], clean) result = list(result) # Unknown files result[4] = [f for f in unknown if (repo.dirstate[f] == '?' and not lfutil.isstandin(f))] # Ignored files must be ignored by both the dirstate and # lfdirstate result[5] = set(ignored).intersection(set(result[5])) # combine normal files and largefiles normals = [[fn for fn in filelist if not lfutil.isstandin(fn)] for filelist in result] result = [sorted(list1 + list2) for (list1, list2) in zip(normals, lfiles)] else: def toname(f): if lfutil.isstandin(f): return lfutil.splitstandin(f) return f result = [[toname(f) for f in items] for items in result] if not listunknown: result[4] = [] if not listignored: result[5] = [] if not listclean: result[6] = [] self.lfstatus = True return result
def commit(self, text="", user=None, date=None, match=None, force=False, editor=False, extra={}): orig = super(lfiles_repo, self).commit wlock = repo.wlock() try: if getattr(repo, "_isrebasing", False): # We have to take the time to pull down the new # largefiles now. Otherwise if we are rebasing, # any largefiles that were modified in the # destination changesets get overwritten, either # by the rebase or in the first commit after the # rebase. lfcommands.updatelfiles(repo.ui, repo) # Case 1: user calls commit with no specific files or # include/exclude patterns: refresh and commit all files that # are "dirty". if ((match is None) or (not match.anypats() and not match.files())): # Spend a bit of time here to get a list of files we know # are modified so we can compare only against those. # It can cost a lot of time (several seconds) # otherwise to update all standins if the largefiles are # large. lfdirstate = lfutil.openlfdirstate(ui, self) dirtymatch = match_.always(repo.root, repo.getcwd()) s = lfdirstate.status(dirtymatch, [], False, False, False) modifiedfiles = [] for i in s: modifiedfiles.extend(i) lfiles = lfutil.listlfiles(self) # this only loops through largefiles that exist (not # removed/renamed) for lfile in lfiles: if lfile in modifiedfiles: if os.path.exists(self.wjoin(lfutil.standin(lfile))): # this handles the case where a rebase is being # performed and the working copy is not updated # yet. if os.path.exists(self.wjoin(lfile)): lfutil.updatestandin(self, lfutil.standin(lfile)) lfdirstate.normal(lfile) for lfile in lfdirstate: if lfile in modifiedfiles: if not os.path.exists( repo.wjoin(lfutil.standin(lfile))): lfdirstate.drop(lfile) lfdirstate.write() return orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) for f in match.files(): if lfutil.isstandin(f): raise util.Abort( _('file "%s" is a largefile standin') % f, hint=('commit the largefile itself instead')) # Case 2: user calls commit with specified patterns: refresh # any matching big files. smatcher = lfutil.composestandinmatcher(self, match) standins = lfutil.dirstate_walk(self.dirstate, smatcher) # No matching big files: get out of the way and pass control to # the usual commit() method. if not standins: return orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) # Refresh all matching big files. It's possible that the # commit will end up failing, in which case the big files will # stay refreshed. No harm done: the user modified them and # asked to commit them, so sooner or later we're going to # refresh the standins. Might as well leave them refreshed. lfdirstate = lfutil.openlfdirstate(ui, self) for standin in standins: lfile = lfutil.splitstandin(standin) if lfdirstate[lfile] <> 'r': lfutil.updatestandin(self, standin) lfdirstate.normal(lfile) else: lfdirstate.drop(lfile) lfdirstate.write() # Cook up a new matcher that only matches regular files or # standins corresponding to the big files requested by the # user. Have to modify _files to prevent commit() from # complaining "not tracked" for big files. lfiles = lfutil.listlfiles(repo) match = copy.copy(match) orig_matchfn = match.matchfn # Check both the list of largefiles and the list of # standins because if a largefile was removed, it # won't be in the list of largefiles at this point match._files += sorted(standins) actualfiles = [] for f in match._files: fstandin = lfutil.standin(f) # ignore known largefiles and standins if f in lfiles or fstandin in standins: continue # append directory separator to avoid collisions if not fstandin.endswith(os.sep): fstandin += os.sep # prevalidate matching standin directories if util.any(st for st in match._files if st.startswith(fstandin)): continue actualfiles.append(f) match._files = actualfiles def matchfn(f): if orig_matchfn(f): return f not in lfiles else: return f in standins match.matchfn = matchfn return orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) finally: wlock.release()
def commit(self, text="", user=None, date=None, match=None, force=False, editor=False, extra={}): orig = super(lfilesrepo, self).commit wlock = self.wlock() try: # Case 0: Automated committing # # While automated committing (like rebase, transplant # and so on), this code path is used to avoid: # (1) updating standins, because standins should # be already updated at this point # (2) aborting when stadnins are matched by "match", # because automated committing may specify them directly # if getattr(self, "_isrebasing", False) or \ getattr(self, "_istransplanting", False): result = orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) if result: lfdirstate = lfutil.openlfdirstate(ui, self) for f in self[result].files(): if lfutil.isstandin(f): lfile = lfutil.splitstandin(f) lfutil.synclfdirstate(self, lfdirstate, lfile, False) lfdirstate.write() return result # Case 1: user calls commit with no specific files or # include/exclude patterns: refresh and commit all files that # are "dirty". if ((match is None) or (not match.anypats() and not match.files())): # Spend a bit of time here to get a list of files we know # are modified so we can compare only against those. # It can cost a lot of time (several seconds) # otherwise to update all standins if the largefiles are # large. lfdirstate = lfutil.openlfdirstate(ui, self) dirtymatch = match_.always(self.root, self.getcwd()) unsure, s = lfdirstate.status(dirtymatch, [], False, False, False) modifiedfiles = unsure + s.modified + s.added + s.removed lfiles = lfutil.listlfiles(self) # this only loops through largefiles that exist (not # removed/renamed) for lfile in lfiles: if lfile in modifiedfiles: if os.path.exists(self.wjoin( lfutil.standin(lfile))): # this handles the case where a rebase is being # performed and the working copy is not updated # yet. if os.path.exists(self.wjoin(lfile)): lfutil.updatestandin( self, lfutil.standin(lfile)) lfdirstate.normal(lfile) result = orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) if result is not None: for lfile in lfdirstate: if lfile in modifiedfiles: if (not os.path.exists(self.wjoin( lfutil.standin(lfile)))) or \ (not os.path.exists(self.wjoin(lfile))): lfdirstate.drop(lfile) # This needs to be after commit; otherwise precommit hooks # get the wrong status lfdirstate.write() return result lfiles = lfutil.listlfiles(self) match._files = self._subdirlfs(match.files(), lfiles) # Case 2: user calls commit with specified patterns: refresh # any matching big files. smatcher = lfutil.composestandinmatcher(self, match) standins = self.dirstate.walk(smatcher, [], False, False) # No matching big files: get out of the way and pass control to # the usual commit() method. if not standins: return orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) # Refresh all matching big files. It's possible that the # commit will end up failing, in which case the big files will # stay refreshed. No harm done: the user modified them and # asked to commit them, so sooner or later we're going to # refresh the standins. Might as well leave them refreshed. lfdirstate = lfutil.openlfdirstate(ui, self) for standin in standins: lfile = lfutil.splitstandin(standin) if lfdirstate[lfile] != 'r': lfutil.updatestandin(self, standin) lfdirstate.normal(lfile) else: lfdirstate.drop(lfile) # Cook up a new matcher that only matches regular files or # standins corresponding to the big files requested by the # user. Have to modify _files to prevent commit() from # complaining "not tracked" for big files. match = copy.copy(match) origmatchfn = match.matchfn # Check both the list of largefiles and the list of # standins because if a largefile was removed, it # won't be in the list of largefiles at this point match._files += sorted(standins) actualfiles = [] for f in match._files: fstandin = lfutil.standin(f) # ignore known largefiles and standins if f in lfiles or fstandin in standins: continue actualfiles.append(f) match._files = actualfiles def matchfn(f): if origmatchfn(f): return f not in lfiles else: return f in standins match.matchfn = matchfn result = orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) # This needs to be after commit; otherwise precommit hooks # get the wrong status lfdirstate.write() return result finally: wlock.release()
def toname(f): if lfutil.isstandin(f): return lfutil.splitstandin(f) return f
def commit(self, text="", user=None, date=None, match=None, force=False, editor=False, extra={}): orig = super(lfilesrepo, self).commit wlock = repo.wlock() try: # Case 0: Rebase or Transplant # We have to take the time to pull down the new largefiles now. # Otherwise, any largefiles that were modified in the # destination changesets get overwritten, either by the rebase # or in the first commit after the rebase or transplant. # updatelfiles will update the dirstate to mark any pulled # largefiles as modified if getattr(repo, "_isrebasing", False) or \ getattr(repo, "_istransplanting", False): lfcommands.updatelfiles(repo.ui, repo, filelist=None, printmessage=False) result = orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) return result # Case 1: user calls commit with no specific files or # include/exclude patterns: refresh and commit all files that # are "dirty". if ((match is None) or (not match.anypats() and not match.files())): # Spend a bit of time here to get a list of files we know # are modified so we can compare only against those. # It can cost a lot of time (several seconds) # otherwise to update all standins if the largefiles are # large. lfdirstate = lfutil.openlfdirstate(ui, self) dirtymatch = match_.always(repo.root, repo.getcwd()) s = lfdirstate.status(dirtymatch, [], False, False, False) modifiedfiles = [] for i in s: modifiedfiles.extend(i) lfiles = lfutil.listlfiles(self) # this only loops through largefiles that exist (not # removed/renamed) for lfile in lfiles: if lfile in modifiedfiles: if os.path.exists( self.wjoin(lfutil.standin(lfile))): # this handles the case where a rebase is being # performed and the working copy is not updated # yet. if os.path.exists(self.wjoin(lfile)): lfutil.updatestandin(self, lfutil.standin(lfile)) lfdirstate.normal(lfile) for lfile in lfdirstate: if lfile in modifiedfiles: if not os.path.exists( repo.wjoin(lfutil.standin(lfile))): lfdirstate.drop(lfile) result = orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) # This needs to be after commit; otherwise precommit hooks # get the wrong status lfdirstate.write() return result for f in match.files(): if lfutil.isstandin(f): raise util.Abort( _('file "%s" is a largefile standin') % f, hint=('commit the largefile itself instead')) # Case 2: user calls commit with specified patterns: refresh # any matching big files. smatcher = lfutil.composestandinmatcher(self, match) standins = lfutil.dirstatewalk(self.dirstate, smatcher) # No matching big files: get out of the way and pass control to # the usual commit() method. if not standins: return orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) # Refresh all matching big files. It's possible that the # commit will end up failing, in which case the big files will # stay refreshed. No harm done: the user modified them and # asked to commit them, so sooner or later we're going to # refresh the standins. Might as well leave them refreshed. lfdirstate = lfutil.openlfdirstate(ui, self) for standin in standins: lfile = lfutil.splitstandin(standin) if lfdirstate[lfile] <> 'r': lfutil.updatestandin(self, standin) lfdirstate.normal(lfile) else: lfdirstate.drop(lfile) # Cook up a new matcher that only matches regular files or # standins corresponding to the big files requested by the # user. Have to modify _files to prevent commit() from # complaining "not tracked" for big files. lfiles = lfutil.listlfiles(repo) match = copy.copy(match) origmatchfn = match.matchfn # Check both the list of largefiles and the list of # standins because if a largefile was removed, it # won't be in the list of largefiles at this point match._files += sorted(standins) actualfiles = [] for f in match._files: fstandin = lfutil.standin(f) # ignore known largefiles and standins if f in lfiles or fstandin in standins: continue # append directory separator to avoid collisions if not fstandin.endswith(os.sep): fstandin += os.sep actualfiles.append(f) match._files = actualfiles def matchfn(f): if origmatchfn(f): return f not in lfiles else: return f in standins match.matchfn = matchfn result = orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) # This needs to be after commit; otherwise precommit hooks # get the wrong status lfdirstate.write() return result finally: wlock.release()
def status(self, node1='.', node2=None, match=None, ignored=False, clean=False, unknown=False, listsubrepos=False): listignored, listclean, listunknown = ignored, clean, unknown orig = super(lfilesrepo, self).status if not self.lfstatus: return orig(node1, node2, match, listignored, listclean, listunknown, listsubrepos) # some calls in this function rely on the old version of status self.lfstatus = False ctx1 = self[node1] ctx2 = self[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] if match is None: match = match_.always(self.root, self.getcwd()) wlock = None try: try: # updating the dirstate is optional # so we don't wait on the lock wlock = self.wlock(False) except error.LockError: pass # First check if paths or patterns were specified on the # command line. If there were, and they don't match any # largefiles, we should just bail here and let super # handle it -- thus gaining a big performance boost. lfdirstate = lfutil.openlfdirstate(ui, self) if not match.always(): for f in lfdirstate: if match(f): break else: return orig(node1, node2, match, listignored, listclean, listunknown, listsubrepos) # Create a copy of match that matches standins instead # of largefiles. def tostandins(files): if not working: return files newfiles = [] dirstate = self.dirstate for f in files: sf = lfutil.standin(f) if sf in dirstate: newfiles.append(sf) elif sf in dirstate.dirs(): # Directory entries could be regular or # standin, check both newfiles.extend((f, sf)) else: newfiles.append(f) return newfiles m = copy.copy(match) m._files = tostandins(m._files) result = orig(node1, node2, m, ignored, clean, unknown, listsubrepos) if working: def sfindirstate(f): sf = lfutil.standin(f) dirstate = self.dirstate return sf in dirstate or sf in dirstate.dirs() match._files = [f for f in match._files if sfindirstate(f)] # Don't waste time getting the ignored and unknown # files from lfdirstate unsure, s = lfdirstate.status(match, [], False, listclean, False) (modified, added, removed, clean) = (s.modified, s.added, s.removed, s.clean) if parentworking: for lfile in unsure: standin = lfutil.standin(lfile) if standin not in ctx1: # from second parent modified.append(lfile) elif ctx1[standin].data().strip() \ != lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: if listclean: clean.append(lfile) lfdirstate.normal(lfile) else: tocheck = unsure + modified + added + clean modified, added, clean = [], [], [] checkexec = self.dirstate._checkexec for lfile in tocheck: standin = lfutil.standin(lfile) if standin in ctx1: abslfile = self.wjoin(lfile) if ((ctx1[standin].data().strip() != lfutil.hashfile(abslfile)) or (checkexec and ('x' in ctx1.flags(standin)) != bool(lfutil.getexecutable(abslfile)))): modified.append(lfile) elif listclean: clean.append(lfile) else: added.append(lfile) # at this point, 'removed' contains largefiles # marked as 'R' in the working context. # then, largefiles not managed also in the target # context should be excluded from 'removed'. removed = [lfile for lfile in removed if lfutil.standin(lfile) in ctx1] # Standins no longer found in lfdirstate has been # removed for standin in ctx1.walk(lfutil.getstandinmatcher(self)): lfile = lfutil.splitstandin(standin) if not match(lfile): continue if lfile not in lfdirstate: removed.append(lfile) # Filter result lists result = list(result) # Largefiles are not really removed when they're # still in the normal dirstate. Likewise, normal # files are not really removed if they are still in # lfdirstate. This happens in merges where files # change type. removed = [f for f in removed if f not in self.dirstate] result[2] = [f for f in result[2] if f not in lfdirstate] lfiles = set(lfdirstate._map) # Unknown files result[4] = set(result[4]).difference(lfiles) # Ignored files result[5] = set(result[5]).difference(lfiles) # combine normal files and largefiles normals = [[fn for fn in filelist if not lfutil.isstandin(fn)] for filelist in result] lfstatus = (modified, added, removed, s.deleted, [], [], clean) result = [sorted(list1 + list2) for (list1, list2) in zip(normals, lfstatus)] else: # not against working directory result = [[lfutil.splitstandin(f) or f for f in items] for items in result] if wlock: lfdirstate.write() finally: if wlock: wlock.release() self.lfstatus = True return scmutil.status(*result)
def status(self, node1='.', node2=None, match=None, ignored=False, clean=False, unknown=False, listsubrepos=False): listignored, listclean, listunknown = ignored, clean, unknown if not self.lfstatus: return super(lfilesrepo, self).status(node1, node2, match, listignored, listclean, listunknown, listsubrepos) else: # some calls in this function rely on the old version of status self.lfstatus = False if isinstance(node1, context.changectx): ctx1 = node1 else: ctx1 = repo[node1] if isinstance(node2, context.changectx): ctx2 = node2 else: ctx2 = repo[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] def inctx(file, ctx): try: if ctx.rev() is None: return file in ctx.manifest() ctx[file] return True except KeyError: return False if match is None: match = match_.always(self.root, self.getcwd()) # First check if there were files specified on the # command line. If there were, and none of them were # largefiles, we should just bail here and let super # handle it -- thus gaining a big performance boost. lfdirstate = lfutil.openlfdirstate(ui, self) if match.files() and not match.anypats(): for f in lfdirstate: if match(f): break else: return super(lfilesrepo, self).status(node1, node2, match, listignored, listclean, listunknown, listsubrepos) # Create a copy of match that matches standins instead # of largefiles. def tostandins(files): if not working: return files newfiles = [] dirstate = repo.dirstate for f in files: sf = lfutil.standin(f) if sf in dirstate: newfiles.append(sf) elif sf in dirstate.dirs(): # Directory entries could be regular or # standin, check both newfiles.extend((f, sf)) else: newfiles.append(f) return newfiles # Create a function that we can use to override what is # normally the ignore matcher. We've already checked # for ignored files on the first dirstate walk, and # unecessarily re-checking here causes a huge performance # hit because lfdirstate only knows about largefiles def _ignoreoverride(self): return False m = copy.copy(match) m._files = tostandins(m._files) # Get ignored files here even if we weren't asked for them; we # must use the result here for filtering later result = super(lfilesrepo, self).status(node1, node2, m, True, clean, unknown, listsubrepos) if working: try: # Any non-largefiles that were explicitly listed must be # taken out or lfdirstate.status will report an error. # The status of these files was already computed using # super's status. # Override lfdirstate's ignore matcher to not do # anything origignore = lfdirstate._ignore lfdirstate._ignore = _ignoreoverride def sfindirstate(f): sf = lfutil.standin(f) dirstate = repo.dirstate return sf in dirstate or sf in dirstate.dirs() match._files = [f for f in match._files if sfindirstate(f)] # Don't waste time getting the ignored and unknown # files again; we already have them s = lfdirstate.status(match, [], False, listclean, False) (unsure, modified, added, removed, missing, unknown, ignored, clean) = s # Replace the list of ignored and unknown files with # the previously caclulated lists, and strip out the # largefiles lfiles = set(lfdirstate._map) ignored = set(result[5]).difference(lfiles) unknown = set(result[4]).difference(lfiles) if parentworking: for lfile in unsure: standin = lfutil.standin(lfile) if standin not in ctx1: # from second parent modified.append(lfile) elif ctx1[standin].data().strip() \ != lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) lfdirstate.normal(lfile) else: tocheck = unsure + modified + added + clean modified, added, clean = [], [], [] for lfile in tocheck: standin = lfutil.standin(lfile) if inctx(standin, ctx1): if ctx1[standin].data().strip() != \ lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) else: added.append(lfile) finally: # Replace the original ignore function lfdirstate._ignore = origignore for standin in ctx1.manifest(): if not lfutil.isstandin(standin): continue lfile = lfutil.splitstandin(standin) if not match(lfile): continue if lfile not in lfdirstate: removed.append(lfile) # Filter result lists result = list(result) # Largefiles are not really removed when they're # still in the normal dirstate. Likewise, normal # files are not really removed if it's still in # lfdirstate. This happens in merges where files # change type. removed = [f for f in removed if f not in repo.dirstate] result[2] = [f for f in result[2] if f not in lfdirstate] # Unknown files unknown = set(unknown).difference(ignored) result[4] = [f for f in unknown if (repo.dirstate[f] == '?' and not lfutil.isstandin(f))] # Ignored files were calculated earlier by the dirstate, # and we already stripped out the largefiles from the list result[5] = ignored # combine normal files and largefiles normals = [[fn for fn in filelist if not lfutil.isstandin(fn)] for filelist in result] lfiles = (modified, added, removed, missing, [], [], clean) result = [sorted(list1 + list2) for (list1, list2) in zip(normals, lfiles)] else: def toname(f): if lfutil.isstandin(f): return lfutil.splitstandin(f) return f result = [[toname(f) for f in items] for items in result] if not listunknown: result[4] = [] if not listignored: result[5] = [] if not listclean: result[6] = [] self.lfstatus = True return result
def commit(self, text="", user=None, date=None, match=None, force=False, editor=False, extra={}): orig = super(lfilesrepo, self).commit wlock = self.wlock() try: # Case 0: Automated committing # # While automated committing (like rebase, transplant # and so on), this code path is used to avoid: # (1) updating standins, because standins should # be already updated at this point # (2) aborting when stadnins are matched by "match", # because automated committing may specify them directly # if getattr(self, "_isrebasing", False) or getattr(self, "_istransplanting", False): result = orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) if result: lfdirstate = lfutil.openlfdirstate(ui, self) for f in self[result].files(): if lfutil.isstandin(f): lfile = lfutil.splitstandin(f) lfutil.synclfdirstate(self, lfdirstate, lfile, False) lfdirstate.write() return result # Case 1: user calls commit with no specific files or # include/exclude patterns: refresh and commit all files that # are "dirty". if (match is None) or (not match.anypats() and not match.files()): # Spend a bit of time here to get a list of files we know # are modified so we can compare only against those. # It can cost a lot of time (several seconds) # otherwise to update all standins if the largefiles are # large. lfdirstate = lfutil.openlfdirstate(ui, self) dirtymatch = match_.always(self.root, self.getcwd()) unsure, s = lfdirstate.status(dirtymatch, [], False, False, False) modifiedfiles = unsure + s.modified + s.added + s.removed lfiles = lfutil.listlfiles(self) # this only loops through largefiles that exist (not # removed/renamed) for lfile in lfiles: if lfile in modifiedfiles: if os.path.exists(self.wjoin(lfutil.standin(lfile))): # this handles the case where a rebase is being # performed and the working copy is not updated # yet. if os.path.exists(self.wjoin(lfile)): lfutil.updatestandin(self, lfutil.standin(lfile)) lfdirstate.normal(lfile) result = orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) if result is not None: for lfile in lfdirstate: if lfile in modifiedfiles: if (not os.path.exists(self.wjoin(lfutil.standin(lfile)))) or ( not os.path.exists(self.wjoin(lfile)) ): lfdirstate.drop(lfile) # This needs to be after commit; otherwise precommit hooks # get the wrong status lfdirstate.write() return result lfiles = lfutil.listlfiles(self) match._files = self._subdirlfs(match.files(), lfiles) # Case 2: user calls commit with specified patterns: refresh # any matching big files. smatcher = lfutil.composestandinmatcher(self, match) standins = self.dirstate.walk(smatcher, [], False, False) # No matching big files: get out of the way and pass control to # the usual commit() method. if not standins: return orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) # Refresh all matching big files. It's possible that the # commit will end up failing, in which case the big files will # stay refreshed. No harm done: the user modified them and # asked to commit them, so sooner or later we're going to # refresh the standins. Might as well leave them refreshed. lfdirstate = lfutil.openlfdirstate(ui, self) for standin in standins: lfile = lfutil.splitstandin(standin) if lfdirstate[lfile] != "r": lfutil.updatestandin(self, standin) lfdirstate.normal(lfile) else: lfdirstate.drop(lfile) # Cook up a new matcher that only matches regular files or # standins corresponding to the big files requested by the # user. Have to modify _files to prevent commit() from # complaining "not tracked" for big files. match = copy.copy(match) origmatchfn = match.matchfn # Check both the list of largefiles and the list of # standins because if a largefile was removed, it # won't be in the list of largefiles at this point match._files += sorted(standins) actualfiles = [] for f in match._files: fstandin = lfutil.standin(f) # ignore known largefiles and standins if f in lfiles or fstandin in standins: continue actualfiles.append(f) match._files = actualfiles def matchfn(f): if origmatchfn(f): return f not in lfiles else: return f in standins match.matchfn = matchfn result = orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) # This needs to be after commit; otherwise precommit hooks # get the wrong status lfdirstate.write() return result finally: wlock.release()
def status(self, node1='.', node2=None, match=None, ignored=False, clean=False, unknown=False, listsubrepos=False): listignored, listclean, listunknown = ignored, clean, unknown orig = super(lfilesrepo, self).status if not self.lfstatus: return orig(node1, node2, match, listignored, listclean, listunknown, listsubrepos) # some calls in this function rely on the old version of status self.lfstatus = False ctx1 = self[node1] ctx2 = self[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] if match is None: match = match_.always(self.root, self.getcwd()) wlock = None try: try: # updating the dirstate is optional # so we don't wait on the lock wlock = self.wlock(False) except error.LockError: pass # First check if paths or patterns were specified on the # command line. If there were, and they don't match any # largefiles, we should just bail here and let super # handle it -- thus gaining a big performance boost. lfdirstate = lfutil.openlfdirstate(ui, self) if not match.always(): for f in lfdirstate: if match(f): break else: return orig(node1, node2, match, listignored, listclean, listunknown, listsubrepos) # Create a copy of match that matches standins instead # of largefiles. def tostandins(files): if not working: return files newfiles = [] dirstate = self.dirstate for f in files: sf = lfutil.standin(f) if sf in dirstate: newfiles.append(sf) elif sf in dirstate.dirs(): # Directory entries could be regular or # standin, check both newfiles.extend((f, sf)) else: newfiles.append(f) return newfiles m = copy.copy(match) m._files = tostandins(m._files) result = orig(node1, node2, m, ignored, clean, unknown, listsubrepos) if working: def sfindirstate(f): sf = lfutil.standin(f) dirstate = self.dirstate return sf in dirstate or sf in dirstate.dirs() match._files = [f for f in match._files if sfindirstate(f)] # Don't waste time getting the ignored and unknown # files from lfdirstate unsure, s = lfdirstate.status(match, [], False, listclean, False) (modified, added, removed, clean) = (s.modified, s.added, s.removed, s.clean) if parentworking: for lfile in unsure: standin = lfutil.standin(lfile) if standin not in ctx1: # from second parent modified.append(lfile) elif ctx1[standin].data().strip() \ != lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: if listclean: clean.append(lfile) lfdirstate.normal(lfile) else: tocheck = unsure + modified + added + clean modified, added, clean = [], [], [] checkexec = self.dirstate._checkexec for lfile in tocheck: standin = lfutil.standin(lfile) if standin in ctx1: abslfile = self.wjoin(lfile) if ((ctx1[standin].data().strip() != lfutil.hashfile(abslfile)) or (checkexec and ('x' in ctx1.flags(standin)) != bool(lfutil.getexecutable(abslfile)))): modified.append(lfile) elif listclean: clean.append(lfile) else: added.append(lfile) # at this point, 'removed' contains largefiles # marked as 'R' in the working context. # then, largefiles not managed also in the target # context should be excluded from 'removed'. removed = [ lfile for lfile in removed if lfutil.standin(lfile) in ctx1 ] # Standins no longer found in lfdirstate has been # removed for standin in ctx1.walk(lfutil.getstandinmatcher(self)): lfile = lfutil.splitstandin(standin) if not match(lfile): continue if lfile not in lfdirstate: removed.append(lfile) # Filter result lists result = list(result) # Largefiles are not really removed when they're # still in the normal dirstate. Likewise, normal # files are not really removed if they are still in # lfdirstate. This happens in merges where files # change type. removed = [f for f in removed if f not in self.dirstate] result[2] = [f for f in result[2] if f not in lfdirstate] lfiles = set(lfdirstate._map) # Unknown files result[4] = set(result[4]).difference(lfiles) # Ignored files result[5] = set(result[5]).difference(lfiles) # combine normal files and largefiles normals = [[ fn for fn in filelist if not lfutil.isstandin(fn) ] for filelist in result] lfstatus = (modified, added, removed, s.deleted, [], [], clean) result = [ sorted(list1 + list2) for (list1, list2) in zip(normals, lfstatus) ] else: # not against working directory result = [[lfutil.splitstandin(f) or f for f in items] for items in result] if wlock: lfdirstate.write() finally: if wlock: wlock.release() self.lfstatus = True return scmutil.status(*result)
def matchfn(f): if lfutil.isstandin(f): return (origmatchfn(lfutil.splitstandin(f)) and (f in repo[None] or f in ctx)) return origmatchfn(f)
def addlargefiles(ui, repo, *pats, **opts): large = opts.pop('large', None) lfsize = lfutil.getminsize(ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None)) lfmatcher = None if lfutil.islfilesrepo(repo): lfpats = ui.configlist(lfutil.longname, 'patterns', default=[]) if lfpats: lfmatcher = match_.match(repo.root, '', list(lfpats)) lfnames = [] m = scmutil.match(repo[None], pats, opts) m.bad = lambda x, y: None wctx = repo[None] for f in repo.walk(m): exact = m.exact(f) lfile = lfutil.standin(f) in wctx nfile = f in wctx exists = lfile or nfile # Don't warn the user when they attempt to add a normal tracked file. # The normal add code will do that for us. if exact and exists: if lfile: ui.warn(_('%s already a largefile\n') % f) continue if (exact or not exists) and not lfutil.isstandin(f): wfile = repo.wjoin(f) # In case the file was removed previously, but not committed # (issue3507) if not os.path.exists(wfile): continue abovemin = (lfsize and os.lstat(wfile).st_size >= lfsize * 1024 * 1024) if large or abovemin or (lfmatcher and lfmatcher(f)): lfnames.append(f) if ui.verbose or not exact: ui.status(_('adding %s as a largefile\n') % m.rel(f)) bad = [] standins = [] # Need to lock, otherwise there could be a race condition between # when standins are created and added to the repo. wlock = repo.wlock() try: if not opts.get('dry_run'): lfdirstate = lfutil.openlfdirstate(ui, repo) for f in lfnames: standinname = lfutil.standin(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() ] finally: wlock.release() return bad
def status( self, node1=".", node2=None, match=None, ignored=False, clean=False, unknown=False, listsubrepos=False ): listignored, listclean, listunknown = ignored, clean, unknown if not self.lfstatus: return super(lfilesrepo, self).status( node1, node2, match, listignored, listclean, listunknown, listsubrepos ) else: # some calls in this function rely on the old version of status self.lfstatus = False if isinstance(node1, context.changectx): ctx1 = node1 else: ctx1 = repo[node1] if isinstance(node2, context.changectx): ctx2 = node2 else: ctx2 = repo[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self["."] def inctx(file, ctx): try: if ctx.rev() is None: return file in ctx.manifest() ctx[file] return True except KeyError: return False if match is None: match = match_.always(self.root, self.getcwd()) # First check if there were files specified on the # command line. If there were, and none of them were # largefiles, we should just bail here and let super # handle it -- thus gaining a big performance boost. lfdirstate = lfutil.openlfdirstate(ui, self) if match.files() and not match.anypats(): for f in lfdirstate: if match(f): break else: return super(lfilesrepo, self).status( node1, node2, match, listignored, listclean, listunknown, listsubrepos ) # Create a copy of match that matches standins instead # of largefiles. def tostandins(files): if not working: return files newfiles = [] dirstate = repo.dirstate for f in files: sf = lfutil.standin(f) if sf in dirstate: newfiles.append(sf) elif sf in dirstate.dirs(): # Directory entries could be regular or # standin, check both newfiles.extend((f, sf)) else: newfiles.append(f) return newfiles # Create a function that we can use to override what is # normally the ignore matcher. We've already checked # for ignored files on the first dirstate walk, and # unecessarily re-checking here causes a huge performance # hit because lfdirstate only knows about largefiles def _ignoreoverride(self): return False m = copy.copy(match) m._files = tostandins(m._files) # Get ignored files here even if we weren't asked for them; we # must use the result here for filtering later result = super(lfilesrepo, self).status(node1, node2, m, True, clean, unknown, listsubrepos) if working: try: # Any non-largefiles that were explicitly listed must be # taken out or lfdirstate.status will report an error. # The status of these files was already computed using # super's status. # Override lfdirstate's ignore matcher to not do # anything origignore = lfdirstate._ignore lfdirstate._ignore = _ignoreoverride def sfindirstate(f): sf = lfutil.standin(f) dirstate = repo.dirstate return sf in dirstate or sf in dirstate.dirs() match._files = [f for f in match._files if sfindirstate(f)] # Don't waste time getting the ignored and unknown # files again; we already have them s = lfdirstate.status(match, [], False, listclean, False) (unsure, modified, added, removed, missing, unknown, ignored, clean) = s # Replace the list of ignored and unknown files with # the previously caclulated lists, and strip out the # largefiles lfiles = set(lfdirstate._map) ignored = set(result[5]).difference(lfiles) unknown = set(result[4]).difference(lfiles) if parentworking: for lfile in unsure: standin = lfutil.standin(lfile) if standin not in ctx1: # from second parent modified.append(lfile) elif ctx1[standin].data().strip() != lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) lfdirstate.normal(lfile) else: tocheck = unsure + modified + added + clean modified, added, clean = [], [], [] for lfile in tocheck: standin = lfutil.standin(lfile) if inctx(standin, ctx1): if ctx1[standin].data().strip() != lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) else: added.append(lfile) finally: # Replace the original ignore function lfdirstate._ignore = origignore for standin in ctx1.manifest(): if not lfutil.isstandin(standin): continue lfile = lfutil.splitstandin(standin) if not match(lfile): continue if lfile not in lfdirstate: removed.append(lfile) # Filter result lists result = list(result) # Largefiles are not really removed when they're # still in the normal dirstate. Likewise, normal # files are not really removed if it's still in # lfdirstate. This happens in merges where files # change type. removed = [f for f in removed if f not in repo.dirstate] result[2] = [f for f in result[2] if f not in lfdirstate] # Unknown files unknown = set(unknown).difference(ignored) result[4] = [f for f in unknown if (repo.dirstate[f] == "?" and not lfutil.isstandin(f))] # Ignored files were calculated earlier by the dirstate, # and we already stripped out the largefiles from the list result[5] = ignored # combine normal files and largefiles normals = [[fn for fn in filelist if not lfutil.isstandin(fn)] for filelist in result] lfiles = (modified, added, removed, missing, [], [], clean) result = [sorted(list1 + list2) for (list1, list2) in zip(normals, lfiles)] else: def toname(f): if lfutil.isstandin(f): return lfutil.splitstandin(f) return f result = [[toname(f) for f in items] for items in result] if not listunknown: result[4] = [] if not listignored: result[5] = [] if not listclean: result[6] = [] self.lfstatus = True return result
def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None, prefix=None, mtime=None, subrepos=None): # No need to lock because we are only reading history and # largefile caches, neither of which are modified. lfcommands.cachelfiles(repo.ui, repo, node) if kind not in archival.archivers: raise util.Abort(_("unknown archive type '%s'") % kind) ctx = repo[node] if kind == 'files': if prefix: raise util.Abort(_('cannot give prefix when archiving to files')) else: prefix = archival.tidyprefix(dest, kind, prefix) def write(name, mode, islink, getdata): if matchfn and not matchfn(name): return data = getdata() if decode: data = repo.wwritedata(name, data) archiver.addfile(prefix + name, mode, islink, data) archiver = archival.archivers[kind](dest, mtime or ctx.date()[0]) if repo.ui.configbool("ui", "archivemeta", True): def metadata(): base = 'repo: %s\nnode: %s\nbranch: %s\n' % (hex( repo.changelog.node(0)), hex(node), ctx.branch()) tags = ''.join('tag: %s\n' % t for t in ctx.tags() if repo.tagtype(t) == 'global') if not tags: repo.ui.pushbuffer() opts = { 'template': '{latesttag}\n{latesttagdistance}', 'style': '', 'patch': None, 'git': None } cmdutil.show_changeset(repo.ui, repo, opts).show(ctx) ltags, dist = repo.ui.popbuffer().split('\n') tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':')) tags += 'latesttagdistance: %s\n' % dist return base + tags write('.hg_archival.txt', 0644, False, metadata) for f in ctx: ff = ctx.flags(f) getdata = ctx[f].data if lfutil.isstandin(f): path = lfutil.findfile(repo, getdata().strip()) if path is None: raise util.Abort( _('largefile %s not found in repo store or system cache') % lfutil.splitstandin(f)) f = lfutil.splitstandin(f) def getdatafn(): fd = None try: fd = open(path, 'rb') return fd.read() finally: if fd: fd.close() getdata = getdatafn write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata) if subrepos: for subpath in sorted(ctx.substate): sub = ctx.sub(subpath) submatch = match_.narrowmatcher(subpath, matchfn) sub.archive(repo.ui, archiver, prefix, submatch) archiver.done()
def status(self, node1='.', node2=None, match=None, ignored=False, clean=False, unknown=False, listsubrepos=False): listignored, listclean, listunknown = ignored, clean, unknown if not self.lfstatus: return super(lfilesrepo, self).status(node1, node2, match, listignored, listclean, listunknown, listsubrepos) else: # some calls in this function rely on the old version of status self.lfstatus = False ctx1 = self[node1] ctx2 = self[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] def inctx(file, ctx): try: if ctx.rev() is None: return file in ctx.manifest() ctx[file] return True except KeyError: return False if match is None: match = match_.always(self.root, self.getcwd()) wlock = None try: try: # updating the dirstate is optional # so we don't wait on the lock wlock = self.wlock(False) except error.LockError: pass # First check if there were files specified on the # command line. If there were, and none of them were # largefiles, we should just bail here and let super # handle it -- thus gaining a big performance boost. lfdirstate = lfutil.openlfdirstate(ui, self) if match.files() and not match.anypats(): for f in lfdirstate: if match(f): break else: return super(lfilesrepo, self).status(node1, node2, match, listignored, listclean, listunknown, listsubrepos) # Create a copy of match that matches standins instead # of largefiles. def tostandins(files): if not working: return files newfiles = [] dirstate = self.dirstate for f in files: sf = lfutil.standin(f) if sf in dirstate: newfiles.append(sf) elif sf in dirstate.dirs(): # Directory entries could be regular or # standin, check both newfiles.extend((f, sf)) else: newfiles.append(f) return newfiles m = copy.copy(match) m._files = tostandins(m._files) result = super(lfilesrepo, self).status(node1, node2, m, ignored, clean, unknown, listsubrepos) if working: def sfindirstate(f): sf = lfutil.standin(f) dirstate = self.dirstate return sf in dirstate or sf in dirstate.dirs() match._files = [ f for f in match._files if sfindirstate(f) ] # Don't waste time getting the ignored and unknown # files from lfdirstate s = lfdirstate.status(match, [], False, listclean, False) (unsure, modified, added, removed, missing, _unknown, _ignored, clean) = s if parentworking: for lfile in unsure: standin = lfutil.standin(lfile) if standin not in ctx1: # from second parent modified.append(lfile) elif ctx1[standin].data().strip() \ != lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) lfdirstate.normal(lfile) else: tocheck = unsure + modified + added + clean modified, added, clean = [], [], [] for lfile in tocheck: standin = lfutil.standin(lfile) if inctx(standin, ctx1): if ctx1[standin].data().strip() != \ lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) else: added.append(lfile) # Standins no longer found in lfdirstate has been # removed for standin in ctx1.manifest(): if not lfutil.isstandin(standin): continue lfile = lfutil.splitstandin(standin) if not match(lfile): continue if lfile not in lfdirstate: removed.append(lfile) # Filter result lists result = list(result) # Largefiles are not really removed when they're # still in the normal dirstate. Likewise, normal # files are not really removed if they are still in # lfdirstate. This happens in merges where files # change type. removed = [ f for f in removed if f not in self.dirstate ] result[2] = [ f for f in result[2] if f not in lfdirstate ] lfiles = set(lfdirstate._map) # Unknown files result[4] = set(result[4]).difference(lfiles) # Ignored files result[5] = set(result[5]).difference(lfiles) # combine normal files and largefiles normals = [[ fn for fn in filelist if not lfutil.isstandin(fn) ] for filelist in result] lfiles = (modified, added, removed, missing, [], [], clean) result = [ sorted(list1 + list2) for (list1, list2) in zip(normals, lfiles) ] else: def toname(f): if lfutil.isstandin(f): return lfutil.splitstandin(f) return f result = [[toname(f) for f in items] for items in result] if wlock: lfdirstate.write() finally: if wlock: wlock.release() if not listunknown: result[4] = [] if not listignored: result[5] = [] if not listclean: result[6] = [] self.lfstatus = True return result
def status(self, node1='.', node2=None, match=None, ignored=False, clean=False, unknown=False, listsubrepos=False): listignored, listclean, listunknown = ignored, clean, unknown if not self.lfstatus: return super(lfilesrepo, self).status(node1, node2, match, listignored, listclean, listunknown, listsubrepos) else: # some calls in this function rely on the old version of status self.lfstatus = False if isinstance(node1, context.changectx): ctx1 = node1 else: ctx1 = self[node1] if isinstance(node2, context.changectx): ctx2 = node2 else: ctx2 = self[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] def inctx(file, ctx): try: if ctx.rev() is None: return file in ctx.manifest() ctx[file] return True except KeyError: return False if match is None: match = match_.always(self.root, self.getcwd()) wlock = None try: try: # updating the dirstate is optional # so we don't wait on the lock wlock = self.wlock(False) except error.LockError: pass # First check if there were files specified on the # command line. If there were, and none of them were # largefiles, we should just bail here and let super # handle it -- thus gaining a big performance boost. lfdirstate = lfutil.openlfdirstate(ui, self) if match.files() and not match.anypats(): for f in lfdirstate: if match(f): break else: return super(lfilesrepo, self).status(node1, node2, match, listignored, listclean, listunknown, listsubrepos) # Create a copy of match that matches standins instead # of largefiles. def tostandins(files): if not working: return files newfiles = [] dirstate = self.dirstate for f in files: sf = lfutil.standin(f) if sf in dirstate: newfiles.append(sf) elif sf in dirstate.dirs(): # Directory entries could be regular or # standin, check both newfiles.extend((f, sf)) else: newfiles.append(f) return newfiles m = copy.copy(match) m._files = tostandins(m._files) result = super(lfilesrepo, self).status(node1, node2, m, ignored, clean, unknown, listsubrepos) if working: def sfindirstate(f): sf = lfutil.standin(f) dirstate = self.dirstate return sf in dirstate or sf in dirstate.dirs() match._files = [f for f in match._files if sfindirstate(f)] # Don't waste time getting the ignored and unknown # files from lfdirstate s = lfdirstate.status(match, [], False, listclean, False) (unsure, modified, added, removed, missing, _unknown, _ignored, clean) = s if parentworking: for lfile in unsure: standin = lfutil.standin(lfile) if standin not in ctx1: # from second parent modified.append(lfile) elif ctx1[standin].data().strip() \ != lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) lfdirstate.normal(lfile) else: tocheck = unsure + modified + added + clean modified, added, clean = [], [], [] for lfile in tocheck: standin = lfutil.standin(lfile) if inctx(standin, ctx1): if ctx1[standin].data().strip() != \ lfutil.hashfile(self.wjoin(lfile)): modified.append(lfile) else: clean.append(lfile) else: added.append(lfile) # Standins no longer found in lfdirstate has been # removed for standin in ctx1.manifest(): if not lfutil.isstandin(standin): continue lfile = lfutil.splitstandin(standin) if not match(lfile): continue if lfile not in lfdirstate: removed.append(lfile) # Filter result lists result = list(result) # Largefiles are not really removed when they're # still in the normal dirstate. Likewise, normal # files are not really removed if they are still in # lfdirstate. This happens in merges where files # change type. removed = [f for f in removed if f not in self.dirstate] result[2] = [f for f in result[2] if f not in lfdirstate] lfiles = set(lfdirstate._map) # Unknown files result[4] = set(result[4]).difference(lfiles) # Ignored files result[5] = set(result[5]).difference(lfiles) # combine normal files and largefiles normals = [[fn for fn in filelist if not lfutil.isstandin(fn)] for filelist in result] lfiles = (modified, added, removed, missing, [], [], clean) result = [sorted(list1 + list2) for (list1, list2) in zip(normals, lfiles)] else: def toname(f): if lfutil.isstandin(f): return lfutil.splitstandin(f) return f result = [[toname(f) for f in items] for items in result] if wlock: lfdirstate.write() finally: if wlock: wlock.release() if not listunknown: result[4] = [] if not listignored: result[5] = [] if not listclean: result[6] = [] self.lfstatus = True return result
def _addchangeset(ui, rsrc, rdst, ctx, revmap): # Convert src parents to dst parents parents = [] for p in ctx.parents(): parents.append(revmap[p.node()]) while len(parents) < 2: parents.append(node.nullid) # Generate list of changed files files = set(ctx.files()) if node.nullid not in parents: mc = ctx.manifest() mp1 = ctx.parents()[0].manifest() mp2 = ctx.parents()[1].manifest() files |= (set(mp1) | set(mp2)) - set(mc) for f in mc: if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None): files.add(f) def getfilectx(repo, memctx, f): if lfutil.standin(f) in files: # if the file isn't in the manifest then it was removed # or renamed, raise IOError to indicate this try: fctx = ctx.filectx(lfutil.standin(f)) except error.LookupError: raise IOError() renamed = fctx.renamed() if renamed: renamed = lfutil.splitstandin(renamed[0]) hash = fctx.data().strip() path = lfutil.findfile(rsrc, hash) ### TODO: What if the file is not cached? data = '' fd = None try: fd = open(path, 'rb') data = fd.read() finally: if fd: fd.close() return context.memfilectx(f, data, 'l' in fctx.flags(), 'x' in fctx.flags(), renamed) else: try: fctx = ctx.filectx(f) except error.LookupError: raise IOError() renamed = fctx.renamed() if renamed: renamed = renamed[0] data = fctx.data() if f == '.hgtags': newdata = [] for line in data.splitlines(): id, name = line.split(' ', 1) newdata.append('%s %s\n' % (node.hex(revmap[node.bin(id)]), name)) data = ''.join(newdata) return context.memfilectx(f, data, 'l' in fctx.flags(), 'x' in fctx.flags(), renamed) dstfiles = [] for file in files: if lfutil.isstandin(file): dstfiles.append(lfutil.splitstandin(file)) else: dstfiles.append(file) # Commit mctx = context.memctx(rdst, parents, ctx.description(), dstfiles, getfilectx, ctx.user(), ctx.date(), ctx.extra()) ret = rdst.commitctx(mctx) rdst.dirstate.setparents(ret) revmap[ctx.node()] = rdst.changelog.tip()