##// END OF EJS Templates
Reduce the absolute/relative path conversion in the purge extension
Emanuele Aina -
r4148:de85ff0a default
parent child Browse files
Show More
@@ -1,178 +1,130 b''
1 1 # Copyright (C) 2006 - Marco Barisione <marco@barisione.org>
2 2 #
3 3 # This is a small extension for Mercurial (http://www.selenic.com/mercurial)
4 4 # that removes files not known to mercurial
5 5 #
6 6 # This program is free software; you can redistribute it and/or modify
7 7 # it under the terms of the GNU General Public License as published by
8 8 # the Free Software Foundation; either version 2 of the License, or
9 9 # (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 19
20 20 from mercurial import hg, util
21 21 from mercurial.i18n import _
22 22 import os
23 23
24 24 class Purge(object):
25 25 def __init__(self, act=True, abort_on_err=False, eol='\n'):
26 26 self._repo = None
27 27 self._ui = None
28 self._hg_root = None
29 28 self._act = act
30 29 self._abort_on_err = abort_on_err
31 30 self._eol = eol
32 31
33 32 def purge(self, ui, repo, dirs=None):
34 33 self._repo = repo
35 34 self._ui = ui
36 self._hg_root = self._split_path(repo.root)
37 35
38 36 directories = []
39 37 files = []
40 38 for src, f, st in repo.dirstate.statwalk(files=dirs, ignored=True,
41 39 directories=True):
42 40 if src == 'd':
43 41 directories.append(f)
44 42 elif src == 'f' and f not in repo.dirstate:
45 43 files.append(f)
46 44
47 45 directories.sort()
48 46
49 47 for f in files:
50 self._remove_file(os.path.join(repo.root, f))
48 self._remove_file(f)
51 49
52 50 for f in directories[::-1]:
53 f = os.path.join(repo.root, f)
54 if not os.listdir(f):
51 if not os.listdir(repo.wjoin(f)):
55 52 self._remove_dir(f)
56 53
57 54 self._repo = None
58 55 self._ui = None
59 self._hg_root = None
60 56
61 57 def _error(self, msg):
62 58 if self._abort_on_err:
63 59 raise util.Abort(msg)
64 60 else:
65 61 self._ui.warn(_('warning: %s\n') % msg)
66 62
67 63 def _remove_file(self, name):
68 relative_name = self._relative_name(name)
69 64 # dirstate.state() requires a path relative to the root
70 65 # directory.
71 if self._repo.dirstate.state(relative_name) != '?':
66 if self._repo.dirstate.state(name) != '?':
72 67 return
73 self._ui.note(_('Removing file %s\n') % relative_name)
74 if self._act:
75 try:
76 os.remove(name)
77 except OSError, e:
78 self._error(_('%s cannot be removed') % relative_name)
79 else:
80 self._ui.write('%s%s' % (relative_name, self._eol))
81
82 def _remove_dir(self, name):
83 relative_name = self._relative_name(name)
84 self._ui.note(_('Removing directory %s\n') % relative_name)
68 self._ui.note(_('Removing file %s\n') % name)
85 69 if self._act:
86 70 try:
87 os.rmdir(name)
71 os.remove(self._repo.wjoin(name))
88 72 except OSError, e:
89 self._error(_('%s cannot be removed') % relative_name)
73 self._error(_('%s cannot be removed') % name)
90 74 else:
91 self._ui.write('%s%s' % (relative_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('\\', '/')
75 self._ui.write('%s%s' % (name, self._eol))
103 76
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
77 def _remove_dir(self, name):
78 self._ui.note(_('Removing directory %s\n') % name)
79 if self._act:
80 try:
81 os.rmdir(self._repo.wjoin(name))
82 except OSError, e:
83 self._error(_('%s cannot be removed') % name)
84 else:
85 self._ui.write('%s%s' % (name, self._eol))
134 86
135 87
136 88 def purge(ui, repo, *dirs, **opts):
137 89 '''removes files not tracked by mercurial
138 90
139 91 Delete files not known to mercurial, this is useful to test local and
140 92 uncommitted changes in the otherwise clean source tree.
141 93
142 94 This means that purge will delete:
143 95 - Unknown files: files marked with "?" by "hg status"
144 96 - Ignored files: files usually ignored by Mercurial because they match
145 97 a pattern in a ".hgignore" file
146 98 - Empty directories: in fact Mercurial ignores directories unless they
147 99 contain files under source control managment
148 100 But it will leave untouched:
149 101 - Unmodified tracked files
150 102 - Modified tracked files
151 103 - New files added to the repository (with "hg add")
152 104
153 105 If directories are given on the command line, only files in these
154 106 directories are considered.
155 107
156 108 Be careful with purge, you could irreversibly delete some files you
157 109 forgot to add to the repository. If you only want to print the list of
158 110 files that this program would delete use the --print option.
159 111 '''
160 112 act = not opts['print']
161 113 abort_on_err = bool(opts['abort_on_err'])
162 114 eol = opts['print0'] and '\0' or '\n'
163 115 if eol == '\0':
164 116 # --print0 implies --print
165 117 act = False
166 118 p = Purge(act, abort_on_err, eol)
167 119 p.purge(ui, repo, dirs)
168 120
169 121
170 122 cmdtable = {
171 123 'purge':
172 124 (purge,
173 125 [('a', 'abort-on-err', None, _('abort if an error occurs')),
174 126 ('p', 'print', None, _('print the file names instead of deleting them')),
175 127 ('0', 'print0', None, _('end filenames with NUL, for use with xargs'
176 128 ' (implies -p)'))],
177 129 _('hg purge [OPTION]... [DIR]...'))
178 130 }
General Comments 0
You need to be logged in to leave comments. Login now