tools.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. # SPDX-License-Identifier: GPL-2.0+
  2. #
  3. # Copyright (c) 2016 Google, Inc
  4. #
  5. import command
  6. import glob
  7. import os
  8. import shutil
  9. import tempfile
  10. import tout
  11. # Output directly (generally this is temporary)
  12. outdir = None
  13. # True to keep the output directory around after exiting
  14. preserve_outdir = False
  15. # Path to the Chrome OS chroot, if we know it
  16. chroot_path = None
  17. # Search paths to use for Filename(), used to find files
  18. search_paths = []
  19. # Tools and the packages that contain them, on debian
  20. packages = {
  21. 'lz4': 'liblz4-tool',
  22. }
  23. def PrepareOutputDir(dirname, preserve=False):
  24. """Select an output directory, ensuring it exists.
  25. This either creates a temporary directory or checks that the one supplied
  26. by the user is valid. For a temporary directory, it makes a note to
  27. remove it later if required.
  28. Args:
  29. dirname: a string, name of the output directory to use to store
  30. intermediate and output files. If is None - create a temporary
  31. directory.
  32. preserve: a Boolean. If outdir above is None and preserve is False, the
  33. created temporary directory will be destroyed on exit.
  34. Raises:
  35. OSError: If it cannot create the output directory.
  36. """
  37. global outdir, preserve_outdir
  38. preserve_outdir = dirname or preserve
  39. if dirname:
  40. outdir = dirname
  41. if not os.path.isdir(outdir):
  42. try:
  43. os.makedirs(outdir)
  44. except OSError as err:
  45. raise CmdError("Cannot make output directory '%s': '%s'" %
  46. (outdir, err.strerror))
  47. tout.Debug("Using output directory '%s'" % outdir)
  48. else:
  49. outdir = tempfile.mkdtemp(prefix='binman.')
  50. tout.Debug("Using temporary directory '%s'" % outdir)
  51. def _RemoveOutputDir():
  52. global outdir
  53. shutil.rmtree(outdir)
  54. tout.Debug("Deleted temporary directory '%s'" % outdir)
  55. outdir = None
  56. def FinaliseOutputDir():
  57. global outdir, preserve_outdir
  58. """Tidy up: delete output directory if temporary and not preserved."""
  59. if outdir and not preserve_outdir:
  60. _RemoveOutputDir()
  61. def GetOutputFilename(fname):
  62. """Return a filename within the output directory.
  63. Args:
  64. fname: Filename to use for new file
  65. Returns:
  66. The full path of the filename, within the output directory
  67. """
  68. return os.path.join(outdir, fname)
  69. def _FinaliseForTest():
  70. """Remove the output directory (for use by tests)"""
  71. global outdir
  72. if outdir:
  73. _RemoveOutputDir()
  74. def SetInputDirs(dirname):
  75. """Add a list of input directories, where input files are kept.
  76. Args:
  77. dirname: a list of paths to input directories to use for obtaining
  78. files needed by binman to place in the image.
  79. """
  80. global indir
  81. indir = dirname
  82. tout.Debug("Using input directories %s" % indir)
  83. def GetInputFilename(fname):
  84. """Return a filename for use as input.
  85. Args:
  86. fname: Filename to use for new file
  87. Returns:
  88. The full path of the filename, within the input directory
  89. """
  90. if not indir:
  91. return fname
  92. for dirname in indir:
  93. pathname = os.path.join(dirname, fname)
  94. if os.path.exists(pathname):
  95. return pathname
  96. raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
  97. (fname, ','.join(indir), os.getcwd()))
  98. def GetInputFilenameGlob(pattern):
  99. """Return a list of filenames for use as input.
  100. Args:
  101. pattern: Filename pattern to search for
  102. Returns:
  103. A list of matching files in all input directories
  104. """
  105. if not indir:
  106. return glob.glob(fname)
  107. files = []
  108. for dirname in indir:
  109. pathname = os.path.join(dirname, pattern)
  110. files += glob.glob(pathname)
  111. return sorted(files)
  112. def Align(pos, align):
  113. if align:
  114. mask = align - 1
  115. pos = (pos + mask) & ~mask
  116. return pos
  117. def NotPowerOfTwo(num):
  118. return num and (num & (num - 1))
  119. def PathHasFile(fname):
  120. """Check if a given filename is in the PATH
  121. Args:
  122. fname: Filename to check
  123. Returns:
  124. True if found, False if not
  125. """
  126. for dir in os.environ['PATH'].split(':'):
  127. if os.path.exists(os.path.join(dir, fname)):
  128. return True
  129. return False
  130. def Run(name, *args):
  131. try:
  132. return command.Run(name, *args, cwd=outdir, capture=True)
  133. except:
  134. if not PathHasFile(name):
  135. msg = "Plesae install tool '%s'" % name
  136. package = packages.get(name)
  137. if package:
  138. msg += " (e.g. from package '%s')" % package
  139. raise ValueError(msg)
  140. raise
  141. def Filename(fname):
  142. """Resolve a file path to an absolute path.
  143. If fname starts with ##/ and chroot is available, ##/ gets replaced with
  144. the chroot path. If chroot is not available, this file name can not be
  145. resolved, `None' is returned.
  146. If fname is not prepended with the above prefix, and is not an existing
  147. file, the actual file name is retrieved from the passed in string and the
  148. search_paths directories (if any) are searched to for the file. If found -
  149. the path to the found file is returned, `None' is returned otherwise.
  150. Args:
  151. fname: a string, the path to resolve.
  152. Returns:
  153. Absolute path to the file or None if not found.
  154. """
  155. if fname.startswith('##/'):
  156. if chroot_path:
  157. fname = os.path.join(chroot_path, fname[3:])
  158. else:
  159. return None
  160. # Search for a pathname that exists, and return it if found
  161. if fname and not os.path.exists(fname):
  162. for path in search_paths:
  163. pathname = os.path.join(path, os.path.basename(fname))
  164. if os.path.exists(pathname):
  165. return pathname
  166. # If not found, just return the standard, unchanged path
  167. return fname
  168. def ReadFile(fname):
  169. """Read and return the contents of a file.
  170. Args:
  171. fname: path to filename to read, where ## signifiies the chroot.
  172. Returns:
  173. data read from file, as a string.
  174. """
  175. with open(Filename(fname), 'rb') as fd:
  176. data = fd.read()
  177. #self._out.Info("Read file '%s' size %d (%#0x)" %
  178. #(fname, len(data), len(data)))
  179. return data
  180. def WriteFile(fname, data):
  181. """Write data into a file.
  182. Args:
  183. fname: path to filename to write
  184. data: data to write to file, as a string
  185. """
  186. #self._out.Info("Write file '%s' size %d (%#0x)" %
  187. #(fname, len(data), len(data)))
  188. with open(Filename(fname), 'wb') as fd:
  189. fd.write(data)