mercurial/shelve.py
changeset 46296 eec8899407f4
parent 46295 f8c5e6ecd008
child 46297 82edad33fd81
equal deleted inserted replaced
46295:f8c5e6ecd008 46296:eec8899407f4
    68 # we never need the user, so we use a
    68 # we never need the user, so we use a
    69 # generic user for all shelve operations
    69 # generic user for all shelve operations
    70 shelveuser = b'shelve@localhost'
    70 shelveuser = b'shelve@localhost'
    71 
    71 
    72 
    72 
       
    73 class ShelfDir(object):
       
    74     def __init__(self, repo, for_backups=False):
       
    75         if for_backups:
       
    76             self.vfs = vfsmod.vfs(repo.vfs.join(backupdir))
       
    77         else:
       
    78             self.vfs = vfsmod.vfs(repo.vfs.join(shelvedir))
       
    79 
       
    80     def get(self, name):
       
    81         return Shelf(self.vfs, name)
       
    82 
       
    83 
    73 class Shelf(object):
    84 class Shelf(object):
    74     """Represents a shelf, including possibly multiple files storing it.
    85     """Represents a shelf, including possibly multiple files storing it.
    75 
    86 
    76     Old shelves will have a .patch and a .hg file. Newer shelves will
    87     Old shelves will have a .patch and a .hg file. Newer shelves will
    77     also have a .shelve file. This class abstracts away some of the
    88     also have a .shelve file. This class abstracts away some of the
    79     """
    90     """
    80 
    91 
    81     def __init__(self, vfs, name):
    92     def __init__(self, vfs, name):
    82         self.vfs = vfs
    93         self.vfs = vfs
    83         self.name = name
    94         self.name = name
    84 
       
    85     @staticmethod
       
    86     def open(repo, name):
       
    87         return Shelf(vfsmod.vfs(repo.vfs.join(shelvedir)), name)
       
    88 
       
    89     @staticmethod
       
    90     def open_backup(repo, name):
       
    91         return Shelf(vfsmod.vfs(repo.vfs.join(backupdir)), name)
       
    92 
    95 
    93     def exists(self):
    96     def exists(self):
    94         return self.vfs.exists(self.name + b'.patch') and self.vfs.exists(
    97         return self.vfs.exists(self.name + b'.patch') and self.vfs.exists(
    95             self.name + b'.hg'
    98             self.name + b'.hg'
    96         )
    99         )
   379     # filenames must not start with '.' as it should not be hidden
   382     # filenames must not start with '.' as it should not be hidden
   380     if label.startswith(b'.'):
   383     if label.startswith(b'.'):
   381         label = label.replace(b'.', b'_', 1)
   384         label = label.replace(b'.', b'_', 1)
   382 
   385 
   383     if name:
   386     if name:
   384         if Shelf.open(repo, name).exists():
   387         if ShelfDir(repo).get(name).exists():
   385             e = _(b"a shelved change named '%s' already exists") % name
   388             e = _(b"a shelved change named '%s' already exists") % name
   386             raise error.Abort(e)
   389             raise error.Abort(e)
   387 
   390 
   388         # ensure we are not creating a subdirectory or a hidden file
   391         # ensure we are not creating a subdirectory or a hidden file
   389         if b'/' in name or b'\\' in name:
   392         if b'/' in name or b'\\' in name:
   392             )
   395             )
   393         if name.startswith(b'.'):
   396         if name.startswith(b'.'):
   394             raise error.Abort(_(b"shelved change names can not start with '.'"))
   397             raise error.Abort(_(b"shelved change names can not start with '.'"))
   395 
   398 
   396     else:
   399     else:
       
   400         shelf_dir = ShelfDir(repo)
   397         for n in gennames():
   401         for n in gennames():
   398             if not Shelf.open(repo, n).exists():
   402             if not shelf_dir.get(n).exists():
   399                 name = n
   403                 name = n
   400                 break
   404                 break
   401 
   405 
   402     return name
   406     return name
   403 
   407 
   469         ui.status(_(b"nothing changed\n"))
   473         ui.status(_(b"nothing changed\n"))
   470 
   474 
   471 
   475 
   472 def _shelvecreatedcommit(repo, node, name, match):
   476 def _shelvecreatedcommit(repo, node, name, match):
   473     info = {b'node': hex(node)}
   477     info = {b'node': hex(node)}
   474     shelf = Shelf.open(repo, name)
   478     shelf = ShelfDir(repo).get(name)
   475     shelf.writeinfo(info)
   479     shelf.writeinfo(info)
   476     bases = list(mutableancestors(repo[node]))
   480     bases = list(mutableancestors(repo[node]))
   477     shelf.writebundle(repo, bases, node)
   481     shelf.writebundle(repo, bases, node)
   478     with shelf.open_patch(b'wb') as fp:
   482     with shelf.open_patch(b'wb') as fp:
   479         cmdutil.exportfile(
   483         cmdutil.exportfile(
   612     if not pats:
   616     if not pats:
   613         raise error.InputError(_(b'no shelved changes specified!'))
   617         raise error.InputError(_(b'no shelved changes specified!'))
   614     with repo.wlock():
   618     with repo.wlock():
   615         backupvfs = vfsmod.vfs(repo.vfs.join(backupdir))
   619         backupvfs = vfsmod.vfs(repo.vfs.join(backupdir))
   616         for name in pats:
   620         for name in pats:
   617             shelf = Shelf.open(repo, name)
   621             shelf = ShelfDir(repo).get(name)
   618             if not shelf.exists():
   622             if not shelf.exists():
   619                 raise error.InputError(
   623                 raise error.InputError(
   620                     _(b"shelved change '%s' not found") % name
   624                     _(b"shelved change '%s' not found") % name
   621                 )
   625                 )
   622             shelf.movetobackup(backupvfs)
   626             shelf.movetobackup(backupvfs)
   653     if not ui.plain():
   657     if not ui.plain():
   654         width = ui.termwidth()
   658         width = ui.termwidth()
   655     namelabel = b'shelve.newest'
   659     namelabel = b'shelve.newest'
   656     ui.pager(b'shelve')
   660     ui.pager(b'shelve')
   657     vfs = vfsmod.vfs(repo.vfs.join(shelvedir))
   661     vfs = vfsmod.vfs(repo.vfs.join(shelvedir))
       
   662     shelf_dir = ShelfDir(repo)
   658     for mtime, name in listshelves(vfs):
   663     for mtime, name in listshelves(vfs):
   659         if pats and name not in pats:
   664         if pats and name not in pats:
   660             continue
   665             continue
   661         ui.write(name, label=namelabel)
   666         ui.write(name, label=namelabel)
   662         namelabel = b'shelve.name'
   667         namelabel = b'shelve.name'
   668         date = dateutil.makedate(mtime)
   673         date = dateutil.makedate(mtime)
   669         age = b'(%s)' % templatefilters.age(date, abbrev=True)
   674         age = b'(%s)' % templatefilters.age(date, abbrev=True)
   670         ui.write(age, label=b'shelve.age')
   675         ui.write(age, label=b'shelve.age')
   671         ui.write(b' ' * (12 - len(age)))
   676         ui.write(b' ' * (12 - len(age)))
   672         used += 12
   677         used += 12
   673         with Shelf.open(repo, name).open_patch() as fp:
   678         with shelf_dir.get(name).open_patch() as fp:
   674             while True:
   679             while True:
   675                 line = fp.readline()
   680                 line = fp.readline()
   676                 if not line:
   681                 if not line:
   677                     break
   682                     break
   678                 if not line.startswith(b'#'):
   683                 if not line.startswith(b'#'):
   701         if not shelves:
   706         if not shelves:
   702             raise error.Abort(_(b"there are no shelves to show"))
   707             raise error.Abort(_(b"there are no shelves to show"))
   703         mtime, name = shelves[0]
   708         mtime, name = shelves[0]
   704         pats = [name]
   709         pats = [name]
   705 
   710 
       
   711     shelf_dir = ShelfDir(repo)
   706     for shelfname in pats:
   712     for shelfname in pats:
   707         if not Shelf.open(repo, shelfname).exists():
   713         if not shelf_dir.get(shelfname).exists():
   708             raise error.Abort(_(b"cannot find shelf %s") % shelfname)
   714             raise error.Abort(_(b"cannot find shelf %s") % shelfname)
   709 
   715 
   710     listcmd(ui, repo, pats, opts)
   716     listcmd(ui, repo, pats, opts)
   711 
   717 
   712 
   718 
   794 
   800 
   795 def unshelvecleanup(ui, repo, name, opts):
   801 def unshelvecleanup(ui, repo, name, opts):
   796     """remove related files after an unshelve"""
   802     """remove related files after an unshelve"""
   797     if not opts.get(b'keep'):
   803     if not opts.get(b'keep'):
   798         backupvfs = vfsmod.vfs(repo.vfs.join(backupdir))
   804         backupvfs = vfsmod.vfs(repo.vfs.join(backupdir))
   799         Shelf.open(repo, name).movetobackup(backupvfs)
   805         ShelfDir(repo).get(name).movetobackup(backupvfs)
   800         cleanupoldbackups(repo)
   806         cleanupoldbackups(repo)
   801 
   807 
   802 
   808 
   803 def unshelvecontinue(ui, repo, state, opts):
   809 def unshelvecontinue(ui, repo, state, opts):
   804     """subcommand to continue an in-progress unshelve"""
   810     """subcommand to continue an in-progress unshelve"""
   894 
   900 
   895 def _unshelverestorecommit(ui, repo, tr, basename):
   901 def _unshelverestorecommit(ui, repo, tr, basename):
   896     """Recreate commit in the repository during the unshelve"""
   902     """Recreate commit in the repository during the unshelve"""
   897     repo = repo.unfiltered()
   903     repo = repo.unfiltered()
   898     node = None
   904     node = None
   899     shelf = Shelf.open(repo, basename)
   905     shelf = ShelfDir(repo).get(basename)
   900     if shelf.hasinfo():
   906     if shelf.hasinfo():
   901         node = shelf.readinfo()[b'node']
   907         node = shelf.readinfo()[b'node']
   902     if node is None or node not in repo:
   908     if node is None or node not in repo:
   903         with ui.configoverride({(b'ui', b'quiet'): True}):
   909         with ui.configoverride({(b'ui', b'quiet'): True}):
   904             shelvectx = shelf.applybundle(repo, tr)
   910             shelvectx = shelf.applybundle(repo, tr)
  1124         basename = shelved[0][1]
  1130         basename = shelved[0][1]
  1125         ui.status(_(b"unshelving change '%s'\n") % basename)
  1131         ui.status(_(b"unshelving change '%s'\n") % basename)
  1126     else:
  1132     else:
  1127         basename = shelved[0]
  1133         basename = shelved[0]
  1128 
  1134 
  1129     if not Shelf.open(repo, basename).exists():
  1135     if not ShelfDir(repo).get(basename).exists():
  1130         raise error.InputError(_(b"shelved change '%s' not found") % basename)
  1136         raise error.InputError(_(b"shelved change '%s' not found") % basename)
  1131 
  1137 
  1132     return _dounshelve(ui, repo, basename, opts)
  1138     return _dounshelve(ui, repo, basename, opts)
  1133 
  1139 
  1134 
  1140