func linuxList(jirix *jiri.X, pkgs []string) (map[string]bool, error) { aptitude, yum, pacman := UsingAptitude(jirix), UsingYum(jirix), UsingPacman(jirix) cmd := "" opt := "" switch { case aptitude: cmd = "dpkg" opt = "-L" case yum: cmd = "yum" opt = "list" case pacman: cmd = "pacman" opt = "-Q" default: return nil, fmt.Errorf("no usable package manager found, tested for aptitude, yum and pacman") } s := jirix.NewSeq() installedPkgs := map[string]bool{} for _, pkg := range pkgs { if err := s.Capture(ioutil.Discard, ioutil.Discard).Last(cmd, opt, pkg); err == nil { installedPkgs[pkg] = true } } return installedPkgs, nil }
func packagesImpl(jirix *jiri.X, cl *packagesFlagValues, args []string) error { mgrs, _, err := availableProfileManagers(jirix, cl.dbPath, args) if err != nil { return err } cl.target.UseCommandLineEnv() root := jiri.NewRelPath(cl.root).Join(profileInstaller) s := jirix.NewSeq() installPackages := cl.installPackages // Never ask a subcommand to install packages. cl.installPackages = false for _, mgr := range mgrs { cmds, err := mgr.packageCmds(jirix, cl, root) if err != nil { return err } for _, cmd := range cmds { if installPackages { if err := s.Verbose(true).Last(cmd[0], cmd[1:]...); err != nil { return err } } else { fmt.Fprintf(jirix.Stdout(), "%s\n", strings.TrimSpace(strings.Join(cmd, " "))) } } } return nil }
func runUpdate(jirix *jiri.X, _ []string) error { seq := jirix.NewSeq() // Create the $JIRI_ROOT/.jiri_root directory if it doesn't already exist. // // TODO(toddw): Remove this logic after the transition to .jiri_root is done. // The bootstrapping logic should create this directory, and jiri should fail // if the directory doesn't exist. if err := seq.MkdirAll(jirix.RootMetaDir(), 0755).Done(); err != nil { return err } // Update all projects to their latest version. // Attempt <attemptsFlag> times before failing. updateFn := func() error { return project.UpdateUniverse(jirix, gcFlag) } if err := retry.Function(jirix.Context, updateFn, retry.AttemptsOpt(attemptsFlag)); err != nil { return err } if err := project.WriteUpdateHistorySnapshot(jirix, ""); err != nil { return err } // Only attempt the bin dir transition after the update has succeeded, to // avoid messy partial states. return project.TransitionBinDir(jirix) }
func getCommitMessageFileName(jirix *jiri.X, branch string) (string, error) { topLevel, err := gitutil.New(jirix.NewSeq()).TopLevel() if err != nil { return "", err } return filepath.Join(topLevel, jiri.ProjectMetaDir, branch, commitMessageFileName), nil }
func runRebuild(jirix *jiri.X, args []string) (e error) { projects, tools, err := project.LoadManifest(jirix) if err != nil { return err } // Create a temporary directory in which tools will be built. tmpDir, err := jirix.NewSeq().TempDir("", "tmp-jiri-rebuild") if err != nil { return fmt.Errorf("TempDir() failed: %v", err) } // Make sure we cleanup the temp directory. defer collect.Error(func() error { return jirix.NewSeq().RemoveAll(tmpDir).Done() }, &e) // Paranoid sanity checking. if _, ok := tools[project.JiriName]; !ok { return fmt.Errorf("tool %q not found", project.JiriName) } // Build and install tools. if err := project.BuildTools(jirix, projects, tools, tmpDir); err != nil { return err } return project.InstallTools(jirix, tmpDir) }
// AtomicAction performs an action 'atomically' by keeping track of successfully // completed actions in the supplied completion log and re-running them if they // are not successfully logged therein after deleting the entire contents of the // dir parameter. Consequently it does not make sense to apply AtomicAction to // the same directory in sequence. func AtomicAction(jirix *jiri.X, installFn func() error, dir, message string) error { atomicFn := func() error { completionLogPath := filepath.Join(dir, ".complete") s := jirix.NewSeq() if dir != "" { if exists, _ := s.IsDir(dir); exists { // If the dir exists but the completionLogPath doesn't, then it // means the previous action didn't finish. // Remove the dir so we can perform the action again. if exists, _ := s.IsFile(completionLogPath); !exists { s.RemoveAll(dir).Done() } else { if jirix.Verbose() { fmt.Fprintf(jirix.Stdout(), "AtomicAction: %s already completed in %s\n", message, dir) } return nil } } } if err := installFn(); err != nil { if dir != "" { s.RemoveAll(dir).Done() } return err } return s.WriteFile(completionLogPath, []byte("completed"), DefaultFilePerm).Done() } return jirix.NewSeq().Call(atomicFn, message).Done() }
// checkDependents makes sure that all CLs in the sequence of // dependent CLs leading to (but not including) the current branch // have been exported to Gerrit. func checkDependents(jirix *jiri.X) (e error) { originalBranch, err := gitutil.New(jirix.NewSeq()).CurrentBranchName() if err != nil { return err } branches, err := getDependentCLs(jirix, originalBranch) if err != nil { return err } for i := 1; i < len(branches); i++ { file, err := getCommitMessageFileName(jirix, branches[i]) if err != nil { return err } if _, err := jirix.NewSeq().Stat(file); err != nil { if !runutil.IsNotExist(err) { return err } return fmt.Errorf(`Failed to export the branch %q to Gerrit because its ancestor %q has not been exported to Gerrit yet. The following steps are needed before the operation can be retried: $ git checkout %v $ jiri cl mail $ git checkout %v # retry the original command `, originalBranch, branches[i], branches[i], originalBranch) } } return nil }
// assertFilesNotCommitted asserts that the files exist and are *not* // committed in the current branch. func assertFilesNotCommitted(t *testing.T, jirix *jiri.X, files []string) { assertFilesExist(t, jirix, files) for _, file := range files { if gitutil.New(jirix.NewSeq()).IsFileCommitted(file) { t.Fatalf("expected file %v not to be committed but it is", file) } } }
// assertStashSize asserts that the stash size matches the expected // size. func assertStashSize(t *testing.T, jirix *jiri.X, want int) { got, err := gitutil.New(jirix.NewSeq()).StashSize() if err != nil { t.Fatalf("%v", err) } if got != want { t.Fatalf("unxpected stash size: got %v, want %v", got, want) } }
// Untar untars the file in srcFile and puts resulting files in directory dstDir. func Untar(jirix *jiri.X, srcFile, dstDir string) error { s := jirix.NewSeq() if err := s.MkdirAll(dstDir, 0755).Done(); err != nil { return err } return s.Output([]string{"untarring " + srcFile + " into " + dstDir}). Pushd(dstDir). Last("tar", "xvf", srcFile) }
// assertCommitCount asserts that the commit count between two // branches matches the expectedCount. func assertCommitCount(t *testing.T, jirix *jiri.X, branch, baseBranch string, expectedCount int) { got, err := gitutil.New(jirix.NewSeq()).CountCommits(branch, baseBranch) if err != nil { t.Fatalf("%v", err) } if want := 1; got != want { t.Fatalf("unexpected number of commits: got %v, want %v", got, want) } }
// assertFilesPushedToRef asserts that the given files have been // pushed to the given remote repository reference. func assertFilesPushedToRef(t *testing.T, jirix *jiri.X, repoPath, gerritPath, pushedRef string, files []string) { chdir(t, jirix, gerritPath) assertCommitCount(t, jirix, pushedRef, "master", 1) if err := gitutil.New(jirix.NewSeq()).CheckoutBranch(pushedRef); err != nil { t.Fatalf("%v", err) } assertFilesCommitted(t, jirix, files) chdir(t, jirix, repoPath) }
// assertFileContent asserts that the content of the given file // matches the expected content. func assertFileContent(t *testing.T, jirix *jiri.X, file, want string) { got, err := jirix.NewSeq().ReadFile(file) if err != nil { t.Fatalf("%v\n", err) } if string(got) != want { t.Fatalf("unexpected content of file %v: got %v, want %v", file, got, want) } }
// assertFilesDoNotExist asserts that the files do not exist. func assertFilesDoNotExist(t *testing.T, jirix *jiri.X, files []string) { s := jirix.NewSeq() for _, file := range files { if _, err := s.Stat(file); err != nil && !runutil.IsNotExist(err) { t.Fatalf("%v", err) } else if err == nil { t.Fatalf("expected file %v to not exist but it did", file) } } }
// commitFile commits a file with the specified content into a branch func commitFile(t *testing.T, jirix *jiri.X, filename string, content string) { s := jirix.NewSeq() if err := s.WriteFile(filename, []byte(content), 0644).Done(); err != nil { t.Fatalf("%v", err) } commitMessage := "Commit " + filename if err := gitutil.New(jirix.NewSeq()).CommitFile(filename, commitMessage); err != nil { t.Fatalf("%v", err) } }
// createRepoFromOrigin creates a Git repo tracking origin/master. func createRepoFromOrigin(t *testing.T, jirix *jiri.X, subpath string, originPath string) string { repoPath := createRepo(t, jirix, subpath) chdir(t, jirix, repoPath) if err := gitutil.New(jirix.NewSeq()).AddRemote("origin", originPath); err != nil { t.Fatalf("%v", err) } if err := gitutil.New(jirix.NewSeq()).Pull("origin", "master"); err != nil { t.Fatalf("%v", err) } return repoPath }
// submit mocks a Gerrit review submit by pushing the Gerrit remote to origin. // Actually origin pulls from Gerrit since origin isn't actually a bare git repo. // Some of our tests actually rely on accessing .git in origin, so it must be non-bare. func submit(t *testing.T, jirix *jiri.X, originPath string, gerritPath string, review *review) { cwd, err := os.Getwd() if err != nil { t.Fatalf("Getwd() failed: %v", err) } chdir(t, jirix, originPath) expectedRef := gerrit.Reference(review.CLOpts) if err := gitutil.New(jirix.NewSeq()).Pull(gerritPath, expectedRef); err != nil { t.Fatalf("Pull gerrit to origin failed: %v", err) } chdir(t, jirix, cwd) }
func checkReadme(t *testing.T, jirix *jiri.X, p project.Project, message string) { if _, err := jirix.NewSeq().Stat(p.Path); err != nil { t.Fatalf("%v", err) } readmeFile := filepath.Join(p.Path, "README") data, err := ioutil.ReadFile(readmeFile) if err != nil { t.Fatalf("ReadFile(%v) failed: %v", readmeFile, err) } if got, want := data, []byte(message); bytes.Compare(got, want) != 0 { t.Fatalf("unexpected content in project %v:\ngot\n%s\nwant\n%s\n", p.Name, got, want) } }
func brewList(jirix *jiri.X) (map[string]bool, error) { var out bytes.Buffer err := jirix.NewSeq().Capture(&out, &out).Last("brew", "list") if err != nil || tool.VerboseFlag { fmt.Fprintf(jirix.Stdout(), "%s", out.String()) } scanner := bufio.NewScanner(&out) pkgs := map[string]bool{} for scanner.Scan() { pkgs[scanner.Text()] = true } return pkgs, err }
func checkReadme(t *testing.T, jirix *jiri.X, project, message string) { s := jirix.NewSeq() if _, err := s.Stat(project); err != nil { t.Fatalf("%v", err) } readmeFile := filepath.Join(project, "README") data, err := s.ReadFile(readmeFile) if err != nil { t.Fatalf("%v", err) } if got, want := data, []byte(message); bytes.Compare(got, want) != 0 { t.Fatalf("unexpected content %v:\ngot\n%s\nwant\n%s\n", project, got, want) } }
// Checks that /.jiri/ is ignored in a local project checkout func checkMetadataIsIgnored(t *testing.T, jirix *jiri.X, p project.Project) { if _, err := jirix.NewSeq().Stat(p.Path); err != nil { t.Fatalf("%v", err) } gitInfoExcludeFile := filepath.Join(p.Path, ".git", "info", "exclude") data, err := ioutil.ReadFile(gitInfoExcludeFile) if err != nil { t.Fatalf("ReadFile(%v) failed: %v", gitInfoExcludeFile, err) } excludeString := "/.jiri/" if !strings.Contains(string(data), excludeString) { t.Fatalf("Did not find \"%v\" in exclude file", excludeString) } }
func newCL(jirix *jiri.X, args []string) error { git := gitutil.New(jirix.NewSeq()) topLevel, err := git.TopLevel() if err != nil { return err } originalBranch, err := git.CurrentBranchName() if err != nil { return err } // Create a new branch using the current branch. newBranch := args[0] if err := git.CreateAndCheckoutBranch(newBranch); err != nil { return err } // Register a cleanup handler in case of subsequent errors. cleanup := true defer func() { if cleanup { git.CheckoutBranch(originalBranch, gitutil.ForceOpt(true)) git.DeleteBranch(newBranch, gitutil.ForceOpt(true)) } }() s := jirix.NewSeq() // Record the dependent CLs for the new branch. The dependent CLs // are recorded in a <dependencyPathFileName> file as a // newline-separated list of branch names. branches, err := getDependentCLs(jirix, originalBranch) if err != nil { return err } branches = append(branches, originalBranch) newMetadataDir := filepath.Join(topLevel, jiri.ProjectMetaDir, newBranch) if err := s.MkdirAll(newMetadataDir, os.FileMode(0755)).Done(); err != nil { return err } file, err := getDependencyPathFileName(jirix, newBranch) if err != nil { return err } if err := s.WriteFile(file, []byte(strings.Join(branches, "\n")), os.FileMode(0644)).Done(); err != nil { return err } cleanup = false return nil }
// runCLMail is a wrapper that sets up and runs a review instance across // multiple projects. func runCLMail(jirix *jiri.X, _ []string) error { mp, err := initForMultiPart(jirix) if err != nil { return err } if mp.clean { if err := mp.cleanMultiPartMetadata(jirix); err != nil { return err } return nil } if mp.current { return runCLMailCurrent(jirix, []string{}) } // multipart mode if err := mp.writeMultiPartMetadata(jirix); err != nil { mp.cleanMultiPartMetadata(jirix) return err } if err := runCLMailCurrent(jirix, []string{}); err != nil { return err } git := gitutil.New(jirix.NewSeq()) branch, err := git.CurrentBranchName() if err != nil { return err } initialMessage, err := strippedGerritCommitMessage(jirix, branch) if err != nil { return err } s := jirix.NewSeq() tmp, err := s.TempFile("", branch+"-") if err != nil { return err } defer func() { tmp.Close() os.Remove(tmp.Name()) }() if _, err := io.WriteString(tmp, initialMessage); err != nil { return err } // Use Capture to make sure that all output from the subcommands is // sent to stdout/stderr. flags := clMailMultiFlags() flags = append(flags, "--commit-message-body-file="+tmp.Name()) return s.Capture(jirix.Stdout(), jirix.Stderr()).Last("jiri", mp.commandline(mp.currentKey, flags)...) }
func (sc *subcommand) packageCmds(jirix *jiri.X, cl *packagesFlagValues, root jiri.RelPath) ([][]string, error) { cmd := []string{"profile-" + sc.installer, "os-packages"} cmd = append(cmd, cl.args()...) cmd = append(cmd, sc.qname) var out bytes.Buffer if err := jirix.NewSeq().Capture(&out, jirix.Stderr()).Last("jiri", cmd...); err != nil { return nil, err } scanner := bufio.NewScanner(&out) cmds := make([][]string, 0, 5) for scanner.Scan() { cmds = append(cmds, strings.Split(scanner.Text(), " ")) } return cmds, nil }
// gitCookies attempts to read and parse cookies from the .gitcookies file in // the users home directory. func gitCookies(jirix *jiri.X) []*http.Cookie { cookies := []*http.Cookie{} homeDir := os.Getenv("HOME") if homeDir == "" { return cookies } cookieFile := filepath.Join(homeDir, ".gitcookies") bytes, err := jirix.NewSeq().ReadFile(cookieFile) if err != nil { return cookies } return parseCookieFile(jirix, bytes) }
// createTestRepos sets up three local repositories: origin, gerrit, // and the main test repository which pulls from origin and can push // to gerrit. func createTestRepos(t *testing.T, jirix *jiri.X) (string, string, string) { // Create origin. originPath := createRepo(t, jirix, "origin") chdir(t, jirix, originPath) if err := gitutil.New(jirix.NewSeq()).CommitWithMessage("initial commit"); err != nil { t.Fatalf("%v", err) } // Create test repo. repoPath := createRepoFromOrigin(t, jirix, "test", originPath) // Add Gerrit remote. gerritPath := createRepoFromOrigin(t, jirix, "gerrit", originPath) // Switch back to test repo. chdir(t, jirix, repoPath) return repoPath, originPath, gerritPath }
// strippedGerritCommitMessage returns the commit message stripped of variable // meta-data such as multipart messages, or change IDs: func strippedGerritCommitMessage(jirix *jiri.X, branch string) (string, error) { filename, err := getCommitMessageFileName(jirix, branch) if err != nil { return "", err } msg, err := jirix.NewSeq().ReadFile(filename) if err != nil { return "", err } // Strip "MultiPart ..." from the commit messages. strippedMessages := multiPartRE.ReplaceAllLiteralString(string(msg), "") // Strip "Change-Id: ..." from the commit messages. strippedMessages = changeIDRE.ReplaceAllLiteralString(strippedMessages, "") return strippedMessages, nil }
// Unzip unzips the file in srcFile and puts resulting files in directory dstDir. func Unzip(jirix *jiri.X, srcFile, dstDir string) error { r, err := zip.OpenReader(srcFile) if err != nil { return err } defer r.Close() unzipFn := func(zFile *zip.File) error { rc, err := zFile.Open() if err != nil { return err } defer rc.Close() s := jirix.NewSeq() fileDst := filepath.Join(dstDir, zFile.Name) if zFile.FileInfo().IsDir() { return s.MkdirAll(fileDst, zFile.Mode()).Done() } // Make sure the parent directory exists. Note that sometimes files // can appear in a zip file before their directory. dirmode := zFile.Mode() | 0100 if dirmode&0060 != 0 { // "group" has read or write permissions, so give // execute permissions on the directory. dirmode = dirmode | 0010 } if err := s.MkdirAll(filepath.Dir(fileDst), dirmode).Done(); err != nil { return err } file, err := s.OpenFile(fileDst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, zFile.Mode()) if err != nil { return err } defer file.Close() _, err = s.Copy(file, rc) return err } s := jirix.NewSeq() s.Output([]string{"unzipping " + srcFile}) for _, zFile := range r.File { s.Output([]string{"extracting " + zFile.Name}) s.Call(func() error { return unzipFn(zFile) }, "unzipFn(%s)", zFile.Name) } return s.Done() }
func (mp *multiPart) cleanMultiPartMetadata(jirix *jiri.X) error { s := jirix.NewSeq() for _, state := range mp.states { filename := filepath.Join(state.Project.Path, jiri.ProjectMetaDir, mp.currentBranch, multiPartMetaDataFileName) ok, err := s.IsFile(filename) if err != nil { return err } if ok { if err := s.Remove(filename).Done(); err != nil { return err } } } return nil }
func (eg *exampleManager) Uninstall(jirix *jiri.X, pdb *profiles.DB, root jiri.RelPath, target profiles.Target) error { version, err := eg.versionInfo.Select(target.Version()) if err != nil { return err } dir := eg.filename(root, target).Abs(jirix) if err := jirix.NewSeq().WriteFile(filepath.Join(dir, "version"), []byte(version), profilesutil.DefaultFilePerm). WriteFile(filepath.Join(dir, version), []byte(version), profilesutil.DefaultFilePerm). Remove(filepath.Join(dir, version)). Done(); err != nil { return err } if pdb.RemoveProfileTarget(eg.installer, eg.name, target) { eg.profile = nil } return nil }