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