blob: 1781c97c56a7d9bb7480ea8f918f4934f4cfd212 [file] [log] [blame]
// 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.
package checklicenses
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"strings"
)
type Gn struct {
gnPath string
outDir string
}
// NewGn returns a GN object that is used to interface with the external GN tool. It can be used to
// discover the dependendcies of a GN target. The path to the external binary is taken from the
// config argument (config.GnPath.) NewGn will return an error if config.GnPath is not a valid
// executable, or if config.BuildDir does not exist.
func NewGn(ctx context.Context, config *Config) (*Gn, error) {
gn := &Gn{}
path, err := exec.LookPath(config.GnPath)
if err != nil {
return nil, err
}
if _, err := os.Stat(config.BuildDir); os.IsNotExist(err) {
return nil, fmt.Errorf("out directory does not exist: %s", config.BuildDir)
}
gn.gnPath = path
gn.outDir = config.BuildDir
return gn, nil
}
// Return the dependencies of the given GN target. Calls out to the external GN executable.
// Dependencies are returned as an array of GN label strings, e.g. //root/dir:target_name(toolchain)
// Both the target name and toolchain are optional. See
// https://gn.googlesource.com/gn/+/HEAD/docs/reference.md#labels for more information.
func (gn *Gn) Dependencies(ctx context.Context, target string) ([]string, error) {
args := []string{
"desc",
gn.outDir,
target,
"deps",
"--all",
}
cmd := exec.CommandContext(ctx, gn.gnPath, args...)
var output bytes.Buffer
cmd.Stdout = &output
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
return []string{}, err
}
result := output.String()
result = strings.TrimSpace(result)
return strings.Split(result, "\n"), nil
}
// Converts a GN label string (such as those returned by Dependencies) and strips any target names
// and toolchains, thereby returning the directory of the label.
func LabelToDirectory(label string) (string, error) {
if !strings.HasPrefix(label, "//") {
return "", fmt.Errorf("Label missing leading `//`: %s", label)
}
label = label[2:]
location := label
if strings.Contains(label, ":") {
location = strings.SplitN(label, ":", 2)[0]
}
return location, nil
}