From 6cc703479f7af518534a33de8a7c1c1bf01af6d2 Mon Sep 17 00:00:00 2001 From: René 'Necoro' Neumann Date: Thu, 12 Nov 2009 01:07:29 +0100 Subject: Update hgshelve extension for hg 1.3.1 --- .hgext/hgshelve.py | 206 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 163 insertions(+), 43 deletions(-) (limited to '.hgext') diff --git a/.hgext/hgshelve.py b/.hgext/hgshelve.py index cd159c9..4e0c121 100644 --- a/.hgext/hgshelve.py +++ b/.hgext/hgshelve.py @@ -10,7 +10,7 @@ from mercurial.i18n import _ from mercurial import cmdutil, commands, cmdutil, hg, mdiff, patch, revlog -from mercurial import util, fancyopts +from mercurial import util, fancyopts, extensions import copy, cStringIO, errno, operator, os, re, shutil, tempfile lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)') @@ -21,6 +21,13 @@ def internalpatch(patchobj, ui, strip, cwd, reverse=False, files={}): Adapted from patch.internalpatch() to support reverse patching. """ + + eolmode = ui.config('patch', 'eol', 'strict') + try: + eol = {'strict': None, 'crlf': '\r\n', 'lf': '\n'}[eolmode.lower()] + except KeyError: + raise util.Abort(_('Unsupported line endings type: %s') % eolmode) + try: fp = file(patchobj, 'rb') except TypeError: @@ -29,8 +36,7 @@ def internalpatch(patchobj, ui, strip, cwd, reverse=False, files={}): curdir = os.getcwd() os.chdir(cwd) try: - ret = patch.applydiff(ui, fp, files, strip=strip, - reverse=reverse) + ret = patch.applydiff(ui, fp, files, strip=strip, eol=eol) finally: if cwd: os.chdir(curdir) @@ -160,8 +166,27 @@ class hunk(object): self.hunk = hunk self.added, self.removed = countchanges(self.hunk) + def __cmp__(self, rhs): + # since the hunk().toline needs to be adjusted when hunks are + # removed/added, we can't take it into account when we cmp + attrs = ['header', 'fromline', 'proc', 'hunk', 'added', 'removed'] + for attr in attrs: + selfattr = getattr(self, attr, None) + rhsattr = getattr(rhs, attr, None) + + if selfattr is None or rhsattr is None: + raise util.Abort(_('non-existant attribute %s') % attr) + + rv = cmp(selfattr, rhsattr) + if rv != 0: + return rv + return rv + + def write(self, fp): delta = len(self.before) + len(self.after) + if self.after and self.after[-1] == '\\ No newline at end of file\n': + delta -= 1 fromlen = delta + self.removed tolen = delta + self.added fp.write('@@ -%d,%d +%d,%d @@%s\n' % @@ -211,7 +236,7 @@ def parsepatch(fp): if self.context: self.before = self.context self.context = [] - self.hunk = data + self.hunk = hunk def newfile(self, hdr): self.addcontext([]) @@ -250,7 +275,7 @@ def parsepatch(fp): state = newstate return p.finished() -def filterpatch(ui, chunks): +def filterpatch(ui, chunks, shouldprompt=True): chunks = list(chunks) chunks.reverse() seen = {} @@ -262,7 +287,14 @@ def filterpatch(ui, chunks): else: consumed.append(chunks.pop()) return consumed + resp_all = [None] + + """ If we're not to prompt (i.e. they specified the --all flag) + we pre-emptively set the 'all' flag """ + if shouldprompt == False: + resp_all = ['y'] + resp_file = [None] applied = {} def prompt(query): @@ -271,24 +303,36 @@ def filterpatch(ui, chunks): if resp_file[0] is not None: return resp_file[0] while True: - r = (ui.prompt(query + _(' [Ynsfdaq?] '), '(?i)[Ynsfdaq?]?$') - or 'y').lower() - if r == '?': + resps = _('[Ynsfdaq?]') + choices = (_('&Yes, shelve this change'), + _('&No, skip this change'), + _('&Skip remaining changes to this file'), + _('Shelve remaining changes to this &file'), + _('&Done, skip remaining changes and files'), + _('Shelve &all changes to all remaining files'), + _('&Quit, shelving no changes'), + _('&?')) + r = ui.promptchoice("%s %s " % (query, resps), choices) + if r == 7: c = shelve.__doc__.find('y - shelve this change') for l in shelve.__doc__[c:].splitlines(): - if l: ui.write(_(l.strip()), '\n') + if l: ui.write(_(l.strip()) + '\n') continue - elif r == 's': - r = resp_file[0] = 'n' - elif r == 'f': - r = resp_file[0] = 'y' - elif r == 'd': - r = resp_all[0] = 'n' - elif r == 'a': - r = resp_all[0] = 'y' - elif r == 'q': + elif r == 0: # yes + ret = 'y' + elif r == 1: # no + ret = 'n' + elif r == 2: # Skip + ret = resp_file[0] = 'n' + elif r == 3: # file (shelve remaining) + ret = resp_file[0] = 'y' + elif r == 4: # done, skip remaining + ret = resp_all[0] = 'n' + elif r == 5: # all + ret = resp_all[0] = 'y' + elif r == 6: # quit raise util.Abort(_('user quit')) - return r + return ret while chunks: chunk = chunks.pop() if isinstance(chunk, header): @@ -301,8 +345,12 @@ def filterpatch(ui, chunks): seen[hdr] = True if resp_all[0] is None: chunk.pretty(ui) - r = prompt(_('shelve changes to %s?') % + if shouldprompt == True: + r = prompt(_('shelve changes to %s?') % _(' and ').join(map(repr, chunk.files()))) + else: + r = 'y' + if r == 'y': applied[chunk.filename()] = [chunk] if chunk.allhunks(): @@ -357,34 +405,60 @@ def makebackup(ui, repo, dir, files): return backups +def getshelfpath(repo, name): + if name: + shelfpath = "shelves/" + name + else: + # Check if a shelf from an older version exists + if os.path.isfile(repo.join('shelve')): + shelfpath = 'shelve' + else: + shelfpath = "shelves/default" + + return shelfpath + def shelve(ui, repo, *pats, **opts): '''interactively select changes to set aside If a list of files is omitted, all changes reported by "hg status" - will be candidates for shelveing. + will be candidates for shelving. You will be prompted for whether to shelve changes to each modified file, and for files with multiple changes, for each - change to use. For each query, the following responses are - possible: + change to use. + + The shelve command works with the Color extension to display + diffs in color. - y - shelve this change - n - skip this change + On each prompt, the following responses are possible: - s - skip remaining changes to this file - f - shelve remaining changes to this file + y - shelve this change + n - skip this change - d - done, skip remaining changes and files - a - shelve all changes to all remaining files - q - quit, shelveing no changes + s - skip remaining changes to this file + f - shelve remaining changes to this file - ? - display help''' + d - done, skip remaining changes and files + a - shelve all changes to all remaining files + q - quit, shelving no changes + + ? - display help''' if not ui.interactive: raise util.Abort(_('shelve can only be run interactively')) + # List all the active shelves by name and return ' + if opts['list']: + listshelves(ui,repo) + return + forced = opts['force'] or opts['append'] - if os.path.exists(repo.join('shelve')) and not forced: + + # Shelf name and path + shelfname = opts.get('name') + shelfpath = getshelfpath(repo, shelfname) + + if os.path.exists(repo.join(shelfpath)) and not forced: raise util.Abort(_('shelve data already exists')) def shelvefunc(ui, repo, message, match, opts): @@ -398,7 +472,8 @@ def shelve(ui, repo, *pats, **opts): fp = cStringIO.StringIO(patch_diff) ac = parsepatch(fp) fp.close() - chunks = filterpatch(ui, ac) + + chunks = filterpatch(ui, ac, not opts['all']) rc = refilterpatch(ac, chunks) contenders = {} @@ -452,9 +527,9 @@ def shelve(ui, repo, *pats, **opts): if doshelve: ui.debug("saving patch to shelve\n") if opts['append']: - f = repo.opener('shelve', "a") + f = repo.opener(shelfpath, "a") else: - f = repo.opener('shelve', "w") + f = repo.opener(shelfpath, "w") f.write(sp.getvalue()) del f del sp @@ -464,7 +539,7 @@ def shelve(ui, repo, *pats, **opts): ui.debug('restoring %r to %r\n' % (tmpname, realname)) util.copyfile(tmpname, repo.wjoin(realname)) ui.debug('removing shelve file\n') - os.unlink(repo.join('shelve')) + os.unlink(repo.join(shelfpath)) except OSError: pass @@ -480,18 +555,38 @@ def shelve(ui, repo, *pats, **opts): fancyopts.fancyopts([], commands.commitopts, opts) return cmdutil.commit(ui, repo, shelvefunc, pats, opts) - -def unshelve(ui, repo, *pats, **opts): +def listshelves(ui, repo): + # Check for shelve file at old location first + if os.path.isfile(repo.join('shelve')): + ui.status('default\n') + + # Now go through all the files in the shelves folder and list them out + dirname = repo.join('shelves') + if os.path.isdir(dirname): + for filename in os.listdir(repo.join('shelves')): + ui.status(filename + '\n') + +def unshelve(ui, repo, **opts): '''restore shelved changes''' + # Shelf name and path + shelfname = opts.get('name') + shelfpath = getshelfpath(repo, shelfname) + + # List all the active shelves by name and return ' + if opts['list']: + listshelves(ui,repo) + return + try: - fp = cStringIO.StringIO() - fp.write(repo.opener('shelve').read()) + patch_diff = repo.opener(shelfpath).read() + fp = cStringIO.StringIO(patch_diff) if opts['inspect']: ui.status(fp.getvalue()) else: files = [] - for chunk in parsepatch(fp): + ac = parsepatch(fp) + for chunk in ac: if isinstance(chunk, header): files += chunk.files() backupdir = repo.join('shelve-backups') @@ -522,11 +617,28 @@ def unshelve(ui, repo, *pats, **opts): if patchdone: ui.debug("removing shelved patches\n") - os.unlink(repo.join('shelve')) + os.unlink(repo.join(shelfpath)) ui.status("unshelve completed\n") except IOError: ui.warn('nothing to unshelve\n') +_ui = None + +def uisetup(ui): + # FIXME: no ui object passed to extsetup()? + global _ui + _ui = ui + + +def extsetup(): + try: + # enable color diff in shelve command via Color extension + color = extensions.find('color') + color._setupcmd(_ui, 'shelve', cmdtable, color.colordiff, + color._diff_effects) + except KeyError: + pass + cmdtable = { "shelve": (shelve, @@ -536,6 +648,11 @@ cmdtable = { _('overwrite existing shelve data')), ('a', 'append', None, _('append to existing shelve data')), + ('', 'all', None, + _('shelve all changes')), + ('n', 'name', '', + _('shelve changes to specified shelf name')), + ('l', 'list', None, _('list active shelves')), ] + commands.walkopts, _('hg shelve [OPTION]... [FILE]...')), "unshelve": @@ -543,6 +660,9 @@ cmdtable = { [('i', 'inspect', None, _('inspect shelved changes only')), ('f', 'force', None, _('proceed even if patches do not unshelve cleanly')), + ('n', 'name', '', + _('unshelve changes from specified shelf name')), + ('l', 'list', None, _('list active shelves')), ], - _('hg unshelve [OPTION]... [FILE]...')), + _('hg unshelve [OPTION]...')), } -- cgit v1.2.3-54-g00ecf