#!/usr/bin/env python3
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

#
# Derivative work of https://chromium.googlesource.com/chromium/src/+/HEAD/build/config/fuchsia/prepare_package_inputs.py
#

"""Creates a archive manifest used for Fuchsia package generation."""

import argparse
import json
import os
import shutil
import subprocess
import sys

# File extension of a component manifest for each Component Framework version
MANIFEST_VERSION_EXTENSIONS = {"v1": ".cmx", "v2": ".cm"}


def make_package_path(file_path, roots):
  """Computes a path for |file_path| relative to one of the |roots|.

  Args:
    file_path: The file path to relativize.
    roots: A list of directory paths which may serve as a relative root for
      |file_path|.

    For example:
        * make_package_path('/foo/bar.txt', ['/foo/']) 'bar.txt'
        * make_package_path('/foo/dir/bar.txt', ['/foo/']) 'dir/bar.txt'
        * make_package_path('/foo/out/Debug/bar.exe', ['/foo/', '/foo/out/Debug/']) 'bar.exe'
  """

  # Prevents greedily matching against a shallow path when a deeper, better
  # matching path exists.
  roots.sort(key=len, reverse=True)

  for next_root in roots:
    if not next_root.endswith(os.sep):
      next_root += os.sep

    if file_path.startswith(next_root):
      relative_path = file_path[len(next_root):]
      return relative_path

  return file_path


def _get_stripped_path(bin_path):
  """Finds the stripped version of |bin_path| in the build output directory.

        returns |bin_path| if no stripped path is found.
  """
  stripped_path = bin_path.replace('lib.unstripped/', 'lib/').replace('exe.unstripped/', '')
  if os.path.exists(stripped_path):
    return stripped_path
  else:
    return bin_path


def _is_binary(path):
  """Checks if the file at |path| is an ELF executable.

        This is done by inspecting its FourCC header.
  """

  with open(path, 'rb') as f:
    file_tag = f.read(4)
  return file_tag == b'\x7fELF'


def _write_build_ids_txt(binary_paths, ids_txt_path):
  """Writes an index text file mapping build IDs to unstripped binaries."""

  READELF_FILE_PREFIX = 'File: '
  READELF_BUILD_ID_PREFIX = 'Build ID: '

  # List of binaries whose build IDs are awaiting processing by readelf.
  # Entries are removed as readelf's output is parsed.
  unprocessed_binary_paths = set(binary_paths)
  build_ids_map = {}

  # Sanity check that unstripped binaries do not also have their stripped
  # counterpart listed.
  for binary_path in binary_paths:
    stripped_binary_path = _get_stripped_path(binary_path)
    if stripped_binary_path != binary_path:
      unprocessed_binary_paths.discard(stripped_binary_path)

  with open(ids_txt_path, 'w') as ids_file:
    # TODO(richkadel): This script (originally from the Fuchsia GN SDK) was
    # changed, adding this `if unprocessed_binary_paths` check, because for
    # the Dart packages I tested (child-view and parent-view), this was
    # empty. Update the Fuchsia GN SDK? (Or figure out if the Dart packages
    # _should_ have at least one unprocessed_binary_path?)
    if unprocessed_binary_paths:
      # Create a set to dedupe stripped binary paths in case both the stripped and
      # unstripped versions of a binary are specified.
      readelf_stdout = subprocess.check_output(['readelf', '-n'] +
                                               sorted(unprocessed_binary_paths)).decode('utf8')

      if len(binary_paths) == 1:
        # Readelf won't report a binary's path if only one was provided to the
        # tool.
        binary_path = binary_paths[0]
      else:
        binary_path = None

      for line in readelf_stdout.split('\n'):
        line = line.strip()

        if line.startswith(READELF_FILE_PREFIX):
          binary_path = line[len(READELF_FILE_PREFIX):]
          assert binary_path in unprocessed_binary_paths

        elif line.startswith(READELF_BUILD_ID_PREFIX):
          # Paths to the unstripped executables listed in "ids.txt" are specified
          # as relative paths to that file.
          unstripped_rel_path = os.path.relpath(
              os.path.abspath(binary_path), os.path.dirname(os.path.abspath(ids_txt_path))
          )

          build_id = line[len(READELF_BUILD_ID_PREFIX):]
          build_ids_map[build_id] = unstripped_rel_path
          unprocessed_binary_paths.remove(binary_path)

      for id_and_path in sorted(build_ids_map.items()):
        ids_file.write(id_and_path[0] + ' ' + id_and_path[1] + '\n')

  # Did readelf forget anything? Make sure that all binaries are accounted for.
  assert not unprocessed_binary_paths


