blob: 1c9bf4e8100151141f0e9e851c91e918064ee046 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glassbe39f052016-07-25 18:59:08 -06002#
3# Copyright (c) 2016 Google, Inc
4#
Simon Glassbe39f052016-07-25 18:59:08 -06005
Simon Glass0362cd22018-07-17 13:25:43 -06006import command
Simon Glassac6328c2018-09-14 04:57:28 -06007import glob
Simon Glassbe39f052016-07-25 18:59:08 -06008import os
9import shutil
10import tempfile
11
12import tout
13
Simon Glass0362cd22018-07-17 13:25:43 -060014# Output directly (generally this is temporary)
Simon Glassbe39f052016-07-25 18:59:08 -060015outdir = None
Simon Glass0362cd22018-07-17 13:25:43 -060016
17# True to keep the output directory around after exiting
Simon Glassbe39f052016-07-25 18:59:08 -060018preserve_outdir = False
19
Simon Glass0362cd22018-07-17 13:25:43 -060020# Path to the Chrome OS chroot, if we know it
21chroot_path = None
22
23# Search paths to use for Filename(), used to find files
24search_paths = []
25
Simon Glass778ab842018-09-14 04:57:25 -060026# Tools and the packages that contain them, on debian
27packages = {
28 'lz4': 'liblz4-tool',
29 }
Simon Glass0362cd22018-07-17 13:25:43 -060030
Simon Glassbe39f052016-07-25 18:59:08 -060031def PrepareOutputDir(dirname, preserve=False):
32 """Select an output directory, ensuring it exists.
33
34 This either creates a temporary directory or checks that the one supplied
35 by the user is valid. For a temporary directory, it makes a note to
36 remove it later if required.
37
38 Args:
39 dirname: a string, name of the output directory to use to store
40 intermediate and output files. If is None - create a temporary
41 directory.
42 preserve: a Boolean. If outdir above is None and preserve is False, the
43 created temporary directory will be destroyed on exit.
44
45 Raises:
46 OSError: If it cannot create the output directory.
47 """
48 global outdir, preserve_outdir
49
50 preserve_outdir = dirname or preserve
51 if dirname:
52 outdir = dirname
53 if not os.path.isdir(outdir):
54 try:
55 os.makedirs(outdir)
56 except OSError as err:
57 raise CmdError("Cannot make output directory '%s': '%s'" %
58 (outdir, err.strerror))
59 tout.Debug("Using output directory '%s'" % outdir)
60 else:
61 outdir = tempfile.mkdtemp(prefix='binman.')
62 tout.Debug("Using temporary directory '%s'" % outdir)
63
64def _RemoveOutputDir():
65 global outdir
66
67 shutil.rmtree(outdir)
68 tout.Debug("Deleted temporary directory '%s'" % outdir)
69 outdir = None
70
71def FinaliseOutputDir():
72 global outdir, preserve_outdir
73
74 """Tidy up: delete output directory if temporary and not preserved."""
75 if outdir and not preserve_outdir:
76 _RemoveOutputDir()
77
78def GetOutputFilename(fname):
79 """Return a filename within the output directory.
80
81 Args:
82 fname: Filename to use for new file
83
84 Returns:
85 The full path of the filename, within the output directory
86 """
87 return os.path.join(outdir, fname)
88
89def _FinaliseForTest():
90 """Remove the output directory (for use by tests)"""
91 global outdir
92
93 if outdir:
94 _RemoveOutputDir()
95
96def SetInputDirs(dirname):
97 """Add a list of input directories, where input files are kept.
98
99 Args:
100 dirname: a list of paths to input directories to use for obtaining
101 files needed by binman to place in the image.
102 """
103 global indir
104
105 indir = dirname
106 tout.Debug("Using input directories %s" % indir)
107
108def GetInputFilename(fname):
109 """Return a filename for use as input.
110
111 Args:
112 fname: Filename to use for new file
113
114 Returns:
115 The full path of the filename, within the input directory
116 """
117 if not indir:
118 return fname
119 for dirname in indir:
120 pathname = os.path.join(dirname, fname)
121 if os.path.exists(pathname):
122 return pathname
123
Simon Glassf2eb0542018-07-17 13:25:45 -0600124 raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
125 (fname, ','.join(indir), os.getcwd()))
Simon Glassbe39f052016-07-25 18:59:08 -0600126
Simon Glassac6328c2018-09-14 04:57:28 -0600127def GetInputFilenameGlob(pattern):
128 """Return a list of filenames for use as input.
129
130 Args:
131 pattern: Filename pattern to search for
132
133 Returns:
134 A list of matching files in all input directories
135 """
136 if not indir:
137 return glob.glob(fname)
138 files = []
139 for dirname in indir:
140 pathname = os.path.join(dirname, pattern)
141 files += glob.glob(pathname)
142 return sorted(files)
143
Simon Glassbe39f052016-07-25 18:59:08 -0600144def Align(pos, align):
145 if align:
146 mask = align - 1
147 pos = (pos + mask) & ~mask
148 return pos
149
150def NotPowerOfTwo(num):
151 return num and (num & (num - 1))
Simon Glass0362cd22018-07-17 13:25:43 -0600152
Simon Glass778ab842018-09-14 04:57:25 -0600153def PathHasFile(fname):
154 """Check if a given filename is in the PATH
155
156 Args:
157 fname: Filename to check
158
159 Returns:
160 True if found, False if not
161 """
162 for dir in os.environ['PATH'].split(':'):
163 if os.path.exists(os.path.join(dir, fname)):
164 return True
165 return False
166
Simon Glass0362cd22018-07-17 13:25:43 -0600167def Run(name, *args):
Simon Glass778ab842018-09-14 04:57:25 -0600168 try:
169 return command.Run(name, *args, cwd=outdir, capture=True)
170 except:
171 if not PathHasFile(name):
172 msg = "Plesae install tool '%s'" % name
173 package = packages.get(name)
174 if package:
175 msg += " (e.g. from package '%s')" % package
176 raise ValueError(msg)
177 raise
Simon Glass0362cd22018-07-17 13:25:43 -0600178
179def Filename(fname):
180 """Resolve a file path to an absolute path.
181
182 If fname starts with ##/ and chroot is available, ##/ gets replaced with
183 the chroot path. If chroot is not available, this file name can not be
184 resolved, `None' is returned.
185
186 If fname is not prepended with the above prefix, and is not an existing
187 file, the actual file name is retrieved from the passed in string and the
188 search_paths directories (if any) are searched to for the file. If found -
189 the path to the found file is returned, `None' is returned otherwise.
190
191 Args:
192 fname: a string, the path to resolve.
193
194 Returns:
195 Absolute path to the file or None if not found.
196 """
197 if fname.startswith('##/'):
198 if chroot_path:
199 fname = os.path.join(chroot_path, fname[3:])
200 else:
201 return None
202
203 # Search for a pathname that exists, and return it if found
204 if fname and not os.path.exists(fname):
205 for path in search_paths:
206 pathname = os.path.join(path, os.path.basename(fname))
207 if os.path.exists(pathname):
208 return pathname
209
210 # If not found, just return the standard, unchanged path
211 return fname
212
213def ReadFile(fname):
214 """Read and return the contents of a file.
215
216 Args:
217 fname: path to filename to read, where ## signifiies the chroot.
218
219 Returns:
220 data read from file, as a string.
221 """
222 with open(Filename(fname), 'rb') as fd:
223 data = fd.read()
224 #self._out.Info("Read file '%s' size %d (%#0x)" %
225 #(fname, len(data), len(data)))
226 return data
227
228def WriteFile(fname, data):
229 """Write data into a file.
230
231 Args:
232 fname: path to filename to write
233 data: data to write to file, as a string
234 """
235 #self._out.Info("Write file '%s' size %d (%#0x)" %
236 #(fname, len(data), len(data)))
237 with open(Filename(fname), 'wb') as fd:
238 fd.write(data)