Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / tools / swarming_client / tools / swarm_cleanup.py
1 #!/usr/bin/env python
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.
5
6 """Cleans up a swarm slave after the tests have run."""
7
8 import errno
9 import glob
10 import itertools
11 import os
12 import shutil
13 import subprocess
14 import sys
15 import tempfile
16 import time
17
18
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.
22
23   Remove the directory located at *path, if it exists.
24
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
28   the tree.
29
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
34   works. :/
35   """
36   file_path = os.path.join(*path)
37   if not os.path.exists(file_path):
38     return
39
40   if sys.platform == 'win32':
41     # Give up and use cmd.exe's rd command.
42     file_path = os.path.normcase(file_path)
43     for i in xrange(4):
44       sys.stdout.flush()
45       if not subprocess.call(['cmd.exe', '/c', 'rd', '/q', '/s', file_path]):
46         break
47       if i == 3:
48         print >> sys.stderr, 'Failed to delete %s' % file_path
49         break
50       time.sleep((i+1)*2)
51     return
52
53   def RemoveWithRetry_non_win(rmfunc, path):
54     if os.path.islink(path):
55       return os.remove(path)
56     else:
57       return rmfunc(path)
58
59   remove_with_retry = RemoveWithRetry_non_win
60
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:
66     > mkdir test
67     > mkdir test\1
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
72     re-raise.
73     """
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
81     # platforms.
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
85         # failure.
86         print 'WARNING:  Failed to list %s during rmtree.  Ignoring.\n' % path
87       else:
88         raise
89     else:
90       raise
91
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.
95     os.chmod(root, 0770)
96     for name in files:
97       remove_with_retry(os.remove, os.path.join(root, name))
98     for name in dirs:
99       remove_with_retry(lambda p: shutil.rmtree(p, onerror=RmTreeOnError),
100                         os.path.join(root, name))
101
102   remove_with_retry(os.rmdir, file_path)
103
104
105 def delete(filename):
106   try:
107     if os.path.isdir(filename):
108       RemoveDirectory(filename)
109     else:
110       os.remove(filename)
111   except OSError:
112     pass
113
114
115 def main():
116   globs_to_delete = [
117     # Clears run_isolated.zip.
118     'run_isolated.zip',
119
120     # Clears temporary directories generated by run_isolated.py.
121     'run_tha_test*',
122     'isolated_out*',
123
124     # Clears temporary directories generated by Chromium tests.
125     # TODO(maruel): This doesn't belong here, I wish these tests stopped
126     # leaking.
127     os.path.join(tempfile.gettempdir(), 'scoped_dir*'),
128     os.path.join(tempfile.gettempdir(), 'zip_package*'),
129   ]
130   if sys.platform == 'darwin':
131     globs_to_delete.append(
132         os.path.join(
133             os.path.expanduser('~'), 'Applications', 'Chromium Apps.localized'))
134   if sys.platform == 'win32':
135     globs_to_delete.append(
136         os.path.join(
137             os.path.expanduser('~'), 'AppData', 'Roaming', 'Microsoft',
138             'Windows', 'Recent', 'CustomDestinations', '*'))
139
140   iterables = (glob.iglob(g) for g in globs_to_delete)
141   for filename in itertools.chain.from_iterable(iterables):
142     delete(filename)
143
144   print ''
145   return 0
146
147
148 if __name__ == '__main__':
149   sys.exit(main())