contrib/purge/purge.py
changeset 4148 de85ff0aaac5
parent 4147 691f9168a815
child 4149 e59286f15189
equal deleted inserted replaced
4147:691f9168a815 4148:de85ff0aaac5
    23 
    23 
    24 class Purge(object):
    24 class Purge(object):
    25     def __init__(self, act=True, abort_on_err=False, eol='\n'):
    25     def __init__(self, act=True, abort_on_err=False, eol='\n'):
    26         self._repo = None
    26         self._repo = None
    27         self._ui = None
    27         self._ui = None
    28         self._hg_root = None
       
    29         self._act = act
    28         self._act = act
    30         self._abort_on_err = abort_on_err
    29         self._abort_on_err = abort_on_err
    31         self._eol = eol
    30         self._eol = eol
    32 
    31 
    33     def purge(self, ui, repo, dirs=None):
    32     def purge(self, ui, repo, dirs=None):
    34         self._repo = repo
    33         self._repo = repo
    35         self._ui = ui
    34         self._ui = ui
    36         self._hg_root = self._split_path(repo.root)
       
    37         
    35         
    38         directories = []
    36         directories = []
    39         files = []
    37         files = []
    40         for src, f, st in repo.dirstate.statwalk(files=dirs, ignored=True,
    38         for src, f, st in repo.dirstate.statwalk(files=dirs, ignored=True,
    41                                                  directories=True):
    39                                                  directories=True):
    45                 files.append(f)
    43                 files.append(f)
    46 
    44 
    47         directories.sort()
    45         directories.sort()
    48 
    46 
    49         for f in files:
    47         for f in files:
    50             self._remove_file(os.path.join(repo.root, f))
    48             self._remove_file(f)
    51 
    49 
    52         for f in directories[::-1]:
    50         for f in directories[::-1]:
    53             f = os.path.join(repo.root, f)
    51             if not os.listdir(repo.wjoin(f)):
    54             if not os.listdir(f):
       
    55                 self._remove_dir(f)
    52                 self._remove_dir(f)
    56 
    53 
    57         self._repo = None
    54         self._repo = None
    58         self._ui = None
    55         self._ui = None
    59         self._hg_root = None
       
    60 
    56 
    61     def _error(self, msg):
    57     def _error(self, msg):
    62         if self._abort_on_err:
    58         if self._abort_on_err:
    63             raise util.Abort(msg)
    59             raise util.Abort(msg)
    64         else:
    60         else:
    65             self._ui.warn(_('warning: %s\n') % msg)
    61             self._ui.warn(_('warning: %s\n') % msg)
    66 
    62 
    67     def _remove_file(self, name):
    63     def _remove_file(self, name):
    68         relative_name = self._relative_name(name)
       
    69         # dirstate.state() requires a path relative to the root
    64         # dirstate.state() requires a path relative to the root
    70         # directory.
    65         # directory.
    71         if self._repo.dirstate.state(relative_name) != '?':
    66         if self._repo.dirstate.state(name) != '?':
    72             return
    67             return
    73         self._ui.note(_('Removing file %s\n') % relative_name)
    68         self._ui.note(_('Removing file %s\n') % name)
    74         if self._act:
    69         if self._act:
    75             try:
    70             try:
    76                 os.remove(name)
    71                 os.remove(self._repo.wjoin(name))
    77             except OSError, e:
    72             except OSError, e:
    78                 self._error(_('%s cannot be removed') % relative_name)
    73                 self._error(_('%s cannot be removed') % name)
    79         else:
    74         else:
    80             self._ui.write('%s%s' % (relative_name, self._eol))
    75             self._ui.write('%s%s' % (name, self._eol))
    81 
    76 
    82     def _remove_dir(self, name):
    77     def _remove_dir(self, name):
    83         relative_name = self._relative_name(name)
    78         self._ui.note(_('Removing directory %s\n') % name)
    84         self._ui.note(_('Removing directory %s\n') % relative_name)
       
    85         if self._act:
    79         if self._act:
    86             try:
    80             try:
    87                 os.rmdir(name)
    81                 os.rmdir(self._repo.wjoin(name))
    88             except OSError, e:
    82             except OSError, e:
    89                 self._error(_('%s cannot be removed') % relative_name)
    83                 self._error(_('%s cannot be removed') % name)
    90         else:
    84         else:
    91             self._ui.write('%s%s' % (relative_name, self._eol))
    85             self._ui.write('%s%s' % (name, self._eol))
    92 
       
    93     def _relative_name(self, path):
       
    94         '''
       
    95         Returns "path" but relative to the root directory of the
       
    96         repository and with '\\' replaced with '/'.
       
    97         This is needed because this is the format required by
       
    98         self._repo.dirstate.state().
       
    99         '''
       
   100         splitted_path = self._split_path(path)[len(self._hg_root):]
       
   101         # Even on Windows self._repo.dirstate.state() wants '/'.
       
   102         return self._join_path(splitted_path).replace('\\', '/')
       
   103 
       
   104     def _split_path(self, path):
       
   105         '''
       
   106         Returns a list of the single files/directories in "path".
       
   107         For instance:
       
   108           '/home/user/test' -> ['/', 'home', 'user', 'test']
       
   109           'C:\\Mercurial'   -> ['C:\\', 'Mercurial']
       
   110         '''
       
   111         ret = []
       
   112         while True:
       
   113             head, tail = os.path.split(path)
       
   114             if tail:
       
   115                 ret.append(tail)
       
   116             if head == path:
       
   117                 ret.append(head)
       
   118                 break
       
   119             path = head
       
   120         ret.reverse()
       
   121         return ret
       
   122 
       
   123     def _join_path(self, splitted_path):
       
   124         '''
       
   125         Joins a list returned by _split_path().
       
   126         '''
       
   127         ret = ''
       
   128         for part in splitted_path:
       
   129             if ret:
       
   130                 ret = os.path.join(ret, part)
       
   131             else:
       
   132                 ret = part
       
   133         return ret
       
   134 
    86 
   135 
    87 
   136 def purge(ui, repo, *dirs, **opts):
    88 def purge(ui, repo, *dirs, **opts):
   137     '''removes files not tracked by mercurial
    89     '''removes files not tracked by mercurial
   138 
    90