[license] Introduce action wrapper template

Use it in a subsequent change in a dependent repo.
Also give check-licenses a much-needed --out_dir.

Change-Id: I5ead2e04f36b4e72a9ded0e5ed42a84bec3dee6c
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/514064
Fuchsia-Auto-Submit: Shai Barack <shayba@google.com>
Reviewed-by: Sean Cuff <seancuff@google.com>
Commit-Queue: Shai Barack <shayba@google.com>
diff --git a/tools/check-licenses/cmd/main.go b/tools/check-licenses/cmd/main.go
index bd366ae..a9dd1ff 100644
--- a/tools/check-licenses/cmd/main.go
+++ b/tools/check-licenses/cmd/main.go
@@ -38,6 +38,7 @@
 
 	logLevel          = flag.Int("log_level", 0, "Log level")
 	baseDir           = flag.String("base_dir", "", "Root location to begin directory traversal.")
+	outDir            = flag.String("out_dir", "", "Directory to write outputs to.")
 	outputLicenseFile = flag.Bool("output_license_file", true, "If true, outputs a license file with all the licenses for the project.")
 	target            = flag.String("target", "", "Analyze the dependency tree of a specific GN build target.")
 )
@@ -168,6 +169,13 @@
 		config.BaseDir = *baseDir
 	}
 
+	if *outDir != "" {
+		if info, err := os.Stat(*outDir); os.IsNotExist(err) && info.IsDir() {
+			return fmt.Errorf("out directory path %q does not exist!", *baseDir)
+		}
+		config.OutDir = *outDir
+	}
+
 	if *target != "" {
 		log.Printf("WARNING: Flag \"target\" was set to \"%v\", but that flag is currently unsupported. check-licenses will parse the full directory tree.\n", *target)
 		//TODO: enable target-based dependency traversal
diff --git a/tools/check-licenses/config.go b/tools/check-licenses/config.go
index df748e6..0f01f28 100644
--- a/tools/check-licenses/config.go
+++ b/tools/check-licenses/config.go
@@ -49,6 +49,7 @@
 	LogLevel    string `json:"logLevel"`
 	MaxReadSize int    `json:"maxReadSize"`
 	BaseDir     string `json:"baseDir"`
+	OutDir      string `json:"outDir"`
 	Target      string `json:"target"`
 }
 
@@ -80,6 +81,9 @@
 	if c.BaseDir == "" {
 		c.BaseDir = "."
 	}
