slp/operators/install.go

117 lines
3.1 KiB
Go

package operators
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing"
)
func Install(pkg string, global bool) error {
modDir := GlobalPath
if !global {
modDir = getModBaseDir()
}
_, err := os.Stat(filepath.Join(modDir, pkg))
if err == nil {
return fmt.Errorf(" \033[2m└\033[0m \033[91mError:\033[0m package %q is already installed", pkg)
}
err = downloadTheDirectory()
if err != nil {
return fmt.Errorf(" \033[2m└\033[0m \033[91mError:\033[0m could not retrieve remote package registry")
}
packages, err := getPackages()
if err != nil {
return fmt.Errorf(" \033[2m└\033[0m \033[91mError:\033[0m could not read from local copy of 'packages.json' registry")
}
_, ok := packages[pkg]
if !ok {
return fmt.Errorf(" \033[2m└\033[0m \033[91mError:\033[0m package %q not found in package list", pkg)
}
stagingDir, err := os.MkdirTemp("", "slope-install-*")
if err != nil {
return fmt.Errorf(" \033[2m└\033[0m \033[91mError:\033[0m could not create staging area, install aborted")
}
depList := map[string]bool{}
err = BuildDepTree(pkg, packages, depList)
if err != nil {
return err
}
failedInstall := make([]string, 0)
for k, _ := range depList {
fmt.Printf(" \033[2m├\033[0m staging %q\n", k)
p := packages[k]
repository, err := git.PlainClone(filepath.Join(stagingDir, p.Title), false, &git.CloneOptions{
URL: p.Repository,
})
if err != nil {
failedInstall = append(failedInstall, err.Error())
continue
}
if p.Tag != "" {
wt, err := repository.Worktree()
if err != nil {
failedInstall = append(failedInstall, err.Error())
continue
}
err = wt.Checkout(&git.CheckoutOptions{
Branch: plumbing.NewTagReferenceName(p.Tag),
})
if err != nil {
failedInstall = append(failedInstall, err.Error())
continue
}
}
_, err = os.Stat(filepath.Join(stagingDir, pkg, "main.slo"))
if err != nil && os.IsNotExist(err) {
failedInstall = append(failedInstall, fmt.Sprintf(" \033[2m└\033[0m \033[91mError:\033[0m package %q does not contain a valid 'main.slo' file", pkg))
}
}
if len(failedInstall) > 0 {
err = os.RemoveAll(stagingDir)
if err != nil {
failedInstall = append(failedInstall, err.Error())
}
return fmt.Errorf(strings.Join(failedInstall, "\n"))
}
fmt.Println(" \033[2m├\033[0m moving staged items to modules folder")
cmd := exec.Command("sh", "-c", fmt.Sprintf("mv %s %s", filepath.Join(stagingDir, "*"), modDir))
err = cmd.Run()
if err != nil {
if global {
return fmt.Errorf("Unable to write modules to final location. Do you have access?")
}
return err
}
return nil
}
func BuildDepTree(pkg string, packages map[string]genOpts, output map[string]bool) error {
_, inOutput := output[pkg]
if inOutput {
return nil
}
output[pkg] = true
for _, d := range packages[pkg].Dependencies {
_, ok := packages[d]
if !ok {
return fmt.Errorf(" \033[2m└\033[0m \033[91mError:\033[0m (sub)dependency %s for %s does not exist in the package registry", d, pkg)
}
return BuildDepTree(d, packages, output)
}
return nil
}