def _parse_component(component_info_file):
  component_info = json.load(open(component_info_file, 'r'))
  return component_info


def _get_component_manifests(component_info):
  return [c for c in component_info if c.get('type') == 'manifest']


# TODO(richkadel): Changed, from the Fuchsia GN SDK version to add this function
# and related code, to include support for a file of resources that aren't known
# until compile time.
def _get_resource_items_from_json_items(component_info):
  nested_resources = []
  files = [c.get('source') for c in component_info if c.get('type') == 'json_of_resources']
  for json_file in files:
    for resource in _parse_component(json_file):
      nested_resources.append(resource)
  return nested_resources


def _get_resource_items(component_info):
  return ([c for c in component_info if c.get('type') == 'resource'] +
          _get_resource_items_from_json_items(component_info))


def _get_expanded_files(runtime_deps_file):
  """ Process the runtime deps file for file paths, recursively walking
    directories as needed.

    Returns a set of expanded files referenced by the runtime deps file.
    """

  # runtime_deps may contain duplicate paths, so use a set for
  # de-duplication.
  expanded_files = set()
  for next_path in open(runtime_deps_file, 'r'):
    next_path = next_path.strip()
    if os.path.isdir(next_path):
      for root, _, files in os.walk(next_path):
        for current_file in files:
          if current_file.startswith('.'):
            continue
          expanded_files.add(os.path.normpath(os.path.join(root, current_file)))
    else:
      expanded_files.add(os.path.normpath(next_path))
  return expanded_files


def _write_gn_deps_file(
    depfile_path, package_manifest, component_manifests, out_dir, expanded_files
):
  with open(depfile_path, 'w') as depfile:
    deps_list = [os.path.relpath(f, out_dir) for f in expanded_files]
    deps_list.extend(component_manifests)

    # The deps file is space-delimited, so filenames containing spaces
    # must have them escaped.
    deps_list = [f.replace(' ', '\\ ') for f in deps_list]

    deps_string = ' '.join(sorted(deps_list))
    depfile.write('%s: %s' % (package_manifest, deps_string))


def _write_meta_package_manifest(
    manifest_entries, manifest_path, app_name, out_dir, package_version
):
  # Write meta/package manifest file and add to archive manifest.
  meta_package = os.path.join(os.path.dirname(manifest_path), 'package')
  with open(meta_package, 'w') as package_json:
    json_payload = {'version': package_version, 'name': app_name}
    json.dump(json_payload, package_json)
    package_json_filepath = os.path.relpath(package_json.name, out_dir)
    manifest_entries['meta/package'] = package_json_filepath


def _write_component_manifest(manifest_entries, component_info, archive_manifest_path, out_dir):
  """Copy component manifest files and add to archive manifest.

    Raises an exception if a component uses a unknown manifest version.
    """

  for component_manifest in _get_component_manifests(component_info):
    manifest_version = component_manifest.get('manifest_version')

    if manifest_version not in MANIFEST_VERSION_EXTENSIONS:
      raise Exception('Unknown manifest_version: {}'.format(manifest_version))

    # TODO(richkadel): Changed, from the Fuchsia GN SDK version, to assume
    # the given `output_name` already includes its extension. This change
    # has not been fully validate, in particular, it has not been tested
    # with CF v2 `.cm` (from `.cml`) files. Original implementation was:
    #
    # extension = MANIFEST_VERSION_EXTENSIONS.get(manifest_version)
    # manifest_dest_file_path = os.path.join(
    #     os.path.dirname(archive_manifest_path),
    #     component_manifest.get('output_name') + extension)
    manifest_dest_file_path = os.path.join(
        os.path.dirname(archive_manifest_path), component_manifest.get('output_name')
    )
    # Add the 'meta/' subdir, for example, if `output_name` includes it
    os.makedirs(os.path.dirname(manifest_dest_file_path), exist_ok=True)
    shutil.copy(component_manifest.get('source'), manifest_dest_file_path)

    manifest_entries['meta/%s' % os.path.basename(manifest_dest_file_path)
                    ] = os.path.relpath(manifest_dest_file_path, out_dir)
  return manifest_dest_file_path


