##// END OF EJS Templates
merge with stable
Matt Mackall -
r20568:d7eb8395 merge default
parent child Browse files
Show More
@@ -1,110 +1,112 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://mercurial.selenic.com/)
3 # This is a small extension for Mercurial (http://mercurial.selenic.com/)
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
6 # This program was inspired by the "cvspurge" script contained in CVS
7 # utilities (http://www.red-bean.com/cvsutils/).
7 # utilities (http://www.red-bean.com/cvsutils/).
8 #
8 #
9 # For help on the usage of "hg purge" use:
9 # For help on the usage of "hg purge" use:
10 # hg help purge
10 # hg help purge
11 #
11 #
12 # This program is free software; you can redistribute it and/or modify
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
15 # (at your option) any later version.
16 #
16 #
17 # This program is distributed in the hope that it will be useful,
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
20 # GNU General Public License for more details.
21 #
21 #
22 # You should have received a copy of the GNU General Public License
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, see <http://www.gnu.org/licenses/>.
23 # along with this program; if not, see <http://www.gnu.org/licenses/>.
24
24
25 '''command to delete untracked files from the working directory'''
25 '''command to delete untracked files from the working directory'''
26
26
27 from mercurial import util, commands, cmdutil, scmutil
27 from mercurial import util, commands, cmdutil, scmutil
28 from mercurial.i18n import _
28 from mercurial.i18n import _
29 import os, stat
29 import os, stat
30
30
31 cmdtable = {}
31 cmdtable = {}
32 command = cmdutil.command(cmdtable)
32 command = cmdutil.command(cmdtable)
33 testedwith = 'internal'
33 testedwith = 'internal'
34
34
35 @command('purge|clean',
35 @command('purge|clean',
36 [('a', 'abort-on-err', None, _('abort if an error occurs')),
36 [('a', 'abort-on-err', None, _('abort if an error occurs')),
37 ('', 'all', None, _('purge ignored files too')),
37 ('', 'all', None, _('purge ignored files too')),
38 ('p', 'print', None, _('print filenames instead of deleting them')),
38 ('p', 'print', None, _('print filenames instead of deleting them')),
39 ('0', 'print0', None, _('end filenames with NUL, for use with xargs'
39 ('0', 'print0', None, _('end filenames with NUL, for use with xargs'
40 ' (implies -p/--print)')),
40 ' (implies -p/--print)')),
41 ] + commands.walkopts,
41 ] + commands.walkopts,
42 _('hg purge [OPTION]... [DIR]...'))
42 _('hg purge [OPTION]... [DIR]...'))
43 def purge(ui, repo, *dirs, **opts):
43 def purge(ui, repo, *dirs, **opts):
44 '''removes files not tracked by Mercurial
44 '''removes files not tracked by Mercurial
45
45
46 Delete files not known to Mercurial. This is useful to test local
46 Delete files not known to Mercurial. This is useful to test local
47 and uncommitted changes in an otherwise-clean source tree.
47 and uncommitted changes in an otherwise-clean source tree.
48
48
49 This means that purge will delete:
49 This means that purge will delete:
50
50
51 - Unknown files: files marked with "?" by :hg:`status`
51 - Unknown files: files marked with "?" by :hg:`status`
52 - Empty directories: in fact Mercurial ignores directories unless
52 - Empty directories: in fact Mercurial ignores directories unless
53 they contain files under source control management
53 they contain files under source control management
54
54
55 But it will leave untouched:
55 But it will leave untouched:
56
56
57 - Modified and unmodified tracked files
57 - Modified and unmodified tracked files
58 - Ignored files (unless --all is specified)
58 - Ignored files (unless --all is specified)
59 - New files added to the repository (with :hg:`add`)
59 - New files added to the repository (with :hg:`add`)
60
60
61 If directories are given on the command line, only files in these
61 If directories are given on the command line, only files in these
62 directories are considered.
62 directories are considered.
63
63
64 Be careful with purge, as you could irreversibly delete some files
64 Be careful with purge, as you could irreversibly delete some files
65 you forgot to add to the repository. If you only want to print the
65 you forgot to add to the repository. If you only want to print the
66 list of files that this program would delete, use the --print
66 list of files that this program would delete, use the --print
67 option.
67 option.
68 '''
68 '''
69 act = not opts['print']
69 act = not opts['print']
70 eol = '\n'
70 eol = '\n'
71 if opts['print0']:
71 if opts['print0']:
72 eol = '\0'
72 eol = '\0'
73 act = False # --print0 implies --print
73 act = False # --print0 implies --print
74
74
75 def remove(remove_func, name):
75 def remove(remove_func, name):
76 if act:
76 if act:
77 try:
77 try:
78 remove_func(repo.wjoin(name))
78 remove_func(repo.wjoin(name))
79 except OSError:
79 except OSError:
80 m = _('%s cannot be removed') % name
80 m = _('%s cannot be removed') % name
81 if opts['abort_on_err']:
81 if opts['abort_on_err']:
82 raise util.Abort(m)
82 raise util.Abort(m)
83 ui.warn(_('warning: %s\n') % m)
83 ui.warn(_('warning: %s\n') % m)
84 else:
84 else:
85 ui.write('%s%s' % (name, eol))
85 ui.write('%s%s' % (name, eol))
86
86
87 def removefile(path):
87 def removefile(path):
88 try:
88 try:
89 os.remove(path)
89 os.remove(path)
90 except OSError:
90 except OSError:
91 # read-only files cannot be unlinked under Windows
91 # read-only files cannot be unlinked under Windows
92 s = os.stat(path)
92 s = os.stat(path)
93 if (s.st_mode & stat.S_IWRITE) != 0:
93 if (s.st_mode & stat.S_IWRITE) != 0:
94 raise
94 raise
95 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
95 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
96 os.remove(path)
96 os.remove(path)
97
97
98 directories = []
98 directories = []
99 match = scmutil.match(repo[None], dirs, opts)
99 match = scmutil.match(repo[None], dirs, opts)
100 match.explicitdir = match.traversedir = directories.append
100 match.explicitdir = match.traversedir = directories.append
101 status = repo.status(match=match, ignored=opts['all'], unknown=True)
101 status = repo.status(match=match, ignored=opts['all'], unknown=True)
102
102
103 for f in sorted(status[4] + status[5]):
103 for f in sorted(status[4] + status[5]):
104 ui.note(_('removing file %s\n') % f)
104 if act:
105 ui.note(_('removing file %s\n') % f)
105 remove(removefile, f)
106 remove(removefile, f)
106
107
107 for f in sorted(directories, reverse=True):
108 for f in sorted(directories, reverse=True):
108 if match(f) and not os.listdir(repo.wjoin(f)):
109 if match(f) and not os.listdir(repo.wjoin(f)):
109 ui.note(_('removing directory %s\n') % f)
110 if act:
111 ui.note(_('removing directory %s\n') % f)
110 remove(os.rmdir, f)
112 remove(os.rmdir, f)
@@ -1,218 +1,218 b''
1 $ cat <<EOF >> $HGRCPATH
1 $ cat <<EOF >> $HGRCPATH
2 > [extensions]
2 > [extensions]
3 > purge =
3 > purge =
4 > EOF
4 > EOF
5
5
6 init
6 init
7
7
8 $ hg init t
8 $ hg init t
9 $ cd t
9 $ cd t
10
10
11 setup
11 setup
12
12
13 $ echo r1 > r1
13 $ echo r1 > r1
14 $ hg ci -qAmr1 -d'0 0'
14 $ hg ci -qAmr1 -d'0 0'
15 $ mkdir directory
15 $ mkdir directory
16 $ echo r2 > directory/r2
16 $ echo r2 > directory/r2
17 $ hg ci -qAmr2 -d'1 0'
17 $ hg ci -qAmr2 -d'1 0'
18 $ echo 'ignored' > .hgignore
18 $ echo 'ignored' > .hgignore
19 $ hg ci -qAmr3 -d'2 0'
19 $ hg ci -qAmr3 -d'2 0'
20
20
21 delete an empty directory
21 delete an empty directory
22
22
23 $ mkdir empty_dir
23 $ mkdir empty_dir
24 $ hg purge -p
24 $ hg purge -p -v
25 empty_dir
25 empty_dir
26 $ hg purge -v
26 $ hg purge -v
27 removing directory empty_dir
27 removing directory empty_dir
28 $ ls
28 $ ls
29 directory
29 directory
30 r1
30 r1
31
31
32 delete an untracked directory
32 delete an untracked directory
33
33
34 $ mkdir untracked_dir
34 $ mkdir untracked_dir
35 $ touch untracked_dir/untracked_file1
35 $ touch untracked_dir/untracked_file1
36 $ touch untracked_dir/untracked_file2
36 $ touch untracked_dir/untracked_file2
37 $ hg purge -p
37 $ hg purge -p
38 untracked_dir/untracked_file1
38 untracked_dir/untracked_file1
39 untracked_dir/untracked_file2
39 untracked_dir/untracked_file2
40 $ hg purge -v
40 $ hg purge -v
41 removing file untracked_dir/untracked_file1
41 removing file untracked_dir/untracked_file1
42 removing file untracked_dir/untracked_file2
42 removing file untracked_dir/untracked_file2
43 removing directory untracked_dir
43 removing directory untracked_dir
44 $ ls
44 $ ls
45 directory
45 directory
46 r1
46 r1
47
47
48 delete an untracked file
48 delete an untracked file
49
49
50 $ touch untracked_file
50 $ touch untracked_file
51 $ touch untracked_file_readonly
51 $ touch untracked_file_readonly
52 $ python <<EOF
52 $ python <<EOF
53 > import os, stat
53 > import os, stat
54 > f= 'untracked_file_readonly'
54 > f= 'untracked_file_readonly'
55 > os.chmod(f, stat.S_IMODE(os.stat(f).st_mode) & ~stat.S_IWRITE)
55 > os.chmod(f, stat.S_IMODE(os.stat(f).st_mode) & ~stat.S_IWRITE)
56 > EOF
56 > EOF
57 $ hg purge -p
57 $ hg purge -p
58 untracked_file
58 untracked_file
59 untracked_file_readonly
59 untracked_file_readonly
60 $ hg purge -v
60 $ hg purge -v
61 removing file untracked_file
61 removing file untracked_file
62 removing file untracked_file_readonly
62 removing file untracked_file_readonly
63 $ ls
63 $ ls
64 directory
64 directory
65 r1
65 r1
66
66
67 delete an untracked file in a tracked directory
67 delete an untracked file in a tracked directory
68
68
69 $ touch directory/untracked_file
69 $ touch directory/untracked_file
70 $ hg purge -p
70 $ hg purge -p
71 directory/untracked_file
71 directory/untracked_file
72 $ hg purge -v
72 $ hg purge -v
73 removing file directory/untracked_file
73 removing file directory/untracked_file
74 $ ls
74 $ ls
75 directory
75 directory
76 r1
76 r1
77
77
78 delete nested directories
78 delete nested directories
79
79
80 $ mkdir -p untracked_directory/nested_directory
80 $ mkdir -p untracked_directory/nested_directory
81 $ hg purge -p
81 $ hg purge -p
82 untracked_directory/nested_directory
82 untracked_directory/nested_directory
83 $ hg purge -v
83 $ hg purge -v
84 removing directory untracked_directory/nested_directory
84 removing directory untracked_directory/nested_directory
85 removing directory untracked_directory
85 removing directory untracked_directory
86 $ ls
86 $ ls
87 directory
87 directory
88 r1
88 r1
89
89
90 delete nested directories from a subdir
90 delete nested directories from a subdir
91
91
92 $ mkdir -p untracked_directory/nested_directory
92 $ mkdir -p untracked_directory/nested_directory
93 $ cd directory
93 $ cd directory
94 $ hg purge -p
94 $ hg purge -p
95 untracked_directory/nested_directory
95 untracked_directory/nested_directory
96 $ hg purge -v
96 $ hg purge -v
97 removing directory untracked_directory/nested_directory
97 removing directory untracked_directory/nested_directory
98 removing directory untracked_directory
98 removing directory untracked_directory
99 $ cd ..
99 $ cd ..
100 $ ls
100 $ ls
101 directory
101 directory
102 r1
102 r1
103
103
104 delete only part of the tree
104 delete only part of the tree
105
105
106 $ mkdir -p untracked_directory/nested_directory
106 $ mkdir -p untracked_directory/nested_directory
107 $ touch directory/untracked_file
107 $ touch directory/untracked_file
108 $ cd directory
108 $ cd directory
109 $ hg purge -p ../untracked_directory
109 $ hg purge -p ../untracked_directory
110 untracked_directory/nested_directory
110 untracked_directory/nested_directory
111 $ hg purge -v ../untracked_directory
111 $ hg purge -v ../untracked_directory
112 removing directory untracked_directory/nested_directory
112 removing directory untracked_directory/nested_directory
113 removing directory untracked_directory
113 removing directory untracked_directory
114 $ cd ..
114 $ cd ..
115 $ ls
115 $ ls
116 directory
116 directory
117 r1
117 r1
118 $ ls directory/untracked_file
118 $ ls directory/untracked_file
119 directory/untracked_file
119 directory/untracked_file
120 $ rm directory/untracked_file
120 $ rm directory/untracked_file
121
121
122 skip ignored files if --all not specified
122 skip ignored files if --all not specified
123
123
124 $ touch ignored
124 $ touch ignored
125 $ hg purge -p
125 $ hg purge -p
126 $ hg purge -v
126 $ hg purge -v
127 $ ls
127 $ ls
128 directory
128 directory
129 ignored
129 ignored
130 r1
130 r1
131 $ hg purge -p --all
131 $ hg purge -p --all
132 ignored
132 ignored
133 $ hg purge -v --all
133 $ hg purge -v --all
134 removing file ignored
134 removing file ignored
135 $ ls
135 $ ls
136 directory
136 directory
137 r1
137 r1
138
138
139 abort with missing files until we support name mangling filesystems
139 abort with missing files until we support name mangling filesystems
140
140
141 $ touch untracked_file
141 $ touch untracked_file
142 $ rm r1
142 $ rm r1
143
143
144 hide error messages to avoid changing the output when the text changes
144 hide error messages to avoid changing the output when the text changes
145
145
146 $ hg purge -p 2> /dev/null
146 $ hg purge -p 2> /dev/null
147 untracked_file
147 untracked_file
148 $ hg st
148 $ hg st
149 ! r1
149 ! r1
150 ? untracked_file
150 ? untracked_file
151
151
152 $ hg purge -p
152 $ hg purge -p
153 untracked_file
153 untracked_file
154 $ hg purge -v 2> /dev/null
154 $ hg purge -v 2> /dev/null
155 removing file untracked_file
155 removing file untracked_file
156 $ hg st
156 $ hg st
157 ! r1
157 ! r1
158
158
159 $ hg purge -v
159 $ hg purge -v
160 $ hg revert --all --quiet
160 $ hg revert --all --quiet
161 $ hg st -a
161 $ hg st -a
162
162
163 tracked file in ignored directory (issue621)
163 tracked file in ignored directory (issue621)
164
164
165 $ echo directory >> .hgignore
165 $ echo directory >> .hgignore
166 $ hg ci -m 'ignore directory'
166 $ hg ci -m 'ignore directory'
167 $ touch untracked_file
167 $ touch untracked_file
168 $ hg purge -p
168 $ hg purge -p
169 untracked_file
169 untracked_file
170 $ hg purge -v
170 $ hg purge -v
171 removing file untracked_file
171 removing file untracked_file
172
172
173 skip excluded files
173 skip excluded files
174
174
175 $ touch excluded_file
175 $ touch excluded_file
176 $ hg purge -p -X excluded_file
176 $ hg purge -p -X excluded_file
177 $ hg purge -v -X excluded_file
177 $ hg purge -v -X excluded_file
178 $ ls
178 $ ls
179 directory
179 directory
180 excluded_file
180 excluded_file
181 r1
181 r1
182 $ rm excluded_file
182 $ rm excluded_file
183
183
184 skip files in excluded dirs
184 skip files in excluded dirs
185
185
186 $ mkdir excluded_dir
186 $ mkdir excluded_dir
187 $ touch excluded_dir/file
187 $ touch excluded_dir/file
188 $ hg purge -p -X excluded_dir
188 $ hg purge -p -X excluded_dir
189 $ hg purge -v -X excluded_dir
189 $ hg purge -v -X excluded_dir
190 $ ls
190 $ ls
191 directory
191 directory
192 excluded_dir
192 excluded_dir
193 r1
193 r1
194 $ ls excluded_dir
194 $ ls excluded_dir
195 file
195 file
196 $ rm -R excluded_dir
196 $ rm -R excluded_dir
197
197
198 skip excluded empty dirs
198 skip excluded empty dirs
199
199
200 $ mkdir excluded_dir
200 $ mkdir excluded_dir
201 $ hg purge -p -X excluded_dir
201 $ hg purge -p -X excluded_dir
202 $ hg purge -v -X excluded_dir
202 $ hg purge -v -X excluded_dir
203 $ ls
203 $ ls
204 directory
204 directory
205 excluded_dir
205 excluded_dir
206 r1
206 r1
207 $ rmdir excluded_dir
207 $ rmdir excluded_dir
208
208
209 skip patterns
209 skip patterns
210
210
211 $ mkdir .svn
211 $ mkdir .svn
212 $ touch .svn/foo
212 $ touch .svn/foo
213 $ mkdir directory/.svn
213 $ mkdir directory/.svn
214 $ touch directory/.svn/foo
214 $ touch directory/.svn/foo
215 $ hg purge -p -X .svn -X '*/.svn'
215 $ hg purge -p -X .svn -X '*/.svn'
216 $ hg purge -p -X re:.*.svn
216 $ hg purge -p -X re:.*.svn
217
217
218 $ cd ..
218 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now