func TestBuildLotsOfTargets(t *testing.T) {
	config, _ := core.ReadConfigFiles(nil)
	state := core.NewBuildState(numWorkers, nil, 4, config)
	pkg := core.NewPackage("pkg")
	state.Graph.AddPackage(pkg)
	for i := 1; i <= size; i++ {
		addTarget(state, i)
	}
	var wg sync.WaitGroup
	wg.Add(numWorkers)
	for i := 0; i < numWorkers; i++ {
		go func() {
			please(i, state)
			wg.Done()
		}()
	}
	// Consume and discard any results
	go func() {
		for result := range state.Results {
			assert.NotEqual(t, core.TargetBuildFailed, result.Status)
			log.Info("%s", result.Description)
		}
	}()
	state.TaskDone() // Initial target adding counts as one.
	wg.Wait()
}
func newState(label string) (*core.BuildState, *core.BuildTarget) {
	config, _ := core.ReadConfigFiles(nil)
	state := core.NewBuildState(1, nil, 4, config)
	target := core.NewBuildTarget(core.ParseBuildLabel(label, ""))
	target.Command = fmt.Sprintf("echo 'output of %s' > $OUT", target.Label)
	state.Graph.AddTarget(target)
	return state, target
}
func TestBazelCompatReplacements(t *testing.T) {
	// Check that we don't do any of these things normally.
	target := makeTarget("//path/to:target", "cp $< $@", nil)
	assert.Equal(t, "cp $< $@", replaceSequences(target))
	// In Bazel compat mode we do though.
	state := core.NewBuildState(1, nil, 1, core.DefaultConfiguration())
	state.Config.Bazel.Compatibility = true
	assert.Equal(t, "cp $SRCS $OUTS", replaceSequences(target))
	// @D is the output dir, for us it's the tmp dir.
	target.Command = "cp $SRCS $@D"
	assert.Equal(t, "cp $SRCS $TMP_DIR", replaceSequences(target))
	// This parenthesised syntax seems to be allowed too.
	target.Command = "cp $(<) $(@)"
	assert.Equal(t, "cp $SRCS $OUTS", replaceSequences(target))
}
func TestGetSubincludeFile(t *testing.T) {
	assertError := func(t *testing.T, ret, msg string) { assert.True(t, strings.HasPrefix(ret, "__"), msg) }

	state := core.NewBuildState(10, nil, 2, core.DefaultConfiguration())
	pkg := core.NewPackage("src/parse")
	pkg2 := core.NewPackage("src/core")
	assert.Equal(t, pyDeferParse, getSubincludeFile(pkg, "//src/core:target"), "Package not loaded yet, should defer")
	assertError(t, getSubincludeFile(pkg, "//src/parse:target"), "Should produce an error on attempts for local subincludes.")
	assertError(t, getSubincludeFile(pkg, ":target"), "Should produce an error on attempts for local subincludes.")
	state.Graph.AddPackage(pkg)
	state.Graph.AddPackage(pkg2)
	assertError(t, getSubincludeFile(pkg, "//src/core:target"), "Produces an error, target does not exist in package.")
	target := core.NewBuildTarget(core.ParseBuildLabel("//src/core:target", ""))
	state.Graph.AddTarget(target)
	assertError(t, getSubincludeFile(pkg, "//src/core:target"), "Errors, target is not visible to subincluding package.")
	target.Visibility = []core.BuildLabel{core.ParseBuildLabel("//src/parse:all", "")}
	assertError(t, getSubincludeFile(pkg, "//src/core:target"), "Errors, target doesn't have any outputs to include.")
	target.AddOutput("test.py")
	assert.Equal(t, pyDeferParse, getSubincludeFile(pkg, "//src/core:target"), "Target isn't built yet, so still deferred")
	target.SetState(core.Built)
	assert.Equal(t, "plz-out/gen/src/core/test.py", getSubincludeFile(pkg, "//src/core:target"), "Success at last")
}
func TestGetLabels(t *testing.T) {
	state := core.NewBuildState(10, nil, 2, core.DefaultConfiguration())
	target1 := core.NewBuildTarget(core.ParseBuildLabel("//src/parse:target1", ""))
	target2 := core.NewBuildTarget(core.ParseBuildLabel("//src/parse:target2", ""))
	target3 := core.NewBuildTarget(core.ParseBuildLabel("//src/parse:target3", ""))
	target1.AddLabel("go")
	target2.AddLabel("py")
	target3.AddLabel("cc")
	target1.AddDependency(target2.Label)
	target1.AddDependency(target3.Label)
	target2.AddDependency(target3.Label)
	state.Graph.AddTarget(target1)
	state.Graph.AddTarget(target2)
	state.Graph.AddTarget(target3)
	state.Graph.AddDependency(target1.Label, target2.Label)
	state.Graph.AddDependency(target1.Label, target3.Label)
	state.Graph.AddDependency(target2.Label, target3.Label)
	// Note labels always come out in sorted order.
	assert.Equal(t, []string{"cc", "go", "py"}, getLabels(target1, "", core.Inactive))
	assert.Equal(t, []string{"cc", "py"}, getLabels(target2, "", core.Inactive))
	assert.Equal(t, []string{"cc"}, getLabels(target3, "", core.Inactive))
	assert.Equal(t, []string{"y"}, getLabels(target1, "p", core.Inactive))
}
// makeState creates a new build state with optionally one or two packages in it.
// Used in various tests above.
func makeState(withPackage1, withPackage2 bool) *core.BuildState {
	state := core.NewBuildState(5, nil, 4, core.DefaultConfiguration())
	if withPackage1 {
		pkg := core.NewPackage("package1")
		state.Graph.AddPackage(pkg)
		pkg.Targets["target1"] = makeTarget("//package1:target1", "//package1:target2", "//package2:target1")
		pkg.Targets["target2"] = makeTarget("//package1:target2", "//package2:target1")
		pkg.Targets["target3"] = makeTarget("//package1:target3", "//package2:target2")
		state.Graph.AddTarget(pkg.Targets["target1"])
		state.Graph.AddTarget(pkg.Targets["target2"])
		state.Graph.AddTarget(pkg.Targets["target3"])
		addDeps(state.Graph, pkg)
	}
	if withPackage2 {
		pkg := core.NewPackage("package2")
		state.Graph.AddPackage(pkg)
		pkg.Targets["target1"] = makeTarget("//package2:target1", "//package2:target2", "//package1:target3")
		pkg.Targets["target2"] = makeTarget("//package2:target2")
		state.Graph.AddTarget(pkg.Targets["target1"])
		state.Graph.AddTarget(pkg.Targets["target2"])
		addDeps(state.Graph, pkg)
	}
	return state
}
func init() {
	core.NewBuildState(1, nil, 1, core.DefaultConfiguration())
}
func TestMain(m *testing.M) {
	core.NewBuildState(10, nil, 2, core.DefaultConfiguration())
	// Need to set this before calling parseSource.
	core.State.Config.Please.BuildFileName = []string{"TEST_BUILD"}
	os.Exit(m.Run())
}
func TestMain(m *testing.M) {
	// Need to set this before calling parseSource. It's a bit of a hack but whatevs.
	buildFileNames = []string{"TEST_BUILD"}
	core.NewBuildState(10, nil, 2, core.DefaultConfiguration())
	os.Exit(m.Run())
}
Example #10
0
func init() {
	cache = newCache(cachePath)
	core.NewBuildState(1, nil, 4, core.DefaultConfiguration())
}
Example #11
0
func main() {
	parser, extraArgs, flagsErr := cli.ParseFlags("Please", &opts, os.Args)
	// Note that we must leave flagsErr for later, because it may be affected by aliases.
	if opts.OutputFlags.Version {
		fmt.Printf("Please version %s\n", core.PleaseVersion)
		os.Exit(0) // Ignore other errors if --version was passed.
	}
	if opts.OutputFlags.Colour {
		output.SetColouredOutput(true)
	} else if opts.OutputFlags.NoColour {
		output.SetColouredOutput(false)
	}
	if opts.OutputFlags.ShowAllOutput {
		opts.OutputFlags.PlainOutput = true
	}
	// Init logging, but don't do file output until we've chdir'd.
	cli.InitLogging(opts.OutputFlags.Verbosity)

	command := activeCommand(parser)
	if command == "init" {
		if flagsErr != nil { // This error otherwise doesn't get checked until later.
			cli.ParseFlagsFromArgsOrDie("Please", core.PleaseVersion.String(), &opts, os.Args)
		}
		// If we're running plz init then we obviously don't expect to read a config file.
		utils.InitConfig(opts.Init.Dir, opts.Init.BazelCompatibility)
		os.Exit(0)
	}
	if opts.BuildFlags.RepoRoot == "" {
		core.FindRepoRoot(true)
		log.Debug("Found repo root at %s", core.RepoRoot)
	} else {
		core.RepoRoot = opts.BuildFlags.RepoRoot
	}

	// Please always runs from the repo root, so move there now.
	if err := os.Chdir(core.RepoRoot); err != nil {
		log.Fatalf("%s", err)
	}
	// Reset this now we're at the repo root.
	if opts.OutputFlags.LogFile != "" {
		cli.InitFileLogging(path.Join(core.RepoRoot, opts.OutputFlags.LogFile), opts.OutputFlags.LogFileLevel)
	}

	config = readConfig(command == "update")
	// Set this in case anything wants to use it soon
	core.NewBuildState(config.Please.NumThreads, nil, opts.OutputFlags.Verbosity, config)

	// Now we've read the config file, we may need to re-run the parser; the aliases in the config
	// can affect how we parse otherwise illegal flag combinations.
	if flagsErr != nil || len(extraArgs) > 0 {
		argv := strings.Join(os.Args, " ")
		for k, v := range config.Aliases {
			argv = strings.Replace(argv, k, v, 1)
		}
		parser = cli.ParseFlagsFromArgsOrDie("Please", core.PleaseVersion.String(), &opts, strings.Fields(argv))
		command = activeCommand(parser)
	}

	if !buildFunctions[command]() {
		os.Exit(7) // Something distinctive, is sometimes useful to identify this externally.
	}
}
Example #12
0
func Please(targets []core.BuildLabel, config *core.Configuration, prettyOutput, shouldBuild, shouldTest bool) (bool, *core.BuildState) {
	if opts.BuildFlags.NumThreads > 0 {
		config.Please.NumThreads = opts.BuildFlags.NumThreads
	} else if config.Please.NumThreads <= 0 {
		config.Please.NumThreads = runtime.NumCPU() + 2
	}
	if opts.NoCacheCleaner {
		config.Cache.DirCacheCleaner = ""
	}
	if opts.BuildFlags.Config != "" {
		config.Build.Config = opts.BuildFlags.Config
	}
	var c *core.Cache
	if !opts.FeatureFlags.NoCache {
		c = cache.NewCache(config)
	}
	state := core.NewBuildState(config.Please.NumThreads, c, opts.OutputFlags.Verbosity, config)
	state.VerifyHashes = !opts.FeatureFlags.NoHashVerification
	state.NumTestRuns = opts.Test.NumRuns + opts.Cover.NumRuns            // Only one of these can be passed.
	state.TestArgs = append(opts.Test.Args.Args, opts.Cover.Args.Args...) // Similarly here.
	state.NeedCoverage = !opts.Cover.Args.Target.IsEmpty()
	state.NeedBuild = shouldBuild
	state.NeedTests = shouldTest
	state.NeedHashesOnly = len(opts.Hash.Args.Targets) > 0
	state.PrepareOnly = opts.Build.Prepare
	state.CleanWorkdirs = !opts.FeatureFlags.KeepWorkdirs
	state.ForceRebuild = len(opts.Rebuild.Args.Targets) > 0
	state.ShowTestOutput = opts.Test.ShowOutput || opts.Cover.ShowOutput
	state.ShowAllOutput = opts.OutputFlags.ShowAllOutput
	state.SetIncludeAndExclude(opts.BuildFlags.Include, opts.BuildFlags.Exclude)
	metrics.InitFromConfig(config)
	// Acquire the lock before we start building
	if (shouldBuild || shouldTest) && !opts.FeatureFlags.NoLock {
		core.AcquireRepoLock()
		defer core.ReleaseRepoLock()
	}
	if opts.BuildFlags.Engine != "" {
		state.Config.Please.ParserEngine = opts.BuildFlags.Engine
	}
	// Start looking for the initial targets to kick the build off
	go findOriginalTasks(state, targets)
	// Start up all the build workers
	var wg sync.WaitGroup
	wg.Add(config.Please.NumThreads)
	for i := 0; i < config.Please.NumThreads; i++ {
		go func(tid int) {
			please(tid, state, opts.ParsePackageOnly, opts.BuildFlags.Include, opts.BuildFlags.Exclude)
			wg.Done()
		}(i)
	}
	// Wait until they've all exited, which they'll do once they have no tasks left.
	go func() {
		wg.Wait()
		close(state.Results) // This will signal MonitorState (below) to stop.
	}()
	// Draw stuff to the screen while there are still results coming through.
	shouldRun := !opts.Run.Args.Target.IsEmpty()
	success := output.MonitorState(state, config.Please.NumThreads, !prettyOutput, opts.BuildFlags.KeepGoing, shouldBuild, shouldTest, shouldRun, opts.OutputFlags.TraceFile)
	metrics.Stop()
	if c != nil {
		(*c).Shutdown()
	}
	return success, state
}