def openstore(repo=None, remote=None, put=False, ui=None): if ui is None: ui = repo.ui if not remote: lfpullsource = getattr(repo, 'lfpullsource', None) if lfpullsource: path = ui.expandpath(lfpullsource) elif put: path = ui.expandpath('default-push', 'default') else: path = ui.expandpath('default') # ui.expandpath() leaves 'default-push' and 'default' alone if # they cannot be expanded: fallback to the empty string, # meaning the current directory. if repo is None: path = ui.expandpath('default') path, _branches = hg.parseurl(path) remote = hg.peer(repo or ui, {}, path) elif path == 'default-push' or path == 'default': path = '' remote = repo else: path, _branches = hg.parseurl(path) remote = hg.peer(repo or ui, {}, path) # The path could be a scheme so use Mercurial's normal functionality # to resolve the scheme to a repository and use its path path = util.safehasattr(remote, 'url') and remote.url() or remote.path match = _scheme_re.match(path) if not match: # regular filesystem path scheme = 'file' else: scheme = match.group(1) try: storeproviders = _storeprovider[scheme] except KeyError: raise error.Abort(_('unsupported URL scheme %r') % scheme) for classobj in storeproviders: try: return classobj(ui, repo, remote) except lfutil.storeprotonotcapable: pass raise error.Abort( _('%s does not appear to be a largefile store') % util.hidepassword(path))
def goutgoing(ui, repo, dest=None, **opts): """show the outgoing changesets alongside an ASCII revision graph Print the outgoing changesets alongside a revision graph drawn with ASCII characters. Nodes printed as an @ character are parents of the working directory. """ check_unsupported_flags(opts) dest, revs, checkout = hg.parseurl( ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev')) if revs: revs = [repo.lookup(rev) for rev in revs] other = hg.repository(cmdutil.remoteui(ui, opts), dest) ui.status(_('comparing with %s\n') % url.hidepassword(dest)) o = repo.findoutgoing(other, force=opts.get('force')) if not o: ui.status(_("no changes found\n")) return o = repo.changelog.nodesbetween(o, revs)[0] revdag = graphrevs(repo, o, opts) fmtdag = asciiformat(ui, repo, revdag, opts) ascii(ui, asciiedges(fmtdag))
def goutgoing(ui, repo, dest=None, **opts): """show the outgoing changesets alongside an ASCII revision graph Print the outgoing changesets alongside a revision graph drawn with ASCII characters. Nodes printed as an @ character are parents of the working directory. """ check_unsupported_flags(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')) other = hg.repository(cmdutil.remoteui(ui, opts), dest) if revs: revs = [repo.lookup(rev) for rev in revs] ui.status(_('comparing with %s\n') % url.hidepassword(dest)) o = repo.findoutgoing(other, force=opts.get('force')) if not o: ui.status(_("no changes found\n")) return o = repo.changelog.nodesbetween(o, revs)[0] revdag = graphrevs(repo, o, opts) displayer = show_changeset(ui, repo, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] generate(ui, revdag, displayer, showparents, asciiedges)
def findoutgoing(ui, repo, remote=None, force=False, opts=None): """utility function to find the first outgoing changeset Used by initialization code""" if opts is None: opts = {} dest = ui.expandpath(remote or 'default-push', remote or 'default') dest, revs = hg.parseurl(dest, None)[:2] ui.status(_('comparing with %s\n') % util.hidepassword(dest)) revs, checkout = hg.addbranchrevs(repo, repo, revs, None) other = hg.peer(repo, opts, dest) if revs: revs = [repo.lookup(rev) for rev in revs] outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force) if not outgoing.missing: raise error.Abort(_('no outgoing ancestors')) roots = list(repo.revs("roots(%ln)", outgoing.missing)) if 1 < len(roots): msg = _('there are ambiguous outgoing revisions') hint = _('see "hg help histedit" for more detail') raise error.Abort(msg, hint=hint) return repo.lookup(roots[0])
def get_repo(alias, url): """Returns a hg.repository object initialized for usage. """ try: from mercurial import hg, ui except ImportError: die("Mercurial python libraries not installed") ui = ui.ui() source, revs = hg.parseurl(ui.expandpath(url), ['tip']) repo = hg.repository(ui, source) prefix = 'refs/hg/%s/' % alias debug("prefix: '%s'", prefix) repo.hg = hg repo.gitdir = "" repo.alias = alias repo.prefix = prefix repo.revs = revs repo.git_hg = GitHg(warn) exporter = GitExporter(repo.git_hg, repo, 'hg.marks', 'git.marks', prefix) non_local = NonLocalHg(repo, alias) repo.exporter = exporter repo.non_local = non_local return repo
def validate_hg_url(self, url): error = _("Invalid Hg URL: '%s'") % url source, branches = hg.parseurl(url) try: hg.repository(ui.ui(), source) except RepoError: raise forms.ValidationError(error)
def diff(orig, ui, repo, *pats, **opts): """ [rdiff] If the first argument to the diff command is a remote repository URL, the diff will be performed against that URL. If revision arguments are given, the first revision is the revision in the source repository, and the second revision is looked up in the destination. The --reverse flag cause the direction of the diff to be reversed. """ url = None rrev = None if pats: path = ui.expandpath(pats[0]) if hasattr(hg, "parseurl"): # parseurl changed from returning two args to three args = hg.parseurl(ui.expandpath(pats[0]), []) path, rrev = args[0], args[-1] if "://" in path or os.path.isdir(os.path.join(path, ".hg")): url = path pats = pats[1:] if url: lrev = None if len(opts["rev"]) > 2 or rrev and len(opts["rev"]) > 1: raise util.Abort(_("too many revisions")) if opts["rev"]: lrev = opts["rev"][0] if len(opts["rev"]) > 1: rrev = opts["rev"][1] return rdiff(ui, repo, url, lrev, rrev, *pats, **opts) else: return orig(ui, repo, *pats, **opts)
def nclone(ui, source, dest=None, **opts): '''make a copy of an existing repository and all nested repositories Create a copy of an existing repository in a new directory. Look at the help of clone command for more informations.''' origsource = ui.expandpath(source) remotesource, remotebranch = hg.parseurl(origsource, opts.get('branch')) if hasattr(hg, 'peer'): remoterepo = hg.peer(ui, opts, remotesource) localrepo = remoterepo.local() if localrepo: remoterepo = localrepo else: remoterepo = hg.repository(hg.remoteui(ui, opts), remotesource) if dest is None: dest = hg.defaultdest(source) ui.status(_("destination directory: %s\n") % dest) for npath in remoterepo.nested: if npath == '.': npath = '' u = util.url(source) if u.scheme: nsource = '%s/%s' % (source, npath) else: nsource = os.path.join(source, npath) ndest = os.path.join(dest, npath) ui.status('[%s]\n' % os.path.normpath( os.path.join(os.path.basename(dest), ndest[len(dest) + 1:]))) commands.clone(ui, nsource, dest=ndest, **opts) ui.status('\n')
def _findbundle(repo, rev): """Returns the backup bundle that contains the given rev. If found, it returns the bundle peer and the full rev hash. If not found, it return None and the given rev value. """ ui = repo.ui backuppath = repo.vfs.join("strip-backup") backups = filter(os.path.isfile, glob.glob(backuppath + "/*.hg")) backups.sort(key=lambda x: os.path.getmtime(x), reverse=True) for backup in backups: # Much of this is copied from the hg incoming logic source = os.path.relpath(backup, pycompat.getcwd()) source = ui.expandpath(source) source, branches = hg.parseurl(source) other = hg.peer(repo, {}, source) quiet = ui.quiet try: ui.quiet = True ret = bundlerepo.getremotechanges(ui, repo, other, None, None, None) localother, chlist, cleanupfn = ret for node in chlist: if hex(node).startswith(rev): return other, node except error.LookupError: continue finally: ui.quiet = quiet return None, rev
def pull(oldpull, ui, repo, source="default", **opts): # translate bookmark args to rev args for actual pull if opts.get('bookmark'): # this is an unpleasant hack as pull will do this internally source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch')) other = hg.repository(hg.remoteui(repo, opts), source) rb = other.listkeys('bookmarks') for b in opts['bookmark']: if b not in rb: raise util.Abort(_('remote bookmark %s not found!') % b) opts.setdefault('rev', []).append(b) result = oldpull(ui, repo, source, **opts) # update specified bookmarks if opts.get('bookmark'): for b in opts['bookmark']: # explicit pull overrides local bookmark if any ui.status(_("importing bookmark %s\n") % b) repo._bookmarks[b] = repo[rb[b]].node() write(repo) return result
def outgoing(self): limit = cmdutil.loglimit(opts) dest, revs, checkout = hg.parseurl( ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev')) if revs: revs = [repo.lookup(rev) for rev in revs] other = hg.repository(cmdutil.remoteui(repo, opts), dest) ui.status(_('comparing with %s\n') % url.hidepassword(dest)) o = repo.findoutgoing(other, force=opts.get('force')) if not o: ui.status(_("no changes found\n")) return 1 o = repo.changelog.nodesbetween(o, revs)[0] if opts.get('newest_first'): o.reverse() displayer = cmdutil.show_changeset(ui, repo, opts) count = 0 for n in o: if count >= limit: break parents = [p for p in repo.changelog.parents(n) if p != nullid] if opts.get('no_merges') and len(parents) == 2: continue count += 1 displayer.show(repo[n])
def incoming(oldincoming, ui, repo, source="default", **opts): if opts.get('bookmarks'): source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch')) other = hg.repository(hg.remoteui(repo, opts), source) ui.status(_('comparing with %s\n') % url.hidepassword(source)) return diffbookmarks(ui, repo, other) else: return oldincoming(ui, repo, source, **opts)
def find_pull_peer(repo, opts, source): source, branches = hg.parseurl(repo.ui.expandpath(source), opts.get('branch')) try: return hg.peer(repo, opts, source) except error.RepoError: if source == "default": return else: raise
def outgoing(oldoutgoing, ui, repo, dest=None, **opts): if opts.get('bookmarks'): dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest, opts.get('branch')) other = hg.repository(hg.remoteui(repo, opts), dest) ui.status(_('comparing with %s\n') % url.hidepassword(dest)) return diffbookmarks(ui, other, repo) else: return oldoutgoing(ui, repo, dest, **opts)
def incoming(self): limit = cmdutil.loglimit(opts) source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev')) other = hg.repository(cmdutil.remoteui(repo, opts), source) ui.status(_('comparing with %s\n') % url.hidepassword(source)) if revs: revs = [other.lookup(rev) for rev in revs] common, incoming, rheads = repo.findcommonincoming(other, heads=revs, force=opts["force"]) if not incoming: try: os.unlink(opts["bundle"]) except: pass ui.status(_("no changes found\n")) return 1 cleanup = None try: fname = opts["bundle"] if fname or not other.local(): # create a bundle (uncompressed if other repo is not local) if revs is None and other.capable('changegroupsubset'): revs = rheads if revs is None: cg = other.changegroup(incoming, "incoming") else: cg = other.changegroupsubset(incoming, revs, 'incoming') bundletype = other.local() and "HG10BZ" or "HG10UN" fname = cleanup = changegroup.writebundle(cg, fname, bundletype) # keep written bundle? if opts["bundle"]: cleanup = None if not other.local(): # use the created uncompressed bundlerepo other = bundlerepo.bundlerepository(ui, repo.root, fname) o = other.changelog.nodesbetween(incoming, revs)[0] if opts.get('newest_first'): o.reverse() displayer = cmdutil.show_changeset(ui, other, opts) count = 0 for n in o: if count >= limit: break parents = [p for p in other.changelog.parents(n) if p != nullid] if opts.get('no_merges') and len(parents) == 2: continue count += 1 displayer.show(other[n]) finally: if hasattr(other, 'close'): other.close() if cleanup: os.unlink(cleanup)
def gincoming(ui, repo, source="default", **opts): """show the incoming changesets alongside an ASCII revision graph Print the incoming changesets alongside a revision graph drawn with ASCII characters. Nodes printed as an @ character are parents of the working directory. """ check_unsupported_flags(opts) source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch')) other = hg.repository(cmdutil.remoteui(repo, opts), source) revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev')) ui.status(_('comparing with %s\n') % url.hidepassword(source)) if revs: revs = [other.lookup(rev) for rev in revs] incoming = repo.findincoming(other, heads=revs, force=opts["force"]) if not incoming: try: os.unlink(opts["bundle"]) except: pass ui.status(_("no changes found\n")) return cleanup = None try: fname = opts["bundle"] if fname or not other.local(): # create a bundle (uncompressed if other repo is not local) if revs is None: cg = other.changegroup(incoming, "incoming") else: cg = other.changegroupsubset(incoming, revs, 'incoming') bundletype = other.local() and "HG10BZ" or "HG10UN" fname = cleanup = changegroup.writebundle(cg, fname, bundletype) # keep written bundle? if opts["bundle"]: cleanup = None if not other.local(): # use the created uncompressed bundlerepo other = bundlerepo.bundlerepository(ui, repo.root, fname) chlist = other.changelog.nodesbetween(incoming, revs)[0] revdag = graphrevs(other, chlist, opts) displayer = show_changeset(ui, other, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] generate(ui, revdag, displayer, showparents, asciiedges) finally: if hasattr(other, 'close'): other.close() if cleanup: os.unlink(cleanup)
def _pull(orig, ui, repo, source="default", **opts): opts = pycompat.byteskwargs(opts) # Copy paste from `pull` command source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch')) scratchbookmarks = {} unfi = repo.unfiltered() unknownnodes = [] for rev in opts.get('rev', []): if rev not in unfi: unknownnodes.append(rev) if opts.get('bookmark'): bookmarks = [] revs = opts.get('rev') or [] for bookmark in opts.get('bookmark'): if _scratchbranchmatcher(bookmark): # rev is not known yet # it will be fetched with listkeyspatterns next scratchbookmarks[bookmark] = 'REVTOFETCH' else: bookmarks.append(bookmark) if scratchbookmarks: other = hg.peer(repo, opts, source) fetchedbookmarks = other.listkeyspatterns( 'bookmarks', patterns=scratchbookmarks) for bookmark in scratchbookmarks: if bookmark not in fetchedbookmarks: raise error.Abort('remote bookmark %s not found!' % bookmark) scratchbookmarks[bookmark] = fetchedbookmarks[bookmark] revs.append(fetchedbookmarks[bookmark]) opts['bookmark'] = bookmarks opts['rev'] = revs if scratchbookmarks or unknownnodes: # Set anyincoming to True extensions.wrapfunction(discovery, 'findcommonincoming', _findcommonincoming) try: # Remote scratch bookmarks will be deleted because remotenames doesn't # know about them. Let's save it before pull and restore after remotescratchbookmarks = _readscratchremotebookmarks(ui, repo, source) result = orig(ui, repo, source, **pycompat.strkwargs(opts)) # TODO(stash): race condition is possible # if scratch bookmarks was updated right after orig. # But that's unlikely and shouldn't be harmful. if common.isremotebooksenabled(ui): remotescratchbookmarks.update(scratchbookmarks) _saveremotebookmarks(repo, remotescratchbookmarks, source) else: _savelocalbookmarks(repo, scratchbookmarks) return result finally: if scratchbookmarks: extensions.unwrapfunction(discovery, 'findcommonincoming')
def parseurl(url, heads=[]): url, heads = hg.parseurl(url, heads) if isinstance(heads, tuple) and len(heads) == 2: # hg 1.6 or later _junk, heads = heads if heads: checkout = heads[0] else: checkout = None return url, heads, checkout
def find_push_peer(repo, opts, dest): dest = repo.ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest, opts.get('branch')) try: return hg.peer(repo, opts, dest) except error.RepoError: if dest == "default-push": return else: raise
def _getsrcrepo(repo): """ Returns the source repository object for a given shared repository. If repo is not a shared repository, return None. """ if repo.sharedpath == repo.path: return None # the sharedpath always ends in the .hg; we want the path to the repo source = repo.vfs.split(repo.sharedpath)[0] srcurl, branches = parseurl(source) return repository(repo.ui, srcurl)
def parseurl(url, heads=[]): parsed = hg.parseurl(url, heads) if len(parsed) == 3: # old hg, remove when we can be 1.5-only svn_url, heads, checkout = parsed else: svn_url, heads = parsed if heads: checkout = heads[0] else: checkout = None return svn_url, heads, checkout
def test(ui, repo, source, **opts): source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch')) other = hg.repository(hg.remoteui(repo, opts), source) revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev')) if revs: try: revs = [other.lookup(rev) for rev in revs] except CapabilityError: err = _("Other repository doesn't support revision lookup, " "so a rev cannot be specified.") raise util.Abort(err)
def getoutgoing(dest, revs): '''Return the revisions present locally but not in dest''' dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest) revs, checkout = hg.addbranchrevs(repo, repo, branches, revs) other = hg.peer(repo, opts, dest) ui.status(_('comparing with %s\n') % util.hidepassword(dest)) common, _anyinc, _heads = discovery.findcommonincoming(repo, other) nodes = revs and map(repo.lookup, revs) or revs o = repo.changelog.findmissing(common, heads=nodes) if not o: ui.status(_("no changes found\n")) return [] return [str(repo.changelog.rev(r)) for r in o]
def pull(self): source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev')) other = hg.repository(cmdutil.remoteui(repo, opts), source) ui.status(_('pulling from %s\n') % url.hidepassword(source)) if revs: try: revs = [other.lookup(rev) for rev in revs] except error.CapabilityError: err = _("Other repository doesn't support revision lookup, " "so a rev cannot be specified.") raise util.Abort(err) modheads = repo.pull(other, heads=revs, force=opts.get('force')) return postincoming(ui, repo, modheads, opts.get('update'), checkout)
def _getoutgoing(repo, dest, revs): '''Return the revisions present locally but not in dest''' ui = repo.ui url = ui.expandpath(dest or 'default-push', dest or 'default') url = hg.parseurl(url)[0] ui.status(_('comparing with %s\n') % util.hidepassword(url)) revs = [r for r in revs if r >= 0] if not revs: revs = [len(repo) - 1] revs = repo.revs('outgoing(%s) and ::%ld', dest or '', revs) if not revs: ui.status(_("no changes found\n")) return revs
def _firefoxtreesrepo(repo): """Obtain a repo that can open the firefoxtrees file. Will return the passed ``repo`` in most cases. But if ``repo`` is shared, we may return the repo from the share source. """ shared = {s.strip() for s in repo.vfs.tryread('shared').splitlines()} if 'firefoxtrees' in shared and repo.sharedpath != repo.path: source = repo.vfs.split(repo.sharedpath)[0] srcurl, branches = hg.parseurl(source) return hg.repository(repo.ui, srcurl) else: return repo
def test(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 hasattr(hg, 'peer'): other = hg.peer(ui, opts, dest) localother = other.local() if localother: other = localother else: other = hg.repository(hg.remoteui(repo, opts), dest) if revs: revs = [other.lookup(rev) for rev in revs]
def outgoing(dest, revs): '''Return the revisions present locally but not in dest''' dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest) revs, checkout = hg.addbranchrevs(repo, repo, branches, revs) if revs: revs = [repo.lookup(rev) for rev in revs] other = hg.repository(cmdutil.remoteui(repo, opts), dest) ui.status(_('comparing with %s\n') % dest) o = repo.findoutgoing(other) if not o: ui.status(_("no changes found\n")) return [] o = repo.changelog.nodesbetween(o, revs)[0] return [str(repo.changelog.rev(r)) for r in o]
def getoutgoing(dest, revs): '''Return the revisions present locally but not in dest''' dest = ui.expandpath(dest or 'default-push', dest or 'default') dest, branches = hg.parseurl(dest) revs, checkout = hg.addbranchrevs(repo, repo, branches, revs) if revs: revs = [repo.lookup(rev) for rev in revs] other = hg.repository(hg.remoteui(repo, opts), dest) ui.status(_('comparing with %s\n') % url.hidepassword(dest)) o = discovery.findoutgoing(repo, other) if not o: ui.status(_("no changes found\n")) return [] o = repo.changelog.nodesbetween(o, revs)[0] return [str(repo.changelog.rev(r)) for r in o]
def push(self): dest, revs, checkout = hg.parseurl( ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev')) other = hg.repository(cmdutil.remoteui(repo, opts), dest) ui.status(_('pushing to %s\n') % url.hidepassword(dest)) if revs: revs = [repo.lookup(rev) for rev in revs] # push subrepos depth-first for coherent ordering c = repo[''] subs = c.substate # only repos that are committed for s in sorted(subs): c.sub(s).push(opts.get('force')) r = repo.push(other, opts.get('force'), revs=revs)
def parseurl(url, heads=[]): parsed = hg.parseurl(url, heads) if len(parsed) == 3: # old hg, remove when we can be 1.5-only svn_url, heads, checkout = parsed else: svn_url, heads = parsed if isinstance(heads, tuple) and len(heads) == 2: # hg 1.6 or later _junk, heads = heads if heads: checkout = heads[0] else: checkout = None return svn_url, heads, checkout
def parseurl(source): '''wrap hg.parseurl to work on 1.5 and 1.6 1.5 redefined parseurl()'s return values, and 1.6 split up the branches parameter into a two-tuple. ''' url, branches = hg.parseurl(source, None)[:2] if _HG_VERSION >= (1, 6, 0): # branches will be None because we passed None into # parseurl(), so we can ignore that safely. hashbranch, branches = branches else: # branches will contain one element or fewer because we passed # None into parseurl(). hashbranch = branches and branches[0] or None return url, hashbranch
def push(self, dest=None, rev=None, force=False): """\ Push changes into destination. If destination is none, the source of this repo will be used. If revision is not specified, the current working dir will be pushed. If this spawns a new head, this operation must be forced. Forcing will have the side effect of creating a new branch, and it may not be desirable. By default, no remote branch will be created. """ # find parents # if there are two parents, take the first one, # (ui should warn users about uncommitted merge/confirmation) # if not force, do it and see if head shows up if rev is None: rev = [self._repo.lookup('.')] dest = self._ui.expandpath(dest or 'default-push', dest or 'default') repo = self._repo dest, branches = hg.parseurl(dest) revs, checkout = hg.addbranchrevs(repo, repo, branches, rev) if dest in ('default', 'default-push',): raise RepoNotFoundError('no suitable target found') other = hg.peer(self._repo, {}, dest) self._ui.status('pushing to %s\n' % (dest)) if revs: revs = [self._repo.lookup(rev) for rev in revs] try: r = self._repo.push(other, force, revs=revs) except Abort: raise ProtocolError() # check to see if this revision is present on destination # XXX assuming other is localrepo try: result = other.lookup(revs[0]) except: result = None return result is not None
def _openstore(repo, remote=None, put=False): ui = repo.ui if not remote: lfpullsource = getattr(repo, 'lfpullsource', None) if lfpullsource: path = ui.expandpath(lfpullsource) elif put: path = ui.expandpath('default-push', 'default') else: path = ui.expandpath('default') # ui.expandpath() leaves 'default-push' and 'default' alone if # they cannot be expanded: fallback to the empty string, # meaning the current directory. if path == 'default-push' or path == 'default': path = '' remote = repo else: path, _branches = hg.parseurl(path) remote = hg.peer(repo, {}, path) # The path could be a scheme so use Mercurial's normal functionality # to resolve the scheme to a repository and use its path path = util.safehasattr(remote, 'url') and remote.url() or remote.path match = _scheme_re.match(path) if not match: # regular filesystem path scheme = 'file' else: scheme = match.group(1) try: storeproviders = _storeprovider[scheme] except KeyError: raise error.Abort(_('unsupported URL scheme %r') % scheme) for classobj in storeproviders: try: return classobj(ui, repo, remote) except lfutil.storeprotonotcapable: pass raise error.Abort( _('%s does not appear to be a largefile store') % util.hidepassword(path))
def share(orig, ui, source, *args, **kwargs): """Wraps hg.share to mark the firefoxtrees file as shared. The .hg/shared file lists things that are shared. We add firefoxtrees to it if we are a Firefox repo. """ res = orig(ui, source, *args, **kwargs) # TODO Mercurial 3.7 introduces a standalone function that receives the # proper arguments so we can avoid this boilerplate. if isinstance(source, str): origsource = ui.expandpath(source) source, branches = hg.parseurl(origsource) srcrepo = hg.repository(ui, source) else: srcrepo = source.local() if not isfirefoxrepo(srcrepo): return res if args: dest = args[0] elif 'dest' in kwargs: dest = kwargs['dest'] else: dest = None if not dest: dest = hg.defaultdest(source) else: dest = ui.expandpath(dest) try: from mercurial.vfs import vfs except ImportError: vfs = scmutil.vfs destwvfs = vfs(dest, realpath=True) r = hg.repository(ui, destwvfs.base) with r.wlock(): with r.vfs('shared', 'ab') as fh: fh.write('firefoxtrees\n') return res
def get_outgoing_bfiles(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] # Mercurial <= 1.5 had remoteui in cmdutil, then it moved to hg try: remoteui = cmdutil.remoteui except AttributeError: remoteui = hg.remoteui try: remote = hg.repository(remoteui(repo, opts), dest) except error.RepoError: return None o = bfutil.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 bfutil.is_standin(f) and f in ctx])) return toupload
def share(orig, ui, source, *args, **kwargs): """Wraps hg.share to mark the firefoxtrees file as shared. The .hg/shared file lists things that are shared. We add firefoxtrees to it if we are a Firefox repo. """ res = orig(ui, source, *args, **kwargs) if not util.safehasattr(source, 'local'): origsource = ui.expandpath(source) source, branches = hg.parseurl(origsource) srcrepo = hg.repository(ui, source) else: srcrepo = source.local() if not isfirefoxrepo(srcrepo): return res if args: dest = args[0] elif 'dest' in kwargs: dest = kwargs['dest'] else: dest = None if not dest: dest = hg.defaultdest(source) else: dest = ui.expandpath(dest) try: from mercurial.vfs import vfs except ImportError: vfs = scmutil.vfs destwvfs = vfs(dest, realpath=True) r = hg.repository(ui, destwvfs.base) with r.wlock(): with r.vfs(b'shared', b'ab') as fh: fh.write(b'firefoxtrees\n') return res
def taskspush(orig, ui, repo, dest=None, **opts): ''' Task push Calls custom push command with new custom args''' # all copied from mercurial/commands.py dest, revs, checkout = hg.parseurl( ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev')) cmdutil.setremoteconfig(ui, opts) other = hg.repository(ui, dest) ui.status(_('pushing to %s\n') % url.hidepassword(dest)) if revs: revs = [repo.lookup(rev) for rev in revs] # add in our new options r = repo.push(other, opts.get('force'), revs=revs, completed_tasks=opts.get('completed_tasks'), all_tasks=opts.get('all_tasks')) return r == 0
def testparse(self): self.assertEqual(hg.parseurl(b'http://example.com/no/anchor'), (b'http://example.com/no/anchor', (None, []))) self.assertEqual(hg.parseurl(b'http://example.com/an/anchor#foo'), (b'http://example.com/an/anchor', (b'foo', []))) self.assertEqual( hg.parseurl(b'http://example.com/no/anchor/branches', [b'foo']), (b'http://example.com/no/anchor/branches', (None, [b'foo']))) self.assertEqual( hg.parseurl(b'http://example.com/an/anchor/branches#bar', [b'foo']), (b'http://example.com/an/anchor/branches', (b'bar', [b'foo']))) self.assertEqual( hg.parseurl(b'http://example.com/an/anchor/branches-None#foo', None), (b'http://example.com/an/anchor/branches-None', (b'foo', []))) self.assertEqual(hg.parseurl(b'http://example.com/'), (b'http://example.com/', (None, []))) self.assertEqual(hg.parseurl(b'http://example.com'), (b'http://example.com/', (None, []))) self.assertEqual(hg.parseurl(b'http://example.com#foo'), (b'http://example.com/', (b'foo', [])))
def findoutgoing(ui, repo, remote=None, force=False, opts={}): """utility function to find the first outgoing changeset Used by initialisation code""" dest = ui.expandpath(remote or 'default-push', remote or 'default') dest, revs = hg.parseurl(dest, None)[:2] ui.status(_('comparing with %s\n') % util.hidepassword(dest)) revs, checkout = hg.addbranchrevs(repo, repo, revs, None) other = hg.peer(repo, opts, dest) if revs: revs = [repo.lookup(rev) for rev in revs] # hexlify nodes from outgoing, because we're going to parse # parent[0] using revsingle below, and if the binary hash # contains special revset characters like ":" the revset # parser can choke. outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force) if not outgoing.missing: raise util.Abort(_('no outgoing ancestors')) return outgoing.missing[0]
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 scmutil.revrange(repo, revs)] try: remote = hg.peer(repo, opts, dest) except error.RepoError: return None outgoing = discovery.findcommonoutgoing(repo, remote.peer(), force=False) if not outgoing.missing: return outgoing.missing o = repo.changelog.nodesbetween(outgoing.missing, 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 sorted(toupload)
def remotemarkers(ui, repo, source, opts): # Disable status output from fetching a remote. ui.quiet = True markers = [] source, branches = hg.parseurl(ui.expandpath(source)) remote = hg.peer(repo, opts, source) with remote.commandexecutor() as e: branchmap = e.callcommand(b'branchmap', {}).result() for branch_name in branchmap: for branch_node in branchmap[branch_name]: markers.append({ 'type': 'branch', 'name': branch_name, 'node': node.hex(branch_node), 'description': None, }) with remote.commandexecutor() as e: remotemarks = bookmarks.unhexlifybookmarks( e.callcommand(b'listkeys', { b'namespace': b'bookmarks', }).result()) for mark in remotemarks: markers.append({ 'type': 'bookmark', 'name': mark, 'node': node.hex(remotemarks[mark]), 'description': None, }) return markers
def diff(orig, ui, repo, *pats, **opts): """ [rdiff] If the first argument to the diff command is a remote repository URL, the diff will be performed against that URL. If revision arguments are given, the first revision is the revision in the source repository, and the second revision is looked up in the destination. The --reverse flag cause the direction of the diff to be reversed. """ url = None rrev = None if pats: path = ui.expandpath(pats[0]) if hasattr(hg, 'parseurl'): args = hg.parseurl(ui.expandpath(pats[0]), []) # parseurl changed from returning two args to three path, rrev = args[0], args[-1] # 1.6 (3d6915f5a2bb): parseurl returns (url, (branch, branches)) if type(rrev) == tuple: rrev = rrev[0] if '://' in path or os.path.isdir(os.path.join(path, '.hg')): url = path pats = pats[1:] if url: lrev = None if len(opts['rev']) > 2 or rrev and len(opts['rev']) > 1: raise util.Abort(_('too many revisions')) if opts['rev']: lrev = opts['rev'][0] if len(opts['rev']) > 1: rrev = opts['rev'][1] return rdiff(ui, repo, url, lrev, rrev, *pats, **opts) else: return orig(ui, repo, *pats, **opts)
def testparse(url, rev=[]): print '%s, revs: %r, checkout: %r' % parseurl(url, rev)
def trackedcmd(ui, repo, remotepath=None, *pats, **opts): """show or change the current narrowspec With no argument, shows the current narrowspec entries, one per line. Each line will be prefixed with 'I' or 'X' for included or excluded patterns, respectively. The narrowspec is comprised of expressions to match remote files and/or directories that should be pulled into your client. The narrowspec has *include* and *exclude* expressions, with excludes always trumping includes: that is, if a file matches an exclude expression, it will be excluded even if it also matches an include expression. Excluding files that were never included has no effect. Each included or excluded entry is in the format described by 'hg help patterns'. The options allow you to add or remove included and excluded expressions. If --clear is specified, then all previous includes and excludes are DROPPED and replaced by the new ones specified to --addinclude and --addexclude. If --clear is specified without any further options, the narrowspec will be empty and will not match any files. """ opts = pycompat.byteskwargs(opts) if repository.NARROW_REQUIREMENT not in repo.requirements: ui.warn(_('The narrow command is only supported on respositories cloned' ' with --narrow.\n')) return 1 # Before supporting, decide whether it "hg tracked --clear" should mean # tracking no paths or all paths. if opts['clear']: ui.warn(_('The --clear option is not yet supported.\n')) return 1 # import rules from a file newrules = opts.get('import_rules') if newrules: try: filepath = os.path.join(encoding.getcwd(), newrules) fdata = util.readfile(filepath) except IOError as inst: raise error.Abort(_("cannot read narrowspecs from '%s': %s") % (filepath, encoding.strtolocal(inst.strerror))) includepats, excludepats, profiles = sparse.parseconfig(ui, fdata, 'narrow') if profiles: raise error.Abort(_("including other spec files using '%include' " "is not supported in narrowspec")) opts['addinclude'].extend(includepats) opts['addexclude'].extend(excludepats) addedincludes = narrowspec.parsepatterns(opts['addinclude']) removedincludes = narrowspec.parsepatterns(opts['removeinclude']) addedexcludes = narrowspec.parsepatterns(opts['addexclude']) removedexcludes = narrowspec.parsepatterns(opts['removeexclude']) only_show = not (addedincludes or removedincludes or addedexcludes or removedexcludes or newrules) oldincludes, oldexcludes = repo.narrowpats # filter the user passed additions and deletions into actual additions and # deletions of excludes and includes addedincludes -= oldincludes removedincludes &= oldincludes addedexcludes -= oldexcludes removedexcludes &= oldexcludes widening = addedincludes or removedexcludes narrowing = removedincludes or addedexcludes # Only print the current narrowspec. if only_show: ui.pager('tracked') fm = ui.formatter('narrow', opts) for i in sorted(oldincludes): fm.startitem() fm.write('status', '%s ', 'I', label='narrow.included') fm.write('pat', '%s\n', i, label='narrow.included') for i in sorted(oldexcludes): fm.startitem() fm.write('status', '%s ', 'X', label='narrow.excluded') fm.write('pat', '%s\n', i, label='narrow.excluded') fm.end() return 0 if not widening and not narrowing: ui.status(_("nothing to widen or narrow\n")) return 0 with repo.wlock(), repo.lock(): cmdutil.bailifchanged(repo) # Find the revisions we have in common with the remote. These will # be used for finding local-only changes for narrowing. They will # also define the set of revisions to update for widening. remotepath = ui.expandpath(remotepath or 'default') url, branches = hg.parseurl(remotepath) ui.status(_('comparing with %s\n') % util.hidepassword(url)) remote = hg.peer(repo, opts, url) # check narrow support before doing anything if widening needs to be # performed. In future we should also abort if client is ellipses and # server does not support ellipses if widening and wireprototypes.NARROWCAP not in remote.capabilities(): raise error.Abort(_("server does not support narrow clones")) commoninc = discovery.findcommonincoming(repo, remote) if narrowing: newincludes = oldincludes - removedincludes newexcludes = oldexcludes | addedexcludes _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes, newincludes, newexcludes, opts['force_delete_local_changes']) # _narrow() updated the narrowspec and _widen() below needs to # use the updated values as its base (otherwise removed includes # and addedexcludes will be lost in the resulting narrowspec) oldincludes = newincludes oldexcludes = newexcludes if widening: newincludes = oldincludes | addedincludes newexcludes = oldexcludes - removedexcludes _widen(ui, repo, remote, commoninc, oldincludes, oldexcludes, newincludes, newexcludes) return 0
def trackedcmd(ui, repo, remotepath=None, *pats, **opts): """show or change the current narrowspec With no argument, shows the current narrowspec entries, one per line. Each line will be prefixed with 'I' or 'X' for included or excluded patterns, respectively. The narrowspec is comprised of expressions to match remote files and/or directories that should be pulled into your client. The narrowspec has *include* and *exclude* expressions, with excludes always trumping includes: that is, if a file matches an exclude expression, it will be excluded even if it also matches an include expression. Excluding files that were never included has no effect. Each included or excluded entry is in the format described by 'hg help patterns'. The options allow you to add or remove included and excluded expressions. If --clear is specified, then all previous includes and excludes are DROPPED and replaced by the new ones specified to --addinclude and --addexclude. If --clear is specified without any further options, the narrowspec will be empty and will not match any files. If --auto-remove-includes is specified, then those includes that don't match any files modified by currently visible local commits (those not shared by the remote) will be added to the set of explicitly specified includes to remove. --import-rules accepts a path to a file containing rules, allowing you to add --addinclude, --addexclude rules in bulk. Like the other include and exclude switches, the changes are applied immediately. """ opts = pycompat.byteskwargs(opts) if repository.NARROW_REQUIREMENT not in repo.requirements: raise error.Abort( _(b'the tracked command is only supported on ' b'repositories cloned with --narrow')) # Before supporting, decide whether it "hg tracked --clear" should mean # tracking no paths or all paths. if opts[b'clear']: raise error.Abort(_(b'the --clear option is not yet supported')) # import rules from a file newrules = opts.get(b'import_rules') if newrules: try: filepath = os.path.join(encoding.getcwd(), newrules) fdata = util.readfile(filepath) except IOError as inst: raise error.Abort( _(b"cannot read narrowspecs from '%s': %s") % (filepath, encoding.strtolocal(inst.strerror))) includepats, excludepats, profiles = sparse.parseconfig( ui, fdata, b'narrow') if profiles: raise error.Abort( _(b"including other spec files using '%include' " b"is not supported in narrowspec")) opts[b'addinclude'].extend(includepats) opts[b'addexclude'].extend(excludepats) addedincludes = narrowspec.parsepatterns(opts[b'addinclude']) removedincludes = narrowspec.parsepatterns(opts[b'removeinclude']) addedexcludes = narrowspec.parsepatterns(opts[b'addexclude']) removedexcludes = narrowspec.parsepatterns(opts[b'removeexclude']) autoremoveincludes = opts[b'auto_remove_includes'] update_working_copy = opts[b'update_working_copy'] only_show = not (addedincludes or removedincludes or addedexcludes or removedexcludes or newrules or autoremoveincludes or update_working_copy) oldincludes, oldexcludes = repo.narrowpats # filter the user passed additions and deletions into actual additions and # deletions of excludes and includes addedincludes -= oldincludes removedincludes &= oldincludes addedexcludes -= oldexcludes removedexcludes &= oldexcludes widening = addedincludes or removedexcludes narrowing = removedincludes or addedexcludes # Only print the current narrowspec. if only_show: ui.pager(b'tracked') fm = ui.formatter(b'narrow', opts) for i in sorted(oldincludes): fm.startitem() fm.write(b'status', b'%s ', b'I', label=b'narrow.included') fm.write(b'pat', b'%s\n', i, label=b'narrow.included') for i in sorted(oldexcludes): fm.startitem() fm.write(b'status', b'%s ', b'X', label=b'narrow.excluded') fm.write(b'pat', b'%s\n', i, label=b'narrow.excluded') fm.end() return 0 if update_working_copy: with repo.wlock(), repo.lock(), repo.transaction(b'narrow-wc'): narrowspec.updateworkingcopy(repo) narrowspec.copytoworkingcopy(repo) return 0 if not (widening or narrowing or autoremoveincludes): ui.status(_(b"nothing to widen or narrow\n")) return 0 with repo.wlock(), repo.lock(): cmdutil.bailifchanged(repo) # Find the revisions we have in common with the remote. These will # be used for finding local-only changes for narrowing. They will # also define the set of revisions to update for widening. remotepath = ui.expandpath(remotepath or b'default') url, branches = hg.parseurl(remotepath) ui.status(_(b'comparing with %s\n') % util.hidepassword(url)) remote = hg.peer(repo, opts, url) # check narrow support before doing anything if widening needs to be # performed. In future we should also abort if client is ellipses and # server does not support ellipses if widening and wireprototypes.NARROWCAP not in remote.capabilities(): raise error.Abort(_(b"server does not support narrow clones")) commoninc = discovery.findcommonincoming(repo, remote) if autoremoveincludes: outgoing = discovery.findcommonoutgoing(repo, remote, commoninc=commoninc) ui.status(_(b'looking for unused includes to remove\n')) localfiles = set() for n in itertools.chain(outgoing.missing, outgoing.excluded): localfiles.update(repo[n].files()) suggestedremovals = [] for include in sorted(oldincludes): match = narrowspec.match(repo.root, [include], oldexcludes) if not any(match(f) for f in localfiles): suggestedremovals.append(include) if suggestedremovals: for s in suggestedremovals: ui.status(b'%s\n' % s) if (ui.promptchoice( _(b'remove these unused includes (yn)?' b'$$ &Yes $$ &No')) == 0): removedincludes.update(suggestedremovals) narrowing = True else: ui.status(_(b'found no unused includes\n')) if narrowing: newincludes = oldincludes - removedincludes newexcludes = oldexcludes | addedexcludes _narrow( ui, repo, remote, commoninc, oldincludes, oldexcludes, newincludes, newexcludes, opts[b'force_delete_local_changes'], ) # _narrow() updated the narrowspec and _widen() below needs to # use the updated values as its base (otherwise removed includes # and addedexcludes will be lost in the resulting narrowspec) oldincludes = newincludes oldexcludes = newexcludes if widening: newincludes = oldincludes | addedincludes newexcludes = oldexcludes - removedexcludes _widen( ui, repo, remote, commoninc, oldincludes, oldexcludes, newincludes, newexcludes, ) return 0
def parseurl(url, heads=[]): checkout = None svn_url, (_junk, heads) = hg.parseurl(url, heads) if heads: checkout = heads[0] return svn_url, heads, checkout
def histedit(ui, repo, *parent, **opts): """hg histedit <parent> """ # TODO only abort if we try and histedit mq patches, not just # blanket if mq patches are applied somewhere mq = getattr(repo, 'mq', None) if mq and mq.applied: raise util.Abort(_('source has mq patches applied')) parent = list(parent) + opts.get('rev', []) if opts.get('outgoing'): if len(parent) > 1: raise util.Abort('only one repo argument allowed with --outgoing') elif parent: parent = parent[0] dest = ui.expandpath(parent or 'default-push', parent or 'default') dest, revs = hg.parseurl(dest, None)[:2] if isinstance(revs, tuple): # hg >= 1.6 revs, checkout = hg.addbranchrevs(repo, repo, revs, None) other = hg.repository(hg.remoteui(repo, opts), dest) # hg >= 1.9 findoutgoing = getattr(discovery, 'findoutgoing', None) if findoutgoing is None: if getattr(discovery, 'outgoing', None) is not None: def findoutgoing(repo, other, force=False): out = discovery.findcommonoutgoing(repo, other, [], force=force) return out.missing[0:1] else: # hg 1.9 and 2.0 def findoutgoing(repo, other, force=False): common, outheads = discovery.findcommonoutgoing( repo, other, [], force=force) return repo.changelog.findmissing(common, outheads)[0:1] else: other = hg.repository(ui, dest) def findoutgoing(repo, other, force=False): return repo.findoutgoing(other, force=force) if revs: revs = [repo.lookup(rev) for rev in revs] ui.status(_('comparing with %s\n') % hidepassword(dest)) parent = findoutgoing(repo, other, force=opts.get('force')) else: if opts.get('force'): raise util.Abort('--force only allowed with --outgoing') if opts.get('continue', False): if len(parent) != 0: raise util.Abort('no arguments allowed with --continue') ( parentctxnode, created, replaced, tmpnodes, existing, rules, keep, tip, ) = readstate(repo) currentparent, wantnull = repo.dirstate.parents() parentctx = repo[parentctxnode] # discover any nodes the user has added in the interim newchildren = [ c for c in parentctx.children() if c.node() not in existing ] action, currentnode = rules.pop(0) while newchildren: if action in [ 'f', 'fold', ]: tmpnodes.extend([n.node() for n in newchildren]) else: created.extend([n.node() for n in newchildren]) newchildren = filter( lambda x: x.node() not in existing, reduce(lambda x, y: x + y, map(lambda r: r.children(), newchildren))) m, a, r, d = repo.status()[:4] oldctx = repo[currentnode] message = oldctx.description() if action in ('e', 'edit', 'm', 'mess'): message = ui.edit(message, ui.username()) elif action in ( 'f', 'fold', ): message = 'fold-temp-revision %s' % currentnode new = None if m or a or r or d: new = repo.commit(text=message, user=oldctx.user(), date=oldctx.date(), extra=oldctx.extra()) if action in ('f', 'fold'): if new: tmpnodes.append(new) else: new = newchildren[-1] ( parentctx, created_, replaced_, tmpnodes_, ) = finishfold(ui, repo, parentctx, oldctx, new, opts, newchildren) replaced.extend(replaced_) created.extend(created_) tmpnodes.extend(tmpnodes_) elif action not in ('d', 'drop'): if new != oldctx.node(): replaced.append(oldctx.node()) if new: if new != oldctx.node(): created.append(new) parentctx = repo[new] elif opts.get('abort', False): if len(parent) != 0: raise util.Abort('no arguments allowed with --abort') ( parentctxnode, created, replaced, tmpnodes, existing, rules, keep, tip, ) = readstate(repo) ui.debug('restore wc to old tip %s\n' % node.hex(tip)) hg.clean(repo, tip) ui.debug('should strip created nodes %s\n' % ', '.join([node.hex(n)[:12] for n in created])) ui.debug('should strip temp nodes %s\n' % ', '.join([node.hex(n)[:12] for n in tmpnodes])) for nodes in ( created, tmpnodes, ): for n in reversed(nodes): try: repair.strip(ui, repo, n) except error.LookupError: pass os.unlink(os.path.join(repo.path, 'histedit-state')) return else: bailifchanged(repo) if os.path.exists(os.path.join(repo.path, 'histedit-state')): raise util.Abort('history edit already in progress, try ' '--continue or --abort') tip, empty = repo.dirstate.parents() if len(parent) != 1: raise util.Abort('requires exactly one parent revision') parent = _revsingle(repo, parent[0]).node() keep = opts.get('keep', False) revs = between(repo, parent, tip, keep) ctxs = [repo[r] for r in revs] existing = [r.node() for r in ctxs] rules = opts.get('commands', '') if not rules: rules = '\n'.join([makedesc(c) for c in ctxs]) rules += editcomment % ( node.hex(parent)[:12], node.hex(tip)[:12], ) rules = ui.edit(rules, ui.username()) # Save edit rules in .hg/histedit-last-edit.txt in case # the user needs to ask for help after something # surprising happens. f = open(repo.join('histedit-last-edit.txt'), 'w') f.write(rules) f.close() else: f = open(rules) rules = f.read() f.close() rules = [ l for l in (r.strip() for r in rules.splitlines()) if l and not l[0] == '#' ] rules = verifyrules(rules, repo, ctxs) parentctx = repo[parent].parents()[0] keep = opts.get('keep', False) replaced = [] tmpnodes = [] created = [] while rules: writestate(repo, parentctx.node(), created, replaced, tmpnodes, existing, rules, keep, tip) action, ha = rules.pop(0) ( parentctx, created_, replaced_, tmpnodes_, ) = actiontable[action](ui, repo, parentctx, ha, opts) created.extend(created_) replaced.extend(replaced_) tmpnodes.extend(tmpnodes_) hg.update(repo, parentctx.node()) if not keep: ui.debug('should strip replaced nodes %s\n' % ', '.join([node.hex(n)[:12] for n in replaced])) for n in sorted(replaced, lambda x, y: cmp(repo[x].rev(), repo[y].rev())): try: repair.strip(ui, repo, n) except error.LookupError: pass ui.debug('should strip temp nodes %s\n' % ', '.join([node.hex(n)[:12] for n in tmpnodes])) for n in reversed(tmpnodes): try: repair.strip(ui, repo, n) except error.LookupError: pass os.unlink(os.path.join(repo.path, 'histedit-state'))
def parseurl(source): '''wrap hg.parseurl to work on 1.3 -> 1.5''' return hg.parseurl(source, None)[:2]