2 # Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Convience stand-alone file operations."""
15 def AtomicWriteFile(data, filename):
16 """Write a file atomically.
18 NOTE: Not atomic on Windows!
20 data: String to write to the file.
21 filename: Filename to write.
23 filename = os.path.abspath(filename)
24 handle, temp_file = tempfile.mkstemp(
25 prefix='atomic_write', suffix='.tmp',
26 dir=os.path.dirname(filename))
27 fh = os.fdopen(handle, 'wb')
30 # Window's can't move into place atomically, delete first.
31 if sys.platform in ['win32', 'cygwin']:
36 os.rename(temp_file, filename)
39 def WriteFile(data, filename):
40 """Write a file in one step.
43 data: String to write to the file.
44 filename: Filename to write.
46 fh = open(filename, 'wb')
51 def ReadFile(filename):
52 """Read a file in one step.
55 filename: Filename to read.
57 String containing complete file.
59 fh = open(filename, 'rb')
65 class ExecutableNotFound(Exception):
69 def Which(command, paths=None, require_executable=True):
70 """Find the absolute path of a command in the current PATH.
73 command: Command name to look for.
74 paths: Optional paths to search.
76 Absolute path of the command (first one found),
77 or default to a bare command if nothing is found.
80 paths = os.environ.get('PATH', '').split(os.pathsep)
82 if sys.platform == 'win32':
83 exe_suffixes += ['.exe']
85 np = os.path.abspath(os.path.join(p, command))
86 for suffix in exe_suffixes:
87 full_path = np + suffix
88 if (os.path.isfile(full_path) and
89 (not require_executable or os.access(full_path, os.X_OK))):
91 raise ExecutableNotFound('Unable to find: ' + command)
94 def MakeDirectoryIfAbsent(path):
95 """Create a directory if it doesn't already exist.
98 path: Directory to create.
100 if not os.path.exists(path):
104 def RemoveDirectoryIfPresent(path):
105 """Remove a directory if it exists.
108 path: Directory to remove.
111 # On Windows, attempts to remove read-only files get Error 5. This
112 # error handler fixes the permissions and retries the removal.
113 def onerror_readonly(func, path, exc_info):
115 if not os.access(path, os.W_OK):
116 os.chmod(path, stat.S_IWUSR)
119 if os.path.exists(path):
120 shutil.rmtree(path, onerror=onerror_readonly)