def _write_package_manifest(
    manifest_entries, expanded_files, out_dir, exclude_file, root_dir, component_info
):
  """Writes the package manifest for a Fuchsia package

    Returns a list of binaries in the package.

    Raises an exception if excluded files are not found."""
  gen_dir = os.path.normpath(os.path.join(out_dir, 'gen'))
  excluded_files_set = set(exclude_file)
  roots = [gen_dir, root_dir, out_dir]

  # Filter out component manifests. These are written out elsewhere.
  excluded_files_set.update([
      make_package_path(os.path.relpath(cf.get('source'), out_dir), roots)
      for cf in _get_component_manifests(component_info)
      if os.path.relpath(cf.get('source'), out_dir) in expanded_files
  ])

  # Filter out json_of_resources since only their contents are written, and we
  # don't know the contained resources until late in the build cycle
  excluded_files_set.update([
      make_package_path(os.path.relpath(cf.get('source'), out_dir), roots)
      for cf in component_info
      if cf.get('type') == 'json_of_resources' and
      os.path.relpath(cf.get('source'), out_dir) in expanded_files
  ])

  # Write out resource files with specific package paths, and exclude them from
  # the list of expanded files so they are not listed twice in the manifest.
  for resource in _get_resource_items(component_info):
    relative_src_file = os.path.relpath(resource.get('source'), out_dir)
    resource_path = make_package_path(relative_src_file, roots)
    manifest_entries[resource.get('dest')] = relative_src_file
    if resource.get('type') == 'resource':
      excluded_files_set.add(resource_path)

  for current_file in expanded_files:
    current_file = _get_stripped_path(current_file)
    # make_package_path() may relativize to either the source root or
    # output directory.
    in_package_path = make_package_path(current_file, roots)

    if in_package_path in excluded_files_set:
      excluded_files_set.remove(in_package_path)
    else:
      manifest_entries[in_package_path] = current_file

  if excluded_files_set:
    raise Exception(
        'Some files were excluded with --exclude-file but '
        'not found in the deps list, or a resource (data) file '
        'was added and not filtered out. Excluded files and resources: '
        '%s' % ', '.join(excluded_files_set)
    )


def _build_manifest(args):
  # Use a sorted list to make sure the manifest order is deterministic.
  expanded_files = sorted(_get_expanded_files(args.runtime_deps_file))
  component_info = _parse_component(args.json_file)
  component_manifests = []

  # Collect the manifest entries in a map since duplication happens
  # because of runtime libraries.
  manifest_entries = {}
  _write_meta_package_manifest(
      manifest_entries, args.manifest_path, args.app_name, args.out_dir, args.package_version
  )
  for component_item in component_info:
    _write_package_manifest(
        manifest_entries, expanded_files, args.out_dir, args.exclude_file, args.root_dir,
        component_item
    )
    component_manifests.append(
        _write_component_manifest(
            manifest_entries, component_item, args.manifest_path, args.out_dir
        )
    )

  with open(args.manifest_path, 'w') as manifest:
    for key in sorted(manifest_entries.keys()):
      manifest.write('%s=%s\n' % (key, manifest_entries[key]))

  binaries = [f for f in expanded_files if _is_binary(f)]
  _write_build_ids_txt(sorted(binaries), args.build_ids_file)

  # Omit any excluded_files from the expanded_files written to the depfile.
  gen_dir = os.path.normpath(os.path.join(args.out_dir, 'gen'))
  roots = [gen_dir, args.root_dir, args.out_dir]
  excluded_files_set = set(args.exclude_file)
  expanded_deps_files = [
      path for path in expanded_files if make_package_path(path, roots) not in excluded_files_set
  ]

  _write_gn_deps_file(
      args.depfile_path, args.manifest_path, component_manifests, args.out_dir, expanded_deps_files
  )
  return 0


def main():
  parser = argparse.ArgumentParser()
  parser.add_argument('--root-dir', required=True, help='Build root directory')
  parser.add_argument('--out-dir', required=True, help='Build output directory')
  parser.add_argument('--app-name', required=True, help='Package name')
  parser.add_argument(
      '--runtime-deps-file', required=True, help='File with the list of runtime dependencies.'
  )
  parser.add_argument('--depfile-path', required=True, help='Path to write GN deps file.')
  parser.add_argument(
      '--exclude-file',
      action='append',
      default=[],
      help='Package-relative file path to exclude from the package.'
  )
  parser.add_argument('--manifest-path', required=True, help='Manifest output path.')
  parser.add_argument('--build-ids-file', required=True, help='Debug symbol index path.')
  parser.add_argument('--json-file', required=True)
  parser.add_argument('--package-version', default='0', help='Version of the package')

  args = parser.parse_args()

  return _build_manifest(args)


if __name__ == '__main__':
  sys.exit(main())
