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

Side by Side Diff: infra_libs/utils.py

Issue 2213143002: Add infra_libs as a bootstrap dependency. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Removed the ugly import hack Created 4 years, 4 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
OLDNEW
(Empty)
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Miscellaneous utility functions."""
6
7
8 import contextlib
9 import errno
10 import json
11 import os
12 import shutil
13 import subprocess
14 import sys
15 import tempfile
16 import time
17
18
19 def read_json_as_utf8(filename=None, text=None):
20 """Read and deserialize a json file or string.
21
22 This function is different from json.load and json.loads in that it
23 returns utf8-encoded string for keys and values instead of unicode.
24
25 Args:
26 filename (str): path of a file to parse
27 text (str): json string to parse
28
29 ``filename`` and ``text`` are mutually exclusive. ValueError is raised if
30 both are provided.
31 """
32
33 if filename is not None and text is not None:
34 raise ValueError('Only one of "filename" and "text" can be provided at '
35 'the same time')
36
37 if filename is None and text is None:
38 raise ValueError('One of "filename" and "text" must be provided')
39
40 def to_utf8(obj):
41 if isinstance(obj, dict):
42 return {to_utf8(key): to_utf8(value) for key, value in obj.iteritems()}
43 if isinstance(obj, list):
44 return [to_utf8(item) for item in obj]
45 if isinstance(obj, unicode):
46 return obj.encode('utf-8')
47 return obj
48
49 if filename:
50 with open(filename, 'rb') as f:
51 obj = json.load(f)
52 else:
53 obj = json.loads(text)
54
55 return to_utf8(obj)
56
57
58 # TODO(hinoka): Add tests crbug.com/500781
59 def rmtree(file_path): # pragma: no cover
60 """Recursively removes a directory, even if it's marked read-only.
61
62 Remove the directory located at file_path, if it exists.
63
64 shutil.rmtree() doesn't work on Windows if any of the files or directories
65 are read-only, which svn repositories and some .svn files are. We need to
66 be able to force the files to be writable (i.e., deletable) as we traverse
67 the tree.
68
69 Even with all this, Windows still sometimes fails to delete a file, citing
70 a permission error (maybe something to do with antivirus scans or disk
71 indexing). The best suggestion any of the user forums had was to wait a
72 bit and try again, so we do that too. It's hand-waving, but sometimes it
73 works. :/
74 """
75 if not os.path.exists(file_path):
76 return
77
78 if sys.platform == 'win32':
79 # Give up and use cmd.exe's rd command.
80 file_path = os.path.normcase(file_path)
81 for _ in xrange(3):
82 if not subprocess.call(['cmd.exe', '/c', 'rd', '/q', '/s', file_path]):
83 break
84 time.sleep(3)
85 return
86
87 def remove_with_retry(rmfunc, path):
88 if os.path.islink(path):
89 return os.remove(path)
90 else:
91 return rmfunc(path)
92
93 def rmtree_on_error(function, _, excinfo):
94 """This works around a problem whereby python 2.x on Windows has no ability
95 to check for symbolic links. os.path.islink always returns False. But
96 shutil.rmtree will fail if invoked on a symbolic link whose target was
97 deleted before the link. E.g., reproduce like this:
98 > mkdir test
99 > mkdir test\1
100 > mklink /D test\current test\1
101 > python -c "import infra_libs; infra_libs.rmtree('test')"
102 To avoid this issue, we pass this error-handling function to rmtree. If
103 we see the exact sort of failure, we ignore it. All other failures we re-
104 raise.
105 """
106
107 exception_type = excinfo[0]
108 exception_value = excinfo[1]
109 # If shutil.rmtree encounters a symbolic link on Windows, os.listdir will
110 # fail with a WindowsError exception with an ENOENT errno (i.e., file not
111 # found). We'll ignore that error. Note that WindowsError is not defined
112 # for non-Windows platforms, so we use OSError (of which it is a subclass)
113 # to avoid lint complaints about an undefined global on non-Windows
114 # platforms.
115 if (function is os.listdir) and issubclass(exception_type, OSError):
116 if exception_value.errno != errno.ENOENT:
117 raise
118 else:
119 raise
120
121 for root, dirs, files in os.walk(file_path, topdown=False):
122 # For POSIX: making the directory writable guarantees removability.
123 # Windows will ignore the non-read-only bits in the chmod value.
124 os.chmod(root, 0770)
125 for name in files:
126 remove_with_retry(os.remove, os.path.join(root, name))
127 for name in dirs:
128 remove_with_retry(lambda p: shutil.rmtree(p, onerror=rmtree_on_error),
129 os.path.join(root, name))
130
131 remove_with_retry(os.rmdir, file_path)
132
133
134 # We're trying to be compatible with Python3 tempfile.TemporaryDirectory
135 # context manager here. And they used 'dir' as a keyword argument.
136 # pylint: disable=redefined-builtin
137 @contextlib.contextmanager
138 def temporary_directory(suffix="", prefix="tmp", dir=None,
139 keep_directory=False):
140 """Create and return a temporary directory. This has the same
141 behavior as mkdtemp but can be used as a context manager. For
142 example:
143
144 with temporary_directory() as tmpdir:
145 ...
146
147 Upon exiting the context, the directory and everything contained
148 in it are removed.
149
150 Args:
151 suffix, prefix, dir: same arguments as for tempfile.mkdtemp.
152 keep_directory (bool): if True, do not delete the temporary directory
153 when exiting. Useful for debugging.
154
155 Returns:
156 tempdir (str): full path to the temporary directory.
157 """
158 tempdir = None # Handle mkdtemp raising an exception
159 try:
160 tempdir = tempfile.mkdtemp(suffix, prefix, dir)
161 yield tempdir
162
163 finally:
164 if tempdir and not keep_directory: # pragma: no branch
165 try:
166 # TODO(pgervais,496347) Make this work reliably on Windows.
167 shutil.rmtree(tempdir, ignore_errors=True)
168 except OSError as ex: # pragma: no cover
169 print >> sys.stderr, (
170 "ERROR: {!r} while cleaning up {!r}".format(ex, tempdir))
OLDNEW
« bootstrap/deps.pyl ('K') | « infra_libs/ts_mon/test/config_test.py ('k') | test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698