| package cmd |
| |
| import ( |
| "fmt" |
| "os" |
| "path" |
| "runtime" |
| "strings" |
| |
| "github.com/Masterminds/cookoo" |
| "golang.org/x/tools/go/vcs" |
| ) |
| |
| const ( |
| NoVCS = "" |
| Git = "git" |
| Bzr = "bzr" |
| Hg = "hg" |
| Svn = "svn" |
| ) |
| |
| // Get fetches a single package and puts it in vendor/. |
| // |
| // Params: |
| // - package (string): Name of the package to get. |
| // - verbose (bool): default false |
| // |
| // Returns: |
| // - *Dependency: A dependency describing this package. |
| func Get(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { |
| name := p.Get("package", "").(string) |
| cfg := p.Get("conf", nil).(*Config) |
| verbose := p.Get("verbose", false).(bool) |
| |
| cwd, err := VendorPath(c) |
| if err != nil { |
| return nil, err |
| } |
| |
| repo, err := vcs.RepoRootForImportPath(name, verbose) |
| if err != nil { |
| return nil, err |
| } |
| |
| if cfg.HasDependency(repo.Root) { |
| return nil, fmt.Errorf("Package '%s' is already in glide.yaml", repo.Root) |
| } |
| |
| if len(repo.Root) == 0 { |
| return nil, fmt.Errorf("Package name is required.") |
| } |
| |
| dep := &Dependency{ |
| Name: repo.Root, |
| VcsType: repo.VCS.Cmd, |
| Repository: repo.Repo, |
| } |
| subpkg := strings.TrimPrefix(name, repo.Root) |
| if len(subpkg) > 0 && subpkg != "/" { |
| dep.Subpackages = []string{subpkg} |
| } |
| |
| dest := path.Join(cwd, repo.Root) |
| if err := repo.VCS.Create(dest, repo.Repo); err != nil { |
| return dep, err |
| } |
| |
| cfg.Imports = append(cfg.Imports, dep) |
| |
| return dep, nil |
| } |
| |
| // GetImports iterates over the imported packages and gets them. |
| func GetImports(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { |
| cfg := p.Get("conf", nil).(*Config) |
| cwd, err := VendorPath(c) |
| if err != nil { |
| Error("Failed to prepare vendor directory: %s", err) |
| return false, err |
| } |
| |
| if len(cfg.Imports) == 0 { |
| Info("No dependencies found. Nothing downloaded.\n") |
| return false, nil |
| } |
| |
| for _, dep := range cfg.Imports { |
| if err := VcsGet(dep, cwd); err != nil { |
| Warn("Skipped getting %s: %s\n", dep.Name, err) |
| } |
| } |
| |
| return true, nil |
| } |
| |
| // UpdateImports iterates over the imported packages and updates them. |
| func UpdateImports(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { |
| cfg := p.Get("conf", nil).(*Config) |
| cwd, err := VendorPath(c) |
| if err != nil { |
| return false, err |
| } |
| |
| if len(cfg.Imports) == 0 { |
| Info("No dependencies found. Nothing updated.\n") |
| return false, nil |
| } |
| |
| for _, dep := range cfg.Imports { |
| if err := VcsUpdate(dep, cwd); err != nil { |
| Warn("Update failed for %s: %s\n", dep.Name, err) |
| } |
| } |
| |
| return true, nil |
| } |
| |
| func SetReference(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { |
| cfg := p.Get("conf", nil).(*Config) |
| cwd, err := VendorPath(c) |
| if err != nil { |
| return false, err |
| } |
| |
| if len(cfg.Imports) == 0 { |
| Info("No references set.\n") |
| return false, nil |
| } |
| |
| for _, dep := range cfg.Imports { |
| if err := VcsVersion(dep, cwd); err != nil { |
| Warn("Failed to set version on %s to %s: %s\n", dep.Name, dep.Reference, err) |
| } |
| } |
| |
| return true, nil |
| } |
| |
| var ( |
| goGet VCS = new(GoGetVCS) |
| git VCS = new(GitVCS) |
| svn VCS = new(SvnVCS) |
| bzr VCS = new(BzrVCS) |
| hg VCS = new(HgVCS) |
| ) |
| |
| // filterArchOs indicates a dependency should be filtered out because it is |
| // the wrong GOOS or GOARCH. |
| func filterArchOs(dep *Dependency) bool { |
| found := false |
| if len(dep.Arch) > 0 { |
| for _, a := range dep.Arch { |
| if a == runtime.GOARCH { |
| found = true |
| } |
| } |
| // If it's not found, it should be filtered out. |
| if !found { |
| return true |
| } |
| } |
| |
| found = false |
| if len(dep.Os) > 0 { |
| for _, o := range dep.Os { |
| if o == runtime.GOOS { |
| found = true |
| } |
| } |
| if !found { |
| return true |
| } |
| |
| } |
| |
| return false |
| } |
| |
| // VcsGet figures out how to fetch a dependency, and then gets it. |
| // |
| // VcsGet installs into the dest. |
| func VcsGet(dep *Dependency, dest string) error { |
| |
| cmd, err := dep.VCSCmd() |
| if err != nil { |
| Error("Could not resolve repository %s\n", dep.Name) |
| } |
| |
| if dep.Repository == "" { |
| dep.Repository = "https://" + dep.Name |
| } |
| |
| if err := cmd.Create(dest, dep.Repository); err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| // VcsUpdate updates to a particular checkout based on the VCS setting. |
| // TODO: The command from go tools checks out a specific hash which causes |
| // problems on future updates. Need to fix. |
| func VcsUpdate(dep *Dependency, vend string) error { |
| Info("Fetching updates for %s.\n", dep.Name) |
| |
| if filterArchOs(dep) { |
| Info("%s is not used for %s/%s.\n", dep.Name, runtime.GOOS, runtime.GOARCH) |
| return nil |
| } |
| |
| dest := path.Join(vend, dep.Name) |
| // If destination doesn't exist we need to perform an initial checkout. |
| if _, err := os.Stat(dest); os.IsNotExist(err) { |
| if err = VcsGet(dep, dest); err != nil { |
| Warn("Unable to checkout %s\n", dep.Name) |
| fmt.Println(err) |
| return err |
| } |
| } else { |
| cmd, err := dep.VCSCmd() |
| if err != nil { |
| return err |
| } |
| // TODO: Handle the case of a VCS switching. The could be the config |
| // for a VCS or the type of VCS. |
| if err := cmd.Download(dest); err != nil { |
| Warn("Download failed.\n") |
| return err |
| } |
| } |
| |
| return nil |
| } |
| |
| func VcsVersion(dep *Dependency, vend string) error { |
| // If there is no refernece configured there is nothing to set. |
| if dep.Reference == "" { |
| return nil |
| } |
| |
| Info("Setting version for %s.\n", dep.Name) |
| |
| cwd := path.Join(vend, dep.Name) |
| cmd, err := dep.VCSCmd() |
| if err != nil { |
| return err |
| } |
| |
| // TagSync assumes the remote for Git is the origin. Doesn't |
| // work with non-origin remotes. |
| if err := cmd.TagSync(cwd, dep.Reference); err != nil { |
| Error("Failed to sync to %s: %s\n", dep.Reference, err) |
| return err |
| } |
| |
| if cmd.Cmd == "git" { |
| Info("XXX: Implement history-since function.\n") |
| } |
| |
| return nil |
| } |
| |
| func VcsLastCommit(dep *Dependency) (string, error) { |
| |
| cmd, err := dep.VCSCmd() |
| if err != nil { |
| return "", err |
| } |
| |
| switch cmd.Cmd { |
| case Git: |
| return git.LastCommit(dep) |
| case Bzr: |
| return bzr.LastCommit(dep) |
| case Hg: |
| return hg.LastCommit(dep) |
| case Svn: |
| return svn.LastCommit(dep) |
| default: |
| if len(dep.Reference) > 0 { |
| Error("Cannot update %s to specific version with VCS %d.\n", dep.Name, dep.VcsType) |
| } |
| return "", nil |
| } |
| } |
| |
| func VcsSetReference(dep *Dependency) error { |
| Warn("Cannot set reference. not implemented.\n") |
| return nil |
| } |
| |
| // GuessVCS attempts to guess guess the VCS used by a package. |
| func GuessVCS(dep *Dependency) (string, error) { |
| cmd, err := dep.VCSCmd() |
| if err != nil { |
| return "", err |
| } |
| return cmd.Cmd, nil |
| } |