blob: e80481438b547b8dc9b2a80964e41d7232d7a5cd [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 Glassbe39f052016-07-25 18:59:08 -06007import os
8import shutil
9import tempfile
10
11import tout
12
Simon Glass0362cd22018-07-17 13:25:43 -060013# Output directly (generally this is temporary)
Simon Glassbe39f052016-07-25 18:59:08 -060014outdir = None
Simon Glass0362cd22018-07-17 13:25:43 -060015
16# True to keep the output directory around after exiting
Simon Glassbe39f052016-07-25 18:59:08 -060017preserve_outdir = False
18
Simon Glass0362cd22018-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
25
Simon Glassbe39f052016-07-25 18:59:08 -060026def 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
Simon Glassf2eb0542018-07-17 13:25:45 -0600119 raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
120 (fname, ','.join(indir), os.getcwd()))
Simon Glassbe39f052016-07-25 18:59:08 -0600121
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))
Simon Glass0362cd22018-07-17 13:25:43 -0600130
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)