From 1e5bc0a5e2205bbfa48d6b2ac3425de291b285b8 Mon Sep 17 00:00:00 2001 From: Leo Dev Date: Tue, 21 May 2024 14:19:11 +0200 Subject: [PATCH] Support with pms and gh releases --- src/gh.go | 155 +++++++++++++++++++++++++++++++++++++++++++++++++ src/info.go | 12 ++-- src/install.go | 96 ++++++++++-------------------- src/request.go | 36 ++++++++++++ 4 files changed, 228 insertions(+), 71 deletions(-) create mode 100644 src/gh.go create mode 100644 src/request.go diff --git a/src/gh.go b/src/gh.go new file mode 100644 index 0000000..ab8c29d --- /dev/null +++ b/src/gh.go @@ -0,0 +1,155 @@ +package main + +import ( + "archive/zip" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "strings" +) + +type Author struct { + Login string `json:"login"` + ID int `json:"id"` + NodeID string `json:"node_id"` + AvatarURL string `json:"avatar_url"` + GravatarID string `json:"gravatar_id"` + URL string `json:"url"` + HTMLURL string `json:"html_url"` + FollowersURL string `json:"followers_url"` + FollowingURL string `json:"following_url"` + GistsURL string `json:"gists_url"` + StarredURL string `json:"starred_url"` + SubscriptionsURL string `json:"subscriptions_url"` + OrganizationsURL string `json:"organizations_url"` + ReposURL string `json:"repos_url"` + EventsURL string `json:"events_url"` + ReceivedEventsURL string `json:"received_events_url"` + Type string `json:"type"` + SiteAdmin bool `json:"site_admin"` +} + +// Define a struct for the Release +type Release struct { + URL string `json:"url"` + AssetsURL string `json:"assets_url"` + UploadURL string `json:"upload_url"` + HTMLURL string `json:"html_url"` + ID int `json:"id"` + Author Author `json:"author"` + NodeID string `json:"node_id"` + TagName string `json:"tag_name"` + TargetCommitish string `json:"target_commitish"` + Name string `json:"name"` + Draft bool `json:"draft"` + Prerelease bool `json:"prerelease"` + CreatedAt string `json:"created_at"` + PublishedAt string `json:"published_at"` + Assets []interface{} `json:"assets"` // Assuming assets is an array of unknown types + TarballURL string `json:"tarball_url"` + ZipballURL string `json:"zipball_url"` + Body string `json:"body"` +} + +func Unzip(src, dest string) error { + r, err := zip.OpenReader(src) + if err != nil { + return err + } + defer func() { + if err := r.Close(); err != nil { + panic(err) + } + }() + + os.MkdirAll(dest, 0755) + + // Closure to address file descriptors issue with all the deferred .Close() methods + extractAndWriteFile := func(f *zip.File) error { + rc, err := f.Open() + if err != nil { + return err + } + defer func() { + if err := rc.Close(); err != nil { + panic(err) + } + }() + + path := filepath.Join(dest, f.Name) + + // Check for ZipSlip (Directory traversal) + if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) { + return fmt.Errorf("illegal file path: %s", path) + } + + if f.FileInfo().IsDir() { + os.MkdirAll(path, f.Mode()) + } else { + os.MkdirAll(filepath.Dir(path), f.Mode()) + f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return err + } + defer func() { + if err := f.Close(); err != nil { + panic(err) + } + }() + + _, err = io.Copy(f, rc) + if err != nil { + return err + } + } + return nil + } + + for _, f := range r.File { + err := extractAndWriteFile(f) + if err != nil { + return err + } + } + + return nil +} + +func getLatestVersion(repoU string) string { + var latest string + jsonBody := []byte("") + res := sendRequest(http.MethodGet, fmt.Sprintf("https://api.github.com/repos%s/releases/latest", repoU), jsonBody) + var release Release + err := json.Unmarshal([]byte(string(res.Body)), &release) + if err != nil { + fmt.Println("Json Error:", err) + return latest + } + latest = release.TagName + return latest +} + +func downloadPackage(repoU, tag string) { + resp, err := http.Get(fmt.Sprintf("https://github.com/%s/archive/refs/tags/%s.zip", strings.Trim(repoU, "/"), tag)) + if err != nil { + fmt.Println("Error:", err) + return + } + defer resp.Body.Close() + + out, err := ioutil.ReadAll(resp.Body) + if err != nil { + fmt.Println("Error reading body:", err) + return + } + + err = ioutil.WriteFile("temp.zip", out, 0644) + if err != nil { + fmt.Println("Error writing file:", err) + return + } +} diff --git a/src/info.go b/src/info.go index 41adf86..9b91769 100644 --- a/src/info.go +++ b/src/info.go @@ -27,10 +27,10 @@ func showPackageInfo(packageName string) { } fmt.Printf("Package: %s\n", packageName) - for version, info := range pkgIndex.Versions { - fmt.Printf("Version: %s\n", version) - fmt.Printf(" Author: %s\n", info.Author) - fmt.Printf(" Description: %s\n", info.Description) - fmt.Println() - } + // for version, info := range pkgIndex.Versions { + // fmt.Printf("Version: %s\n", version) + // fmt.Printf(" Author: %s\n", info.Author) + // fmt.Printf(" Description: %s\n", info.Description) + // fmt.Println() + // } } diff --git a/src/install.go b/src/install.go index 23d8b05..3ce1135 100644 --- a/src/install.go +++ b/src/install.go @@ -3,96 +3,62 @@ package main import ( "encoding/json" "fmt" - "io" "net/http" + "net/url" "os" - "path/filepath" + "strings" ) -type PackageVersion struct { +type Package struct { Author string `json:"author"` Description string `json:"description"` URL string `json:"url"` } type PackageIndex struct { - Versions map[string]PackageVersion `json:"versions"` + Name string `json:"name"` + Repo string `json:"repo"` } func installPackage(packageName, packageVersion string) { - url := fmt.Sprintf("https://raw.githubusercontent.com/wyst-lang/index/master/%s/index.json", packageName) - resp, err := http.Get(url) + var pkgidx PackageIndex + jsonBody := []byte(fmt.Sprintf(`{"name": "%s"}`, packageName)) + resBody := sendRequest(http.MethodGet, "http://localhost:3000", jsonBody) + err := json.Unmarshal(resBody.Body, &pkgidx) if err != nil { - fmt.Printf("Error fetching package info: %v\n", err) - return - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - fmt.Printf("Error: %s\n", resp.Status) + fmt.Println("Json Error: ", err) return } - var pkgIndex PackageIndex - if err := json.NewDecoder(resp.Body).Decode(&pkgIndex); err != nil { - fmt.Printf("Error decoding package info: %v\n", err) - return + fmt.Printf("repo: %s\n", pkgidx.Repo) + + repoU, err := url.Parse(pkgidx.Repo) + if err != nil { + panic(err) } if packageVersion == "" { - packageVersion = getLatestVersion(pkgIndex) + packageVersion = getLatestVersion(repoU.Path) } - - pkgVersion, exists := pkgIndex.Versions[packageVersion] - if !exists { - fmt.Printf("Version %s not found for package %s\n", packageVersion, packageName) - return + downloadPackage(repoU.Path, packageVersion) + Unzip("temp.zip", "wyst_tmp") + entries, err := os.ReadDir("./wyst_tmp") + if err != nil { + panic(err) } - - downloadAndSavePackage(pkgVersion.URL, packageName, packageVersion) -} - -func getLatestVersion(pkgIndex PackageIndex) string { - var latest string - for version := range pkgIndex.Versions { - if version > latest { - latest = version + if err := os.Mkdir("lib", os.ModePerm); err != nil { + ERR := fmt.Sprintf("%s", err) + if !strings.Contains(strings.ToLower(ERR), "file exists") { + panic(ERR) } } - return latest -} - -func downloadAndSavePackage(url, packageName, packageVersion string) { - resp, err := http.Get(url) - if err != nil { - fmt.Printf("Error downloading package: %v\n", err) - return + for _, e := range entries { + os.Rename("wyst_tmp/"+e.Name(), "lib/"+packageName) } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - fmt.Printf("Error: %s\n", resp.Status) - return + if err := os.RemoveAll("wyst_tmp"); err != nil { + panic(err) } - - libDir := "lib" - if err := os.MkdirAll(libDir, 0755); err != nil { - fmt.Printf("Error creating lib directory: %v\n", err) - return - } - - filename := filepath.Base(url) - packageFile := filepath.Join(libDir, filename) - out, err := os.Create(packageFile) - if err != nil { - fmt.Printf("Error creating package file: %v\n", err) - return - } - defer out.Close() - - if _, err := io.Copy(out, resp.Body); err != nil { - fmt.Printf("Error saving package: %v\n", err) - } else { - fmt.Printf("Package %s version %s downloaded and saved successfully as %s\n", packageName, packageVersion, filename) + if err := os.Remove("temp.zip"); err != nil { + panic(err) } } diff --git a/src/request.go b/src/request.go new file mode 100644 index 0000000..e99ad32 --- /dev/null +++ b/src/request.go @@ -0,0 +1,36 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "os" +) + +type Request struct { + Body []byte + StatusCode int +} + +func sendRequest(method, url string, jsonBody []byte) Request { + bodyReader := bytes.NewReader(jsonBody) + req, err := http.NewRequest(method, url, bodyReader) + if err != nil { + fmt.Printf("Error fetching package info: %v\n", err) + return Request{Body: []byte(""), StatusCode: 402} + } + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + if err != nil { + fmt.Printf("client: error making http request: %s\n", err) + os.Exit(1) + } + defer res.Body.Close() + resBody, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Printf("client: could not read response body: %s\n", err) + os.Exit(1) + } + return Request{Body: resBody, StatusCode: res.StatusCode} +}