make_container.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import os
  2. import shutil
  3. import stat
  4. import struct
  5. import subprocess
  6. import sys
  7. # Explicitly enable local imports
  8. # Don't forget to add imported scripts to inputs of the calling command!
  9. sys.path.append(os.path.dirname(os.path.abspath(__file__)))
  10. import container # 1
  11. def main(output_path, entry_path, input_paths, squashfs_path):
  12. output_tmp_path = output_path + '.tmp'
  13. shutil.copy2(entry_path, output_tmp_path)
  14. st = os.stat(output_tmp_path)
  15. os.chmod(output_tmp_path, st.st_mode | stat.S_IWUSR)
  16. layer_paths = []
  17. other_paths = []
  18. for input_path in input_paths:
  19. (layer_paths if input_path.endswith('.container_layer') else other_paths).append(input_path)
  20. if len(other_paths) == 0:
  21. raise Exception('No program in container dependencies')
  22. if len(other_paths) > 1:
  23. raise Exception('Multiple non-layer inputs')
  24. program_path = other_paths[0]
  25. program_container_path = os.path.basename(program_path)
  26. os.symlink(program_container_path, 'entry')
  27. add_cmd = [os.path.join(squashfs_path, 'mksquashfs')]
  28. add_cmd.extend([program_path, 'entry', 'program_layer'])
  29. subprocess.run(add_cmd)
  30. layer_paths.append('program_layer')
  31. container.join_layers(layer_paths, 'container_data', squashfs_path)
  32. size = 0
  33. block_size = 1024 * 1024
  34. with open(output_tmp_path, 'ab') as output:
  35. with open('container_data', 'rb') as input_:
  36. while True:
  37. data = input_.read(block_size)
  38. output.write(data)
  39. size += len(data)
  40. if len(data) < block_size:
  41. break
  42. with open(os.path.join(squashfs_path, 'unsquashfs'), 'rb') as input_:
  43. while True:
  44. data = input_.read(block_size)
  45. output.write(data)
  46. size += len(data)
  47. if len(data) == 0:
  48. break
  49. output.write(struct.pack('<Q', size))
  50. os.rename(output_tmp_path, output_path)
  51. def entry():
  52. import argparse
  53. parser = argparse.ArgumentParser()
  54. parser.add_argument('-o', '--output', required=True)
  55. parser.add_argument('-s', '--squashfs-path', required=True)
  56. parser.add_argument('input', nargs='*')
  57. args = parser.parse_args()
  58. def is_container_entry(path):
  59. return os.path.basename(path) == '_container_entry'
  60. input_paths = []
  61. entry_paths = []
  62. for input_path in args.input:
  63. (entry_paths if is_container_entry(input_path) else input_paths).append(input_path)
  64. if len(entry_paths) != 1:
  65. raise Exception('Could not select container entry from {}'.format(entry_paths))
  66. return main(args.output, entry_paths[0], input_paths, args.squashfs_path)
  67. if __name__ == '__main__':
  68. sys.exit(entry())