Commits

Christian Widmer committed e8674d5

Add support for 'added' and 'removed' files

Edited by: Oleg Oshmyan <chortos@inbox.lv>

Comments (0)

Files changed (2)

 '''interactive change selection to set aside that may be restored later'''
 
 from mercurial.i18n import _
-from mercurial import cmdutil, commands, hg, mdiff, patch
+from mercurial import cmdutil, commands, hg, mdiff, patch, scmutil
 from mercurial import util, fancyopts, extensions
-import copy, cStringIO, errno, operator, os, re, shutil, tempfile
+import copy, cStringIO, errno, operator, os, re, shutil, tempfile, sys
 
 lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
 
 
     backups = {}
     for f in files:
-        fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
-                                       dir=dir)
-        os.close(fd)
-        ui.debug('backup %r as %r\n' % (f, tmpname))
-        util.copyfile(repo.wjoin(f), tmpname)
-        backups[f] = tmpname
+        if os.path.isfile(repo.wjoin(f)):
+            fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
+                                           dir=dir)
+            os.close(fd)
+            ui.debug('backup %r as %r\n' % (f, tmpname))
+            util.copyfile(repo.wjoin(f), tmpname)
+            backups[f] = tmpname
 
     return backups
 
         raise util.Abort(_('shelve data already exists'))
             
     def shelvefunc(ui, repo, message, match, opts):
+        parents = repo.dirstate.parents()
         changes = repo.status(match=match)[:5]
         modified, added, removed = changes[:3]
         files = modified + added + removed
         diffopts = mdiff.diffopts(git=True, nodates=True)
-        patch_diff = ''.join(patch.diff(repo, repo.dirstate.parents()[0],
+        patch_diff = ''.join(patch.diff(repo, parents[0],
                            match=match, changes=changes, opts=diffopts))
         
         fp = cStringIO.StringIO(patch_diff)
         chunks = filterpatch(ui, ac, not opts['all'])
         rc = refilterpatch(ac, chunks)
 
+        # set of files to be processed
         contenders = {}
         for h in chunks:
             try: contenders.update(dict.fromkeys(h.files()))
             except AttributeError: pass
 
-        newfiles = [f for f in files if f in contenders]
+        # exclude sources of copies that are otherwise untouched
+        newfiles = set(f for f in files if f in contenders)
 
         if not newfiles:
             ui.status(_('no changes to shelve\n'))
             return 0
 
-        modified = dict.fromkeys(changes[0])
-
         backupdir = repo.join('shelve-backups')
 
         try:
-            bkfiles = [f for f in newfiles if f in modified]
-            backups = makebackup(ui, repo, backupdir, bkfiles)
+            backups = makebackup(ui, repo, backupdir, newfiles)
             
             # patch to shelve
             sp = cStringIO.StringIO()
             for c in chunks:
-                if c.filename() in backups:
-                    c.write(sp)
-            doshelve = sp.tell()
+                c.write(sp)
 
             # patch to apply to shelved files
             fp = cStringIO.StringIO()
             for c in rc:
-                if c.filename() in backups:
+                # skip files not selected for shelving
+                if c.filename() in newfiles:
                     c.write(fp)
             dopatch = fp.tell()
             fp.seek(0)
 
             try:
                 # 3a. apply filtered patch to clean repo (clean)
-                if backups:
-                    hg.revert(repo, repo.dirstate.parents()[0], backups.has_key)
+                opts['no_backup'] = True
+                cmdutil.revert(ui, repo, repo['.'], parents, *newfiles, **opts)
+                for f in added:
+                    if f in newfiles:
+                        util.unlinkpath(repo.wjoin(f))
 
                 # 3b. apply filtered patch to clean repo (apply)
                 if dopatch:
                 del fp
 
                 # 3c. apply filtered patch to clean repo (shelve)
-                if doshelve:
-                    ui.debug("saving patch to shelve\n")
-                    if opts['append']:
-                        sp.write(repo.opener(shelfpath).read())
-                    sp.seek(0)
-                    f = repo.opener(shelfpath, "w")
-                    f.write(sp.getvalue())
-                    del f
-                del sp
+                ui.debug("saving patch to shelve\n")
+                if opts['append']:
+                    sp.write(repo.opener(shelfpath).read())
+                sp.seek(0)
+                f = repo.opener(shelfpath, "w")
+                f.write(sp.getvalue())
+                del f, sp
             except:
+                ui.warn("shelving failed: %s\n" % sys.exc_info()[1])
                 try:
+                    # re-schedule remove
+                    matchremoved = scmutil.matchfiles(repo, removed)
+                    cmdutil.forget(ui, repo, matchremoved, "", True)
+                    for f in removed:
+                        if f in newfiles and os.path.isfile(f):
+                            os.unlink(f)
+                    # copy back backups
                     for realname, tmpname in backups.iteritems():
                         ui.debug('restoring %r to %r\n' % (tmpname, realname))
                         util.copyfile(tmpname, repo.wjoin(realname))
+                    # re-schedule add
+                    matchadded = scmutil.matchfiles(repo, added)
+                    cmdutil.add(ui, repo, matchadded, False, False, "", True)
+
                     ui.debug('removing shelve file\n')
-                    os.unlink(repo.join(shelfpath))
-                except OSError:
+                    if os.path.isfile(repo.wjoin(shelfpath)):
+                        os.unlink(repo.join(shelfpath))
+                except OSError, err:
+                    ui.warn("restoring backup failed: %s\n" % err)
                     pass
 
             return 0
                     ui.debug('removing backup for %r : %r\n' % (realname, tmpname))
                     os.unlink(tmpname)
                 os.rmdir(backupdir)
-            except OSError:
+            except OSError, err:
+                ui.warn("removing backup failed: %s\n" % err)
                 pass
     fancyopts.fancyopts([], commands.commitopts, opts)
     
   M tip.bundle
   $ hg unshelve
   nothing to unshelve
+
+Check shelving newly added files
+
+  $ hg up -C tip >/dev/null
+  $ cp file1.txt file3.txt
+  $ hg add file3.txt
+  $ hg status
+  A file3.txt
+  $ hg shelve --all file3.txt
+  $ hg status
+  $ hg unshelve
+  unshelve completed
+  $ hg status
+  A file3.txt
+  $ diff file1.txt file3.txt
+
+Check shelving removed files
+
+  $ hg commit -d '4 0' -m 'third file' file3.txt
+  $ hg rm file3.txt
+  $ hg status
+  R file3.txt
+  $ hg shelve --all file3.txt
+  $ hg status
+  $ hg unshelve
+  unshelve completed
+  $ hg status
+  R file3.txt
+  $ diff file1.txt file3.txt
+  diff: file3.txt: No such file or directory
+  [2]
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.