def setwithlimit(self, hexnode, manifest, limit=-1): """Writes a manifest to the cache. Returns True if the cache already contains the item or if the write is successful. Returns False if the write fails. Raises CacheFullException if writing the cache entry would cause us to pass the limit. """ if hexnode in self: return True path = self._pathfromnode(hexnode) if (isinstance(manifest, cfastmanifest.fastmanifest) or isinstance(manifest, fastmanifestdict)): fm = manifest else: fm = cfastmanifest.fastmanifest(manifest.text()) tmpfpath = util.mktempcopy(path, True) entrysize = fm.bytes() if limit != -1 and self.totalsize()[0] + entrysize > limit: raise CacheFullException() try: fm._save(tmpfpath) util.rename(tmpfpath, path) return True except EnvironmentError: return False finally: try: os.unlink(tmpfpath) except OSError: pass
def unshelveabort(ui, repo, state, opts): """subcommand that abort an in-progress unshelve""" wlock = repo.wlock() lock = None try: checkparents(repo, state) util.rename(repo.join('unshelverebasestate'), repo.join('rebasestate')) try: rebase.rebase(ui, repo, **{ 'abort' : True }) except Exception: util.rename(repo.join('rebasestate'), repo.join('unshelverebasestate')) raise lock = repo.lock() mergefiles(ui, repo, state.wctx, state.pendingctx) repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve') shelvedstate.clear(repo) ui.warn(_("unshelve of '%s' aborted\n") % state.name) finally: lockmod.release(lock, wlock)
def unshare(ui, repo): """convert a shared repository to a normal one Copy the store data to the repo and remove the sharedpath data. """ if not repo.shared(): raise error.Abort(_("this is not a shared repo")) destlock = lock = None lock = repo.lock() try: # we use locks here because if we race with commit, we # can end up with extra data in the cloned revlogs that's # not pointed to by changesets, thus causing verify to # fail destlock = hg.copystore(ui, repo, repo.path) sharefile = repo.join('sharedpath') util.rename(sharefile, sharefile + '.old') repo.requirements.discard('sharedpath') repo._writerequirements() finally: destlock and destlock.release() lock and lock.release() # update store, spath, svfs and sjoin of repo repo.unfiltered().__init__(repo.baseui, repo.root)
def _gethash(self, filename, hash): """Get file with the provided hash and store it in the local repo's store and in the usercache. filename is for informational messages only. """ util.makedirs(lfutil.storepath(self.repo, '')) storefilename = lfutil.storepath(self.repo, hash) tmpname = storefilename + '.tmp' tmpfile = util.atomictempfile( tmpname, createmode=self.repo.store.createmode) try: gothash = self._getfile(tmpfile, filename, hash) except StoreError as err: self.ui.warn(err.longmessage()) gothash = "" tmpfile.close() if gothash != hash: if gothash != "": self.ui.warn( _('%s: data corruption (expected %s, got %s)\n') % (filename, hash, gothash)) util.unlink(tmpname) return False util.rename(tmpname, storefilename) lfutil.linktousercache(self.repo, hash) return True
def rollback(self, dryrun=False): if os.path.exists(self.join('undo.bookmarks')): if not dryrun: util.rename(self.join('undo.bookmarks'), self.join('bookmarks')) elif not os.path.exists(self.sjoin("undo")): # avoid "no rollback information available" message return 0 return super(bookmark_repo, self).rollback(dryrun)
def _bind(self, sock): # use a unique temp address so we can stat the file and do ownership # check later tempaddress = _tempaddress(self._realaddress) util.bindunixsocket(sock, tempaddress) self._socketstat = os.stat(tempaddress) # rename will replace the old socket file if exists atomically. the # old server will detect ownership change and exit. util.rename(tempaddress, self._realaddress)
def backup(self, repo, files, copy=False): # backup local changes in --force case for f in sorted(files): absf = repo.wjoin(f) if os.path.lexists(absf): self.ui.note(_('saving current version of %s as %s\n') % (f, f + '.orig')) if copy: util.copyfile(absf, absf + '.orig') else: util.rename(absf, absf + '.orig')
def get(self, files): '''Get the specified largefiles from the store and write to local files under repo.root. files is a list of (filename, hash) tuples. Return (success, missing), lists of files successfully downloaded and those not found in the store. success is a list of (filename, hash) tuples; missing is a list of filenames that we could not get. (The detailed error message will already have been presented to the user, so missing is just supplied as a summary.)''' success = [] missing = [] ui = self.ui util.makedirs(lfutil.storepath(self.repo, '')) at = 0 available = self.exists(set(hash for (_filename, hash) in files)) for filename, hash in files: ui.progress(_('getting largefiles'), at, unit='lfile', total=len(files)) at += 1 ui.note(_('getting %s:%s\n') % (filename, hash)) if not available.get(hash): ui.warn(_('%s: largefile %s not available from %s\n') % (filename, hash, self.url)) missing.append(filename) continue storefilename = lfutil.storepath(self.repo, hash) tmpfile = util.atomictempfile(storefilename + '.tmp', createmode=self.repo.store.createmode) try: hhash = self._getfile(tmpfile, filename, hash) except StoreError, err: ui.warn(err.longmessage()) hhash = "" tmpfile.close() if hhash != hash: if hhash != "": ui.warn(_('%s: data corruption (expected %s, got %s)\n') % (filename, hash, hhash)) util.unlink(storefilename + '.tmp') missing.append(filename) continue util.rename(storefilename + '.tmp', storefilename) lfutil.linktousercache(self.repo, hash) success.append((filename, hhash))
def pickle_atomic(data, file_path, dir=None): """pickle some data to a path atomically. This is present because I kept corrupting my revmap by managing to hit ^C during the pickle of that file. """ try: f, path = tempfile.mkstemp(prefix='pickling', dir=dir) f = os.fdopen(f, 'w') pickle.dump(data, f) f.close() except: #pragma: no cover raise else: hgutil.rename(path, file_path)
def mergefiles(ui, repo, wctx, shelvectx): """updates to wctx and merges the changes from shelvectx into the dirstate.""" with ui.configoverride({('ui', 'quiet'): True}): hg.update(repo, wctx.node()) files = [] files.extend(shelvectx.files()) files.extend(shelvectx.parents()[0].files()) # revert will overwrite unknown files, so move them out of the way for file in repo.status(unknown=True).unknown: if file in files: util.rename(file, scmutil.origpath(ui, repo, file)) ui.pushbuffer(True) cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(), *pathtofiles(repo, files), **{'no_backup': True}) ui.popbuffer()
def unshelvecontinue(ui, repo, state, opts): """subcommand to continue an in-progress unshelve""" # We're finishing off a merge. First parent is our original # parent, second is the temporary "fake" commit we're unshelving. wlock = repo.wlock() lock = None try: checkparents(repo, state) ms = merge.mergestate(repo) if [f for f in ms if ms[f] == 'u']: raise error.Abort( _("unresolved conflicts, can't continue"), hint=_("see 'hg resolve', then 'hg unshelve --continue'")) lock = repo.lock() util.rename(repo.join('unshelverebasestate'), repo.join('rebasestate')) try: rebase.rebase(ui, repo, **{ 'continue' : True }) except Exception: util.rename(repo.join('rebasestate'), repo.join('unshelverebasestate')) raise shelvectx = repo['tip'] if not shelvectx in state.pendingctx.children(): # rebase was a no-op, so it produced no child commit shelvectx = state.pendingctx else: # only strip the shelvectx if the rebase produced it state.stripnodes.append(shelvectx.node()) mergefiles(ui, repo, state.wctx, shelvectx) repair.strip(ui, repo, state.stripnodes, backup=False, topic='shelve') shelvedstate.clear(repo) unshelvecleanup(ui, repo, state.name, opts) ui.status(_("unshelve of '%s' complete\n") % state.name) finally: lockmod.release(lock, wlock)
def server_bind(self): # use a unique temp address so we can stat the file and do ownership # check later tempaddress = _tempaddress(self.server_address) # use relative path instead of full path at bind() if possible, since # AF_UNIX path has very small length limit (107 chars) on common # platforms (see sys/un.h) dirname, basename = os.path.split(tempaddress) bakwdfd = None if dirname: bakwdfd = os.open('.', os.O_DIRECTORY) os.chdir(dirname) self.socket.bind(basename) self._socketstat = os.stat(basename) # rename will replace the old socket file if exists atomically. the # old server will detect ownership change and exit. util.rename(basename, self.server_address) if bakwdfd: os.fchdir(bakwdfd) os.close(bakwdfd)
def mergefiles(ui, repo, wctx, shelvectx): """updates to wctx and merges the changes from shelvectx into the dirstate.""" oldquiet = ui.quiet try: ui.quiet = True hg.update(repo, wctx.node()) files = [] files.extend(shelvectx.files()) files.extend(shelvectx.parents()[0].files()) # revert will overwrite unknown files, so move them out of the way m, a, r, d, u = repo.status(unknown=True)[:5] for file in u: if file in files: util.rename(file, file + ".orig") cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(), *pathtofiles(repo, files), **{'no_backup': True}) finally: ui.quiet = oldquiet
def stripmarker(ui, repo, markers): """remove <markers> from the repo obsstore The old obsstore content is saved in a `obsstore.prestrip` file """ repo = repo.unfiltered() repo.destroying() oldmarkers = list(repo.obsstore._all) util.rename(repo.sjoin('obsstore'), repo.join('obsstore.prestrip')) del repo.obsstore # drop the cache newstore = repo.obsstore assert not newstore # should be empty after rename newmarkers = [m for m in oldmarkers if m not in markers] tr = repo.transaction('drophack') try: newstore.add(tr, newmarkers) tr.close() finally: tr.release() repo.destroyed()
def unsharejournal(orig, ui, repo, repopath): """Copy shared journal entries into this repo when unsharing""" if (repo.path == repopath and repo.shared() and util.safehasattr(repo, 'journal')): sharedrepo = share._getsrcrepo(repo) sharedfeatures = _readsharedfeatures(repo) if sharedrepo and sharedfeatures > set(['journal']): # there is a shared repository and there are shared journal entries # to copy. move shared date over from source to destination but # move the local file first if repo.vfs.exists('namejournal'): journalpath = repo.join('namejournal') util.rename(journalpath, journalpath + '.bak') storage = repo.journal local = storage._open( repo.vfs, filename='namejournal.bak', _newestfirst=False) shared = ( e for e in storage._open(sharedrepo.vfs, _newestfirst=False) if sharednamespaces.get(e.namespace) in sharedfeatures) for entry in _mergeentriesiter(local, shared, order=min): storage._write(repo.vfs, entry) return orig(ui, repo, repopath)
if tmpwctx.node() != shelvectx.parents()[0].node(): ui.status(_('rebasing shelved changes\n')) try: rebase.rebase(ui, repo, **{ 'rev' : [shelvectx.rev()], 'dest' : str(tmpwctx.rev()), 'keep' : True, }) except error.InterventionRequired: tr.close() stripnodes = [repo.changelog.node(rev) for rev in xrange(oldtiprev, len(repo))] shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes) util.rename(repo.join('rebasestate'), repo.join('unshelverebasestate')) raise error.InterventionRequired( _("unresolved conflicts (see 'hg resolve', then " "'hg unshelve --continue')")) # refresh ctx after rebase completes shelvectx = repo['tip'] if not shelvectx in tmpwctx.children(): # rebase was a no-op, so it produced no child commit shelvectx = tmpwctx mergefiles(ui, repo, pctx, shelvectx) shelvedstate.clear(repo) # The transaction aborting will strip all the commits for us,
def rollback(self, *args): if os.path.exists(self.join('undo.bookmarks')): util.rename(self.join('undo.bookmarks'), self.join('bookmarks')) return super(bookmark_repo, self).rollback(*args)
def movetobackup(self): if not self.backupvfs.isdir(): self.backupvfs.makedir() util.rename(self.filename(), self.backupfilename())
def rollback(self): if os.path.exists(self.join('undo.bookmarks')): util.rename(self.join('undo.bookmarks'), self.join('bookmarks')) return super(bookmark_repo, self).rollback()
def uncrustify(ui, repo, *patterns, **options): """Run uncrustify on the specified files or directories. If no files are specified, operates on the whole working directory. Note: Files that don't have a .cc or .h suffix are always ignored, even if specified on the command line explicitly. By default, prints a list of files that are not clean according to uncrustify, using a similar output format as with hg status. No changes are made to the working directory. With the --diff option, prints the changes suggested by uncrustify in unified diff format. No changes are made to the working directory. With the --modify option, actually performs the changes suggested by uncrustify. The original (dirty) files are backed up with a .crusty suffix. Existing files with such a suffix are silently overwritten. To disable these backups, use --no-backup. This command always operates on the working directory, not on arbitrary repository revisions. Returns 0 on success. """ if options["diff"] and options["modify"]: raise util.Abort("cannot specify --diff and --modify at the same time") if options["diff"]: mode = "diff" elif options["modify"]: mode = "modify" else: mode = "status" no_backup = options["no_backup"] show_clean = options["show_clean"] paths = [path for path in _get_files(repo, patterns, options) if path.endswith((".cc", ".h"))] uncrustify_cfg = repo.pathto(".uncrustify.cfg") relpaths = [repo.pathto(path) for path in paths] if not os.path.exists(uncrustify_cfg): raise util.Abort("could not find .uncrustify.cfg in repository root") _run_uncrustify(uncrustify_cfg, relpaths) ctx = repo[None] for path in paths: relpath = repo.pathto(path) uncr_path = path + SUFFIX uncr_relpath = relpath + SUFFIX have_changes = (ctx[path].data() != ctx[uncr_path].data()) if have_changes: if mode == "status": ui.write("M %s\n" % relpath, label="status.modified") util.unlink(uncr_relpath) elif mode == "diff": _run_diff(relpath, uncr_relpath) util.unlink(uncr_relpath) elif mode == "modify": if not no_backup: util.rename(relpath, relpath + ".crusty") util.rename(uncr_relpath, relpath) if not ui.quiet: ui.write("%s uncrustified\n" % relpath) else: if show_clean: if mode == "status": ui.write("C %s\n" % relpath, label="status.clean") elif mode == "modify": ui.write("%s is clean\n" % relpath) util.unlink(uncr_relpath)
def _createsymlink(self): if self._baseaddress == self._realaddress: return tempaddress = _tempaddress(self._baseaddress) os.symlink(os.path.basename(self._realaddress), tempaddress) util.rename(tempaddress, self._baseaddress)
class basestore(object): def __init__(self, ui, repo, url): self.ui = ui self.repo = repo self.url = url def put(self, source, hash): '''Put source file into the store so it can be retrieved by hash.''' raise NotImplementedError('abstract method') def exists(self, hashes): '''Check to see if the store contains the given hashes. Given an iterable of hashes it returns a mapping from hash to bool.''' raise NotImplementedError('abstract method') def get(self, files): '''Get the specified largefiles from the store and write to local files under repo.root. files is a list of (filename, hash) tuples. Return (success, missing), lists of files successfully downloaded and those not found in the store. success is a list of (filename, hash) tuples; missing is a list of filenames that we could not get. (The detailed error message will already have been presented to the user, so missing is just supplied as a summary.)''' success = [] missing = [] ui = self.ui at = 0 available = self.exists(set(hash for (_filename, hash) in files)) for filename, hash in files: ui.progress(_('getting largefiles'), at, unit='lfile', total=len(files)) at += 1 ui.note(_('getting %s:%s\n') % (filename, hash)) if not available.get(hash): ui.warn( _('%s: largefile %s not available from %s\n') % (filename, hash, util.hidepassword(self.url))) missing.append(filename) continue if self._gethash(filename, hash): success.append((filename, hash)) else: missing.append(filename) ui.progress(_('getting largefiles'), None) return (success, missing) def _gethash(self, filename, hash): """Get file with the provided hash and store it in the local repo's store and in the usercache. filename is for informational messages only. """ util.makedirs(lfutil.storepath(self.repo, '')) storefilename = lfutil.storepath(self.repo, hash) tmpname = storefilename + '.tmp' tmpfile = util.atomictempfile(tmpname, createmode=self.repo.store.createmode) try: gothash = self._getfile(tmpfile, filename, hash) except StoreError, err: self.ui.warn(err.longmessage()) gothash = "" tmpfile.close() if gothash != hash: if gothash != "": self.ui.warn( _('%s: data corruption (expected %s, got %s)\n') % (filename, hash, gothash)) util.unlink(tmpname) return False util.rename(tmpname, storefilename) lfutil.linktousercache(self.repo, hash) return True
def rollback(self): if os.path.exists(self.join('tasks/undo.tasks')): util.rename(self.join('tasks/undo.tasks'), self.join('tasks/tasks')) return super(task_repo, self).rollback()
def uncrustify(ui, repo, *patterns, **options): """Run uncrustify on the specified files or directories. If no files are specified, operates on the whole working directory. Note: Files that don't have a .cc or .h suffix are always ignored, even if specified on the command line explicitly. By default, prints a list of files that are not clean according to uncrustify, using a similar output format as with hg status. No changes are made to the working directory. With the --diff option, prints the changes suggested by uncrustify in unified diff format. No changes are made to the working directory. With the --modify option, actually performs the changes suggested by uncrustify. The original (dirty) files are backed up with a .crusty suffix. Existing files with such a suffix are silently overwritten. To disable these backups, use --no-backup. This command always operates on the working directory, not on arbitrary repository revisions. Returns 0 on success. """ if options["diff"] and options["modify"]: raise util.Abort("cannot specify --diff and --modify at the same time") if options["diff"]: mode = "diff" elif options["modify"]: mode = "modify" else: mode = "status" no_backup = options["no_backup"] show_clean = options["show_clean"] paths = [ path for path in _get_files(repo, patterns, options) if path.endswith((".cc", ".h")) ] uncrustify_cfg = repo.pathto(".uncrustify.cfg") relpaths = [repo.pathto(path) for path in paths] if not os.path.exists(uncrustify_cfg): raise util.Abort("could not find .uncrustify.cfg in repository root") _run_uncrustify(uncrustify_cfg, relpaths) ctx = repo[None] for path in paths: relpath = repo.pathto(path) uncr_path = path + SUFFIX uncr_relpath = relpath + SUFFIX have_changes = (ctx[path].data() != ctx[uncr_path].data()) if have_changes: if mode == "status": ui.write("M %s\n" % relpath, label="status.modified") util.unlink(uncr_relpath) elif mode == "diff": _run_diff(relpath, uncr_relpath) util.unlink(uncr_relpath) elif mode == "modify": if not no_backup: util.rename(relpath, relpath + ".crusty") util.rename(uncr_relpath, relpath) if not ui.quiet: ui.write("%s uncrustified\n" % relpath) else: if show_clean: if mode == "status": ui.write("C %s\n" % relpath, label="status.clean") elif mode == "modify": ui.write("%s is clean\n" % relpath) util.unlink(uncr_relpath)
def _dounshelve(ui, repo, *shelved, **opts): abortf = opts.get('abort') continuef = opts.get('continue') if not abortf and not continuef: cmdutil.checkunfinished(repo) if abortf or continuef: if abortf and continuef: raise error.Abort(_('cannot use both abort and continue')) if shelved: raise error.Abort(_('cannot combine abort/continue with ' 'naming a shelved change')) if abortf and opts.get('tool', False): ui.warn(_('tool option will be ignored\n')) try: state = shelvedstate.load(repo) except IOError as err: if err.errno != errno.ENOENT: raise cmdutil.wrongtooltocontinue(repo, _('unshelve')) except error.CorruptedState as err: ui.debug(str(err) + '\n') if continuef: msg = _('corrupted shelved state file') hint = _('please run hg unshelve --abort to abort unshelve ' 'operation') raise error.Abort(msg, hint=hint) elif abortf: msg = _('could not read shelved state file, your working copy ' 'may be in an unexpected state\nplease update to some ' 'commit\n') ui.warn(msg) shelvedstate.clear(repo) return if abortf: return unshelveabort(ui, repo, state, opts) elif continuef: return unshelvecontinue(ui, repo, state, opts) elif len(shelved) > 1: raise error.Abort(_('can only unshelve one change at a time')) elif not shelved: shelved = listshelves(repo) if not shelved: raise error.Abort(_('no shelved changes to apply!')) basename = util.split(shelved[0][1])[1] ui.status(_("unshelving change '%s'\n") % basename) else: basename = shelved[0] if not shelvedfile(repo, basename, 'patch').exists(): raise error.Abort(_("shelved change '%s' not found") % basename) oldquiet = ui.quiet lock = tr = None forcemerge = ui.backupconfig('ui', 'forcemerge') try: ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'unshelve') lock = repo.lock() tr = repo.transaction('unshelve', report=lambda x: None) oldtiprev = len(repo) pctx = repo['.'] tmpwctx = pctx # The goal is to have a commit structure like so: # ...-> pctx -> tmpwctx -> shelvectx # where tmpwctx is an optional commit with the user's pending changes # and shelvectx is the unshelved changes. Then we merge it all down # to the original pctx. # Store pending changes in a commit and remember added in case a shelve # contains unknown files that are part of the pending change s = repo.status() addedbefore = frozenset(s.added) if s.modified or s.added or s.removed or s.deleted: ui.status(_("temporarily committing pending changes " "(restore with 'hg unshelve --abort')\n")) def commitfunc(ui, repo, message, match, opts): hasmq = util.safehasattr(repo, 'mq') if hasmq: saved, repo.mq.checkapplied = repo.mq.checkapplied, False backup = repo.ui.backupconfig('phases', 'new-commit') try: repo.ui.setconfig('phases', 'new-commit', phases.secret) return repo.commit(message, 'shelve@localhost', opts.get('date'), match) finally: repo.ui.restoreconfig(backup) if hasmq: repo.mq.checkapplied = saved tempopts = {} tempopts['message'] = "pending changes temporary commit" tempopts['date'] = opts.get('date') ui.quiet = True node = cmdutil.commit(ui, repo, commitfunc, [], tempopts) tmpwctx = repo[node] ui.quiet = True shelvedfile(repo, basename, 'hg').applybundle() ui.quiet = oldquiet shelvectx = repo['tip'] branchtorestore = '' if shelvectx.branch() != shelvectx.p1().branch(): branchtorestore = shelvectx.branch() # If the shelve is not immediately on top of the commit # we'll be merging with, rebase it to be on top. if tmpwctx.node() != shelvectx.parents()[0].node(): ui.status(_('rebasing shelved changes\n')) try: rebase.rebase(ui, repo, **{ 'rev' : [shelvectx.rev()], 'dest' : str(tmpwctx.rev()), 'keep' : True, 'tool' : opts.get('tool', ''), }) except error.InterventionRequired: tr.close() stripnodes = [repo.changelog.node(rev) for rev in xrange(oldtiprev, len(repo))] shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes, branchtorestore) util.rename(repo.join('rebasestate'), repo.join('unshelverebasestate')) raise error.InterventionRequired( _("unresolved conflicts (see 'hg resolve', then " "'hg unshelve --continue')")) # refresh ctx after rebase completes shelvectx = repo['tip'] if not shelvectx in tmpwctx.children(): # rebase was a no-op, so it produced no child commit shelvectx = tmpwctx mergefiles(ui, repo, pctx, shelvectx) restorebranch(ui, repo, branchtorestore) # Forget any files that were unknown before the shelve, unknown before # unshelve started, but are now added. shelveunknown = shelvectx.extra().get('shelve_unknown') if shelveunknown: shelveunknown = frozenset(shelveunknown.split('\0')) addedafter = frozenset(repo.status().added) toforget = (addedafter & shelveunknown) - addedbefore repo[None].forget(toforget) shelvedstate.clear(repo) # The transaction aborting will strip all the commits for us, # but it doesn't update the inmemory structures, so addchangegroup # hooks still fire and try to operate on the missing commits. # Clean up manually to prevent this. repo.unfiltered().changelog.strip(oldtiprev, tr) unshelvecleanup(ui, repo, basename, opts) _aborttransaction(repo) finally: ui.quiet = oldquiet if tr: tr.release() lockmod.release(lock) ui.restoreconfig(forcemerge)
def unshelve(ui, repo, *shelved, **opts): """restore a shelved change to the working directory This command accepts an optional name of a shelved change to restore. If none is given, the most recent shelved change is used. If a shelved change is applied successfully, the bundle that contains the shelved changes is moved to a backup location (.hg/shelve-backup). Since you can restore a shelved change on top of an arbitrary commit, it is possible that unshelving will result in a conflict between your changes and the commits you are unshelving onto. If this occurs, you must resolve the conflict, then use ``--continue`` to complete the unshelve operation. (The bundle will not be moved until you successfully complete the unshelve.) (Alternatively, you can use ``--abort`` to abandon an unshelve that causes a conflict. This reverts the unshelved changes, and leaves the bundle in place.) After a successful unshelve, the shelved changes are stored in a backup directory. Only the N most recent backups are kept. N defaults to 10 but can be overridden using the ``shelve.maxbackups`` configuration option. .. container:: verbose Timestamp in seconds is used to decide order of backups. More than ``maxbackups`` backups are kept, if same timestamp prevents from deciding exact order of them, for safety. """ abortf = opts['abort'] continuef = opts['continue'] if not abortf and not continuef: cmdutil.checkunfinished(repo) if abortf or continuef: if abortf and continuef: raise error.Abort(_('cannot use both abort and continue')) if shelved: raise error.Abort( _('cannot combine abort/continue with ' 'naming a shelved change')) try: state = shelvedstate.load(repo) except IOError as err: if err.errno != errno.ENOENT: raise raise error.Abort(_('no unshelve operation underway')) if abortf: return unshelveabort(ui, repo, state, opts) elif continuef: return unshelvecontinue(ui, repo, state, opts) elif len(shelved) > 1: raise error.Abort(_('can only unshelve one change at a time')) elif not shelved: shelved = listshelves(repo) if not shelved: raise error.Abort(_('no shelved changes to apply!')) basename = util.split(shelved[0][1])[1] ui.status(_("unshelving change '%s'\n") % basename) else: basename = shelved[0] if not shelvedfile(repo, basename, 'patch').exists(): raise error.Abort(_("shelved change '%s' not found") % basename) oldquiet = ui.quiet wlock = lock = tr = None try: wlock = repo.wlock() lock = repo.lock() tr = repo.transaction('unshelve', report=lambda x: None) oldtiprev = len(repo) pctx = repo['.'] tmpwctx = pctx # The goal is to have a commit structure like so: # ...-> pctx -> tmpwctx -> shelvectx # where tmpwctx is an optional commit with the user's pending changes # and shelvectx is the unshelved changes. Then we merge it all down # to the original pctx. # Store pending changes in a commit s = repo.status() if s.modified or s.added or s.removed or s.deleted: ui.status( _("temporarily committing pending changes " "(restore with 'hg unshelve --abort')\n")) def commitfunc(ui, repo, message, match, opts): hasmq = util.safehasattr(repo, 'mq') if hasmq: saved, repo.mq.checkapplied = repo.mq.checkapplied, False backup = repo.ui.backupconfig('phases', 'new-commit') try: repo.ui.setconfig('phases', 'new-commit', phases.secret) return repo.commit(message, 'shelve@localhost', opts.get('date'), match) finally: repo.ui.restoreconfig(backup) if hasmq: repo.mq.checkapplied = saved tempopts = {} tempopts['message'] = "pending changes temporary commit" tempopts['date'] = opts.get('date') ui.quiet = True node = cmdutil.commit(ui, repo, commitfunc, [], tempopts) tmpwctx = repo[node] ui.quiet = True shelvedfile(repo, basename, 'hg').applybundle() ui.quiet = oldquiet shelvectx = repo['tip'] # If the shelve is not immediately on top of the commit # we'll be merging with, rebase it to be on top. if tmpwctx.node() != shelvectx.parents()[0].node(): ui.status(_('rebasing shelved changes\n')) try: rebase.rebase( ui, repo, **{ 'rev': [shelvectx.rev()], 'dest': str(tmpwctx.rev()), 'keep': True, }) except error.InterventionRequired: tr.close() stripnodes = [ repo.changelog.node(rev) for rev in xrange(oldtiprev, len(repo)) ] shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes) util.rename(repo.join('rebasestate'), repo.join('unshelverebasestate')) raise error.InterventionRequired( _("unresolved conflicts (see 'hg resolve', then " "'hg unshelve --continue')")) # refresh ctx after rebase completes shelvectx = repo['tip'] if not shelvectx in tmpwctx.children(): # rebase was a no-op, so it produced no child commit shelvectx = tmpwctx mergefiles(ui, repo, pctx, shelvectx) shelvedstate.clear(repo) # The transaction aborting will strip all the commits for us, # but it doesn't update the inmemory structures, so addchangegroup # hooks still fire and try to operate on the missing commits. # Clean up manually to prevent this. repo.unfiltered().changelog.strip(oldtiprev, tr) unshelvecleanup(ui, repo, basename, opts) _aborttransaction(repo) finally: ui.quiet = oldquiet if tr: tr.release() lockmod.release(lock, wlock)
def shrink(ui, repo, **opts): """ Shrink revlog by re-ordering revisions. Will operate on manifest for the given repository if no other revlog is specified.""" # Unbuffer stdout for nice progress output. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) if not repo.local(): raise util.Abort('not a local repository: %s' % repo.root) fn = opts.get('revlog') if not fn: indexfn = repo.sjoin('00manifest.i') else: if not fn.endswith('.i'): raise util.Abort('--revlog option must specify the revlog index ' 'file (*.i), not %s' % opts.get('revlog')) indexfn = os.path.realpath(fn) store = repo.sjoin('') if not indexfn.startswith(store): raise util.Abort('--revlog option must specify a revlog in %s, ' 'not %s' % (store, indexfn)) datafn = indexfn[:-2] + '.d' if not os.path.exists(indexfn): raise util.Abort('no such file: %s' % indexfn) if '00changelog' in indexfn: raise util.Abort('shrinking the changelog will corrupt your repository') if not os.path.exists(datafn): # This is just a lazy shortcut because I can't be bothered to # handle all the special cases that entail from no .d file. raise util.Abort('%s does not exist: revlog not big enough ' 'to be worth shrinking' % datafn) oldindexfn = indexfn + '.old' olddatafn = datafn + '.old' if os.path.exists(oldindexfn) or os.path.exists(olddatafn): raise util.Abort('one or both of\n' ' %s\n' ' %s\n' 'exists from a previous run; please clean up before ' 'running again' % (oldindexfn, olddatafn)) ui.write('shrinking %s\n' % indexfn) prefix = os.path.basename(indexfn)[:-1] (tmpfd, tmpindexfn) = tempfile.mkstemp(dir=os.path.dirname(indexfn), prefix=prefix, suffix='.i') tmpdatafn = tmpindexfn[:-2] + '.d' os.close(tmpfd) r1 = revlog.revlog(util.opener(os.getcwd(), audit=False), indexfn) r2 = revlog.revlog(util.opener(os.getcwd(), audit=False), tmpindexfn) # Don't use repo.transaction(), because then things get hairy with # paths: some need to be relative to .hg, and some need to be # absolute. Doing it this way keeps things simple: everything is an # absolute path. lock = repo.lock(wait=False) tr = transaction.transaction(ui.warn, open, repo.sjoin('journal')) try: try: order = toposort(ui, r1) writerevs(ui, r1, r2, order, tr) report(ui, datafn, tmpdatafn) tr.close() except: # Abort transaction first, so we truncate the files before # deleting them. tr.abort() if os.path.exists(tmpindexfn): os.unlink(tmpindexfn) if os.path.exists(tmpdatafn): os.unlink(tmpdatafn) raise if not opts.get('dry_run'): # Racy since both files cannot be renamed atomically util.os_link(indexfn, oldindexfn) util.os_link(datafn, olddatafn) util.rename(tmpindexfn, indexfn) util.rename(tmpdatafn, datafn) else: os.unlink(tmpindexfn) os.unlink(tmpdatafn) finally: lock.release() if not opts.get('dry_run'): ui.write('note: old revlog saved in:\n' ' %s\n' ' %s\n' '(You can delete those files when you are satisfied that your\n' 'repository is still sane. ' 'Running \'hg verify\' is strongly recommended.)\n' % (oldindexfn, olddatafn))
def _dounshelve(ui, repo, *shelved, **opts): abortf = opts.get('abort') continuef = opts.get('continue') if not abortf and not continuef: cmdutil.checkunfinished(repo) if abortf or continuef: if abortf and continuef: raise error.Abort(_('cannot use both abort and continue')) if shelved: raise error.Abort( _('cannot combine abort/continue with ' 'naming a shelved change')) if abortf and opts.get('tool', False): ui.warn(_('tool option will be ignored\n')) try: state = shelvedstate.load(repo) except IOError as err: if err.errno != errno.ENOENT: raise cmdutil.wrongtooltocontinue(repo, _('unshelve')) if abortf: return unshelveabort(ui, repo, state, opts) elif continuef: return unshelvecontinue(ui, repo, state, opts) elif len(shelved) > 1: raise error.Abort(_('can only unshelve one change at a time')) elif not shelved: shelved = listshelves(repo) if not shelved: raise error.Abort(_('no shelved changes to apply!')) basename = util.split(shelved[0][1])[1] ui.status(_("unshelving change '%s'\n") % basename) else: basename = shelved[0] if not shelvedfile(repo, basename, 'patch').exists(): raise error.Abort(_("shelved change '%s' not found") % basename) oldquiet = ui.quiet lock = tr = None forcemerge = ui.backupconfig('ui', 'forcemerge') try: ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'unshelve') lock = repo.lock() tr = repo.transaction('unshelve', report=lambda x: None) oldtiprev = len(repo) pctx = repo['.'] tmpwctx = pctx # The goal is to have a commit structure like so: # ...-> pctx -> tmpwctx -> shelvectx # where tmpwctx is an optional commit with the user's pending changes # and shelvectx is the unshelved changes. Then we merge it all down # to the original pctx. # Store pending changes in a commit and remember added in case a shelve # contains unknown files that are part of the pending change s = repo.status() addedbefore = frozenset(s.added) if s.modified or s.added or s.removed or s.deleted: ui.status( _("temporarily committing pending changes " "(restore with 'hg unshelve --abort')\n")) def commitfunc(ui, repo, message, match, opts): hasmq = util.safehasattr(repo, 'mq') if hasmq: saved, repo.mq.checkapplied = repo.mq.checkapplied, False backup = repo.ui.backupconfig('phases', 'new-commit') try: repo.ui.setconfig('phases', 'new-commit', phases.secret) return repo.commit(message, 'shelve@localhost', opts.get('date'), match) finally: repo.ui.restoreconfig(backup) if hasmq: repo.mq.checkapplied = saved tempopts = {} tempopts['message'] = "pending changes temporary commit" tempopts['date'] = opts.get('date') ui.quiet = True node = cmdutil.commit(ui, repo, commitfunc, [], tempopts) tmpwctx = repo[node] ui.quiet = True shelvedfile(repo, basename, 'hg').applybundle() ui.quiet = oldquiet shelvectx = repo['tip'] branchtorestore = '' if shelvectx.branch() != shelvectx.p1().branch(): branchtorestore = shelvectx.branch() # If the shelve is not immediately on top of the commit # we'll be merging with, rebase it to be on top. if tmpwctx.node() != shelvectx.parents()[0].node(): ui.status(_('rebasing shelved changes\n')) try: rebase.rebase( ui, repo, **{ 'rev': [shelvectx.rev()], 'dest': str(tmpwctx.rev()), 'keep': True, 'tool': opts.get('tool', ''), }) except error.InterventionRequired: tr.close() stripnodes = [ repo.changelog.node(rev) for rev in xrange(oldtiprev, len(repo)) ] shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes, branchtorestore) util.rename(repo.join('rebasestate'), repo.join('unshelverebasestate')) raise error.InterventionRequired( _("unresolved conflicts (see 'hg resolve', then " "'hg unshelve --continue')")) # refresh ctx after rebase completes shelvectx = repo['tip'] if not shelvectx in tmpwctx.children(): # rebase was a no-op, so it produced no child commit shelvectx = tmpwctx mergefiles(ui, repo, pctx, shelvectx) restorebranch(ui, repo, branchtorestore) # Forget any files that were unknown before the shelve, unknown before # unshelve started, but are now added. shelveunknown = shelvectx.extra().get('shelve_unknown') if shelveunknown: shelveunknown = frozenset(shelveunknown.split('\0')) addedafter = frozenset(repo.status().added) toforget = (addedafter & shelveunknown) - addedbefore repo[None].forget(toforget) shelvedstate.clear(repo) # The transaction aborting will strip all the commits for us, # but it doesn't update the inmemory structures, so addchangegroup # hooks still fire and try to operate on the missing commits. # Clean up manually to prevent this. repo.unfiltered().changelog.strip(oldtiprev, tr) unshelvecleanup(ui, repo, basename, opts) _aborttransaction(repo) finally: ui.quiet = oldquiet if tr: tr.release() lockmod.release(lock) ui.restoreconfig(forcemerge)
tr.close() except: # re-raises # Abort transaction first, so we truncate the files before # deleting them. tr.abort() for fn in (tmpindexfn, tmpdatafn): ignoremissing(os.unlink)(fn) raise if not opts.get('dry_run'): # racy, both files cannot be renamed atomically # copy files util.oslink(indexfn, oldindexfn) ignoremissing(util.oslink)(datafn, olddatafn) # rename util.rename(tmpindexfn, indexfn) try: os.chmod(tmpdatafn, os.stat(datafn).st_mode) util.rename(tmpdatafn, datafn) except OSError, inst: if inst.errno != errno.ENOENT: raise ignoremissing(os.unlink)(datafn) else: for fn in (tmpindexfn, tmpdatafn): ignoremissing(os.unlink)(fn) finally: lock.release() if not opts.get('dry_run'): ui.write(
def unshelve(ui, repo, *shelved, **opts): """restore a shelved change to the working directory This command accepts an optional name of a shelved change to restore. If none is given, the most recent shelved change is used. If a shelved change is applied successfully, the bundle that contains the shelved changes is moved to a backup location (.hg/shelve-backup). Since you can restore a shelved change on top of an arbitrary commit, it is possible that unshelving will result in a conflict between your changes and the commits you are unshelving onto. If this occurs, you must resolve the conflict, then use ``--continue`` to complete the unshelve operation. (The bundle will not be moved until you successfully complete the unshelve.) (Alternatively, you can use ``--abort`` to abandon an unshelve that causes a conflict. This reverts the unshelved changes, and leaves the bundle in place.) After a successful unshelve, the shelved changes are stored in a backup directory. Only the N most recent backups are kept. N defaults to 10 but can be overridden using the ``shelve.maxbackups`` configuration option. .. container:: verbose Timestamp in seconds is used to decide order of backups. More than ``maxbackups`` backups are kept, if same timestamp prevents from deciding exact order of them, for safety. """ abortf = opts['abort'] continuef = opts['continue'] if not abortf and not continuef: cmdutil.checkunfinished(repo) if abortf or continuef: if abortf and continuef: raise error.Abort(_('cannot use both abort and continue')) if shelved: raise error.Abort(_('cannot combine abort/continue with ' 'naming a shelved change')) try: state = shelvedstate.load(repo) except IOError as err: if err.errno != errno.ENOENT: raise raise error.Abort(_('no unshelve operation underway')) if abortf: return unshelveabort(ui, repo, state, opts) elif continuef: return unshelvecontinue(ui, repo, state, opts) elif len(shelved) > 1: raise error.Abort(_('can only unshelve one change at a time')) elif not shelved: shelved = listshelves(repo) if not shelved: raise error.Abort(_('no shelved changes to apply!')) basename = util.split(shelved[0][1])[1] ui.status(_("unshelving change '%s'\n") % basename) else: basename = shelved[0] if not shelvedfile(repo, basename, 'patch').exists(): raise error.Abort(_("shelved change '%s' not found") % basename) oldquiet = ui.quiet wlock = lock = tr = None try: wlock = repo.wlock() lock = repo.lock() tr = repo.transaction('unshelve', report=lambda x: None) oldtiprev = len(repo) pctx = repo['.'] tmpwctx = pctx # The goal is to have a commit structure like so: # ...-> pctx -> tmpwctx -> shelvectx # where tmpwctx is an optional commit with the user's pending changes # and shelvectx is the unshelved changes. Then we merge it all down # to the original pctx. # Store pending changes in a commit s = repo.status() if s.modified or s.added or s.removed or s.deleted: ui.status(_("temporarily committing pending changes " "(restore with 'hg unshelve --abort')\n")) def commitfunc(ui, repo, message, match, opts): hasmq = util.safehasattr(repo, 'mq') if hasmq: saved, repo.mq.checkapplied = repo.mq.checkapplied, False backup = repo.ui.backupconfig('phases', 'new-commit') try: repo.ui. setconfig('phases', 'new-commit', phases.secret) return repo.commit(message, 'shelve@localhost', opts.get('date'), match) finally: repo.ui.restoreconfig(backup) if hasmq: repo.mq.checkapplied = saved tempopts = {} tempopts['message'] = "pending changes temporary commit" tempopts['date'] = opts.get('date') ui.quiet = True node = cmdutil.commit(ui, repo, commitfunc, [], tempopts) tmpwctx = repo[node] ui.quiet = True shelvedfile(repo, basename, 'hg').applybundle() ui.quiet = oldquiet shelvectx = repo['tip'] # If the shelve is not immediately on top of the commit # we'll be merging with, rebase it to be on top. if tmpwctx.node() != shelvectx.parents()[0].node(): ui.status(_('rebasing shelved changes\n')) try: rebase.rebase(ui, repo, **{ 'rev' : [shelvectx.rev()], 'dest' : str(tmpwctx.rev()), 'keep' : True, }) except error.InterventionRequired: tr.close() stripnodes = [repo.changelog.node(rev) for rev in xrange(oldtiprev, len(repo))] shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes) util.rename(repo.join('rebasestate'), repo.join('unshelverebasestate')) raise error.InterventionRequired( _("unresolved conflicts (see 'hg resolve', then " "'hg unshelve --continue')")) # refresh ctx after rebase completes shelvectx = repo['tip'] if not shelvectx in tmpwctx.children(): # rebase was a no-op, so it produced no child commit shelvectx = tmpwctx mergefiles(ui, repo, pctx, shelvectx) shelvedstate.clear(repo) # The transaction aborting will strip all the commits for us, # but it doesn't update the inmemory structures, so addchangegroup # hooks still fire and try to operate on the missing commits. # Clean up manually to prevent this. repo.unfiltered().changelog.strip(oldtiprev, tr) unshelvecleanup(ui, repo, basename, opts) _aborttransaction(repo) finally: ui.quiet = oldquiet if tr: tr.release() lockmod.release(lock, wlock)
def close(self): if not self.closed: posixfile_utf8.close(self) util.rename(self._tempname, util.localpath(self.__name))
def _createsymlink(self): if self.baseaddress == self.address: return tempaddress = _tempaddress(self.baseaddress) os.symlink(os.path.basename(self.address), tempaddress) util.rename(tempaddress, self.baseaddress)
def rollback(self): if os.path.exists(self.join("undo.bookmarks")): util.rename(self.join("undo.bookmarks"), self.join("bookmarks")) return super(bookmark_repo, self).rollback()