##// END OF EJS Templates
purge: remove read-only files under Windows (issue583)...
Patrick Mezard -
r8043:b777dd8f default
parent child Browse files
Show More
@@ -1,99 +1,106 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 was inspired by the "cvspurge" script contained in CVS utilities
7 7 # (http://www.red-bean.com/cvsutils/).
8 8 #
9 9 # To enable the "purge" extension put these lines in your ~/.hgrc:
10 10 # [extensions]
11 11 # hgext.purge =
12 12 #
13 13 # For help on the usage of "hg purge" use:
14 14 # hg help purge
15 15 #
16 16 # This program is free software; you can redistribute it and/or modify
17 17 # it under the terms of the GNU General Public License as published by
18 18 # the Free Software Foundation; either version 2 of the License, or
19 19 # (at your option) any later version.
20 20 #
21 21 # This program is distributed in the hope that it will be useful,
22 22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 24 # GNU General Public License for more details.
25 25 #
26 26 # You should have received a copy of the GNU General Public License
27 27 # along with this program; if not, write to the Free Software
28 28 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 29
30 30 from mercurial import util, commands, cmdutil
31 31 from mercurial.i18n import _
32 import os
32 import os, stat
33 33
34 34 def purge(ui, repo, *dirs, **opts):
35 35 '''removes files not tracked by Mercurial
36 36
37 37 Delete files not known to Mercurial. This is useful to test local
38 38 and uncommitted changes in an otherwise-clean source tree.
39 39
40 40 This means that purge will delete:
41 41 - Unknown files: files marked with "?" by "hg status"
42 42 - Empty directories: in fact Mercurial ignores directories unless
43 43 they contain files under source control managment
44 44 But it will leave untouched:
45 45 - Modified and unmodified tracked files
46 46 - Ignored files (unless --all is specified)
47 47 - New files added to the repository (with "hg add")
48 48
49 49 If directories are given on the command line, only files in these
50 50 directories are considered.
51 51
52 52 Be careful with purge, as you could irreversibly delete some files
53 53 you forgot to add to the repository. If you only want to print the
54 54 list of files that this program would delete, use the --print
55 55 option.
56 56 '''
57 57 act = not opts['print']
58 58 eol = '\n'
59 59 if opts['print0']:
60 60 eol = '\0'
61 61 act = False # --print0 implies --print
62 62
63 63 def remove(remove_func, name):
64 64 if act:
65 65 try:
66 66 remove_func(repo.wjoin(name))
67 67 except OSError:
68 68 m = _('%s cannot be removed') % name
69 69 if opts['abort_on_err']:
70 70 raise util.Abort(m)
71 71 ui.warn(_('warning: %s\n') % m)
72 72 else:
73 73 ui.write('%s%s' % (name, eol))
74 74
75 def removefile(path):
76 # read-only files cannot be unlinked under Windows
77 s = os.stat(path)
78 if (s.st_dev & stat.S_IWRITE) == 0:
79 os.chmod(path, s.st_mode | stat.S_IWRITE)
80 os.remove(path)
81
75 82 directories = []
76 83 match = cmdutil.match(repo, dirs, opts)
77 84 match.dir = directories.append
78 85 status = repo.status(match=match, ignored=opts['all'], unknown=True)
79 86
80 87 for f in util.sort(status[4] + status[5]):
81 88 ui.note(_('Removing file %s\n') % f)
82 remove(os.remove, f)
89 remove(removefile, f)
83 90
84 91 for f in util.sort(directories)[::-1]:
85 92 if match(f) and not os.listdir(repo.wjoin(f)):
86 93 ui.note(_('Removing directory %s\n') % f)
87 94 remove(os.rmdir, f)
88 95
89 96 cmdtable = {
90 97 'purge|clean':
91 98 (purge,
92 99 [('a', 'abort-on-err', None, _('abort if an error occurs')),
93 100 ('', 'all', None, _('purge ignored files too')),
94 101 ('p', 'print', None, _('print the file names instead of deleting them')),
95 102 ('0', 'print0', None, _('end filenames with NUL, for use with xargs'
96 103 ' (implies -p)')),
97 104 ] + commands.walkopts,
98 105 _('hg purge [OPTION]... [DIR]...'))
99 106 }
@@ -1,132 +1,138 b''
1 1 #!/bin/sh
2 2
3 3 cat <<EOF >> $HGRCPATH
4 4 [extensions]
5 5 hgext.purge=
6 6 EOF
7 7
8 8 echo % init
9 9 hg init t
10 10 cd t
11 11
12 12 echo % setup
13 13 echo r1 > r1
14 14 hg ci -qAmr1 -d'0 0'
15 15 mkdir directory
16 16 echo r2 > directory/r2
17 17 hg ci -qAmr2 -d'1 0'
18 18 echo 'ignored' > .hgignore
19 19 hg ci -qAmr3 -d'2 0'
20 20
21 21 echo % delete an empty directory
22 22 mkdir empty_dir
23 23 hg purge -p
24 24 hg purge -v
25 25 ls
26 26
27 27 echo % delete an untracked directory
28 28 mkdir untracked_dir
29 29 touch untracked_dir/untracked_file1
30 30 touch untracked_dir/untracked_file2
31 31 hg purge -p
32 32 hg purge -v
33 33 ls
34 34
35 35 echo % delete an untracked file
36 36 touch untracked_file
37 touch untracked_file_readonly
38 python <<EOF
39 import os, stat
40 f= 'untracked_file_readonly'
41 os.chmod(f, os.stat(f).st_mode & ~stat.S_IWRITE)
42 EOF
37 43 hg purge -p
38 44 hg purge -v
39 45 ls
40 46
41 47 echo % delete an untracked file in a tracked directory
42 48 touch directory/untracked_file
43 49 hg purge -p
44 50 hg purge -v
45 51 ls
46 52
47 53 echo % delete nested directories
48 54 mkdir -p untracked_directory/nested_directory
49 55 hg purge -p
50 56 hg purge -v
51 57 ls
52 58
53 59 echo % delete nested directories from a subdir
54 60 mkdir -p untracked_directory/nested_directory
55 61 cd directory
56 62 hg purge -p
57 63 hg purge -v
58 64 cd ..
59 65 ls
60 66
61 67 echo % delete only part of the tree
62 68 mkdir -p untracked_directory/nested_directory
63 69 touch directory/untracked_file
64 70 cd directory
65 71 hg purge -p ../untracked_directory
66 72 hg purge -v ../untracked_directory
67 73 cd ..
68 74 ls
69 75 ls directory/untracked_file
70 76 rm directory/untracked_file
71 77
72 78 echo % skip ignored files if --all not specified
73 79 touch ignored
74 80 hg purge -p
75 81 hg purge -v
76 82 ls
77 83 hg purge -p --all
78 84 hg purge -v --all
79 85 ls
80 86
81 87 echo % abort with missing files until we support name mangling filesystems
82 88 touch untracked_file
83 89 rm r1
84 90 # hide error messages to avoid changing the output when the text changes
85 91 hg purge -p 2> /dev/null
86 92 hg st
87 93
88 94 hg purge -p
89 95 hg purge -v 2> /dev/null
90 96 hg st
91 97
92 98 hg purge -v
93 99 hg revert --all --quiet
94 100 hg st -a
95 101
96 102 echo '% tracked file in ignored directory (issue621)'
97 103 echo directory >> .hgignore
98 104 hg ci -m 'ignore directory'
99 105 touch untracked_file
100 106 hg purge -p
101 107 hg purge -v
102 108
103 109 echo % skip excluded files
104 110 touch excluded_file
105 111 hg purge -p -X excluded_file
106 112 hg purge -v -X excluded_file
107 113 ls
108 114 rm excluded_file
109 115
110 116 echo % skip files in excluded dirs
111 117 mkdir excluded_dir
112 118 touch excluded_dir/file
113 119 hg purge -p -X excluded_dir
114 120 hg purge -v -X excluded_dir
115 121 ls
116 122 ls excluded_dir
117 123 rm -R excluded_dir
118 124
119 125 echo % skip excluded empty dirs
120 126 mkdir excluded_dir
121 127 hg purge -p -X excluded_dir
122 128 hg purge -v -X excluded_dir
123 129 ls
124 130 rmdir excluded_dir
125 131
126 132 echo % skip patterns
127 133 mkdir .svn
128 134 touch .svn/foo
129 135 mkdir directory/.svn
130 136 touch directory/.svn/foo
131 137 hg purge -p -X .svn -X '*/.svn'
132 138 hg purge -p -X re:.*.svn
@@ -1,76 +1,78 b''
1 1 % init
2 2 % setup
3 3 % delete an empty directory
4 4 empty_dir
5 5 Removing directory empty_dir
6 6 directory
7 7 r1
8 8 % delete an untracked directory
9 9 untracked_dir/untracked_file1
10 10 untracked_dir/untracked_file2
11 11 Removing file untracked_dir/untracked_file1
12 12 Removing file untracked_dir/untracked_file2
13 13 Removing directory untracked_dir
14 14 directory
15 15 r1
16 16 % delete an untracked file
17 17 untracked_file
18 untracked_file_readonly
18 19 Removing file untracked_file
20 Removing file untracked_file_readonly
19 21 directory
20 22 r1
21 23 % delete an untracked file in a tracked directory
22 24 directory/untracked_file
23 25 Removing file directory/untracked_file
24 26 directory
25 27 r1
26 28 % delete nested directories
27 29 untracked_directory/nested_directory
28 30 Removing directory untracked_directory/nested_directory
29 31 Removing directory untracked_directory
30 32 directory
31 33 r1
32 34 % delete nested directories from a subdir
33 35 untracked_directory/nested_directory
34 36 Removing directory untracked_directory/nested_directory
35 37 Removing directory untracked_directory
36 38 directory
37 39 r1
38 40 % delete only part of the tree
39 41 untracked_directory/nested_directory
40 42 Removing directory untracked_directory/nested_directory
41 43 Removing directory untracked_directory
42 44 directory
43 45 r1
44 46 directory/untracked_file
45 47 % skip ignored files if --all not specified
46 48 directory
47 49 ignored
48 50 r1
49 51 ignored
50 52 Removing file ignored
51 53 directory
52 54 r1
53 55 % abort with missing files until we support name mangling filesystems
54 56 untracked_file
55 57 ! r1
56 58 ? untracked_file
57 59 untracked_file
58 60 Removing file untracked_file
59 61 ! r1
60 62 % tracked file in ignored directory (issue621)
61 63 untracked_file
62 64 Removing file untracked_file
63 65 % skip excluded files
64 66 directory
65 67 excluded_file
66 68 r1
67 69 % skip files in excluded dirs
68 70 directory
69 71 excluded_dir
70 72 r1
71 73 file
72 74 % skip excluded empty dirs
73 75 directory
74 76 excluded_dir
75 77 r1
76 78 % skip patterns
General Comments 0
You need to be logged in to leave comments. Login now