2 # Copyright 2012 The Swarming Authors. All rights reserved.
3 # Use of this source code is governed under the Apache License, Version 2.0 that
4 # can be found in the LICENSE file.
6 """Cleans up a swarm slave after the tests have run."""
19 # This is copied from Chromium's project build/scripts/common/chromium_utils.py.
20 def RemoveDirectory(*path):
21 """Recursively removes a directory, even if it's marked read-only.
23 Remove the directory located at *path, if it exists.
25 shutil.rmtree() doesn't work on Windows if any of the files or directories
26 are read-only, which svn repositories and some .svn files are. We need to
27 be able to force the files to be writable (i.e., deletable) as we traverse
30 Even with all this, Windows still sometimes fails to delete a file, citing
31 a permission error (maybe something to do with antivirus scans or disk
32 indexing). The best suggestion any of the user forums had was to wait a
33 bit and try again, so we do that too. It's hand-waving, but sometimes it
36 file_path = os.path.join(*path)
37 if not os.path.exists(file_path):
40 if sys.platform == 'win32':
41 # Give up and use cmd.exe's rd command.
42 file_path = os.path.normcase(file_path)
45 if not subprocess.call(['cmd.exe', '/c', 'rd', '/q', '/s', file_path]):
48 print >> sys.stderr, 'Failed to delete %s' % file_path
53 def RemoveWithRetry_non_win(rmfunc, path):
54 if os.path.islink(path):
55 return os.remove(path)
59 remove_with_retry = RemoveWithRetry_non_win
61 def RmTreeOnError(function, path, excinfo):
62 """This works around a problem whereby python 2.x on Windows has no ability
63 to check for symbolic links. os.path.islink() always returns False but
64 shutil.rmtree() will fail if invoked on a symbolic link whose target was
65 deleted before the link. E.g., reproduce like this:
68 > mklink /D test\current test\1
69 > python -c "import shutl; shutil.rmtree('test')"
70 To avoid this issue, we pass this error-handling function to rmtree. If we
71 see the exact sort of failure, we ignore it. All other failures we
74 exception_type = excinfo[0]
75 exception_value = excinfo[1]
76 # If shutil.rmtree encounters a symbolic link on Windows, os.listdir will
77 # fail with a WindowsError exception with an ENOENT errno (i.e., file not
78 # found). We'll ignore that error. Note that WindowsError is not defined
79 # for non-Windows platforms, so we use OSError (of which it is a subclass)
80 # to avoid lint complaints about an undefined global on non-Windows
82 if (function is os.listdir) and issubclass(exception_type, OSError):
83 if exception_value.errno == errno.ENOENT:
84 # File does not exist, and we're trying to delete, so we can ignore the
86 print 'WARNING: Failed to list %s during rmtree. Ignoring.\n' % path
92 for root, dirs, files in os.walk(file_path, topdown=False):
93 # For POSIX: making the directory writable guarantees removability.
94 # Windows will ignore the non-read-only bits in the chmod value.
97 remove_with_retry(os.remove, os.path.join(root, name))
99 remove_with_retry(lambda p: shutil.rmtree(p, onerror=RmTreeOnError),
100 os.path.join(root, name))
102 remove_with_retry(os.rmdir, file_path)
105 def delete(filename):
107 if os.path.isdir(filename):
108 RemoveDirectory(filename)
117 # Clears run_isolated.zip.
120 # Clears temporary directories generated by run_isolated.py.
124 # Clears temporary directories generated by Chromium tests.
125 # TODO(maruel): This doesn't belong here, I wish these tests stopped
127 os.path.join(tempfile.gettempdir(), 'scoped_dir*'),
128 os.path.join(tempfile.gettempdir(), 'zip_package*'),
130 if sys.platform == 'darwin':
131 globs_to_delete.append(
133 os.path.expanduser('~'), 'Applications', 'Chromium Apps.localized'))
134 if sys.platform == 'win32':
135 globs_to_delete.append(
137 os.path.expanduser('~'), 'AppData', 'Roaming', 'Microsoft',
138 'Windows', 'Recent', 'CustomDestinations', '*'))
140 iterables = (glob.iglob(g) for g in globs_to_delete)
141 for filename in itertools.chain.from_iterable(iterables):
148 if __name__ == '__main__':