##// END OF EJS Templates
purge: eliminate dopurge
Matt Mackall -
r6573:44cd348e default
parent child Browse files
Show More
@@ -1,152 +1,145 b''
1 # Copyright (C) 2006 - Marco Barisione <marco@barisione.org>
1 # Copyright (C) 2006 - Marco Barisione <marco@barisione.org>
2 #
2 #
3 # This is a small extension for Mercurial (http://www.selenic.com/mercurial)
3 # This is a small extension for Mercurial (http://www.selenic.com/mercurial)
4 # that removes files not known to mercurial
4 # that removes files not known to mercurial
5 #
5 #
6 # This program was inspired by the "cvspurge" script contained in CVS utilities
6 # This program was inspired by the "cvspurge" script contained in CVS utilities
7 # (http://www.red-bean.com/cvsutils/).
7 # (http://www.red-bean.com/cvsutils/).
8 #
8 #
9 # To enable the "purge" extension put these lines in your ~/.hgrc:
9 # To enable the "purge" extension put these lines in your ~/.hgrc:
10 # [extensions]
10 # [extensions]
11 # hgext.purge =
11 # hgext.purge =
12 #
12 #
13 # For help on the usage of "hg purge" use:
13 # For help on the usage of "hg purge" use:
14 # hg help purge
14 # hg help purge
15 #
15 #
16 # This program is free software; you can redistribute it and/or modify
16 # This program is free software; you can redistribute it and/or modify
17 # it under the terms of the GNU General Public License as published by
17 # it under the terms of the GNU General Public License as published by
18 # the Free Software Foundation; either version 2 of the License, or
18 # the Free Software Foundation; either version 2 of the License, or
19 # (at your option) any later version.
19 # (at your option) any later version.
20 #
20 #
21 # This program is distributed in the hope that it will be useful,
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 # GNU General Public License for more details.
24 # GNU General Public License for more details.
25 #
25 #
26 # You should have received a copy of the GNU General Public License
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29
29
30 from mercurial import util, commands
30 from mercurial import util, commands
31 from mercurial.i18n import _
31 from mercurial.i18n import _
32 import os
32 import os
33
33
34 def dopurge(ui, repo, dirs=None, act=True, ignored=False,
34 def purge(ui, repo, *dirs, **opts):
35 abort_on_err=False, eol='\n',
35 '''removes files not tracked by mercurial
36 force=False, include=None, exclude=None):
36
37 Delete files not known to mercurial, this is useful to test local and
38 uncommitted changes in the otherwise clean source tree.
39
40 This means that purge will delete:
41 - Unknown files: files marked with "?" by "hg status"
42 - Ignored files: files usually ignored by Mercurial because they match
43 a pattern in a ".hgignore" file
44 - Empty directories: in fact Mercurial ignores directories unless they
45 contain files under source control managment
46 But it will leave untouched:
47 - Unmodified tracked files
48 - Modified tracked files
49 - New files added to the repository (with "hg add")
50
51 If directories are given on the command line, only files in these
52 directories are considered.
53
54 Be careful with purge, you could irreversibly delete some files you
55 forgot to add to the repository. If you only want to print the list of
56 files that this program would delete use the --print option.
57 '''
58 act = not opts['print']
59 ignored = bool(opts['all'])
60 abort_on_err = bool(opts['abort_on_err'])
61 eol = opts['print0'] and '\0' or '\n'
62 if eol == '\0':
63 # --print0 implies --print
64 act = False
65 force = bool(opts['force'])
66 include = opts['include']
67 exclude = opts['exclude']
68
37 def error(msg):
69 def error(msg):
38 if abort_on_err:
70 if abort_on_err:
39 raise util.Abort(msg)
71 raise util.Abort(msg)
40 else:
72 else:
41 ui.warn(_('warning: %s\n') % msg)
73 ui.warn(_('warning: %s\n') % msg)
42
74
43 def remove(remove_func, name):
75 def remove(remove_func, name):
44 if act:
76 if act:
45 try:
77 try:
46 remove_func(os.path.join(repo.root, name))
78 remove_func(os.path.join(repo.root, name))
47 except OSError, e:
79 except OSError, e:
48 error(_('%s cannot be removed') % name)
80 error(_('%s cannot be removed') % name)
49 else:
81 else:
50 ui.write('%s%s' % (name, eol))
82 ui.write('%s%s' % (name, eol))
51
83
52 if not force:
84 if not force:
53 _check_fs(ui, repo)
85 _check_fs(ui, repo)
54
86
55 directories = []
87 directories = []
56 files = []
88 files = []
57 missing = []
89 missing = []
58 roots, match, anypats = util.cmdmatcher(repo.root, repo.getcwd(), dirs,
90 roots, match, anypats = util.cmdmatcher(repo.root, repo.getcwd(), dirs,
59 include, exclude)
91 include, exclude)
60 for src, f, st in repo.dirstate.statwalk(files=roots, match=match,
92 for src, f, st in repo.dirstate.statwalk(roots, match,
61 ignored=ignored, directories=True):
93 ignored=ignored, directories=True):
62 if src == 'd':
94 if src == 'd':
63 directories.append(f)
95 directories.append(f)
64 elif src == 'm':
96 elif src == 'm':
65 missing.append(f)
97 missing.append(f)
66 elif src == 'f' and f not in repo.dirstate:
98 elif src == 'f' and f not in repo.dirstate:
67 files.append(f)
99 files.append(f)
68
100
69 directories.sort()
101 directories.sort()
70
102
71 for f in files:
103 for f in files:
72 if f not in repo.dirstate:
104 if f not in repo.dirstate:
73 ui.note(_('Removing file %s\n') % f)
105 ui.note(_('Removing file %s\n') % f)
74 remove(os.remove, f)
106 remove(os.remove, f)
75
107
76 for f in directories[::-1]:
108 for f in directories[::-1]:
77 if match(f) and not os.listdir(repo.wjoin(f)):
109 if match(f) and not os.listdir(repo.wjoin(f)):
78 ui.note(_('Removing directory %s\n') % f)
110 ui.note(_('Removing directory %s\n') % f)
79 remove(os.rmdir, f)
111 remove(os.rmdir, f)
80
112
81 def _check_fs(ui, repo):
113 def _check_fs(ui, repo):
82 """Abort if there is the chance of having problems with name-mangling fs
114 """Abort if there is the chance of having problems with name-mangling fs
83
115
84 In a name mangling filesystem (e.g. a case insensitive one)
116 In a name mangling filesystem (e.g. a case insensitive one)
85 dirstate.walk() can yield filenames different from the ones
117 dirstate.walk() can yield filenames different from the ones
86 stored in the dirstate. This already confuses the status and
118 stored in the dirstate. This already confuses the status and
87 add commands, but with purge this may cause data loss.
119 add commands, but with purge this may cause data loss.
88
120
89 To prevent this, this function will abort if there are uncommitted
121 To prevent this, this function will abort if there are uncommitted
90 changes.
122 changes.
91 """
123 """
92
124
93 # We can't use (files, match) to do a partial walk here - we wouldn't
125 # We can't use (files, match) to do a partial walk here - we wouldn't
94 # notice a modified README file if the user ran "hg purge readme"
126 # notice a modified README file if the user ran "hg purge readme"
95 modified, added, removed, deleted = repo.status()[:4]
127 modified, added, removed, deleted = repo.status()[:4]
96 if modified or added or removed or deleted:
128 if modified or added or removed or deleted:
97 if not util.checkfolding(repo.path) and not ui.quiet:
129 if not util.checkfolding(repo.path) and not ui.quiet:
98 ui.warn(_("Purging on name mangling filesystems is not "
130 ui.warn(_("Purging on name mangling filesystems is not "
99 "fully supported.\n"))
131 "fully supported.\n"))
100 raise util.Abort(_("outstanding uncommitted changes"))
132 raise util.Abort(_("outstanding uncommitted changes"))
101
133
102
103 def purge(ui, repo, *dirs, **opts):
104 '''removes files not tracked by mercurial
105
106 Delete files not known to mercurial, this is useful to test local and
107 uncommitted changes in the otherwise clean source tree.
108
109 This means that purge will delete:
110 - Unknown files: files marked with "?" by "hg status"
111 - Ignored files: files usually ignored by Mercurial because they match
112 a pattern in a ".hgignore" file
113 - Empty directories: in fact Mercurial ignores directories unless they
114 contain files under source control managment
115 But it will leave untouched:
116 - Unmodified tracked files
117 - Modified tracked files
118 - New files added to the repository (with "hg add")
119
120 If directories are given on the command line, only files in these
121 directories are considered.
122
123 Be careful with purge, you could irreversibly delete some files you
124 forgot to add to the repository. If you only want to print the list of
125 files that this program would delete use the --print option.
126 '''
127 act = not opts['print']
128 ignored = bool(opts['all'])
129 abort_on_err = bool(opts['abort_on_err'])
130 eol = opts['print0'] and '\0' or '\n'
131 if eol == '\0':
132 # --print0 implies --print
133 act = False
134 force = bool(opts['force'])
135 include = opts['include']
136 exclude = opts['exclude']
137 dopurge(ui, repo, dirs, act, ignored, abort_on_err,
138 eol, force, include, exclude)
139
140
141 cmdtable = {
134 cmdtable = {
142 'purge|clean':
135 'purge|clean':
143 (purge,
136 (purge,
144 [('a', 'abort-on-err', None, _('abort if an error occurs')),
137 [('a', 'abort-on-err', None, _('abort if an error occurs')),
145 ('', 'all', None, _('purge ignored files too')),
138 ('', 'all', None, _('purge ignored files too')),
146 ('f', 'force', None, _('purge even when there are uncommitted changes')),
139 ('f', 'force', None, _('purge even when there are uncommitted changes')),
147 ('p', 'print', None, _('print the file names instead of deleting them')),
140 ('p', 'print', None, _('print the file names instead of deleting them')),
148 ('0', 'print0', None, _('end filenames with NUL, for use with xargs'
141 ('0', 'print0', None, _('end filenames with NUL, for use with xargs'
149 ' (implies -p)')),
142 ' (implies -p)')),
150 ] + commands.walkopts,
143 ] + commands.walkopts,
151 _('hg purge [OPTION]... [DIR]...'))
144 _('hg purge [OPTION]... [DIR]...'))
152 }
145 }
General Comments 0
You need to be logged in to leave comments. Login now