blob: d1b6132fd7e86bcff5b17a5f2213396a01d731b2 [file] [log] [blame]
// Copyright 2022 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 util
import (
"fmt"
"regexp"
"sort"
"strings"
)
type Target struct {
Name string `json:"name"`
AllDependentConfigs []string `json:"all_dependent_configs"`
Deps []string `json:"deps"`
Args []string `json:"args,omitempty"`
Inputs []string `json:"inputs,omitempty"`
Sources []string `json:"sources,omitempty"`
PublicConfigs []string `json:"public_configs,omitempty"`
IncludeDirs []string `json:"include_dirs,omitempty"`
Script string `json:"script,omitempty"`
LibDirs []string `json:"lib_dirs,omitempty"`
Libs []string `json:"libs,omitempty"`
Toolchain string `json:"toolchain,omitempty"`
CleanNames []string `json:"cleanNames"`
CleanDeps []string `json:"cleanDeps"`
IsClean bool `json:"is_clean"`
Children []*Target `json:"-"`
}
func (t *Target) Clean(re *regexp.Regexp) error {
if t.IsClean {
return fmt.Errorf("Target '%s' is already clean", t.Name)
}
paths := make([]string, 0)
paths = append(paths, t.Deps...)
paths = append(paths, t.Inputs...)
paths = append(paths, t.LibDirs...)
paths = append(paths, t.Libs...)
paths = append(paths, t.Sources...)
paths = append(paths, t.PublicConfigs...)
paths = append(paths, t.IncludeDirs...)
// "include_dirs" entries often have a trailing slash.
// That trailing slash can cause string matching to fail later on.
for _, d := range t.IncludeDirs {
prefix, found := strings.CutSuffix(d, "/")
if found {
paths = append(paths, prefix)
}
}
var err error
t.CleanNames, err = clean([]string{t.Name}, re)
if err != nil {
return err
}
t.CleanDeps, err = clean(paths, re)
if err != nil {
return err
}
t.IsClean = true
return 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 clean(paths []string, re *regexp.Regexp) ([]string, error) {
set := make(map[string]bool, 0)
for _, path := range paths {
thisSet := make(map[string]bool, 0)
thisSet[path] = true
cutColon := true
if strings.Contains(path, "third_party/golibs") || strings.Contains(path, "rust_crates") {
cutColon = false
}
// If this target isn't a rust crate target, we still want to retrieve
// the relevant directory, not the target name in that directory.
// If a colon exists in this string, delete it and everything after it.
if strings.Contains(path, ":") && cutColon {
thisSet[strings.Split(path, ":")[0]] = true
}
// Same goes for toolchain definitions.
// If a parenthesis exists in this string, delete it and everything after it.
if strings.Contains(path, "(") {
thisSet[strings.Split(path, "(")[0]] = true
}
// Many rust crate libraries have a version string in their target name,
// but no version string in their folder path. If we see this specific
// version string pattern, remove it from the string.
if strings.Contains(path, "{") {
thisSet[re.ReplaceAllString(path, "-$1.$2.$3")] = true
}
for k := range thisSet {
set[k] = true
}
// Go lib dependencies are all linked into the build system
// using targets that are defined in the "golibs/BUILD.gn" file.
// We want to add the actual go library subdirectory as a dependency,
// but there is no easy way to determine that from the build target name.
if strings.Contains(path, "third_party/golibs") {
for k := range thisSet {
set[strings.ReplaceAll(k, ":", "/vendor/")] = true
}
}
// Rust crate dependencies are all linked into the build system
// using targets that are defined in the "rust_crates/BUILD.gn" file.
// We want to add the actual rust_crate subdirectory as a dependency,
// but there is no easy way to determine that from the build target name.
//
// This adds all possible directories to the list. There is no harm if
// a given directory doesn't actually exist -- check-licenses will ignore
// those entries.
if strings.Contains(path, "rust_crates") {
for k := range thisSet {
k = re.ReplaceAllString(k, "$1-$2.$3.$4")
set[strings.ReplaceAll(k, ":", "/vendor/")] = true
set[strings.ReplaceAll(k, ":", "/ask2patch/")] = true
set[strings.ReplaceAll(k, ":", "/compat/")] = true
set[strings.ReplaceAll(k, ":", "/empty/")] = true
set[strings.ReplaceAll(k, ":", "/forks/")] = true
set[strings.ReplaceAll(k, ":", "/mirrors/")] = true
set[strings.ReplaceAll(k, ":", "/src/")] = true
}
}
}
// Sort the results, so the outputs are deterministic.
results := make([]string, 0)
for k := range set {
results = append(results, k)
}
sort.Strings(results)
return results, nil
}