annotate purge.py @ 2374:ffc2ed61061b

Even on Windows self._repo.dirstate.state() wants '/' in paths
author demian@gaudron.lan
date Tue, 16 May 2006 21:05:00 +0200
parents 61976a27aa2b
children 9f4f77693890
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
1 #!/usr/bin/env python
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
2 #
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
3 # Copyright (C) 2006 - Marco Barisione <marco@barisione.org>
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
4 #
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
5 # This is a small extension for Mercurial (http://www.selenic.com/mercurial)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
6 # that removes files not known to mercurial
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
7 #
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
8 # This program is free software; you can redistribute it and/or modify
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
9 # it under the terms of the GNU General Public License as published by
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
10 # the Free Software Foundation; either version 2 of the License, or
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
11 # (at your option) any later version.
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
12 #
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
13 # This program is distributed in the hope that it will be useful,
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
16 # GNU General Public License for more details.
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
17 #
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
18 # You should have received a copy of the GNU General Public License
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
19 # along with this program; if not, write to the Free Software
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
20 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
21
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
22 from mercurial import hg, util
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
23 import os
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
24
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
25 class Purge(object):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
26 def __init__(self, act=True, abort_on_err=False):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
27 self._repo = None
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
28 self._ui = None
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
29 self._hg_root = None
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
30 self._act = act
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
31 self._abort_on_err = abort_on_err
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
32
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
33 def purge(self, ui, repo, paths=None):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
34 self._repo = repo
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
35 self._ui = ui
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
36 self._hg_root = self._split_path(repo.root)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
37
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
38 if not paths:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
39 paths = [repo.root]
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
40
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
41 for path in paths:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
42 path = os.path.abspath(path)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
43 for root, dirs, files in os.walk(path, topdown=False):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
44 if '.hg' in self._split_path(root):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
45 # Skip files in the .hg directory.
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
46 # Note that if the repository is in a directory
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
47 # called .hg this command does not work.
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
48 continue
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
49 for name in files:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
50 self._remove_file(os.path.join(root, name))
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
51 if not os.listdir(root):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
52 # Remove this directory if it is empty.
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
53 self._remove_dir(root)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
54
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
55 self._repo = None
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
56 self._ui = None
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
57 self._hg_root = None
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
58
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
59 def _error(self, msg):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
60 if self._abort_on_err:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
61 raise util.Abort(msg)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
62 else:
2373
61976a27aa2b Some functions were called as globals (i.e. I forgot some "self.")
demian@gaudron.lan
parents: 2372
diff changeset
63 self._ui.warn('warning: ' + msg + '\n')
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
64
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
65 def _remove_file(self, name):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
66 relative_name = self._relative_name(name)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
67 # dirstate.state() requires a path relative to the root
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
68 # directory.
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
69 if self._repo.dirstate.state(relative_name) != '?':
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
70 return
2371
e39300cdb8ff Use self._ui.note(...) instead of if self._ui.verbose: self._ui.status(...)
demian@gaudron.lan
parents: 2370
diff changeset
71 self._ui.note(name + '\n')
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
72 if self._act:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
73 try:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
74 os.remove(name)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
75 except OSError, e:
2373
61976a27aa2b Some functions were called as globals (i.e. I forgot some "self.")
demian@gaudron.lan
parents: 2372
diff changeset
76 self._error('"%s" cannot be removed' % name)
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
77
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
78 def _remove_dir(self, name):
2371
e39300cdb8ff Use self._ui.note(...) instead of if self._ui.verbose: self._ui.status(...)
demian@gaudron.lan
parents: 2370
diff changeset
79 self._ui.note(name + '\n')
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
80 if self._act:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
81 try:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
82 os.rmdir(name)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
83 except OSError, e:
2373
61976a27aa2b Some functions were called as globals (i.e. I forgot some "self.")
demian@gaudron.lan
parents: 2372
diff changeset
84 self._error('"%s" cannot be removed' % name)
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
85
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
86 def _relative_name(self, name):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
87 splitted_path = self._split_path(name)[len(self._hg_root):]
2374
ffc2ed61061b Even on Windows self._repo.dirstate.state() wants '/' in paths
demian@gaudron.lan
parents: 2373
diff changeset
88 # Even on Windows self._repo.dirstate.state() wants '/'.
ffc2ed61061b Even on Windows self._repo.dirstate.state() wants '/' in paths
demian@gaudron.lan
parents: 2373
diff changeset
89 return self._join_path(splitted_path).replace('\\', '/')
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
90
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
91 def _split_path(self, path):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
92 ret = []
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
93 while True:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
94 head, tail = os.path.split(path)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
95 if tail:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
96 ret.append(tail)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
97 if head == path:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
98 ret.append(head)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
99 break
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
100 path = head
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
101 ret.reverse()
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
102 return ret
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
103
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
104 def _join_path(self, splitted_path):
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
105 ret = ''
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
106 for part in splitted_path:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
107 if ret:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
108 ret = os.path.join(ret, part)
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
109 else:
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
110 ret = part
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
111 return ret
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
112
2369
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
113
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
114 def purge(ui, repo, *paths, **opts):
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
115 '''removes files not tracked by mercurial
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
116
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
117 Delete files not known to mercurial, this is useful to test local and
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
118 uncommitted changes in the otherwise clean source tree.
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
119
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
120 This means that purge will delete:
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
121 - Unknown files: files marked with "?" by "hg status"
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
122 - Ignored files: files usually ignored by Mercurial because they match a
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
123 pattern in a ".hgignore" file
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
124 - Empty directories: infact Mercurial ignores directories unless they
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
125 contain files under source control managment
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
126 But it will leave untouched:
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
127 - Unmodified tracked files
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
128 - Modified tracked files
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
129 - New files added to the repository (with "hg add")
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
130
2369
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
131 If names are given, only files matching the names are considered, else
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
132 all files in the repository directory are considered.
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
133
2369
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
134 Be careful with purge, you could irreversibly delete some files you
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
135 forgot to add to the repository. If you only want to print the list of
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
136 files that this program would delete use the -vn options.
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
137 '''
2372
449906e17576 Changset de893ad6bd17 wrongly reversed the meaning of --nothing
demian@gaudron.lan
parents: 2371
diff changeset
138 act = not opts['nothing']
2370
de893ad6bd17 Command line options are read in a saner way
demian@gaudron.lan
parents: 2369
diff changeset
139 abort_on_err = bool(opts['abort_on_err'])
2369
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
140 p = Purge(act, abort_on_err)
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
141 p.purge(ui, repo, paths)
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
142
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
143
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
144 cmdtable = {
2369
9da3dd62c827 Purge.from_command is now a function called purge
demian@gaudron.lan
parents: 2364
diff changeset
145 'purge': (purge,
2364
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
146 [('a', 'abort-on-err', None, 'abort if an error occurs'),
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
147 ('n', 'nothing', None, 'do nothing on files, useful with --verbose'),
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
148 ],
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
149 'hg purge [OPTIONS] [NAME]')
f368a1c302d5 Initial commit
demian@gaudron.lan
parents:
diff changeset
150 }