blob: 6d07705ac5c198bf874f288318d39f478483e559 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2017 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 json
import os
import sys
from sdk_common import Atom, AtomId, detect_category_violations, detect_collisions, gather_dependencies
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--id',
help='The atom\'s identifier',
required=True)
parser.add_argument('--domain',
help='Name of the domain the element belongs to',
required=True)
name_group = parser.add_mutually_exclusive_group(required=True)
name_group.add_argument('--name',
help='Name of the element')
name_group.add_argument('--name-file',
help='Path to the file containing the name of the element')
parser.add_argument('--out',
help='Path to the output file',
required=True)
parser.add_argument('--base',
help='Path to the element\'s source directory',
required=True)
parser.add_argument('--deps',
help='List of manifest paths for dependencies',
nargs='*')
parser.add_argument('--package-deps',
help='List of manifest paths for runtime dependencies',
nargs='*')
parser.add_argument('--files',
help='A source=destination mapping',
nargs='+')
# TODO(DX-340): merge new-files and files. The former is needed to
# transition to destination paths relative to the SDK root as opposed to
# the atom root.
parser.add_argument('--new-files',
help='Same as files, but new',
nargs="*",
default=[])
parser.add_argument('--tags',
help='List of tags for the included elements',
nargs='*')
parser.add_argument('--tags-file',
help='A file containing tags',
required=False)
parser.add_argument('--gn-label',
help='GN label of the atom',
required=True)
parser.add_argument('--category',
help='Publication level',
required=True)
parser.add_argument('--meta',
help="Path to the atom's metadata file in the SDK",
default='',
required=False)
args = parser.parse_args()
if args.name:
name = args.name
else:
with open(args.name_file, 'r') as name_file:
name = name_file.read()
# Gather the definitions of other atoms this atom depends on.
(deps, atoms) = gather_dependencies(args.deps)
(_, package_atoms) = gather_dependencies(args.package_deps)
all_atoms = atoms
all_atoms.update(package_atoms)
# Build the list of files making up this atom.
files = []
has_packaged_files = False
base = os.path.realpath(args.base)
for mapping in args.files:
mode, pair = mapping.split(':', 1)
is_packaged = (mode == 'packaged')
destination, source = pair.split('=', 1)
real_source = os.path.realpath(source)
if not os.path.exists(real_source):
raise Exception('Missing source file: %s' % real_source)
if destination:
if destination.find('..') != -1:
raise Exception('Destination for %s cannot contain "..": %s.' %
(source, destination))
else:
if not real_source.startswith(base):
raise Exception('Destination for %s must be given as it is not'
' under source directory %s' % (source, base))
destination = os.path.relpath(real_source, base)
if os.path.isabs(destination):
raise Exception('Destination cannot be absolute: %s' % destination)
files.append({
'source': real_source,
'destination': destination,
'packaged': is_packaged
})
has_packaged_files = has_packaged_files or is_packaged
new_files = []
for mapping in args.new_files:
destination, source = mapping.split('=', 1)
new_files.append({
'source': source,
'destination': destination,
# TODO(DX-340): remove this attribute as the presence of atom
# metadata in SDKs makes it obsolete.
'packaged': False,
})
id = {
'domain': args.domain,
'name': name,
}
all_package_deps = set()
if has_packaged_files:
all_package_deps.add(AtomId(id))
for atom in all_atoms:
all_package_deps.update(atom.package_deps)
tags = dict(map(lambda t: t.split(':', 1), args.tags))
if args.tags_file:
with open(args.tags_file, 'r') as tags_file:
data = json.load(tags_file)
assert isinstance(data, dict)
tags.update(data)
tags['domain'] = args.domain
all_atoms.update([Atom({
'id': id,
# TODO(DX-340): rename this to "id" once domain/name are gone.
'identifier': args.id,
'meta': args.meta,
'gn-label': args.gn_label,
'category': args.category,
'tags': tags,
'deps': map(lambda i: i.json, sorted(list(deps))),
'package-deps': map(lambda i: i.json, sorted(list(all_package_deps))),
'files': files,
'new-files':new_files,
})])
if detect_collisions(all_atoms):
print('Name collisions detected!')
return 1
if detect_category_violations(args.category, all_atoms):
print('Publication level violations detected!')
return 1
manifest = {
'ids': [id],
'atoms': map(lambda a: a.json, sorted(list(all_atoms))),
}
with open(os.path.abspath(args.out), 'w') as out:
json.dump(manifest, out, indent=2, sort_keys=True)
if __name__ == '__main__':
sys.exit(main())