Support with pms and gh releases
This commit is contained in:
@@ -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
@@ -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
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user