1# SPDX-License-Identifier: GPL-2.0+ 2# 3# Copyright (c) 2016 Google, Inc 4# 5 6import command 7import os 8import shutil 9import tempfile 10 11import tout 12 13# Output directly (generally this is temporary) 14outdir = None 15 16# True to keep the output directory around after exiting 17preserve_outdir = False 18 19# Path to the Chrome OS chroot, if we know it 20chroot_path = None 21 22# Search paths to use for Filename(), used to find files 23search_paths = [] 24 25 26def PrepareOutputDir(dirname, preserve=False): 27 """Select an output directory, ensuring it exists. 28 29 This either creates a temporary directory or checks that the one supplied 30 by the user is valid. For a temporary directory, it makes a note to 31 remove it later if required. 32 33 Args: 34 dirname: a string, name of the output directory to use to store 35 intermediate and output files. If is None - create a temporary 36 directory. 37 preserve: a Boolean. If outdir above is None and preserve is False, the 38 created temporary directory will be destroyed on exit. 39 40 Raises: 41 OSError: If it cannot create the output directory. 42 """ 43 global outdir, preserve_outdir 44 45 preserve_outdir = dirname or preserve 46 if dirname: 47 outdir = dirname 48 if not os.path.isdir(outdir): 49 try: 50 os.makedirs(outdir) 51 except OSError as err: 52 raise CmdError("Cannot make output directory '%s': '%s'" % 53 (outdir, err.strerror)) 54 tout.Debug("Using output directory '%s'" % outdir) 55 else: 56 outdir = tempfile.mkdtemp(prefix='binman.') 57 tout.Debug("Using temporary directory '%s'" % outdir) 58 59def _RemoveOutputDir(): 60 global outdir 61 62 shutil.rmtree(outdir) 63 tout.Debug("Deleted temporary directory '%s'" % outdir) 64 outdir = None 65 66def FinaliseOutputDir(): 67 global outdir, preserve_outdir 68 69 """Tidy up: delete output directory if temporary and not preserved.""" 70 if outdir and not preserve_outdir: 71 _RemoveOutputDir() 72 73def GetOutputFilename(fname): 74 """Return a filename within the output directory. 75 76 Args: 77 fname: Filename to use for new file 78 79 Returns: 80 The full path of the filename, within the output directory 81 """ 82 return os.path.join(outdir, fname) 83 84def _FinaliseForTest(): 85 """Remove the output directory (for use by tests)""" 86 global outdir 87 88 if outdir: 89 _RemoveOutputDir() 90 91def SetInputDirs(dirname): 92 """Add a list of input directories, where input files are kept. 93 94 Args: 95 dirname: a list of paths to input directories to use for obtaining 96 files needed by binman to place in the image. 97 """ 98 global indir 99 100 indir = dirname 101 tout.Debug("Using input directories %s" % indir) 102 103def GetInputFilename(fname): 104 """Return a filename for use as input. 105 106 Args: 107 fname: Filename to use for new file 108 109 Returns: 110 The full path of the filename, within the input directory 111 """ 112 if not indir: 113 return fname 114 for dirname in indir: 115 pathname = os.path.join(dirname, fname) 116 if os.path.exists(pathname): 117 return pathname 118 119 raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" % 120 (fname, ','.join(indir), os.getcwd())) 121 122def Align(pos, align): 123 if align: 124 mask = align - 1 125 pos = (pos + mask) & ~mask 126 return pos 127 128def NotPowerOfTwo(num): 129 return num and (num & (num - 1)) 130 131def Run(name, *args): 132 command.Run(name, *args, cwd=outdir) 133 134def Filename(fname): 135 """Resolve a file path to an absolute path. 136 137 If fname starts with ##/ and chroot is available, ##/ gets replaced with 138 the chroot path. If chroot is not available, this file name can not be 139 resolved, `None' is returned. 140 141 If fname is not prepended with the above prefix, and is not an existing 142 file, the actual file name is retrieved from the passed in string and the 143 search_paths directories (if any) are searched to for the file. If found - 144 the path to the found file is returned, `None' is returned otherwise. 145 146 Args: 147 fname: a string, the path to resolve. 148 149 Returns: 150 Absolute path to the file or None if not found. 151 """ 152 if fname.startswith('##/'): 153 if chroot_path: 154 fname = os.path.join(chroot_path, fname[3:]) 155 else: 156 return None 157 158 # Search for a pathname that exists, and return it if found 159 if fname and not os.path.exists(fname): 160 for path in search_paths: 161 pathname = os.path.join(path, os.path.basename(fname)) 162 if os.path.exists(pathname): 163 return pathname 164 165 # If not found, just return the standard, unchanged path 166 return fname 167 168def ReadFile(fname): 169 """Read and return the contents of a file. 170 171 Args: 172 fname: path to filename to read, where ## signifiies the chroot. 173 174 Returns: 175 data read from file, as a string. 176 """ 177 with open(Filename(fname), 'rb') as fd: 178 data = fd.read() 179 #self._out.Info("Read file '%s' size %d (%#0x)" % 180 #(fname, len(data), len(data))) 181 return data 182 183def WriteFile(fname, data): 184 """Write data into a file. 185 186 Args: 187 fname: path to filename to write 188 data: data to write to file, as a string 189 """ 190 #self._out.Info("Write file '%s' size %d (%#0x)" % 191 #(fname, len(data), len(data))) 192 with open(Filename(fname), 'wb') as fd: 193 fd.write(data) 194