github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/cmd/soong_ui/main.go (about)

     1  // Copyright 2017 Google Inc. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"context"
    19  	"flag"
    20  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  
    27  	"android/soong/ui/build"
    28  	"android/soong/ui/logger"
    29  	"android/soong/ui/tracer"
    30  )
    31  
    32  func indexList(s string, list []string) int {
    33  	for i, l := range list {
    34  		if l == s {
    35  			return i
    36  		}
    37  	}
    38  
    39  	return -1
    40  }
    41  
    42  func inList(s string, list []string) bool {
    43  	return indexList(s, list) != -1
    44  }
    45  
    46  func main() {
    47  	log := logger.New(os.Stderr)
    48  	defer log.Cleanup()
    49  
    50  	if len(os.Args) < 2 || !(inList("--make-mode", os.Args) ||
    51  		os.Args[1] == "--dumpvars-mode" ||
    52  		os.Args[1] == "--dumpvar-mode") {
    53  
    54  		log.Fatalln("The `soong` native UI is not yet available.")
    55  	}
    56  
    57  	ctx, cancel := context.WithCancel(context.Background())
    58  	defer cancel()
    59  
    60  	trace := tracer.New(log)
    61  	defer trace.Close()
    62  
    63  	build.SetupSignals(log, cancel, func() {
    64  		trace.Close()
    65  		log.Cleanup()
    66  	})
    67  
    68  	buildCtx := build.Context{&build.ContextImpl{
    69  		Context:        ctx,
    70  		Logger:         log,
    71  		Tracer:         trace,
    72  		StdioInterface: build.StdioImpl{},
    73  	}}
    74  	var config build.Config
    75  	if os.Args[1] == "--dumpvars-mode" || os.Args[1] == "--dumpvar-mode" {
    76  		config = build.NewConfig(buildCtx)
    77  	} else {
    78  		config = build.NewConfig(buildCtx, os.Args[1:]...)
    79  	}
    80  
    81  	log.SetVerbose(config.IsVerbose())
    82  	build.SetupOutDir(buildCtx, config)
    83  
    84  	if config.Dist() {
    85  		logsDir := filepath.Join(config.DistDir(), "logs")
    86  		os.MkdirAll(logsDir, 0777)
    87  		log.SetOutput(filepath.Join(logsDir, "soong.log"))
    88  		trace.SetOutput(filepath.Join(logsDir, "build.trace"))
    89  	} else {
    90  		log.SetOutput(filepath.Join(config.OutDir(), "soong.log"))
    91  		trace.SetOutput(filepath.Join(config.OutDir(), "build.trace"))
    92  	}
    93  
    94  	if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
    95  		if !strings.HasSuffix(start, "N") {
    96  			if start_time, err := strconv.ParseUint(start, 10, 64); err == nil {
    97  				log.Verbosef("Took %dms to start up.",
    98  					time.Since(time.Unix(0, int64(start_time))).Nanoseconds()/time.Millisecond.Nanoseconds())
    99  				buildCtx.CompleteTrace("startup", start_time, uint64(time.Now().UnixNano()))
   100  			}
   101  		}
   102  
   103  		if executable, err := os.Executable(); err == nil {
   104  			trace.ImportMicrofactoryLog(filepath.Join(filepath.Dir(executable), "."+filepath.Base(executable)+".trace"))
   105  		}
   106  	}
   107  
   108  	f := build.NewSourceFinder(buildCtx, config)
   109  	defer f.Shutdown()
   110  	build.FindSources(buildCtx, config, f)
   111  
   112  	if os.Args[1] == "--dumpvar-mode" {
   113  		dumpVar(buildCtx, config, os.Args[2:])
   114  	} else if os.Args[1] == "--dumpvars-mode" {
   115  		dumpVars(buildCtx, config, os.Args[2:])
   116  	} else {
   117  		toBuild := build.BuildAll
   118  		if config.Checkbuild() {
   119  			toBuild |= build.RunBuildTests
   120  		}
   121  		build.Build(buildCtx, config, toBuild)
   122  	}
   123  }
   124  
   125  func dumpVar(ctx build.Context, config build.Config, args []string) {
   126  	flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
   127  	flags.Usage = func() {
   128  		fmt.Fprintf(os.Stderr, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
   129  		fmt.Fprintln(os.Stderr, "In dumpvar mode, print the value of the legacy make variable VAR to stdout")
   130  		fmt.Fprintln(os.Stderr, "")
   131  
   132  		fmt.Fprintln(os.Stderr, "'report_config' is a special case that prints the human-readable config banner")
   133  		fmt.Fprintln(os.Stderr, "from the beginning of the build.")
   134  		fmt.Fprintln(os.Stderr, "")
   135  		flags.PrintDefaults()
   136  	}
   137  	abs := flags.Bool("abs", false, "Print the absolute path of the value")
   138  	flags.Parse(args)
   139  
   140  	if flags.NArg() != 1 {
   141  		flags.Usage()
   142  		os.Exit(1)
   143  	}
   144  
   145  	varName := flags.Arg(0)
   146  	if varName == "report_config" {
   147  		varData, err := build.DumpMakeVars(ctx, config, nil, build.BannerVars)
   148  		if err != nil {
   149  			ctx.Fatal(err)
   150  		}
   151  
   152  		fmt.Println(build.Banner(varData))
   153  	} else {
   154  		varData, err := build.DumpMakeVars(ctx, config, nil, []string{varName})
   155  		if err != nil {
   156  			ctx.Fatal(err)
   157  		}
   158  
   159  		if *abs {
   160  			var res []string
   161  			for _, path := range strings.Fields(varData[varName]) {
   162  				if abs, err := filepath.Abs(path); err == nil {
   163  					res = append(res, abs)
   164  				} else {
   165  					ctx.Fatalln("Failed to get absolute path of", path, err)
   166  				}
   167  			}
   168  			fmt.Println(strings.Join(res, " "))
   169  		} else {
   170  			fmt.Println(varData[varName])
   171  		}
   172  	}
   173  }
   174  
   175  func dumpVars(ctx build.Context, config build.Config, args []string) {
   176  	flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
   177  	flags.Usage = func() {
   178  		fmt.Fprintf(os.Stderr, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
   179  		fmt.Fprintln(os.Stderr, "In dumpvars mode, dump the values of one or more legacy make variables, in")
   180  		fmt.Fprintln(os.Stderr, "shell syntax. The resulting output may be sourced directly into a shell to")
   181  		fmt.Fprintln(os.Stderr, "set corresponding shell variables.")
   182  		fmt.Fprintln(os.Stderr, "")
   183  
   184  		fmt.Fprintln(os.Stderr, "'report_config' is a special case that dumps a variable containing the")
   185  		fmt.Fprintln(os.Stderr, "human-readable config banner from the beginning of the build.")
   186  		fmt.Fprintln(os.Stderr, "")
   187  		flags.PrintDefaults()
   188  	}
   189  
   190  	varsStr := flags.String("vars", "", "Space-separated list of variables to dump")
   191  	absVarsStr := flags.String("abs-vars", "", "Space-separated list of variables to dump (using absolute paths)")
   192  
   193  	varPrefix := flags.String("var-prefix", "", "String to prepend to all variable names when dumping")
   194  	absVarPrefix := flags.String("abs-var-prefix", "", "String to prepent to all absolute path variable names when dumping")
   195  
   196  	flags.Parse(args)
   197  
   198  	if flags.NArg() != 0 {
   199  		flags.Usage()
   200  		os.Exit(1)
   201  	}
   202  
   203  	vars := strings.Fields(*varsStr)
   204  	absVars := strings.Fields(*absVarsStr)
   205  
   206  	allVars := append([]string{}, vars...)
   207  	allVars = append(allVars, absVars...)
   208  
   209  	if i := indexList("report_config", allVars); i != -1 {
   210  		allVars = append(allVars[:i], allVars[i+1:]...)
   211  		allVars = append(allVars, build.BannerVars...)
   212  	}
   213  
   214  	if len(allVars) == 0 {
   215  		return
   216  	}
   217  
   218  	varData, err := build.DumpMakeVars(ctx, config, nil, allVars)
   219  	if err != nil {
   220  		ctx.Fatal(err)
   221  	}
   222  
   223  	for _, name := range vars {
   224  		if name == "report_config" {
   225  			fmt.Printf("%sreport_config='%s'\n", *varPrefix, build.Banner(varData))
   226  		} else {
   227  			fmt.Printf("%s%s='%s'\n", *varPrefix, name, varData[name])
   228  		}
   229  	}
   230  	for _, name := range absVars {
   231  		var res []string
   232  		for _, path := range strings.Fields(varData[name]) {
   233  			abs, err := filepath.Abs(path)
   234  			if err != nil {
   235  				ctx.Fatalln("Failed to get absolute path of", path, err)
   236  			}
   237  			res = append(res, abs)
   238  		}
   239  		fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
   240  	}
   241  }