DescribeCmd string DiffCmd string // run in sandbox repos CreateCmd string LinkCmd string ExistsCmd string FetchCmd string CheckoutCmd string // If nil, LinkCmd is used. LinkFunc func(dir, remote, url string) error } var vcsBzr = &VCS{ vcs: vcs.ByCmd("bzr"), IdentifyCmd: "version-info --custom --template {revision_id}", DescribeCmd: "revno", // TODO(kr): find tag names if possible DiffCmd: "diff -r {rev}", } var vcsGit = &VCS{ vcs: vcs.ByCmd("git"), IdentifyCmd: "rev-parse HEAD", DescribeCmd: "describe --tags", DiffCmd: "diff {rev}", CreateCmd: "init --bare", LinkCmd: "remote add {remote} {url}",
// setup for a gccgoEnv clones the gofrontend repo to workpath/go at the hash // and clones the latest GCC branch to repo.Path/gcc. The gccgo sources are // replaced with the updated sources in the gofrontend repo and gcc gets // gets configured and built in workpath/gcc-objdir. The path to // workpath/gcc-objdir is returned. func (env *gccgoEnv) setup(repo *Repo, workpath, hash string, envv []string) (string, error) { gccpath := filepath.Join(repo.Path, "gcc") // get a handle to Git vcs.Cmd for pulling down GCC from the mirror. git := vcs.ByCmd("git") // only pull down gcc if we don't have a local copy. if _, err := os.Stat(gccpath); err != nil { if err := timeout(*cmdTimeout, func() error { // pull down a working copy of GCC. return git.Create(gccpath, *gccPath) }); err != nil { return "", err } } if err := git.Download(gccpath); err != nil { return "", err } // get the modified files for this commit. var buf bytes.Buffer if err := run(exec.Command("hg", "status", "--no-status", "--change", hash), allOutput(&buf), runDir(repo.Path), runEnv(envv)); err != nil { return "", fmt.Errorf("Failed to find the modified files for %s: %s", hash, err) } modifiedFiles := strings.Split(buf.String(), "\n") var isMirrored bool for _, f := range modifiedFiles { if strings.HasPrefix(f, "go/") || strings.HasPrefix(f, "libgo/") { isMirrored = true break } } // use git log to find the corresponding commit to sync to in the gcc mirror. // If the files modified in the gofrontend are mirrored to gcc, we expect a // commit with a similar description in the gcc mirror. If the files modified are // not mirrored, e.g. in support/, we can sync to the most recent gcc commit that // occurred before those files were modified to verify gccgo's status at that point. logCmd := []string{ "log", "-1", "--format=%H", } var errMsg string if isMirrored { commitDesc, err := repo.Master.VCS.LogAtRev(repo.Path, hash, "{desc|firstline|escape}") if err != nil { return "", err } quotedDesc := regexp.QuoteMeta(string(commitDesc)) logCmd = append(logCmd, "--grep", quotedDesc, "--regexp-ignore-case", "--extended-regexp") errMsg = fmt.Sprintf("Failed to find a commit with a similar description to '%s'", string(commitDesc)) } else { commitDate, err := repo.Master.VCS.LogAtRev(repo.Path, hash, "{date|rfc3339date}") if err != nil { return "", err } logCmd = append(logCmd, "--before", string(commitDate)) errMsg = fmt.Sprintf("Failed to find a commit before '%s'", string(commitDate)) } buf.Reset() if err := run(exec.Command("git", logCmd...), runEnv(envv), allOutput(&buf), runDir(gccpath)); err != nil { return "", fmt.Errorf("%s: %s", errMsg, err) } gccRev := buf.String() if gccRev == "" { return "", fmt.Errorf(errMsg) } // checkout gccRev // TODO(cmang): Fix this to work in parallel mode. if err := run(exec.Command("git", "reset", "--hard", strings.TrimSpace(gccRev)), runEnv(envv), runDir(gccpath)); err != nil { return "", fmt.Errorf("Failed to checkout commit at revision %s: %s", gccRev, err) } // make objdir to work in gccobjdir := filepath.Join(workpath, "gcc-objdir") if err := os.Mkdir(gccobjdir, mkdirPerm); err != nil { return "", err } // configure GCC with substituted gofrontend and libgo if err := run(exec.Command(filepath.Join(gccpath, "configure"), "--enable-languages=c,c++,go", "--disable-bootstrap", "--disable-multilib", ), runEnv(envv), runDir(gccobjdir)); err != nil { return "", fmt.Errorf("Failed to configure GCC: %v", err) } // build gcc if err := run(exec.Command("make"), runTimeout(*buildTimeout), runEnv(envv), runDir(gccobjdir)); err != nil { return "", fmt.Errorf("Failed to build GCC: %s", err) } return gccobjdir, nil }
// setup for a gccgoEnv clones the gofrontend repo to workpath/go at the hash // and clones the latest GCC branch to repo.Path/gcc. The gccgo sources are // replaced with the updated sources in the gofrontend repo and gcc gets // gets configured and built in workpath/gcc-objdir. The path to // workpath/gcc-objdir is returned. func (env *gccgoEnv) setup(repo *Repo, workpath, hash string, envv []string) (string, error) { gofrontendpath := filepath.Join(workpath, "gofrontend") gccpath := filepath.Join(repo.Path, "gcc") gccgopath := filepath.Join(gccpath, "gcc", "go", "gofrontend") gcclibgopath := filepath.Join(gccpath, "libgo") // get a handle to SVN vcs.Cmd for pulling down GCC. svn := vcs.ByCmd("svn") // only pull down gcc if we don't have a local copy. if _, err := os.Stat(gccpath); err != nil { if err := timeout(*cmdTimeout, func() error { // pull down a working copy of GCC. return svn.Create(gccpath, *gccPath) }); err != nil { return "", err } } else { // make sure to remove gccgopath and gcclibgopath before // updating the repo to avoid file clobbering. if err := os.RemoveAll(gccgopath); err != nil { return "", err } if err := os.RemoveAll(gcclibgopath); err != nil { return "", err } } if err := svn.Download(gccpath); err != nil { return "", err } // clone gofrontend repo at specified revision if _, err := repo.Clone(gofrontendpath, hash); err != nil { return "", err } // remove gccgopath and gcclibgopath before copying over gofrontend. if err := os.RemoveAll(gccgopath); err != nil { return "", err } if err := os.RemoveAll(gcclibgopath); err != nil { return "", err } // copy gofrontend and libgo to appropriate locations if err := copyDir(filepath.Join(gofrontendpath, "go"), gccgopath); err != nil { return "", fmt.Errorf("Failed to copy gofrontend/go to gcc/go/gofrontend: %s\n", err) } if err := copyDir(filepath.Join(gofrontendpath, "libgo"), gcclibgopath); err != nil { return "", fmt.Errorf("Failed to copy gofrontend/libgo to gcc/libgo: %s\n", err) } // make objdir to work in gccobjdir := filepath.Join(workpath, "gcc-objdir") if err := os.Mkdir(gccobjdir, mkdirPerm); err != nil { return "", err } // configure GCC with substituted gofrontend and libgo gccConfigCmd := []string{ filepath.Join(gccpath, "configure"), "--enable-languages=c,c++,go", "--disable-bootstrap", "--disable-multilib", } if _, err := runOutput(*cmdTimeout, envv, ioutil.Discard, gccobjdir, gccConfigCmd...); err != nil { return "", fmt.Errorf("Failed to configure GCC: %s", err) } // build gcc if _, err := runOutput(*buildTimeout, envv, ioutil.Discard, gccobjdir, "make"); err != nil { return "", fmt.Errorf("Failed to build GCC: %s", err) } return gccobjdir, nil }