// TranslateExitCode translates errors from the "os/exec" package that // contain exit codes into cmdline.ErrExitCode errors. func TranslateExitCode(err error) error { if exit, ok := err.(*exec.ExitError); ok { if wait, ok := exit.Sys().(syscall.WaitStatus); ok { if status := wait.ExitStatus(); wait.Exited() && status != 0 { return cmdline.ErrExitCode(status) } } } return err }
// InstallTools installs the tools from the given directory into // $JIRI_ROOT/devtools/bin. func InstallTools(ctx *tool.Context, dir string) error { ctx.TimerPush("install tools") defer ctx.TimerPop() if ctx.DryRun() { // In "dry run" mode, no binaries are built. return nil } binDir, err := ToAbs(devtoolsBinDir) if err != nil { return err } fis, err := ioutil.ReadDir(dir) if err != nil { return fmt.Errorf("ReadDir(%v) failed: %v", dir, err) } failed := false for _, fi := range fis { installFn := func() error { src := filepath.Join(dir, fi.Name()) dst := filepath.Join(binDir, fi.Name()) if err := ctx.Run().Rename(src, dst); err != nil { return err } return nil } opts := runutil.Opts{Verbose: true} if err := ctx.Run().FunctionWithOpts(opts, installFn, "install tool %q", fi.Name()); err != nil { fmt.Fprintf(ctx.Stderr(), "%v\n", err) failed = true } } if failed { return cmdline.ErrExitCode(2) } // Delete old "v23" tool, and the old jiri-xprofile command. // TODO(nlacasse): Once everybody has had a chance to update, remove this // code. v23SubCmds := []string{ "jiri-xprofile", "v23", } for _, subCmd := range v23SubCmds { subCmdPath := filepath.Join(binDir, subCmd) if err := ctx.Run().RemoveAll(subCmdPath); err != nil { return err } } return nil }
// buildToolsFromMaster builds and installs all jiri tools using the version // available in the local master branch of the tools repository. Notably, this // function does not perform any version control operation on the master // branch. func buildToolsFromMaster(ctx *tool.Context, tools Tools, outputDir string) error { localProjects, err := LocalProjects(ctx, FastScan) if err != nil { return err } failed := false toolsToBuild, toolProjects := Tools{}, Projects{} toolNames := []string{} // Used for logging purposes. for _, tool := range tools { // Skip tools with no package specified. Besides increasing // robustness, this step also allows us to create jiri root // fakes without having to provide an implementation for the "jiri" // tool, which every manifest needs to specify. if tool.Package == "" { continue } project, ok := localProjects[tool.Project] if !ok { fmt.Errorf("unknown project %v for tool %v", tool.Project, tool.Name) } toolProjects[tool.Project] = project toolsToBuild[tool.Name] = tool toolNames = append(toolNames, tool.Name) } updateFn := func() error { return ApplyToLocalMaster(ctx, toolProjects, func() error { return BuildTools(ctx, toolsToBuild, outputDir) }) } // Always log the output of updateFn, irrespective of // the value of the verbose flag. opts := runutil.Opts{Verbose: true} if err := ctx.Run().FunctionWithOpts(opts, updateFn, "build tools: %v", strings.Join(toolNames, " ")); err != nil { fmt.Fprintf(ctx.Stderr(), "%v\n", err) failed = true } if failed { return cmdline.ErrExitCode(2) } return nil }
func runSnapshotList(env *cmdline.Env, args []string) error { ctx := tool.NewContextFromEnv(env) if err := checkSnapshotDir(ctx); err != nil { return err } snapshotDir, err := getSnapshotDir() if err != nil { return err } if len(args) == 0 { // Identify all known snapshot labels, using a // heuristic that looks for all symbolic links <foo> // in the snapshot directory that point to a file in // the "labels/<foo>" subdirectory of the snapshot // directory. fileInfoList, err := ioutil.ReadDir(snapshotDir) if err != nil { return fmt.Errorf("ReadDir(%v) failed: %v", snapshotDir, err) } for _, fileInfo := range fileInfoList { if fileInfo.Mode()&os.ModeSymlink != 0 { path := filepath.Join(snapshotDir, fileInfo.Name()) dst, err := filepath.EvalSymlinks(path) if err != nil { return fmt.Errorf("EvalSymlinks(%v) failed: %v", path, err) } if strings.HasSuffix(filepath.Dir(dst), filepath.Join("labels", fileInfo.Name())) { args = append(args, fileInfo.Name()) } } } } // Check that all labels exist. failed := false for _, label := range args { labelDir := filepath.Join(snapshotDir, "labels", label) if _, err := ctx.Run().Stat(labelDir); err != nil { if !os.IsNotExist(err) { return err } failed = true fmt.Fprintf(env.Stderr, "snapshot label %q not found", label) } } if failed { return cmdline.ErrExitCode(2) } // Print snapshots for all labels. sort.Strings(args) for _, label := range args { // Scan the snapshot directory "labels/<label>" printing // all snapshots. labelDir := filepath.Join(snapshotDir, "labels", label) fileInfoList, err := ioutil.ReadDir(labelDir) if err != nil { return fmt.Errorf("ReadDir(%v) failed: %v", labelDir, err) } fmt.Fprintf(env.Stdout, "snapshots of label %q:\n", label) for _, fileInfo := range fileInfoList { fmt.Fprintf(env.Stdout, " %v\n", fileInfo.Name()) } } return nil }
func updateProjects(ctx *tool.Context, remoteProjects Projects, gc bool) error { ctx.TimerPush("update projects") defer ctx.TimerPop() scanMode := FastScan if gc { scanMode = FullScan } localProjects, err := LocalProjects(ctx, scanMode) if err != nil { return err } gitHost, gitHostErr := GitHost(ctx) if gitHostErr == nil && googlesource.IsGoogleSourceHost(gitHost) { // Attempt to get the repo statuses from remote so we can detect when a // local project is already up-to-date. if repoStatuses, err := googlesource.GetRepoStatuses(ctx, gitHost); err != nil { // Log the error but don't fail. fmt.Fprintf(ctx.Stderr(), "Error fetching repo statuses from remote: %v\n", err) } else { for name, rp := range remoteProjects { status, ok := repoStatuses[rp.Name] if !ok { continue } masterRev, ok := status.Branches["master"] if !ok || masterRev == "" { continue } rp.Revision = masterRev remoteProjects[name] = rp } } } ops, err := computeOperations(localProjects, remoteProjects, gc) if err != nil { return err } for _, op := range ops { if err := op.Test(ctx); err != nil { return err } } failed := false manifest := &Manifest{Label: ctx.Manifest()} for _, op := range ops { updateFn := func() error { return op.Run(ctx, manifest) } // Always log the output of updateFn, irrespective of // the value of the verbose flag. opts := runutil.Opts{Verbose: true} if err := ctx.Run().FunctionWithOpts(opts, updateFn, "%v", op); err != nil { fmt.Fprintf(ctx.Stderr(), "%v\n", err) failed = true } } if failed { return cmdline.ErrExitCode(2) } if err := writeCurrentManifest(ctx, manifest); err != nil { return err } return nil }