blob: e9f17ae8690835d45311a7850e970a4f554f1423 [file] [log] [blame]
#!/usr/bin/env python3.8
# Copyright 2020 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import io
import json
import os
import re
import shutil
import sys
import tarfile
class GatherPackageDeps:
"""Helper class to take a `package_manifest.json` and copy all files referenced
into an archive that will then be available at runtime.
Args:
package_json (string): Path to the package's `package_manifest.json` file.
meta_far (string): Path to the package's `meta.far` file.
depfile (string): Path to the depfile to write to.
Raises: ValueError if any parameter is empty.
"""
def __init__(self, package_json, meta_far, output_tar, depfile):
if package_json and os.path.exists(package_json):
self.package_json = package_json
else:
raise ValueError('package_json must be to a valid file')
if meta_far and os.path.exists(meta_far):
self.meta_far = meta_far
else:
raise ValueError('meta_far must be to a valid file')
if output_tar:
self.output_tar = output_tar
else:
raise ValueError('output_tar cannot be empty')
if depfile:
self.depfile = depfile
else:
raise ValueError('depfile cannot be empty')
def parse_package_json(self):
manifest_paths = []
with open(self.package_json) as f:
data = json.load(f)
for file in data['blobs']:
if file['path'].startswith('meta/'):
continue
manifest_paths.append((file['path'], file['source_path']))
return manifest_paths
def create_archive(self, manifest_paths):
# Explicitly use the GNU_FORMAT because the current dart library
# (v.3.0.0) does not support parsing other tar formats that allow for
# filenames longer than 100 characters.
with tarfile.open(self.output_tar, 'w',
format=tarfile.GNU_FORMAT) as tar:
# Follow symlinks
tar.dereference = True
# Create package.manifest in memory and add it to archive.
manifest_lines = []
# Add all source files to archive and add manfiest lines.
for (archive_path, source_path) in manifest_paths:
tar.add(source_path, arcname=archive_path)
manifest_lines.append(f'{archive_path}={archive_path}')
# Add meta.far to archive and insert corresponding manfiest line.
tar.add(self.meta_far, arcname='meta.far')
manifest_lines.append('meta/package=meta.far\n')
with io.BytesIO('\n'.join(manifest_lines).encode()) as manifest:
tarinfo = tarfile.TarInfo('package.manifest')
tarinfo.size = len(manifest.getvalue())
tar.addfile(tarinfo, fileobj=manifest)
def run(self):
manifest_paths = self.parse_package_json()
self.create_archive(manifest_paths)
with open(self.depfile, 'w') as f:
f.write(
"{}: {}\n".format(
self.output_tar, ' '.join(
os.path.relpath(source_path)
for (_, source_path) in manifest_paths)))
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--package_json',
required=True,
help=
'The path to the package_manifest.json generated by a `fuchsia_package`.'
)
parser.add_argument(
'--meta_far', required=True, help="The path to the package's meta.far.")
parser.add_argument(
'--output_tar', required=True, help='The path to the output archive.')
parser.add_argument(
'--depfile',
required=True,
help='The path to write a depfile, see depfile from GN.',
)
args = parser.parse_args()
gatherer = GatherPackageDeps(
args.package_json, args.meta_far, args.output_tar, args.depfile).run()
return 0
if __name__ == '__main__':
sys.exit(main())