1 # SPDX-License-Identifier: GPL-2.0+
3 # Copyright (c) 2016 Google, Inc
15 # Output directly (generally this is temporary)
18 # True to keep the output directory around after exiting
19 preserve_outdir = False
21 # Path to the Chrome OS chroot, if we know it
24 # Search paths to use for Filename(), used to find files
27 # Tools and the packages that contain them, on debian
32 # List of paths to use when looking for an input file
35 def PrepareOutputDir(dirname, preserve=False):
36 """Select an output directory, ensuring it exists.
38 This either creates a temporary directory or checks that the one supplied
39 by the user is valid. For a temporary directory, it makes a note to
40 remove it later if required.
43 dirname: a string, name of the output directory to use to store
44 intermediate and output files. If is None - create a temporary
46 preserve: a Boolean. If outdir above is None and preserve is False, the
47 created temporary directory will be destroyed on exit.
50 OSError: If it cannot create the output directory.
52 global outdir, preserve_outdir
54 preserve_outdir = dirname or preserve
57 if not os.path.isdir(outdir):
60 except OSError as err:
61 raise CmdError("Cannot make output directory '%s': '%s'" %
62 (outdir, err.strerror))
63 tout.Debug("Using output directory '%s'" % outdir)
65 outdir = tempfile.mkdtemp(prefix='binman.')
66 tout.Debug("Using temporary directory '%s'" % outdir)
68 def _RemoveOutputDir():
72 tout.Debug("Deleted temporary directory '%s'" % outdir)
75 def FinaliseOutputDir():
76 global outdir, preserve_outdir
78 """Tidy up: delete output directory if temporary and not preserved."""
79 if outdir and not preserve_outdir:
82 def GetOutputFilename(fname):
83 """Return a filename within the output directory.
86 fname: Filename to use for new file
89 The full path of the filename, within the output directory
91 return os.path.join(outdir, fname)
93 def _FinaliseForTest():
94 """Remove the output directory (for use by tests)"""
100 def SetInputDirs(dirname):
101 """Add a list of input directories, where input files are kept.
104 dirname: a list of paths to input directories to use for obtaining
105 files needed by binman to place in the image.
110 tout.Debug("Using input directories %s" % indir)
112 def GetInputFilename(fname):
113 """Return a filename for use as input.
116 fname: Filename to use for new file
119 The full path of the filename, within the input directory
123 for dirname in indir:
124 pathname = os.path.join(dirname, fname)
125 if os.path.exists(pathname):
128 raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
129 (fname, ','.join(indir), os.getcwd()))
131 def GetInputFilenameGlob(pattern):
132 """Return a list of filenames for use as input.
135 pattern: Filename pattern to search for
138 A list of matching files in all input directories
141 return glob.glob(fname)
143 for dirname in indir:
144 pathname = os.path.join(dirname, pattern)
145 files += glob.glob(pathname)
148 def Align(pos, align):
151 pos = (pos + mask) & ~mask
154 def NotPowerOfTwo(num):
155 return num and (num & (num - 1))
157 def PathHasFile(fname):
158 """Check if a given filename is in the PATH
161 fname: Filename to check
164 True if found, False if not
166 for dir in os.environ['PATH'].split(':'):
167 if os.path.exists(os.path.join(dir, fname)):
171 def Run(name, *args, **kwargs):
173 return command.Run(name, *args, cwd=outdir, capture=True, **kwargs)
175 if not PathHasFile(name):
176 msg = "Plesae install tool '%s'" % name
177 package = packages.get(name)
179 msg += " (e.g. from package '%s')" % package
180 raise ValueError(msg)
184 """Resolve a file path to an absolute path.
186 If fname starts with ##/ and chroot is available, ##/ gets replaced with
187 the chroot path. If chroot is not available, this file name can not be
188 resolved, `None' is returned.
190 If fname is not prepended with the above prefix, and is not an existing
191 file, the actual file name is retrieved from the passed in string and the
192 search_paths directories (if any) are searched to for the file. If found -
193 the path to the found file is returned, `None' is returned otherwise.
196 fname: a string, the path to resolve.
199 Absolute path to the file or None if not found.
201 if fname.startswith('##/'):
203 fname = os.path.join(chroot_path, fname[3:])
207 # Search for a pathname that exists, and return it if found
208 if fname and not os.path.exists(fname):
209 for path in search_paths:
210 pathname = os.path.join(path, os.path.basename(fname))
211 if os.path.exists(pathname):
214 # If not found, just return the standard, unchanged path
217 def ReadFile(fname, binary=True):
218 """Read and return the contents of a file.
221 fname: path to filename to read, where ## signifiies the chroot.
224 data read from file, as a string.
226 with open(Filename(fname), binary and 'rb' or 'r') as fd:
228 #self._out.Info("Read file '%s' size %d (%#0x)" %
229 #(fname, len(data), len(data)))
232 def WriteFile(fname, data):
233 """Write data into a file.
236 fname: path to filename to write
237 data: data to write to file, as a string
239 #self._out.Info("Write file '%s' size %d (%#0x)" %
240 #(fname, len(data), len(data)))
241 with open(Filename(fname), 'wb') as fd:
244 def GetBytes(byte, size):
245 """Get a string of bytes of a given size
247 This handles the unfortunate different between Python 2 and Python 2.
250 byte: Numeric byte value to use
251 size: Size of bytes/string to return
254 A bytes type with 'byte' repeated 'size' times
256 if sys.version_info[0] >= 3:
257 data = bytes([byte]) * size
259 data = chr(byte) * size
263 """Make sure a value is a unicode string
265 This allows some amount of compatibility between Python 2 and Python3. For
266 the former, it returns a unicode object.
269 val: string or unicode object
272 unicode version of val
274 if sys.version_info[0] >= 3:
276 return val if isinstance(val, unicode) else val.decode('utf-8')
278 def FromUnicode(val):
279 """Make sure a value is a non-unicode string
281 This allows some amount of compatibility between Python 2 and Python3. For
282 the former, it converts a unicode object to a string.
285 val: string or unicode object
288 non-unicode version of val
290 if sys.version_info[0] >= 3:
292 return val if isinstance(val, str) else val.encode('utf-8')
295 """Convert a character to an ASCII value
297 This is useful because in Python 2 bytes is an alias for str, but in
298 Python 3 they are separate types. This function converts the argument to
299 an ASCII value in either case.
302 ch: A string (Python 2) or byte (Python 3) value
305 integer ASCII value for ch
307 return ord(ch) if type(ch) == str else ch
310 """Convert a byte to a character
312 This is useful because in Python 2 bytes is an alias for str, but in
313 Python 3 they are separate types. This function converts an ASCII value to
314 a value with the appropriate type in either case.
317 byte: A byte or str value
319 return chr(byte) if type(byte) != str else byte
321 def ToChars(byte_list):
322 """Convert a list of bytes to a str/bytes type
325 byte_list: List of ASCII values representing the string
328 string made by concatenating all the ASCII values
330 return ''.join([chr(byte) for byte in byte_list])
333 """Convert a str type into a bytes type
336 string: string to convert value
339 Python 3: A bytes type
340 Python 2: A string type
342 if sys.version_info[0] >= 3:
343 return string.encode('utf-8')