func (g *Goop) parseAndInstall(goopfile *os.File, writeLockFile bool) error { defer goopfile.Close() deps, err := parser.Parse(goopfile) if err != nil { return err } srcPath := path.Join(g.vendorDir(), "src") tmpGoPath := path.Join(g.vendorDir(), "tmp") tmpSrcPath := path.Join(tmpGoPath, "src") err = os.RemoveAll(tmpGoPath) if err != nil { return err } err = os.MkdirAll(tmpSrcPath, 0775) if err != nil { return err } repos := map[string]*vcs.RepoRoot{} lockedDeps := map[string]*parser.Dependency{} for _, dep := range deps { if dep.URL == "" { g.stdout.Write([]byte(colors.OK + "=> Fetching " + dep.Pkg + "..." + colors.Reset + "\n")) } else { g.stdout.Write([]byte(colors.OK + "=> Fetching " + dep.Pkg + " from " + dep.URL + "..." + colors.Reset + "\n")) } repo, err := repoForDep(dep) if err != nil { return err } repos[dep.Pkg] = repo pkgPath := path.Join(srcPath, repo.Root) tmpPkgPath := path.Join(tmpSrcPath, repo.Root) err = os.MkdirAll(path.Join(tmpPkgPath, ".."), 0775) if err != nil { return err } noclone := false exists, err := pathExists(pkgPath) if err != nil { return err } tmpExists, err := pathExists(tmpPkgPath) if err != nil { return err } if exists { // if package already exists, just symlink package dir and skip cloning g.stderr.Write([]byte(colors.Warn + "Warning: " + pkgPath + " already exists; skipping!" + colors.Reset + "\n")) if !tmpExists { err = os.Symlink(pkgPath, tmpPkgPath) if err != nil { return err } } noclone = true } else { noclone = tmpExists } if !noclone { // clone repo err = g.clone(repo.VCS.Cmd, repo.Repo, tmpPkgPath) if err != nil { return err } } // if rev is not given, record current rev in path if dep.Rev == "" { rev, err := g.currentRev(repo.VCS.Cmd, tmpPkgPath) if err != nil { return err } dep.Rev = rev } lockedDeps[dep.Pkg] = dep // checkout specified rev err = g.checkout(repo.VCS.Cmd, tmpPkgPath, dep.Rev) if err != nil { return err } } for _, dep := range deps { g.stdout.Write([]byte(colors.OK + "=> Fetching dependencies for " + dep.Pkg + "..." + colors.Reset + "\n")) repo := repos[dep.Pkg] tmpPkgPath := path.Join(tmpSrcPath, repo.Root) // fetch sub-dependencies subdeps, err := g.goGet(tmpPkgPath, tmpGoPath) if err != nil { return err } for _, subdep := range subdeps { subdepRepo, err := vcs.RepoRootForImportPath(subdep, true) if err != nil { return err } subdepPkgPath := path.Join(tmpSrcPath, subdepRepo.Root) rev, err := g.currentRev(subdepRepo.VCS.Cmd, subdepPkgPath) if err != nil { return err } err = g.checkout(subdepRepo.VCS.Cmd, subdepPkgPath, rev) if err != nil { return err } repos[subdep] = subdepRepo lockedDeps[subdep] = &parser.Dependency{Pkg: subdep, Rev: rev} } } for _, dep := range lockedDeps { g.stdout.Write([]byte(colors.OK + "=> Installing " + dep.Pkg + "..." + colors.Reset + "\n")) repo := repos[dep.Pkg] pkgPath := path.Join(srcPath, repo.Root) tmpPkgPath := path.Join(tmpSrcPath, repo.Root) err = os.MkdirAll(path.Join(pkgPath, ".."), 0775) if err != nil { return err } lfi, err := os.Lstat(tmpPkgPath) if err != nil && !os.IsNotExist(err) { return err } if err == nil { if lfi.Mode()&os.ModeSymlink == 0 { // move package to vendor path err = os.RemoveAll(pkgPath) if err != nil { return err } err = os.Rename(tmpPkgPath, pkgPath) } else { // package already in vendor path, just remove the symlink err = os.Remove(tmpPkgPath) } if err != nil { return err } } } for _, dep := range lockedDeps { // install repo := repos[dep.Pkg] pkgPath := path.Join(srcPath, repo.Root) cmd := g.command(pkgPath, "go", "install", "-x", dep.Pkg) cmd.Env = g.patchedEnv(true).Strings() cmd.Run() } err = os.RemoveAll(tmpGoPath) if err != nil { return err } // in order to minimize diffs, we sort lockedDeps first and write the // sorted results if writeLockFile { lf, err := os.Create(path.Join(g.dir, "Goopfile.lock")) defer lf.Close() var keys []string for k := range lockedDeps { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { dep := lockedDeps[k] _, err = lf.WriteString(dep.String() + "\n") if err != nil { return err } } } g.stdout.Write([]byte(colors.OK + "=> Done!" + colors.Reset + "\n")) return nil }
func Test(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "parser") } var _ = Describe("parser", func() { Describe("Parse()", func() { var ( deps []*parser.Dependency err error ) Context("empty Goopfile", func() { BeforeEach(func() { deps, err = parser.Parse(bytes.NewBufferString("")) }) It("returns an empty slice", func() { Expect(err).To(BeNil()) Expect(deps).NotTo(BeNil()) Expect(deps).To(HaveLen(0)) }) }) Context("one entry", func() { Context("with no revision specified", func() { BeforeEach(func() { deps, err = parser.Parse(bytes.NewBufferString(` github.com/karmakaze/goop `))