# 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.

import("config/config.gni")

# Internal template for the cmc tool.
#
# Invokes cmc
#
# Example:
#
# ```
# _cmc_tool("validate_cmx") {
#   inputs = [ manifest ]
#   outputs = [ stamp_file ]
#
#   args = [
#      "--stamp",
#      rebase_path(stamp_file, root_build_dir),
#      "validate",
#      rebase_path(invoker.manifest),
#   ]
# }
# ```
#
# Parameters:
#
#  inputs (required)
#    List of files that are input for cmc.
#    Type: list(path)
#
#  outputs (required)
#    List paths that are output for the run of cmc.
#    Type: list(path)
#
#  args (required)
#    List command line args  for  cmc.
#    Type: list(path)
#
#  deps
#  public_deps
#  testonly
#  visibility
#
template("_cmc_tool") {
  action(target_name) {
    forward_variables_from(invoker,
                           [
                             "deps",
                             "public_deps",
                             "testonly",
                             "visibility",
                           ])
    script = "//build/gn_run_binary.py"
    _cmc_tool_path = "${fuchsia_tool_dir}/cmc"

    assert(defined(invoker.inputs), "inputs is a required parameter.")
    assert(defined(invoker.outputs), "outputs is a required parameter.")
    assert(defined(invoker.args), "args is a required parameter.")

    inputs =
        [
          _cmc_tool_path,

          # Depend on the SDK hash, to ensure rebuild if the SDK tools change.
          fuchsia_sdk_manifest_file,
        ] + invoker.inputs

    outputs = invoker.outputs

    args = [ rebase_path(_cmc_tool_path, root_build_dir) ] + invoker.args
  }
}

# Compiles a Components Framework v2 manifest (.cml) file to .cm
#
# Example:
#
# ```
# cmc_compile(_compiled_manifest_target) {
#      forward_variables_from(invoker, [ "deps" ])
#      manifest = rebase_path(manifest)
# }
# ```
#
# Parameters:
#
#   manifest (required)
#     The input Component Framework v2 manifest source (.cml) file.
#     The file must have the extension ".cml".
#
#   output_name (optional)
#     Name of the output file to generate. Defaults to $target_name.
#     This should not include a file extension (.cm)
#
#   deps
#   public_deps
#   testonly
#   visibility
#
template("cmc_compile") {
  output_name = target_name
  if (defined(invoker.output_name)) {
    output_name = invoker.output_name
  }

  _cmc_tool(target_name) {
    forward_variables_from(invoker,
                           [
                             "deps",
                             "manifest",
                             "public_deps",
                             "testonly",
                             "visibility",
                           ])
    assert(defined(manifest), "manifest file required")

    inputs = [ manifest ]

    output_file = "$target_out_dir/$output_name.cm"
    outputs = [ output_file ]

    depfile = "$target_out_dir/$target_name.d"

    args = [
      "compile",
      rebase_path(manifest, root_build_dir),
      "--output",
      rebase_path(output_file, root_build_dir),
      "--includeroot",
      rebase_path("//", root_build_dir),
      "--includepath",
      rebase_path("$fuchsia_sdk/pkg/", root_build_dir),
      "--depfile",
      rebase_path(depfile, root_build_dir),
    ]
  }
}

# Validates a component manifest file
#
# The cmc_validate template will ensure that a given cmx file is conformant to
# the cmx schema, as defined by //tools/cmc/schema.json. A stamp file is
# generated to mark that a given cmx file has passed.
#
# Parameters:
#
#   manifest (required)
#     [file] The path to the cmx file that is to be validated
#
#   deps
#   testonly
#   visibility
#
template("cmc_validate") {
  _cmc_tool(target_name) {
    forward_variables_from(invoker,
                           [
                             "manifest",
                             "deps",
                             "testonly",
                             "visibility",
                           ])
    stamp_file = "$target_gen_dir/$target_name.verified"

    assert(defined(manifest), "manifest file required")

    inputs = [ manifest ]

    outputs = [ stamp_file ]

    args = [
      "--stamp",
      rebase_path(stamp_file, root_build_dir),
      "validate",
      rebase_path(invoker.manifest),
    ]
  }
}

# Merges multiple component manifest files into one.
#
# Combines mutliple component manifests into a single manifest.
# This is useful for merging fragments of sandbox configurations into
# a single component manifest.
#
# Example
#
# ```
#   cmc_merge("combined_cmx") {
#     sources = ["sandbox.cmx", "services.cmx", "program.cmx"]
#     output_name = "my-component.cmx"
#   }
# ```
#
# Parameters
#
#   sources
#     The list of cmx files to merge together.
#
#     Type: list of strings (filepath)
#
#   output_name [optional]
#     The name of the merged cmx file. This file is created in $target_out_dir.
#     If not specified, $target_name.cmx is used.
#
#     Type: string
#
#   Standard parameters:
#     deps
#     testonly
#     visibility
#
template("cmc_merge") {
  _cmc_tool(target_name) {
    forward_variables_from(invoker,
                           [
                             "deps",
                             "output_name",
                             "sources",
                             "testonly",
                             "visibility",
                           ])
    if (!defined(output_name)) {
      # TODO(richkadel): THE GN SDK VERSION OF CMC.GNI IS INCONSISTENT WITH fuchsia.git!
      # The default name should be `target_name`, which should already include the
      # extension... Or change fuchsia.git to add the extension, and fix calls that
      # append .cmx to the target name, like flutter_dart_component.gni.
      # With the target_name representing the base of the CMC filename results
      # in a "Duplicate definition" error in GN, because "flutter_component()"
      # typically has the same target name. My current workaround is to
      # redundantly assign `output_name` to the same value as the `target_name`,
      # which includes the `.cmx` extension.
      output_name = "${target_name}.cmx"
    }

    merged_output = "${target_out_dir}/${output_name}"
    inputs = invoker.sources
    outputs = [ merged_output ]

    args = [
      "merge",
      "--output",
      rebase_path(merged_output, root_build_dir),
    ]

    foreach(source, sources) {
      args += [ rebase_path(source, root_build_dir) ]
    }
  }
}
