Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(954)

Side by Side Diff: gclient_utils.py

Issue 6628032: Shorten RemoveDirectory and rename to rmtree. Remove rmtree from fake_repos. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: rebase against trunk Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/fake_repos.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Generic utils.""" 5 """Generic utils."""
6 6
7 import errno 7 import errno
8 import logging 8 import logging
9 import os 9 import os
10 import Queue 10 import Queue
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 175
176 176
177 def FileWrite(filename, content, mode='w'): 177 def FileWrite(filename, content, mode='w'):
178 f = open(filename, mode) 178 f = open(filename, mode)
179 try: 179 try:
180 f.write(content) 180 f.write(content)
181 finally: 181 finally:
182 f.close() 182 f.close()
183 183
184 184
185 def RemoveDirectory(*path): 185 def rmtree(path):
186 """Recursively removes a directory, even if it's marked read-only. 186 """shutil.rmtree() on steroids.
187 187
188 Remove the directory located at *path, if it exists. 188 Recursively removes a directory, even if it's marked read-only.
189 189
190 shutil.rmtree() doesn't work on Windows if any of the files or directories 190 shutil.rmtree() doesn't work on Windows if any of the files or directories
191 are read-only, which svn repositories and some .svn files are. We need to 191 are read-only, which svn repositories and some .svn files are. We need to
192 be able to force the files to be writable (i.e., deletable) as we traverse 192 be able to force the files to be writable (i.e., deletable) as we traverse
193 the tree. 193 the tree.
194 194
195 Even with all this, Windows still sometimes fails to delete a file, citing 195 Even with all this, Windows still sometimes fails to delete a file, citing
196 a permission error (maybe something to do with antivirus scans or disk 196 a permission error (maybe something to do with antivirus scans or disk
197 indexing). The best suggestion any of the user forums had was to wait a 197 indexing). The best suggestion any of the user forums had was to wait a
198 bit and try again, so we do that too. It's hand-waving, but sometimes it 198 bit and try again, so we do that too. It's hand-waving, but sometimes it
199 works. :/ 199 works. :/
200 200
201 On POSIX systems, things are a little bit simpler. The modes of the files 201 On POSIX systems, things are a little bit simpler. The modes of the files
202 to be deleted doesn't matter, only the modes of the directories containing 202 to be deleted doesn't matter, only the modes of the directories containing
203 them are significant. As the directory tree is traversed, each directory 203 them are significant. As the directory tree is traversed, each directory
204 has its mode set appropriately before descending into it. This should 204 has its mode set appropriately before descending into it. This should
205 result in the entire tree being removed, with the possible exception of 205 result in the entire tree being removed, with the possible exception of
206 *path itself, because nothing attempts to change the mode of its parent. 206 *path itself, because nothing attempts to change the mode of its parent.
207 Doing so would be hazardous, as it's not a directory slated for removal. 207 Doing so would be hazardous, as it's not a directory slated for removal.
208 In the ordinary case, this is not a problem: for our purposes, the user 208 In the ordinary case, this is not a problem: for our purposes, the user
209 will never lack write permission on *path's parent. 209 will never lack write permission on *path's parent.
210 """ 210 """
211 logging.debug(path) 211 if not os.path.exists(path):
212 file_path = os.path.join(*path)
213 if not os.path.exists(file_path):
214 return 212 return
215 213
216 if os.path.islink(file_path) or not os.path.isdir(file_path): 214 if os.path.islink(path) or not os.path.isdir(path):
217 raise Error('RemoveDirectory asked to remove non-directory %s' % file_path) 215 raise Error('Called rmtree(%s) in non-directory' % path)
218 216
219 has_win32api = False
220 if sys.platform == 'win32': 217 if sys.platform == 'win32':
221 has_win32api = True
222 # Some people don't have the APIs installed. In that case we'll do without. 218 # Some people don't have the APIs installed. In that case we'll do without.
223 try: 219 try:
224 win32api = __import__('win32api') 220 win32api = __import__('win32api')
225 win32con = __import__('win32con') 221 win32con = __import__('win32con')
226 except ImportError: 222 except ImportError:
227 has_win32api = False 223 pass
228 else: 224 else:
229 # On POSIX systems, we need the x-bit set on the directory to access it, 225 # On POSIX systems, we need the x-bit set on the directory to access it,
230 # the r-bit to see its contents, and the w-bit to remove files from it. 226 # the r-bit to see its contents, and the w-bit to remove files from it.
231 # The actual modes of the files within the directory is irrelevant. 227 # The actual modes of the files within the directory is irrelevant.
232 os.chmod(file_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) 228 os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
233 for fn in os.listdir(file_path):
234 fullpath = os.path.join(file_path, fn)
235 229
230 def remove(func, subpath):
231 if sys.platform == 'win32':
232 os.chmod(subpath, stat.S_IWRITE)
233 if win32api and win32con:
234 win32api.SetFileAttributes(subpath, win32con.FILE_ATTRIBUTE_NORMAL)
235 try:
236 func(subpath)
237 except OSError, e:
238 if e.errno != errno.EACCES or sys.platform != 'win32':
239 raise
240 # Failed to delete, try again after a 100ms sleep.
241 time.sleep(0.1)
242 func(subpath)
243
244 for fn in os.listdir(path):
236 # If fullpath is a symbolic link that points to a directory, isdir will 245 # If fullpath is a symbolic link that points to a directory, isdir will
237 # be True, but we don't want to descend into that as a directory, we just 246 # be True, but we don't want to descend into that as a directory, we just
238 # want to remove the link. Check islink and treat links as ordinary files 247 # want to remove the link. Check islink and treat links as ordinary files
239 # would be treated regardless of what they reference. 248 # would be treated regardless of what they reference.
249 fullpath = os.path.join(path, fn)
240 if os.path.islink(fullpath) or not os.path.isdir(fullpath): 250 if os.path.islink(fullpath) or not os.path.isdir(fullpath):
241 if sys.platform == 'win32': 251 remove(os.remove, fullpath)
242 os.chmod(fullpath, stat.S_IWRITE)
243 if has_win32api:
244 win32api.SetFileAttributes(fullpath, win32con.FILE_ATTRIBUTE_NORMAL)
245 try:
246 os.remove(fullpath)
247 except OSError, e:
248 if e.errno != errno.EACCES or sys.platform != 'win32':
249 raise
250 print 'Failed to delete %s: trying again' % fullpath
251 time.sleep(0.1)
252 os.remove(fullpath)
253 else: 252 else:
254 RemoveDirectory(fullpath) 253 # Recurse.
254 rmtree(fullpath)
255 255
256 if sys.platform == 'win32': 256 remove(os.rmdir, path)
257 os.chmod(file_path, stat.S_IWRITE) 257
258 if has_win32api: 258 # TODO(maruel): Rename the references.
259 win32api.SetFileAttributes(file_path, win32con.FILE_ATTRIBUTE_NORMAL) 259 RemoveDirectory = rmtree
260 try:
261 os.rmdir(file_path)
262 except OSError, e:
263 if e.errno != errno.EACCES or sys.platform != 'win32':
264 raise
265 print 'Failed to remove %s: trying again' % file_path
266 time.sleep(0.1)
267 os.rmdir(file_path)
268 260
269 261
270 def CheckCallAndFilterAndHeader(args, always=False, **kwargs): 262 def CheckCallAndFilterAndHeader(args, always=False, **kwargs):
271 """Adds 'header' support to CheckCallAndFilter. 263 """Adds 'header' support to CheckCallAndFilter.
272 264
273 If |always| is True, a message indicating what is being done 265 If |always| is True, a message indicating what is being done
274 is printed to stdout all the time even if not output is generated. Otherwise 266 is printed to stdout all the time even if not output is generated. Otherwise
275 the message header is printed only if the call generated any ouput. 267 the message header is printed only if the call generated any ouput.
276 """ 268 """
277 stdout = kwargs.get('stdout', None) or sys.stdout 269 stdout = kwargs.get('stdout', None) or sys.stdout
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after
708 logging.info('Caught exception in thread %s' % self.item.name) 700 logging.info('Caught exception in thread %s' % self.item.name)
709 logging.info(str(sys.exc_info())) 701 logging.info(str(sys.exc_info()))
710 work_queue.exceptions.put(sys.exc_info()) 702 work_queue.exceptions.put(sys.exc_info())
711 logging.info('Task %s done' % self.item.name) 703 logging.info('Task %s done' % self.item.name)
712 704
713 work_queue.ready_cond.acquire() 705 work_queue.ready_cond.acquire()
714 try: 706 try:
715 work_queue.ready_cond.notifyAll() 707 work_queue.ready_cond.notifyAll()
716 finally: 708 finally:
717 work_queue.ready_cond.release() 709 work_queue.ready_cond.release()
OLDNEW
« no previous file with comments | « no previous file | tests/fake_repos.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698