+	if c.OutDir == "" {
+		c.OutDir = "."
+	}
 
 	// Ensure we aren't skipping any directories in the CustomProjectLicenses map.
 	for _, k := range c.CustomProjectLicenses {
@@ -120,6 +124,9 @@
 	if c.BaseDir == "" {
 		c.BaseDir = other.BaseDir
 	}
+	if c.OutDir == "" {
+		c.OutDir = other.OutDir
+	}
 	if c.Target == "" {
 		c.Target = other.Target
 	}
@@ -150,6 +157,9 @@
 	if c.BaseDir == "" {
 		c.BaseDir = other.BaseDir
 	}
+	if c.OutDir == "" {
+		c.OutDir = other.OutDir
+	}
 	if c.Target == "" {
 		c.Target = other.Target
 	}
diff --git a/tools/check-licenses/license_data.gni b/tools/check-licenses/license_data.gni
new file mode 100644
index 0000000..9bfbedc
--- /dev/null
+++ b/tools/check-licenses/license_data.gni
@@ -0,0 +1,86 @@
+# Copyright 2021 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.
+
+# Invokes the check-licenses tool.
+#
+# Parameters
+#
+#   configs (optional)
+#     [list] Paths to config files.
+#     Default: "//tools/check-licenses/config/config.json"
+#
+#   skip_dirs (optional)
+#     [list] Directories to skip checking.
+#
+#   notice_txt (optional)
+#     [list] Paths to NOTICE.txt files to parse.
+#
+#   license_allow_list (optional)
+#     [list] Map of license pattern file (.lic) to list of directories
+#     where the license can be used.
+#
+#   testonly, visibility
+template("license_data") {
+  action(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "configs",
+                             "license_allow_list",
+                             "notice_txt",
+                             "outputs",
+                             "skip_dirs",
+                             "testonly",
+                             "visibility",
+                           ])
+
+    # check-licenses assumes that it runs from //,
+    # but actions run from root_build_dir.
+    # This shell script sets the CWD and then calls check-licenses.
+    script = "//tools/check-licenses/license_data.sh"
+
+    license_tool = "//tools/check-licenses($host_toolchain)"
+    deps = [ license_tool ]
+
+    if (!defined(configs)) {
+      configs = [ "//tools/check-licenses/config/config.json" ]
+    }
+    sources = configs
+
+    outputs = [
+      "$target_out_dir/NOTICE.html.gz",
+      "$target_out_dir/NOTICE.txt.gz",
+    ]
+
+    args = [
+      ### Args for license_data.sh
+      rebase_path("//", root_build_dir),
+      rebase_path(
+          get_label_info(license_tool, "root_out_dir") + "/check-licenses",
+          "//"),
+
+      ### Args for check-licenses
+      # TODO: Remove once all files are attributed in the file generated by
+      # check-licenses.
+      "--exit_on_unlicensed_files=false",
+      "--config_file",
+      string_join(",", rebase_path(configs, "//")),
+      "--out_dir",
+      rebase_path(target_out_dir, "//"),
+    ]
+
+    if (defined(skip_dirs)) {
+      args += [ "--skip_dirs" ] + string_join(",", rebase_path(skip_dirs, "//"))
+    }
+
+    if (defined(notice_txt)) {
+      args +=
+          [ "--notice_txt" ] + string_join(",", rebase_path(notice_txt, "//"))
+    }
+
+    if (defined(license_allow_list)) {
+      args += [ "--license_allow_list" ] + "{ " +
+              string_join(", ", rebase_path(notice_txt, "//")) + " }"
+    }
+  }
+}
diff --git a/tools/check-licenses/license_data.sh b/tools/check-licenses/license_data.sh
new file mode 100755
index 0000000..88d7ae2
--- /dev/null
+++ b/tools/check-licenses/license_data.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+# Copyright 2021 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.
+
+readonly dir="$1"
+shift 1
+readonly tool="$1"
+shift 1
+
+cd "${dir}"
+"${tool}" $*
diff --git a/tools/check-licenses/testdata/config/merge/want.json b/tools/check-licenses/testdata/config/merge/want.json
index 6ba5f5b..aa82f2c 100644
--- a/tools/check-licenses/testdata/config/merge/want.json
+++ b/tools/check-licenses/testdata/config/merge/want.json
@@ -16,6 +16,7 @@
   "licensePatternDir": "tools/check-licenses/golden/patterns",
   "licenseAllowList": {},
   "baseDir": ".",
+  "outDir": ".",
   "target": "all",
   "logLevel": "verbose"
 }
diff --git a/tools/check-licenses/traverse.go b/tools/check-licenses/traverse.go
index 3b36496f..a21d84c 100644
--- a/tools/check-licenses/traverse.go
+++ b/tools/check-licenses/traverse.go
@@ -11,6 +11,7 @@
 	"io/ioutil"
 	"log"
 	"os"
+	"path/filepath"
 	"runtime/trace"
 	"sort"
 	"strings"
@@ -120,7 +121,7 @@
 	if config.OutputLicenseFile {
 		for _, extension := range config.OutputFileExtensions {
 			path := config.OutputFilePrefix + "." + extension
-			if err := saveToOutputFile(path, licenses, config); err != nil {
+			if err := saveToOutputFile(filepath.Join(config.OutDir, path), licenses, config); err != nil {
 				return err
 			}
 		}