github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/blueprint/bootstrap/command.go (about)

     1  // Copyright 2014 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 bootstrap
    16  
    17  import (
    18  	"bytes"
    19  	"flag"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  	"runtime"
    25  	"runtime/debug"
    26  	"runtime/pprof"
    27  	"runtime/trace"
    28  
    29  	"github.com/google/blueprint"
    30  	"github.com/google/blueprint/deptools"
    31  )
    32  
    33  var (
    34  	outFile        string
    35  	depFile        string
    36  	docFile        string
    37  	cpuprofile     string
    38  	memprofile     string
    39  	traceFile      string
    40  	runGoTests     bool
    41  	noGC           bool
    42  	moduleListFile string
    43  
    44  	BuildDir      string
    45  	NinjaBuildDir string
    46  	SrcDir        string
    47  )
    48  
    49  func init() {
    50  	flag.StringVar(&outFile, "o", "build.ninja", "the Ninja file to output")
    51  	flag.StringVar(&BuildDir, "b", ".", "the build output directory")
    52  	flag.StringVar(&NinjaBuildDir, "n", "", "the ninja builddir directory")
    53  	flag.StringVar(&depFile, "d", "", "the dependency file to output")
    54  	flag.StringVar(&docFile, "docs", "", "build documentation file to output")
    55  	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
    56  	flag.StringVar(&traceFile, "trace", "", "write trace to file")
    57  	flag.StringVar(&memprofile, "memprofile", "", "write memory profile to file")
    58  	flag.BoolVar(&noGC, "nogc", false, "turn off GC for debugging")
    59  	flag.BoolVar(&runGoTests, "t", false, "build and run go tests during bootstrap")
    60  	flag.StringVar(&moduleListFile, "l", "", "file that lists filepaths to parse")
    61  }
    62  
    63  func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...string) {
    64  	if !flag.Parsed() {
    65  		flag.Parse()
    66  	}
    67  
    68  	runtime.GOMAXPROCS(runtime.NumCPU())
    69  
    70  	if noGC {
    71  		debug.SetGCPercent(-1)
    72  	}
    73  
    74  	if cpuprofile != "" {
    75  		f, err := os.Create(cpuprofile)
    76  		if err != nil {
    77  			fatalf("error opening cpuprofile: %s", err)
    78  		}
    79  		pprof.StartCPUProfile(f)
    80  		defer f.Close()
    81  		defer pprof.StopCPUProfile()
    82  	}
    83  
    84  	if traceFile != "" {
    85  		f, err := os.Create(traceFile)
    86  		if err != nil {
    87  			fatalf("error opening trace: %s", err)
    88  		}
    89  		trace.Start(f)
    90  		defer f.Close()
    91  		defer trace.Stop()
    92  	}
    93  
    94  	if flag.NArg() != 1 {
    95  		fatalf("no Blueprints file specified")
    96  	}
    97  
    98  	SrcDir = filepath.Dir(flag.Arg(0))
    99  	if moduleListFile != "" {
   100  		ctx.SetModuleListFile(moduleListFile)
   101  		extraNinjaFileDeps = append(extraNinjaFileDeps, moduleListFile)
   102  	} else {
   103  		fatalf("-l <moduleListFile> is required and must be nonempty")
   104  	}
   105  	filesToParse, err := ctx.ListModulePaths(SrcDir)
   106  	if err != nil {
   107  		fatalf("could not enumerate files: %v\n", err.Error())
   108  	}
   109  
   110  	if NinjaBuildDir == "" {
   111  		NinjaBuildDir = BuildDir
   112  	}
   113  
   114  	stage := StageMain
   115  	if c, ok := config.(ConfigInterface); ok {
   116  		if c.GeneratingPrimaryBuilder() {
   117  			stage = StagePrimary
   118  		}
   119  	}
   120  
   121  	bootstrapConfig := &Config{
   122  		stage: stage,
   123  		topLevelBlueprintsFile: flag.Arg(0),
   124  		runGoTests:             runGoTests,
   125  		moduleListFile:         moduleListFile,
   126  	}
   127  
   128  	ctx.RegisterBottomUpMutator("bootstrap_plugin_deps", pluginDeps)
   129  	ctx.RegisterModuleType("bootstrap_go_package", newGoPackageModuleFactory(bootstrapConfig))
   130  	ctx.RegisterModuleType("bootstrap_go_binary", newGoBinaryModuleFactory(bootstrapConfig, false))
   131  	ctx.RegisterModuleType("blueprint_go_binary", newGoBinaryModuleFactory(bootstrapConfig, true))
   132  	ctx.RegisterSingletonType("bootstrap", newSingletonFactory(bootstrapConfig))
   133  
   134  	ctx.RegisterSingletonType("glob", globSingletonFactory(ctx))
   135  
   136  	deps, errs := ctx.ParseFileList(filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), filesToParse)
   137  	if len(errs) > 0 {
   138  		fatalErrors(errs)
   139  	}
   140  
   141  	// Add extra ninja file dependencies
   142  	deps = append(deps, extraNinjaFileDeps...)
   143  
   144  	extraDeps, errs := ctx.ResolveDependencies(config)
   145  	if len(errs) > 0 {
   146  		fatalErrors(errs)
   147  	}
   148  	deps = append(deps, extraDeps...)
   149  
   150  	if docFile != "" {
   151  		err := writeDocs(ctx, docFile)
   152  		if err != nil {
   153  			fatalErrors([]error{err})
   154  		}
   155  		return
   156  	}
   157  
   158  	if c, ok := config.(ConfigStopBefore); ok {
   159  		if c.StopBefore() == StopBeforePrepareBuildActions {
   160  			return
   161  		}
   162  	}
   163  
   164  	extraDeps, errs = ctx.PrepareBuildActions(config)
   165  	if len(errs) > 0 {
   166  		fatalErrors(errs)
   167  	}
   168  	deps = append(deps, extraDeps...)
   169  
   170  	buf := bytes.NewBuffer(nil)
   171  	err = ctx.WriteBuildFile(buf)
   172  	if err != nil {
   173  		fatalf("error generating Ninja file contents: %s", err)
   174  	}
   175  
   176  	const outFilePermissions = 0666
   177  	err = ioutil.WriteFile(outFile, buf.Bytes(), outFilePermissions)
   178  	if err != nil {
   179  		fatalf("error writing %s: %s", outFile, err)
   180  	}
   181  
   182  	if depFile != "" {
   183  		err := deptools.WriteDepFile(depFile, outFile, deps)
   184  		if err != nil {
   185  			fatalf("error writing depfile: %s", err)
   186  		}
   187  	}
   188  
   189  	if c, ok := config.(ConfigRemoveAbandonedFilesUnder); ok {
   190  		under := c.RemoveAbandonedFilesUnder()
   191  		err := removeAbandonedFilesUnder(ctx, bootstrapConfig, SrcDir, under)
   192  		if err != nil {
   193  			fatalf("error removing abandoned files: %s", err)
   194  		}
   195  	}
   196  
   197  	if memprofile != "" {
   198  		f, err := os.Create(memprofile)
   199  		if err != nil {
   200  			fatalf("error opening memprofile: %s", err)
   201  		}
   202  		defer f.Close()
   203  		pprof.WriteHeapProfile(f)
   204  	}
   205  }
   206  
   207  func fatalf(format string, args ...interface{}) {
   208  	fmt.Printf(format, args...)
   209  	fmt.Print("\n")
   210  	os.Exit(1)
   211  }
   212  
   213  func fatalErrors(errs []error) {
   214  	red := "\x1b[31m"
   215  	unred := "\x1b[0m"
   216  
   217  	for _, err := range errs {
   218  		switch err := err.(type) {
   219  		case *blueprint.BlueprintError,
   220  			*blueprint.ModuleError,
   221  			*blueprint.PropertyError:
   222  			fmt.Printf("%serror:%s %s\n", red, unred, err.Error())
   223  		default:
   224  			fmt.Printf("%sinternal error:%s %s\n", red, unred, err)
   225  		}
   226  	}
   227  	os.Exit(1)
   228  }