From 42c21bf8c552f4e9fb9f924f1993a10493f0341d Mon Sep 17 00:00:00 2001 From: sloum Date: Fri, 27 Aug 2021 15:02:36 -0700 Subject: [PATCH] Handles recursive dependency installation --- operators/docs.go | 37 +++++++++++++++++++++ operators/install.go | 66 ++++++++++++++++++++++++++++++------- operators/list.go | 26 --------------- operators/search.go | 32 ++++++++++++++++++ operators/show.go | 50 ++++++++++++++++++++++++++++ operators/util.go | 78 ++++++-------------------------------------- 6 files changed, 184 insertions(+), 105 deletions(-) create mode 100644 operators/docs.go create mode 100644 operators/search.go create mode 100644 operators/show.go diff --git a/operators/docs.go b/operators/docs.go new file mode 100644 index 0000000..5983571 --- /dev/null +++ b/operators/docs.go @@ -0,0 +1,37 @@ +package operators + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func ReadDocs(pkg string) error { + modDir := getModBaseDir() + glob, err := filepath.Glob(filepath.Join(modDir, pkg, "*")) + if err != nil { + return err + } + pager := os.Getenv("PAGER") + if pager == "" { + pager = "less" + } + for _, p := range glob { + base := filepath.Base(p) + if strings.HasPrefix(strings.ToLower(base), "readme") { + cmd := exec.Command(pager, p) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + return err + } + return nil + } + } + return fmt.Errorf("Package %q does not have a README file", pkg) +} + diff --git a/operators/install.go b/operators/install.go index 685cade..6bac18d 100644 --- a/operators/install.go +++ b/operators/install.go @@ -3,7 +3,9 @@ package operators import ( "fmt" "os" + "os/exec" "path/filepath" + "strings" "gopkg.in/src-d/go-git.v4" ) @@ -19,28 +21,70 @@ func Install(pkg string) error { return err } - repo, ok := packages[pkg] + _, ok := packages[pkg] if !ok { return fmt.Errorf("package %q not found in package list", pkg) } - modDir := getModBaseDir() - - _, err = git.PlainClone(filepath.Join(modDir, pkg), false, &git.CloneOptions{ - URL: repo.Repository, - }) + stagingDir,err := os.MkdirTemp("", "slope-install-*") if err != nil { return err } - _, err = os.Stat(filepath.Join(modDir, pkg, "main.slo")) - if err != nil && os.IsNotExist(err) { - err = Remove(pkg) + modDir := getModBaseDir() + + depList := map[string]bool{} + err = BuildDepTree(pkg, packages, depList) + if err != nil { + return err + } + + failedInstall := make([]string, 0) + for k, _ := range depList { + p := packages[k] + _, err = git.PlainClone(filepath.Join(stagingDir, k), false, &git.CloneOptions{ + URL: p.Repository, + }) + if err != nil { - return fmt.Errorf("package %q was not a valid slope package, an attempt to remove the files failed: %s", pkg, repo) + failedInstall = append(failedInstall, err.Error()) + continue } - return fmt.Errorf("package %q does not contain a valid 'main.slo' file, the failed package has been removed", pkg) + + _, err = os.Stat(filepath.Join(stagingDir, pkg, "main.slo")) + if err != nil && os.IsNotExist(err) { + failedInstall = append(failedInstall, fmt.Sprintf("install error: 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")) + } + cmd := exec.Command("sh", "-c", fmt.Sprintf("mv %s %s", filepath.Join(stagingDir, "*"), modDir)) + err = cmd.Run() + if err != nil { + 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("install error: (sub)dependency %s for %s does not exist in the package registry", d, pkg) + } + return BuildDepTree(d, packages, output) + } + return nil +} + diff --git a/operators/list.go b/operators/list.go index 3a1b3d3..94f9cb7 100644 --- a/operators/list.go +++ b/operators/list.go @@ -2,7 +2,6 @@ package operators import ( "fmt" - "regexp" "sort" ) @@ -20,31 +19,6 @@ func (p pkgs) Less(i, j int) bool { return p[i].Title < p[j].Title } -func Search(val string) error { - err := downloadTheDirectory() - if err != nil { - return err - } - - packages, err := getPackages() - if err != nil { - return err - } - - sorted := sortPackages(packages) - - for _, p := range sorted { - match, err := regexp.MatchString(fmt.Sprintf(".*%s.*", val), p.Title) - match2, _ := regexp.MatchString(fmt.Sprintf(".*%s.*", val), p.Description) - if err == nil && (match || match2) { - fmt.Println(packageString(p)) - } - } - - return nil -} - - // List lists all available packages // from packages.json func List() error { diff --git a/operators/search.go b/operators/search.go new file mode 100644 index 0000000..d77dd86 --- /dev/null +++ b/operators/search.go @@ -0,0 +1,32 @@ +package operators + +import ( + "fmt" + "regexp" +) + + +func Search(val string) error { + err := downloadTheDirectory() + if err != nil { + return err + } + + packages, err := getPackages() + if err != nil { + return err + } + + sorted := sortPackages(packages) + + for _, p := range sorted { + match, err := regexp.MatchString(fmt.Sprintf(".*%s.*", val), p.Title) + match2, _ := regexp.MatchString(fmt.Sprintf(".*%s.*", val), p.Description) + if err == nil && (match || match2) { + fmt.Println(packageString(p)) + } + } + + return nil +} + diff --git a/operators/show.go b/operators/show.go new file mode 100644 index 0000000..61a7b64 --- /dev/null +++ b/operators/show.go @@ -0,0 +1,50 @@ +package operators + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" +) + +func Show(pkg string) error { + modDir := getModBaseDir() + path := filepath.Join(modDir, pkg) + + if _, err := os.Stat(path); err != nil { + err := downloadTheDirectory() + if err != nil { + return err + } + + packages, err := getPackages() + if err != nil { + return err + } + + pakg, ok := packages[pkg] + if !ok { + return fmt.Errorf("package '%s' not found", pkg) + } + fmt.Println(pakg.String()) + return nil + } + + path = filepath.Join(path, "module.json") + if _, err := os.Stat(path); err != nil { + return fmt.Errorf("package '%s' does not have a 'module.json' file", pkg) + } + bytes, err := ioutil.ReadFile(path) + if err != nil { + return err + } + var info genOpts + err = json.Unmarshal(bytes, &info) + if err != nil { + return err + } + fmt.Println(info.String()) + + return nil +} diff --git a/operators/util.go b/operators/util.go index a10d7a8..1e26eaa 100644 --- a/operators/util.go +++ b/operators/util.go @@ -7,10 +7,10 @@ import ( "io/ioutil" "net/http" "os" - "os/exec" "os/user" "path/filepath" "strings" + "time" ) const ( @@ -67,18 +67,21 @@ func getModBaseDir() string { func downloadTheDirectory() error { modDir := getModBaseDir() + path := filepath.Join(modDir, "package.json") + + // Only get a new file every, at most, 15 minutes + f, err := os.Stat(path) + if err == nil && f.ModTime().Before(time.Now().Add(-15 * time.Minute)) { + return nil + } - // XXX this was moved from underneath the file creation - // no reason to truncate a file if we cant get the new - // one. Delete this comment once the change is verified - // as functional resp, err := http.Get(packageListURL) if err != nil { return fmt.Errorf("Unable to retrieve package registry") } defer resp.Body.Close() - out, err := os.Create(filepath.Join(modDir, "packages.json")) + out, err := os.Create(path) if err != nil { return err } @@ -95,7 +98,7 @@ func downloadTheDirectory() error { func getPackages() (map[string]genOpts, error) { modDir := getModBaseDir() - data, err := ioutil.ReadFile(filepath.Join(modDir, "packages.json")) + data, err := ioutil.ReadFile(filepath.Join(modDir, "package.json")) if err != nil { return nil, err } @@ -110,64 +113,3 @@ func getPackages() (map[string]genOpts, error) { return packages, nil } -func ReadDocs(pkg string) error { - modDir := getModBaseDir() - glob, err := filepath.Glob(filepath.Join(modDir, pkg, "*")) - if err != nil { - return err - } - for _, p := range glob { - base := filepath.Base(p) - if strings.HasPrefix(strings.ToLower(base), "readme") { - cmd := exec.Command("less", p) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Run() - return nil - } - } - return fmt.Errorf("Package %q does not have a README file", pkg) -} - -func Show(pkg string) error { - modDir := getModBaseDir() - path := filepath.Join(modDir, pkg) - - if _, err := os.Stat(path); err != nil { - err := downloadTheDirectory() - if err != nil { - return err - } - - packages, err := getPackages() - if err != nil { - return err - } - - pakg, ok := packages[pkg] - if !ok { - return fmt.Errorf("package '%s' not found", pkg) - } - fmt.Println(pakg.String()) - return nil - } - - path = filepath.Join(path, "module.json") - if _, err := os.Stat(path); err != nil { - return fmt.Errorf("package '%s' does not have a 'module.json' file", pkg) - } - bytes, err := ioutil.ReadFile(path) - if err != nil { - return err - } - var info genOpts - err = json.Unmarshal(bytes, &info) - if err != nil { - return err - } - fmt.Println(info.String()) - - return nil -} -