Merge branch 'master' of git://git.denx.de/u-boot-sh
[platform/kernel/u-boot.git] / tools / patman / tools.py
1 # SPDX-License-Identifier: GPL-2.0+
2 #
3 # Copyright (c) 2016 Google, Inc
4 #
5
6 import command
7 import glob
8 import os
9 import shutil
10 import tempfile
11
12 import tout
13
14 # Output directly (generally this is temporary)
15 outdir = None
16
17 # True to keep the output directory around after exiting
18 preserve_outdir = False
19
20 # Path to the Chrome OS chroot, if we know it
21 chroot_path = None
22
23 # Search paths to use for Filename(), used to find files
24 search_paths = []
25
26 # Tools and the packages that contain them, on debian
27 packages = {
28     'lz4': 'liblz4-tool',
29     }
30
31 def 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
64 def _RemoveOutputDir():
65     global outdir
66
67     shutil.rmtree(outdir)
68     tout.Debug("Deleted temporary directory '%s'" % outdir)
69     outdir = None
70
71 def 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
78 def 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
89 def _FinaliseForTest():
90     """Remove the output directory (for use by tests)"""
91     global outdir
92
93     if outdir:
94         _RemoveOutputDir()
95
96 def 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
108 def 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
124     raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
125                      (fname, ','.join(indir), os.getcwd()))
126
127 def 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
144 def Align(pos, align):
145     if align:
146         mask = align - 1
147         pos = (pos + mask) & ~mask
148     return pos
149
150 def NotPowerOfTwo(num):
151     return num and (num & (num - 1))
152
153 def 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
167 def Run(name, *args):
168     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
178
179 def 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
213 def 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
228 def 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)