func checkAndReplaceSequence(target, dep *core.BuildTarget, in string, runnable, multiple, dir, outPrefix, hash, test, allOutputs, tool bool) string { if allOutputs && !multiple && len(dep.Outputs()) != 1 { // Label must have only one output. panic(fmt.Sprintf("Rule %s can't use %s; %s has multiple outputs.", target.Label, in, dep.Label)) } else if runnable && !dep.IsBinary { panic(fmt.Sprintf("Rule %s can't $(exe %s), it's not executable", target.Label, dep.Label)) } else if runnable && len(dep.Outputs()) == 0 { panic(fmt.Sprintf("Rule %s is tagged as binary but produces no output.", dep.Label)) } if hash { return base64.RawURLEncoding.EncodeToString(mustShortTargetHash(core.State, dep)) } output := "" for _, out := range dep.Outputs() { if allOutputs || out == in { if tool { abs, err := filepath.Abs(handleDir(dep.OutDir(), out, dir)) if err != nil { log.Fatalf("Couldn't calculate relative path: %s", err) } output += quote(abs) + " " } else { output += quote(fileDestination(target, dep, out, dir, outPrefix, test)) + " " } if dir { break } } } if runnable && dep.HasLabel("java_non_exe") { // The target is a Java target that isn't self-executable, hence it needs something to run it. output = "java -jar " + output } return strings.TrimRight(output, " ") }
// buildFilegroup runs the manual build steps for a filegroup rule. // We don't force this to be done in bash to avoid errors with maximum command lengths, // and it's actually quite fiddly to get just so there. func buildFilegroup(tid int, state *core.BuildState, target *core.BuildTarget) error { if err := prepareDirectory(target.OutDir(), false); err != nil { return err } if err := os.RemoveAll(ruleHashFileName(target)); err != nil { return err } changed := false outDir := target.OutDir() for _, source := range target.Sources { fullPaths := source.FullPaths(state.Graph) for i, sourcePath := range source.LocalPaths(state.Graph) { outPath := path.Join(outDir, sourcePath) c, err := moveOutput(target, fullPaths[i], outPath, true) if err != nil { return err } changed = changed || c } } if target.HasLabel("py") && !target.IsBinary { // Pre-emptively create __init__.py files so the outputs can be loaded dynamically. // It's a bit cheeky to do non-essential language-specific logic but this enables // a lot of relatively normal Python workflows. // Errors are deliberately ignored. createInitPy(outDir) } if _, err := calculateAndCheckRuleHash(state, target); err != nil { return err } else if changed { target.SetState(core.Built) } else { target.SetState(core.Unchanged) } state.LogBuildResult(tid, target.Label, core.TargetBuilt, "Built") return nil }