예제 #1
0
파일: goop.go 프로젝트: karmakaze/goop
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
}
예제 #2
0
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
					`))