tools.py 5.4 KB

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