Merge tag 'dm-9oct18' of git://git.denx.de/u-boot-dm
[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 # List of paths to use when looking for an input file
32 indir = []
33
34 def PrepareOutputDir(dirname, preserve=False):
35     """Select an output directory, ensuring it exists.
36
37     This either creates a temporary directory or checks that the one supplied
38     by the user is valid. For a temporary directory, it makes a note to
39     remove it later if required.
40
41     Args:
42         dirname: a string, name of the output directory to use to store
43                 intermediate and output files. If is None - create a temporary
44                 directory.
45         preserve: a Boolean. If outdir above is None and preserve is False, the
46                 created temporary directory will be destroyed on exit.
47
48     Raises:
49         OSError: If it cannot create the output directory.
50     """
51     global outdir, preserve_outdir
52
53     preserve_outdir = dirname or preserve
54     if dirname:
55         outdir = dirname
56         if not os.path.isdir(outdir):
57             try:
58                 os.makedirs(outdir)
59             except OSError as err:
60                 raise CmdError("Cannot make output directory '%s': '%s'" %
61                                 (outdir, err.strerror))
62         tout.Debug("Using output directory '%s'" % outdir)
63     else:
64         outdir = tempfile.mkdtemp(prefix='binman.')
65         tout.Debug("Using temporary directory '%s'" % outdir)
66
67 def _RemoveOutputDir():
68     global outdir
69
70     shutil.rmtree(outdir)
71     tout.Debug("Deleted temporary directory '%s'" % outdir)
72     outdir = None
73
74 def FinaliseOutputDir():
75     global outdir, preserve_outdir
76
77     """Tidy up: delete output directory if temporary and not preserved."""
78     if outdir and not preserve_outdir:
79         _RemoveOutputDir()
80
81 def GetOutputFilename(fname):
82     """Return a filename within the output directory.
83
84     Args:
85         fname: Filename to use for new file
86
87     Returns:
88         The full path of the filename, within the output directory
89     """
90     return os.path.join(outdir, fname)
91
92 def _FinaliseForTest():
93     """Remove the output directory (for use by tests)"""
94     global outdir
95
96     if outdir:
97         _RemoveOutputDir()
98
99 def SetInputDirs(dirname):
100     """Add a list of input directories, where input files are kept.
101
102     Args:
103         dirname: a list of paths to input directories to use for obtaining
104                 files needed by binman to place in the image.
105     """
106     global indir
107
108     indir = dirname
109     tout.Debug("Using input directories %s" % indir)
110
111 def GetInputFilename(fname):
112     """Return a filename for use as input.
113
114     Args:
115         fname: Filename to use for new file
116
117     Returns:
118         The full path of the filename, within the input directory
119     """
120     if not indir:
121         return fname
122     for dirname in indir:
123         pathname = os.path.join(dirname, fname)
124         if os.path.exists(pathname):
125             return pathname
126
127     raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
128                      (fname, ','.join(indir), os.getcwd()))
129
130 def GetInputFilenameGlob(pattern):
131     """Return a list of filenames for use as input.
132
133     Args:
134         pattern: Filename pattern to search for
135
136     Returns:
137         A list of matching files in all input directories
138     """
139     if not indir:
140         return glob.glob(fname)
141     files = []
142     for dirname in indir:
143         pathname = os.path.join(dirname, pattern)
144         files += glob.glob(pathname)
145     return sorted(files)
146
147 def Align(pos, align):
148     if align:
149         mask = align - 1
150         pos = (pos + mask) & ~mask
151     return pos
152
153 def NotPowerOfTwo(num):
154     return num and (num & (num - 1))
155
156 def PathHasFile(fname):
157     """Check if a given filename is in the PATH
158
159     Args:
160         fname: Filename to check
161
162     Returns:
163         True if found, False if not
164     """
165     for dir in os.environ['PATH'].split(':'):
166         if os.path.exists(os.path.join(dir, fname)):
167             return True
168     return False
169
170 def Run(name, *args):
171     try:
172         return command.Run(name, *args, cwd=outdir, capture=True)
173     except:
174         if not PathHasFile(name):
175             msg = "Plesae install tool '%s'" % name
176             package = packages.get(name)
177             if package:
178                  msg += " (e.g. from package '%s')" % package
179             raise ValueError(msg)
180         raise
181
182 def Filename(fname):
183     """Resolve a file path to an absolute path.
184
185     If fname starts with ##/ and chroot is available, ##/ gets replaced with
186     the chroot path. If chroot is not available, this file name can not be
187     resolved, `None' is returned.
188
189     If fname is not prepended with the above prefix, and is not an existing
190     file, the actual file name is retrieved from the passed in string and the
191     search_paths directories (if any) are searched to for the file. If found -
192     the path to the found file is returned, `None' is returned otherwise.
193
194     Args:
195       fname: a string,  the path to resolve.
196
197     Returns:
198       Absolute path to the file or None if not found.
199     """
200     if fname.startswith('##/'):
201       if chroot_path:
202         fname = os.path.join(chroot_path, fname[3:])
203       else:
204         return None
205
206     # Search for a pathname that exists, and return it if found
207     if fname and not os.path.exists(fname):
208         for path in search_paths:
209             pathname = os.path.join(path, os.path.basename(fname))
210             if os.path.exists(pathname):
211                 return pathname
212
213     # If not found, just return the standard, unchanged path
214     return fname
215
216 def ReadFile(fname):
217     """Read and return the contents of a file.
218
219     Args:
220       fname: path to filename to read, where ## signifiies the chroot.
221
222     Returns:
223       data read from file, as a string.
224     """
225     with open(Filename(fname), 'rb') as fd:
226         data = fd.read()
227     #self._out.Info("Read file '%s' size %d (%#0x)" %
228                    #(fname, len(data), len(data)))
229     return data
230
231 def WriteFile(fname, data):
232     """Write data into a file.
233
234     Args:
235         fname: path to filename to write
236         data: data to write to file, as a string
237     """
238     #self._out.Info("Write file '%s' size %d (%#0x)" %
239                    #(fname, len(data), len(data)))
240     with open(Filename(fname), 'wb') as fd:
241         fd.write(data)