soong_ui: Add build actions commands in soong_ui.
Add the following build actions {BUILD_MODULES_IN_A_DIRECTORY, BUILD_MODULES_IN_DIRECTORIES} in soong_ui config so the bash code version of build commands (m, mm, mma, mmm, mmma) in build/make/envsetup.sh can be deprecated. This is to allow up to date bug fixes on the build commands. Bug: b/130049705 Test: Unit test cases Change-Id: I772db1d4e9c1da5273374d1994eb5e8f17cd52f2
This commit is contained in:
@@ -61,6 +61,28 @@ type configImpl struct {
|
||||
|
||||
const srcDirFileCheck = "build/soong/root.bp"
|
||||
|
||||
type BuildAction uint
|
||||
|
||||
const (
|
||||
// Builds all of the modules and their dependencies of a specified directory, relative to the root
|
||||
// directory of the source tree.
|
||||
BUILD_MODULES_IN_A_DIRECTORY BuildAction = iota
|
||||
|
||||
// Builds all of the modules and their dependencies of a list of specified directories. All specified
|
||||
// directories are relative to the root directory of the source tree.
|
||||
BUILD_MODULES_IN_DIRECTORIES
|
||||
)
|
||||
|
||||
// checkTopDir validates that the current directory is at the root directory of the source tree.
|
||||
func checkTopDir(ctx Context) {
|
||||
if _, err := os.Stat(srcDirFileCheck); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
ctx.Fatalf("Current working directory must be the source tree. %q not found.", srcDirFileCheck)
|
||||
}
|
||||
ctx.Fatalln("Error verifying tree state:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func NewConfig(ctx Context, args ...string) Config {
|
||||
ret := &configImpl{
|
||||
environ: OsEnvironment(),
|
||||
@@ -154,12 +176,7 @@ func NewConfig(ctx Context, args ...string) Config {
|
||||
ret.environ.Set("TMPDIR", absPath(ctx, ret.TempDir()))
|
||||
|
||||
// Precondition: the current directory is the top of the source tree
|
||||
if _, err := os.Stat(srcDirFileCheck); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
log.Fatalf("Current working directory must be the source tree. %q not found", srcDirFileCheck)
|
||||
}
|
||||
log.Fatalln("Error verifying tree state:", err)
|
||||
}
|
||||
checkTopDir(ctx)
|
||||
|
||||
if srcDir := absPath(ctx, "."); strings.ContainsRune(srcDir, ' ') {
|
||||
log.Println("You are building in a directory whose absolute path contains a space character:")
|
||||
@@ -229,6 +246,203 @@ func NewConfig(ctx Context, args ...string) Config {
|
||||
return Config{ret}
|
||||
}
|
||||
|
||||
// NewBuildActionConfig returns a build configuration based on the build action. The arguments are
|
||||
// processed based on the build action and extracts any arguments that belongs to the build action.
|
||||
func NewBuildActionConfig(action BuildAction, dir string, buildDependencies bool, ctx Context, args ...string) Config {
|
||||
return NewConfig(ctx, getConfigArgs(action, dir, buildDependencies, ctx, args)...)
|
||||
}
|
||||
|
||||
// getConfigArgs processes the command arguments based on the build action and creates a set of new
|
||||
// arguments to be accepted by Config.
|
||||
func getConfigArgs(action BuildAction, dir string, buildDependencies bool, ctx Context, args []string) []string {
|
||||
// The next block of code verifies that the current directory is the root directory of the source
|
||||
// tree. It then finds the relative path of dir based on the root directory of the source tree
|
||||
// and verify that dir is inside of the source tree.
|
||||
checkTopDir(ctx)
|
||||
topDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
ctx.Fatalf("Error retrieving top directory: %v", err)
|
||||
}
|
||||
dir, err = filepath.Abs(dir)
|
||||
if err != nil {
|
||||
ctx.Fatalf("Unable to find absolute path %s: %v", dir, err)
|
||||
}
|
||||
relDir, err := filepath.Rel(topDir, dir)
|
||||
if err != nil {
|
||||
ctx.Fatalf("Unable to find relative path %s of %s: %v", relDir, topDir, err)
|
||||
}
|
||||
// If there are ".." in the path, it's not in the source tree.
|
||||
if strings.Contains(relDir, "..") {
|
||||
ctx.Fatalf("Directory %s is not under the source tree %s", dir, topDir)
|
||||
}
|
||||
|
||||
configArgs := args[:]
|
||||
|
||||
// If the arguments contains GET-INSTALL-PATH, change the target name prefix from MODULES-IN- to
|
||||
// GET-INSTALL-PATH-IN- to extract the installation path instead of building the modules.
|
||||
targetNamePrefix := "MODULES-IN-"
|
||||
if inList("GET-INSTALL-PATH", configArgs) {
|
||||
targetNamePrefix = "GET-INSTALL-PATH-IN-"
|
||||
configArgs = removeFromList("GET-INSTALL-PATH", configArgs)
|
||||
}
|
||||
|
||||
var buildFiles []string
|
||||
var targets []string
|
||||
|
||||
switch action {
|
||||
case BUILD_MODULES_IN_A_DIRECTORY:
|
||||
// If dir is the root source tree, all the modules are built of the source tree are built so
|
||||
// no need to find the build file.
|
||||
if topDir == dir {
|
||||
break
|
||||
}
|
||||
// Find the build file from the directory where the build action was triggered by traversing up
|
||||
// the source tree. If a blank build filename is returned, simply use the directory where the build
|
||||
// action was invoked.
|
||||
buildFile := findBuildFile(ctx, relDir)
|
||||
if buildFile == "" {
|
||||
buildFile = filepath.Join(relDir, "Android.mk")
|
||||
}
|
||||
buildFiles = []string{buildFile}
|
||||
targets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
|
||||
case BUILD_MODULES_IN_DIRECTORIES:
|
||||
newConfigArgs, dirs := splitArgs(configArgs)
|
||||
configArgs = newConfigArgs
|
||||
targets, buildFiles = getTargetsFromDirs(ctx, relDir, dirs, targetNamePrefix)
|
||||
}
|
||||
|
||||
// This is to support building modules without building their dependencies. Soon, this will be
|
||||
// deprecated.
|
||||
if !buildDependencies && len(buildFiles) > 0 {
|
||||
if err := os.Setenv("ONE_SHOT_MAKEFILE", strings.Join(buildFiles, " ")); err != nil {
|
||||
ctx.Fatalf("Unable to set ONE_SHOT_MAKEFILE environment variable: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tidy only override all other specified targets.
|
||||
tidyOnly := os.Getenv("WITH_TIDY_ONLY")
|
||||
if tidyOnly == "true" || tidyOnly == "1" {
|
||||
configArgs = append(configArgs, "tidy_only")
|
||||
} else {
|
||||
configArgs = append(configArgs, targets...)
|
||||
}
|
||||
|
||||
return configArgs
|
||||
}
|
||||
|
||||
// convertToTarget replaces "/" to "-" in dir and pre-append the targetNamePrefix to the target name.
|
||||
func convertToTarget(dir string, targetNamePrefix string) string {
|
||||
return targetNamePrefix + strings.ReplaceAll(dir, "/", "-")
|
||||
}
|
||||
|
||||
// findBuildFile finds a build file (makefile or blueprint file) by looking at dir first. If not
|
||||
// found, go up one level and repeat again until one is found and the path of that build file
|
||||
// relative to the root directory of the source tree is returned. The returned filename of build
|
||||
// file is "Android.mk". If one was not found, a blank string is returned.
|
||||
func findBuildFile(ctx Context, dir string) string {
|
||||
// If the string is empty, assume it is top directory of the source tree.
|
||||
if dir == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
for ; dir != "."; dir = filepath.Dir(dir) {
|
||||
for _, buildFile := range []string{"Android.bp", "Android.mk"} {
|
||||
_, err := os.Stat(filepath.Join(dir, buildFile))
|
||||
if err == nil {
|
||||
// Returning the filename Android.mk as it might be used for ONE_SHOT_MAKEFILE variable.
|
||||
return filepath.Join(dir, "Android.mk")
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
ctx.Fatalf("Error retrieving the build file stats: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// splitArgs iterates over the arguments list and splits into two lists: arguments and directories.
|
||||
func splitArgs(args []string) (newArgs []string, dirs []string) {
|
||||
specialArgs := map[string]bool{
|
||||
"showcommands": true,
|
||||
"snod": true,
|
||||
"dist": true,
|
||||
"checkbuild": true,
|
||||
}
|
||||
|
||||
newArgs = []string{}
|
||||
dirs = []string{}
|
||||
|
||||
for _, arg := range args {
|
||||
// It's a dash argument if it starts with "-" or it's a key=value pair, it's not a directory.
|
||||
if strings.IndexRune(arg, '-') == 0 || strings.IndexRune(arg, '=') != -1 {
|
||||
newArgs = append(newArgs, arg)
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := specialArgs[arg]; ok {
|
||||
newArgs = append(newArgs, arg)
|
||||
continue
|
||||
}
|
||||
|
||||
dirs = append(dirs, arg)
|
||||
}
|
||||
|
||||
return newArgs, dirs
|
||||
}
|
||||
|
||||
// getTargetsFromDirs iterates over the dirs list and creates a list of targets to build. If a
|
||||
// directory from the dirs list does not exist, a fatal error is raised. relDir is related to the
|
||||
// source root tree where the build action command was invoked. Each directory is validated if the
|
||||
// build file can be found and follows the format "dir1:target1,target2,...". Target is optional.
|
||||
func getTargetsFromDirs(ctx Context, relDir string, dirs []string, targetNamePrefix string) (targets []string, buildFiles []string) {
|
||||
for _, dir := range dirs {
|
||||
// The directory may have specified specific modules to build. ":" is the separator to separate
|
||||
// the directory and the list of modules.
|
||||
s := strings.Split(dir, ":")
|
||||
l := len(s)
|
||||
if l > 2 { // more than one ":" was specified.
|
||||
ctx.Fatalf("%s not in proper directory:target1,target2,... format (\":\" was specified more than once)", dir)
|
||||
}
|
||||
|
||||
dir = filepath.Join(relDir, s[0])
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
ctx.Fatalf("couldn't find directory %s", dir)
|
||||
}
|
||||
|
||||
// Verify that if there are any targets specified after ":". Each target is separated by ",".
|
||||
var newTargets []string
|
||||
if l == 2 && s[1] != "" {
|
||||
newTargets = strings.Split(s[1], ",")
|
||||
if inList("", newTargets) {
|
||||
ctx.Fatalf("%s not in proper directory:target1,target2,... format", dir)
|
||||
}
|
||||
}
|
||||
|
||||
buildFile := findBuildFile(ctx, dir)
|
||||
if buildFile == "" {
|
||||
ctx.Fatalf("Build file not found for %s directory", dir)
|
||||
}
|
||||
buildFileDir := filepath.Dir(buildFile)
|
||||
|
||||
// If there are specified targets, find the build file in the directory. If dir does not
|
||||
// contain the build file, bail out as it is required for one shot build. If there are no
|
||||
// target specified, build all the modules in dir (or the closest one in the dir path).
|
||||
if len(newTargets) > 0 {
|
||||
if buildFileDir != dir {
|
||||
ctx.Fatalf("Couldn't locate a build file from %s directory", dir)
|
||||
}
|
||||
} else {
|
||||
newTargets = []string{convertToTarget(buildFileDir, targetNamePrefix)}
|
||||
}
|
||||
|
||||
buildFiles = append(buildFiles, buildFile)
|
||||
targets = append(targets, newTargets...)
|
||||
}
|
||||
|
||||
return targets, buildFiles
|
||||
}
|
||||
|
||||
func (c *configImpl) parseArgs(ctx Context, args []string) {
|
||||
for i := 0; i < len(args); i++ {
|
||||
arg := strings.TrimSpace(args[i])
|
||||
|
@@ -17,6 +17,10 @@ package build
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -173,3 +177,877 @@ func TestConfigParseArgsVars(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigCheckTopDir(t *testing.T) {
|
||||
ctx := testContext()
|
||||
buildRootDir := filepath.Dir(srcDirFileCheck)
|
||||
expectedErrStr := fmt.Sprintf("Current working directory must be the source tree. %q not found.", srcDirFileCheck)
|
||||
|
||||
tests := []struct {
|
||||
// ********* Setup *********
|
||||
// Test description.
|
||||
description string
|
||||
|
||||
// ********* Action *********
|
||||
// If set to true, the build root file is created.
|
||||
rootBuildFile bool
|
||||
|
||||
// The current path where Soong is being executed.
|
||||
path string
|
||||
|
||||
// ********* Validation *********
|
||||
// Expecting error and validate the error string against expectedErrStr.
|
||||
wantErr bool
|
||||
}{{
|
||||
description: "current directory is the root source tree",
|
||||
rootBuildFile: true,
|
||||
path: ".",
|
||||
wantErr: false,
|
||||
}, {
|
||||
description: "one level deep in the source tree",
|
||||
rootBuildFile: true,
|
||||
path: "1",
|
||||
wantErr: true,
|
||||
}, {
|
||||
description: "very deep in the source tree",
|
||||
rootBuildFile: true,
|
||||
path: "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7",
|
||||
wantErr: true,
|
||||
}, {
|
||||
description: "outside of source tree",
|
||||
rootBuildFile: false,
|
||||
path: "1/2/3/4/5",
|
||||
wantErr: true,
|
||||
}}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
defer logger.Recover(func(err error) {
|
||||
if !tt.wantErr {
|
||||
t.Fatalf("Got unexpected error: %v", err)
|
||||
}
|
||||
if expectedErrStr != err.Error() {
|
||||
t.Fatalf("expected %s, got %s", expectedErrStr, err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
// Create the root source tree.
|
||||
rootDir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(rootDir)
|
||||
|
||||
// Create the build root file. This is to test if topDir returns an error if the build root
|
||||
// file does not exist.
|
||||
if tt.rootBuildFile {
|
||||
dir := filepath.Join(rootDir, buildRootDir)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
t.Errorf("failed to create %s directory: %v", dir, err)
|
||||
}
|
||||
f := filepath.Join(rootDir, srcDirFileCheck)
|
||||
if err := ioutil.WriteFile(f, []byte{}, 0644); err != nil {
|
||||
t.Errorf("failed to create file %s: %v", f, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Next block of code is to set the current directory.
|
||||
dir := rootDir
|
||||
if tt.path != "" {
|
||||
dir = filepath.Join(dir, tt.path)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
t.Errorf("failed to create %s directory: %v", dir, err)
|
||||
}
|
||||
}
|
||||
curDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get the current directory: %v", err)
|
||||
}
|
||||
defer func() { os.Chdir(curDir) }()
|
||||
|
||||
if err := os.Chdir(dir); err != nil {
|
||||
t.Fatalf("failed to change directory to %s: %v", dir, err)
|
||||
}
|
||||
|
||||
checkTopDir(ctx)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigConvertToTarget(t *testing.T) {
|
||||
tests := []struct {
|
||||
// ********* Setup *********
|
||||
// Test description.
|
||||
description string
|
||||
|
||||
// ********* Action *********
|
||||
// The current directory where Soong is being executed.
|
||||
dir string
|
||||
|
||||
// The current prefix string to be pre-appended to the target.
|
||||
prefix string
|
||||
|
||||
// ********* Validation *********
|
||||
// The expected target to be invoked in ninja.
|
||||
expectedTarget string
|
||||
}{{
|
||||
description: "one level directory in source tree",
|
||||
dir: "test1",
|
||||
prefix: "MODULES-IN-",
|
||||
expectedTarget: "MODULES-IN-test1",
|
||||
}, {
|
||||
description: "multiple level directories in source tree",
|
||||
dir: "test1/test2/test3/test4",
|
||||
prefix: "GET-INSTALL-PATH-IN-",
|
||||
expectedTarget: "GET-INSTALL-PATH-IN-test1-test2-test3-test4",
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
target := convertToTarget(tt.dir, tt.prefix)
|
||||
if target != tt.expectedTarget {
|
||||
t.Errorf("expected %s, got %s for target", tt.expectedTarget, target)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setTop(t *testing.T, dir string) func() {
|
||||
curDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get current directory: %v", err)
|
||||
}
|
||||
if err := os.Chdir(dir); err != nil {
|
||||
t.Fatalf("failed to change directory to top dir %s: %v", dir, err)
|
||||
}
|
||||
return func() { os.Chdir(curDir) }
|
||||
}
|
||||
|
||||
func createBuildFiles(t *testing.T, topDir string, buildFiles []string) {
|
||||
for _, buildFile := range buildFiles {
|
||||
buildFile = filepath.Join(topDir, buildFile)
|
||||
if err := ioutil.WriteFile(buildFile, []byte{}, 0644); err != nil {
|
||||
t.Errorf("failed to create file %s: %v", buildFile, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createDirectories(t *testing.T, topDir string, dirs []string) {
|
||||
for _, dir := range dirs {
|
||||
dir = filepath.Join(topDir, dir)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
t.Errorf("failed to create %s directory: %v", dir, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigGetTargets(t *testing.T) {
|
||||
ctx := testContext()
|
||||
tests := []struct {
|
||||
// ********* Setup *********
|
||||
// Test description.
|
||||
description string
|
||||
|
||||
// Directories that exist in the source tree.
|
||||
dirsInTrees []string
|
||||
|
||||
// Build files that exists in the source tree.
|
||||
buildFiles []string
|
||||
|
||||
// ********* Action *********
|
||||
// Directories passed in to soong_ui.
|
||||
dirs []string
|
||||
|
||||
// Current directory that the user executed the build action command.
|
||||
curDir string
|
||||
|
||||
// ********* Validation *********
|
||||
// Expected targets from the function.
|
||||
expectedTargets []string
|
||||
|
||||
// Expected build from the build system.
|
||||
expectedBuildFiles []string
|
||||
|
||||
// Expecting error from running test case.
|
||||
errStr string
|
||||
}{{
|
||||
description: "one target dir specified",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp"},
|
||||
dirs: []string{"1/2/3"},
|
||||
curDir: "0",
|
||||
expectedTargets: []string{"MODULES-IN-0-1-2-3"},
|
||||
expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
|
||||
}, {
|
||||
description: "one target dir specified, build file does not exist",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{},
|
||||
dirs: []string{"1/2/3"},
|
||||
curDir: "0",
|
||||
errStr: "Build file not found for 0/1/2/3 directory",
|
||||
}, {
|
||||
description: "one target dir specified, invalid targets specified",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{},
|
||||
dirs: []string{"1/2/3:t1:t2"},
|
||||
curDir: "0",
|
||||
errStr: "1/2/3:t1:t2 not in proper directory:target1,target2,... format (\":\" was specified more than once)",
|
||||
}, {
|
||||
description: "one target dir specified, no targets specified but has colon",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp"},
|
||||
dirs: []string{"1/2/3:"},
|
||||
curDir: "0",
|
||||
expectedTargets: []string{"MODULES-IN-0-1-2-3"},
|
||||
expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
|
||||
}, {
|
||||
description: "one target dir specified, two targets specified",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp"},
|
||||
dirs: []string{"1/2/3:t1,t2"},
|
||||
curDir: "0",
|
||||
expectedTargets: []string{"t1", "t2"},
|
||||
expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
|
||||
}, {
|
||||
description: "one target dir specified, no targets and has a comma",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp"},
|
||||
dirs: []string{"1/2/3:,"},
|
||||
curDir: "0",
|
||||
errStr: "0/1/2/3 not in proper directory:target1,target2,... format",
|
||||
}, {
|
||||
description: "one target dir specified, improper targets defined",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp"},
|
||||
dirs: []string{"1/2/3:,t1"},
|
||||
curDir: "0",
|
||||
errStr: "0/1/2/3 not in proper directory:target1,target2,... format",
|
||||
}, {
|
||||
description: "one target dir specified, blank target",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp"},
|
||||
dirs: []string{"1/2/3:t1,"},
|
||||
curDir: "0",
|
||||
errStr: "0/1/2/3 not in proper directory:target1,target2,... format",
|
||||
}, {
|
||||
description: "one target dir specified, many targets specified",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp"},
|
||||
dirs: []string{"1/2/3:t1,t2,t3,t4,t5,t6,t7,t8,t9,t10"},
|
||||
curDir: "0",
|
||||
expectedTargets: []string{"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10"},
|
||||
expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
|
||||
}, {
|
||||
description: "one target dir specified, one target specified, build file does not exist",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{},
|
||||
dirs: []string{"1/2/3:t1"},
|
||||
curDir: "0",
|
||||
errStr: "Build file not found for 0/1/2/3 directory",
|
||||
}, {
|
||||
description: "one target dir specified, one target specified, build file not in target dir",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{"0/1/2/Android.mk"},
|
||||
dirs: []string{"1/2/3:t1"},
|
||||
curDir: "0",
|
||||
errStr: "Couldn't locate a build file from 0/1/2/3 directory",
|
||||
}, {
|
||||
description: "one target dir specified, build file not in target dir",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{"0/1/2/Android.mk"},
|
||||
dirs: []string{"1/2/3"},
|
||||
curDir: "0",
|
||||
expectedTargets: []string{"MODULES-IN-0-1-2"},
|
||||
expectedBuildFiles: []string{"0/1/2/Android.mk"},
|
||||
}, {
|
||||
description: "multiple targets dir specified, targets specified",
|
||||
dirsInTrees: []string{"0/1/2/3", "0/3/4"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
|
||||
dirs: []string{"1/2/3:t1,t2", "3/4:t3,t4,t5"},
|
||||
curDir: "0",
|
||||
expectedTargets: []string{"t1", "t2", "t3", "t4", "t5"},
|
||||
expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
|
||||
}, {
|
||||
description: "multiple targets dir specified, one directory has targets specified",
|
||||
dirsInTrees: []string{"0/1/2/3", "0/3/4"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
|
||||
dirs: []string{"1/2/3:t1,t2", "3/4"},
|
||||
curDir: "0",
|
||||
expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
|
||||
expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
|
||||
}, {
|
||||
description: "two dirs specified, only one dir exist",
|
||||
dirsInTrees: []string{"0/1/2/3"},
|
||||
buildFiles: []string{"0/1/2/3/Android.mk"},
|
||||
dirs: []string{"1/2/3:t1", "3/4"},
|
||||
curDir: "0",
|
||||
errStr: "couldn't find directory 0/3/4",
|
||||
}, {
|
||||
description: "multiple targets dirs specified at root source tree",
|
||||
dirsInTrees: []string{"0/1/2/3", "0/3/4"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
|
||||
dirs: []string{"0/1/2/3:t1,t2", "0/3/4"},
|
||||
curDir: ".",
|
||||
expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
|
||||
expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
|
||||
}, {
|
||||
description: "no directories specified",
|
||||
dirsInTrees: []string{"0/1/2/3", "0/3/4"},
|
||||
buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
|
||||
dirs: []string{},
|
||||
curDir: ".",
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
defer logger.Recover(func(err error) {
|
||||
if tt.errStr == "" {
|
||||
t.Fatalf("Got unexpected error: %v", err)
|
||||
}
|
||||
if tt.errStr != err.Error() {
|
||||
t.Errorf("expected %s, got %s", tt.errStr, err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
// Create the root source tree.
|
||||
topDir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(topDir)
|
||||
|
||||
createDirectories(t, topDir, tt.dirsInTrees)
|
||||
createBuildFiles(t, topDir, tt.buildFiles)
|
||||
r := setTop(t, topDir)
|
||||
defer r()
|
||||
|
||||
targets, buildFiles := getTargetsFromDirs(ctx, tt.curDir, tt.dirs, "MODULES-IN-")
|
||||
if !reflect.DeepEqual(targets, tt.expectedTargets) {
|
||||
t.Errorf("expected %v, got %v for targets", tt.expectedTargets, targets)
|
||||
}
|
||||
if !reflect.DeepEqual(buildFiles, tt.expectedBuildFiles) {
|
||||
t.Errorf("expected %v, got %v for build files", tt.expectedBuildFiles, buildFiles)
|
||||
}
|
||||
|
||||
// If the execution reached here and there was an expected error code, the unit test case failed.
|
||||
if tt.errStr != "" {
|
||||
t.Errorf("expecting error %s", tt.errStr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigFindBuildFile(t *testing.T) {
|
||||
ctx := testContext()
|
||||
|
||||
tests := []struct {
|
||||
// ********* Setup *********
|
||||
// Test description.
|
||||
description string
|
||||
|
||||
// Array of build files to create in dir.
|
||||
buildFiles []string
|
||||
|
||||
// ********* Action *********
|
||||
// Directory to create, also the base directory is where findBuildFile is invoked.
|
||||
dir string
|
||||
|
||||
// ********* Validation *********
|
||||
// Expected build file path to find.
|
||||
expectedBuildFile string
|
||||
}{{
|
||||
description: "build file exists at leaf directory",
|
||||
buildFiles: []string{"1/2/3/Android.bp"},
|
||||
dir: "1/2/3",
|
||||
expectedBuildFile: "1/2/3/Android.mk",
|
||||
}, {
|
||||
description: "build file exists in all directory paths",
|
||||
buildFiles: []string{"1/Android.mk", "1/2/Android.mk", "1/2/3/Android.mk"},
|
||||
dir: "1/2/3",
|
||||
expectedBuildFile: "1/2/3/Android.mk",
|
||||
}, {
|
||||
description: "build file does not exist in all directory paths",
|
||||
buildFiles: []string{},
|
||||
dir: "1/2/3",
|
||||
expectedBuildFile: "",
|
||||
}, {
|
||||
description: "build file exists only at top directory",
|
||||
buildFiles: []string{"Android.bp"},
|
||||
dir: "1/2/3",
|
||||
expectedBuildFile: "",
|
||||
}, {
|
||||
description: "build file exist in a subdirectory",
|
||||
buildFiles: []string{"1/2/Android.bp"},
|
||||
dir: "1/2/3",
|
||||
expectedBuildFile: "1/2/Android.mk",
|
||||
}, {
|
||||
description: "build file exists in a subdirectory",
|
||||
buildFiles: []string{"1/Android.mk"},
|
||||
dir: "1/2/3",
|
||||
expectedBuildFile: "1/Android.mk",
|
||||
}, {
|
||||
description: "top directory",
|
||||
buildFiles: []string{"Android.bp"},
|
||||
dir: ".",
|
||||
expectedBuildFile: "",
|
||||
}}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
defer logger.Recover(func(err error) {
|
||||
t.Fatalf("Got unexpected error: %v", err)
|
||||
})
|
||||
|
||||
topDir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(topDir)
|
||||
|
||||
if tt.dir != "" {
|
||||
createDirectories(t, topDir, []string{tt.dir})
|
||||
}
|
||||
|
||||
createBuildFiles(t, topDir, tt.buildFiles)
|
||||
|
||||
curDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("Could not get working directory: %v", err)
|
||||
}
|
||||
defer func() { os.Chdir(curDir) }()
|
||||
if err := os.Chdir(topDir); err != nil {
|
||||
t.Fatalf("Could not change top dir to %s: %v", topDir, err)
|
||||
}
|
||||
|
||||
buildFile := findBuildFile(ctx, tt.dir)
|
||||
if buildFile != tt.expectedBuildFile {
|
||||
t.Errorf("expected %q, got %q for build file", tt.expectedBuildFile, buildFile)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigSplitArgs(t *testing.T) {
|
||||
tests := []struct {
|
||||
// ********* Setup *********
|
||||
// Test description.
|
||||
description string
|
||||
|
||||
// ********* Action *********
|
||||
// Arguments passed in to soong_ui.
|
||||
args []string
|
||||
|
||||
// ********* Validation *********
|
||||
// Expected newArgs list after extracting the directories.
|
||||
expectedNewArgs []string
|
||||
|
||||
// Expected directories
|
||||
expectedDirs []string
|
||||
}{{
|
||||
description: "flags but no directories specified",
|
||||
args: []string{"showcommands", "-j", "-k"},
|
||||
expectedNewArgs: []string{"showcommands", "-j", "-k"},
|
||||
expectedDirs: []string{},
|
||||
}, {
|
||||
description: "flags and one directory specified",
|
||||
args: []string{"snod", "-j", "dir:target1,target2"},
|
||||
expectedNewArgs: []string{"snod", "-j"},
|
||||
expectedDirs: []string{"dir:target1,target2"},
|
||||
}, {
|
||||
description: "flags and directories specified",
|
||||
args: []string{"dist", "-k", "dir1", "dir2:target1,target2"},
|
||||
expectedNewArgs: []string{"dist", "-k"},
|
||||
expectedDirs: []string{"dir1", "dir2:target1,target2"},
|
||||
}, {
|
||||
description: "only directories specified",
|
||||
args: []string{"dir1", "dir2", "dir3:target1,target2"},
|
||||
expectedNewArgs: []string{},
|
||||
expectedDirs: []string{"dir1", "dir2", "dir3:target1,target2"},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
args, dirs := splitArgs(tt.args)
|
||||
if !reflect.DeepEqual(tt.expectedNewArgs, args) {
|
||||
t.Errorf("expected %v, got %v for arguments", tt.expectedNewArgs, args)
|
||||
}
|
||||
if !reflect.DeepEqual(tt.expectedDirs, dirs) {
|
||||
t.Errorf("expected %v, got %v for directories", tt.expectedDirs, dirs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type envVar struct {
|
||||
name string
|
||||
value string
|
||||
}
|
||||
|
||||
type buildActionTestCase struct {
|
||||
// ********* Setup *********
|
||||
// Test description.
|
||||
description string
|
||||
|
||||
// Directories that exist in the source tree.
|
||||
dirsInTrees []string
|
||||
|
||||
// Build files that exists in the source tree.
|
||||
buildFiles []string
|
||||
|
||||
// ********* Action *********
|
||||
// Arguments passed in to soong_ui.
|
||||
args []string
|
||||
|
||||
// Directory where the build action was invoked.
|
||||
curDir string
|
||||
|
||||
// WITH_TIDY_ONLY environment variable specified.
|
||||
tidyOnly string
|
||||
|
||||
// ********* Validation *********
|
||||
// Expected arguments to be in Config instance.
|
||||
expectedArgs []string
|
||||
|
||||
// Expected environment variables to be set.
|
||||
expectedEnvVars []envVar
|
||||
}
|
||||
|
||||
func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction, buildDependencies bool) {
|
||||
ctx := testContext()
|
||||
|
||||
// Environment variables to set it to blank on every test case run.
|
||||
resetEnvVars := []string{
|
||||
"ONE_SHOT_MAKEFILE",
|
||||
"WITH_TIDY_ONLY",
|
||||
}
|
||||
|
||||
for _, name := range resetEnvVars {
|
||||
if err := os.Unsetenv(name); err != nil {
|
||||
t.Fatalf("failed to unset environment variable %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
if tt.tidyOnly != "" {
|
||||
if err := os.Setenv("WITH_TIDY_ONLY", tt.tidyOnly); err != nil {
|
||||
t.Errorf("failed to set WITH_TIDY_ONLY to %s: %v", tt.tidyOnly, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create the root source tree.
|
||||
topDir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(topDir)
|
||||
|
||||
createDirectories(t, topDir, tt.dirsInTrees)
|
||||
createBuildFiles(t, topDir, tt.buildFiles)
|
||||
|
||||
r := setTop(t, topDir)
|
||||
defer r()
|
||||
|
||||
// The next block is to create the root build file.
|
||||
rootBuildFileDir := filepath.Dir(srcDirFileCheck)
|
||||
if err := os.MkdirAll(rootBuildFileDir, 0755); err != nil {
|
||||
t.Fatalf("Failed to create %s directory: %v", rootBuildFileDir, err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(srcDirFileCheck, []byte{}, 0644); err != nil {
|
||||
t.Fatalf("failed to create %s file: %v", srcDirFileCheck, err)
|
||||
}
|
||||
|
||||
args := getConfigArgs(action, tt.curDir, buildDependencies, ctx, tt.args)
|
||||
if !reflect.DeepEqual(tt.expectedArgs, args) {
|
||||
t.Fatalf("expected %v, got %v for config arguments", tt.expectedArgs, args)
|
||||
}
|
||||
|
||||
for _, env := range tt.expectedEnvVars {
|
||||
if val := os.Getenv(env.name); val != env.value {
|
||||
t.Errorf("expecting %s, got %s for environment variable %s", env.value, val, env.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this test case once mm shell build command has been deprecated.
|
||||
func TestGetConfigArgsBuildModulesInDirecotoryNoDeps(t *testing.T) {
|
||||
tests := []buildActionTestCase{{
|
||||
description: "normal execution in a directory",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{"0/1/2/Android.mk"},
|
||||
args: []string{"-j", "-k", "showcommands", "fake-module"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"-j", "-k", "showcommands", "fake-module", "MODULES-IN-0-1-2"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: "0/1/2/Android.mk"}},
|
||||
}, {
|
||||
description: "makefile in parent directory",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{"0/1/Android.mk"},
|
||||
args: []string{},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"MODULES-IN-0-1"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: "0/1/Android.mk"}},
|
||||
}, {
|
||||
description: "build file not found",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{},
|
||||
args: []string{},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"MODULES-IN-0-1-2"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: "0/1/2/Android.mk"}},
|
||||
}, {
|
||||
description: "build action executed at root directory",
|
||||
dirsInTrees: []string{},
|
||||
buildFiles: []string{},
|
||||
args: []string{},
|
||||
curDir: ".",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: ""}},
|
||||
}, {
|
||||
description: "GET-INSTALL-PATH specified,",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{"0/1/Android.mk"},
|
||||
args: []string{"GET-INSTALL-PATH"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: "0/1/Android.mk"}},
|
||||
}, {
|
||||
description: "tidy only environment variable specified,",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{"0/1/Android.mk"},
|
||||
args: []string{"GET-INSTALL-PATH"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "true",
|
||||
expectedArgs: []string{"tidy_only"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: "0/1/Android.mk"}},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run("build action BUILD_MODULES_IN_DIR without their dependencies, "+tt.description, func(t *testing.T) {
|
||||
testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY, false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConfigArgsBuildModulesInDirectory(t *testing.T) {
|
||||
tests := []buildActionTestCase{{
|
||||
description: "normal execution in a directory",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{"0/1/2/Android.mk"},
|
||||
args: []string{"fake-module"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
|
||||
expectedEnvVars: []envVar{},
|
||||
}, {
|
||||
description: "build file in parent directory",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{"0/1/Android.mk"},
|
||||
args: []string{},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"MODULES-IN-0-1"},
|
||||
expectedEnvVars: []envVar{},
|
||||
},
|
||||
{
|
||||
description: "build file in parent directory, multiple module names passed in",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{"0/1/Android.mk"},
|
||||
args: []string{"fake-module1", "fake-module2", "fake-module3"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"fake-module1", "fake-module2", "fake-module3", "MODULES-IN-0-1"},
|
||||
expectedEnvVars: []envVar{},
|
||||
}, {
|
||||
description: "build file in 2nd level parent directory",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{"0/Android.bp"},
|
||||
args: []string{},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"MODULES-IN-0"},
|
||||
expectedEnvVars: []envVar{},
|
||||
}, {
|
||||
description: "build action executed at root directory",
|
||||
dirsInTrees: []string{},
|
||||
buildFiles: []string{},
|
||||
args: []string{},
|
||||
curDir: ".",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{},
|
||||
expectedEnvVars: []envVar{},
|
||||
}, {
|
||||
description: "build file not found - no error is expected to return",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{},
|
||||
args: []string{},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"MODULES-IN-0-1-2"},
|
||||
expectedEnvVars: []envVar{},
|
||||
}, {
|
||||
description: "GET-INSTALL-PATH specified,",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{"0/1/Android.mk"},
|
||||
args: []string{"GET-INSTALL-PATH", "-j", "-k", "GET-INSTALL-PATH"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"-j", "-k", "GET-INSTALL-PATH-IN-0-1"},
|
||||
expectedEnvVars: []envVar{},
|
||||
}, {
|
||||
description: "tidy only environment variable specified,",
|
||||
dirsInTrees: []string{"0/1/2"},
|
||||
buildFiles: []string{"0/1/Android.mk"},
|
||||
args: []string{"GET-INSTALL-PATH"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "true",
|
||||
expectedArgs: []string{"tidy_only"},
|
||||
expectedEnvVars: []envVar{},
|
||||
}, {
|
||||
description: "normal execution in root directory with args",
|
||||
dirsInTrees: []string{},
|
||||
buildFiles: []string{},
|
||||
args: []string{"-j", "-k", "fake_module"},
|
||||
curDir: "",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"-j", "-k", "fake_module"},
|
||||
expectedEnvVars: []envVar{},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run("build action BUILD_MODULES_IN_DIR, "+tt.description, func(t *testing.T) {
|
||||
testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY, true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this test case once mmm shell build command has been deprecated.
|
||||
func TestGetConfigArgsBuildModulesInDirectoriesNoDeps(t *testing.T) {
|
||||
tests := []buildActionTestCase{{
|
||||
description: "normal execution in a directory",
|
||||
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
|
||||
buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
|
||||
args: []string{"3.1/:t1,t2", "3.2/:t3,t4", "3.3/:t5,t6"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"t1", "t2", "t3", "t4", "t5", "t6"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
|
||||
}, {
|
||||
description: "GET-INSTALL-PATH specified",
|
||||
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
|
||||
buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
|
||||
args: []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3/:t6"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1-2-3.1", "GET-INSTALL-PATH-IN-0-1-2-3.2", "t6"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
|
||||
}, {
|
||||
description: "tidy only environment variable specified",
|
||||
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
|
||||
buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
|
||||
args: []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3/:t6"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "1",
|
||||
expectedArgs: []string{"tidy_only"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
|
||||
}, {
|
||||
description: "normal execution from top dir directory",
|
||||
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
|
||||
buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
|
||||
args: []string{"0/1/2/3.1", "0/1/2/3.2/:t3,t4", "0/1/2/3.3/:t5,t6"},
|
||||
curDir: ".",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "t3", "t4", "t5", "t6"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run("build action BUILD_MODULES_IN_DIRS_NO_DEPS, "+tt.description, func(t *testing.T) {
|
||||
testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES, false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConfigArgsBuildModulesInDirectories(t *testing.T) {
|
||||
tests := []buildActionTestCase{{
|
||||
description: "normal execution in a directory",
|
||||
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
|
||||
buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
|
||||
args: []string{"3.1/", "3.2/", "3.3/"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-2-3.3"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: ""}},
|
||||
}, {
|
||||
description: "GET-INSTALL-PATH specified",
|
||||
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3"},
|
||||
buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/Android.bp"},
|
||||
args: []string{"GET-INSTALL-PATH", "2/3.1/", "2/3.2", "3"},
|
||||
curDir: "0/1",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1-2-3.1", "GET-INSTALL-PATH-IN-0-1-2-3.2", "GET-INSTALL-PATH-IN-0-1"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: ""}},
|
||||
}, {
|
||||
description: "tidy only environment variable specified",
|
||||
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
|
||||
buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
|
||||
args: []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3"},
|
||||
curDir: "0/1/2",
|
||||
tidyOnly: "1",
|
||||
expectedArgs: []string{"tidy_only"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: ""}},
|
||||
}, {
|
||||
description: "normal execution from top dir directory",
|
||||
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
|
||||
buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/3/Android.bp", "0/2/Android.bp"},
|
||||
args: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
|
||||
curDir: ".",
|
||||
tidyOnly: "",
|
||||
expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-3", "MODULES-IN-0-2"},
|
||||
expectedEnvVars: []envVar{
|
||||
envVar{
|
||||
name: "ONE_SHOT_MAKEFILE",
|
||||
value: ""}},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run("build action BUILD_MODULES_IN_DIRS, "+tt.description, func(t *testing.T) {
|
||||
testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES, true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -44,6 +44,17 @@ func inList(s string, list []string) bool {
|
||||
return indexList(s, list) != -1
|
||||
}
|
||||
|
||||
// removeFromlist removes all occurrences of the string in list.
|
||||
func removeFromList(s string, list []string) []string {
|
||||
filteredList := make([]string, 0, len(list))
|
||||
for _, ls := range list {
|
||||
if s != ls {
|
||||
filteredList = append(filteredList, ls)
|
||||
}
|
||||
}
|
||||
return filteredList
|
||||
}
|
||||
|
||||
// ensureDirectoriesExist is a shortcut to os.MkdirAll, sending errors to the ctx logger.
|
||||
func ensureDirectoriesExist(ctx Context, dirs ...string) {
|
||||
for _, dir := range dirs {
|
||||
|
Reference in New Issue
Block a user