diff -r 7db1619af061 -r ce0bc2952e2a mercurial/narrowspec.py --- a/mercurial/narrowspec.py Fri Jul 13 11:26:46 2018 -0700 +++ b/mercurial/narrowspec.py Fri Dec 21 10:13:49 2018 -0800 @@ -13,12 +13,16 @@ from . import ( error, match as matchmod, + merge, repository, sparse, util, ) +# The file in .hg/store/ that indicates which paths exit in the store FILENAME = 'narrowspec' +# The file in .hg/ that indicates which paths exit in the dirstate +DIRSTATE_FILENAME = 'narrowspec.dirstate' # Pattern prefixes that are allowed in narrow patterns. This list MUST # only contain patterns that are fast and safe to evaluate. Keep in mind @@ -157,6 +161,18 @@ spec = format(includepats, excludepats) repo.svfs.write(FILENAME, spec) +def copytoworkingcopy(repo, tr): + if tr: + def write(file): + spec = repo.svfs.read(FILENAME) + file.write(spec) + file.close() + tr.addfilegenerator('narrowspec', (DIRSTATE_FILENAME,), write, + location='plain') + else: + spec = repo.svfs.read(FILENAME) + repo.vfs.write(DIRSTATE_FILENAME, spec) + def savebackup(repo, backupname): if repository.NARROW_REQUIREMENT not in repo.requirements: return @@ -226,3 +242,57 @@ else: res_includes = set(req_includes) return res_includes, res_excludes, invalid_includes + +# These two are extracted for extensions (specifically for Google's CitC file +# system) +def _deletecleanfiles(repo, files): + for f in files: + repo.wvfs.unlinkpath(f) + +def _writeaddedfiles(repo, pctx, files): + actions = merge.emptyactions() + addgaction = actions['g'].append + mf = repo['.'].manifest() + for f in files: + if not repo.wvfs.exists(f): + addgaction((f, (mf.flags(f), False), "narrowspec updated")) + merge.applyupdates(repo, actions, wctx=repo[None], + mctx=repo['.'], overwrite=False) + +def checkworkingcopynarrowspec(repo): + storespec = repo.svfs.tryread(FILENAME) + wcspec = repo.vfs.tryread(DIRSTATE_FILENAME) + if wcspec != storespec: + raise error.Abort(_("working copy's narrowspec is stale"), + hint=_("run 'hg tracked --update-working-copy'")) + +def updateworkingcopy(repo, tr): + oldspec = repo.vfs.tryread(DIRSTATE_FILENAME) + newspec = repo.svfs.tryread(FILENAME) + + oldincludes, oldexcludes = parseconfig(repo.ui, oldspec) + newincludes, newexcludes = parseconfig(repo.ui, newspec) + oldmatch = match(repo.root, include=oldincludes, exclude=oldexcludes) + newmatch = match(repo.root, include=newincludes, exclude=newexcludes) + addedmatch = matchmod.differencematcher(newmatch, oldmatch) + removedmatch = matchmod.differencematcher(oldmatch, newmatch) + + ds = repo.dirstate + lookup, status = ds.status(removedmatch, subrepos=[], ignored=False, + clean=True, unknown=False) + _deletecleanfiles(repo, status.clean) + trackeddirty = lookup + status.modified + status.added + for f in sorted(trackeddirty): + repo.ui.status(_('not deleting possibly dirty file %s\n') % f) + for f in status.clean + trackeddirty: + ds.drop(f) + + repo.narrowpats = newincludes, newexcludes + repo._narrowmatch = newmatch + pctx = repo['.'] + newfiles = [f for f in pctx.manifest().walk(addedmatch) if f not in ds] + for f in newfiles: + ds.normallookup(f) + _writeaddedfiles(repo, pctx, newfiles) + + ds.write(tr)