Support with pms and gh releases

This commit is contained in:
2024-05-21 14:19:11 +02:00
parent 2f0d129aea
commit 1e5bc0a5e2
4 changed files with 228 additions and 71 deletions
+155
View File
@@ -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
}
}
+6 -6
View File
@@ -27,10 +27,10 @@ func showPackageInfo(packageName string) {
} }
fmt.Printf("Package: %s\n", packageName) fmt.Printf("Package: %s\n", packageName)
for version, info := range pkgIndex.Versions { // for version, info := range pkgIndex.Versions {
fmt.Printf("Version: %s\n", version) // fmt.Printf("Version: %s\n", version)
fmt.Printf(" Author: %s\n", info.Author) // fmt.Printf(" Author: %s\n", info.Author)
fmt.Printf(" Description: %s\n", info.Description) // fmt.Printf(" Description: %s\n", info.Description)
fmt.Println() // fmt.Println()
} // }
} }
+31 -65
View File
@@ -3,96 +3,62 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"net/http" "net/http"
"net/url"
"os" "os"
"path/filepath" "strings"
) )
type PackageVersion struct { type Package struct {
Author string `json:"author"` Author string `json:"author"`
Description string `json:"description"` Description string `json:"description"`
URL string `json:"url"` URL string `json:"url"`
} }
type PackageIndex struct { type PackageIndex struct {
Versions map[string]PackageVersion `json:"versions"` Name string `json:"name"`
Repo string `json:"repo"`
} }
func installPackage(packageName, packageVersion string) { func installPackage(packageName, packageVersion string) {
url := fmt.Sprintf("https://raw.githubusercontent.com/wyst-lang/index/master/%s/index.json", packageName) var pkgidx PackageIndex
resp, err := http.Get(url) jsonBody := []byte(fmt.Sprintf(`{"name": "%s"}`, packageName))
resBody := sendRequest(http.MethodGet, "http://localhost:3000", jsonBody)
err := json.Unmarshal(resBody.Body, &pkgidx)
if err != nil { if err != nil {
fmt.Printf("Error fetching package info: %v\n", err) fmt.Println("Json Error: ", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Printf("Error: %s\n", resp.Status)
return return
} }
var pkgIndex PackageIndex fmt.Printf("repo: %s\n", pkgidx.Repo)
if err := json.NewDecoder(resp.Body).Decode(&pkgIndex); err != nil {
fmt.Printf("Error decoding package info: %v\n", err) repoU, err := url.Parse(pkgidx.Repo)
return if err != nil {
panic(err)
} }
if packageVersion == "" { if packageVersion == "" {
packageVersion = getLatestVersion(pkgIndex) packageVersion = getLatestVersion(repoU.Path)
} }
downloadPackage(repoU.Path, packageVersion)
pkgVersion, exists := pkgIndex.Versions[packageVersion] Unzip("temp.zip", "wyst_tmp")
if !exists { entries, err := os.ReadDir("./wyst_tmp")
fmt.Printf("Version %s not found for package %s\n", packageVersion, packageName) if err != nil {
return panic(err)
} }
if err := os.Mkdir("lib", os.ModePerm); err != nil {
downloadAndSavePackage(pkgVersion.URL, packageName, packageVersion) ERR := fmt.Sprintf("%s", err)
} if !strings.Contains(strings.ToLower(ERR), "file exists") {
panic(ERR)
func getLatestVersion(pkgIndex PackageIndex) string {
var latest string
for version := range pkgIndex.Versions {
if version > latest {
latest = version
} }
} }
return latest for _, e := range entries {
} os.Rename("wyst_tmp/"+e.Name(), "lib/"+packageName)
func downloadAndSavePackage(url, packageName, packageVersion string) {
resp, err := http.Get(url)
if err != nil {
fmt.Printf("Error downloading package: %v\n", err)
return
} }
defer resp.Body.Close() if err := os.RemoveAll("wyst_tmp"); err != nil {
panic(err)
if resp.StatusCode != http.StatusOK {
fmt.Printf("Error: %s\n", resp.Status)
return
} }
if err := os.Remove("temp.zip"); err != nil {
libDir := "lib" panic(err)
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)
} }
} }
+36
View File
@@ -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}
}