parent
912e575463
commit
d710717489
@ -0,0 +1,157 @@
|
||||
package operators
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func inStringSlice(slice []string, value string) bool {
|
||||
for i := range slice {
|
||||
if slice[i] == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func InstallFromSolo(repoName, repo, tag, targetDir string) error {
|
||||
// Get the repo
|
||||
tarGzName, err := getSoloTarGz(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tarGzName)
|
||||
|
||||
// Un-gzip the repo
|
||||
tarName, err := unGzip(tarGzName, filepath.Dir(tarGzName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tarName)
|
||||
|
||||
repoFolder, err := unTar(tarName, filepath.Dir(tarName))
|
||||
if err != nil {
|
||||
// return err
|
||||
return fmt.Errorf("3")
|
||||
}
|
||||
defer os.RemoveAll(repoFolder)
|
||||
tagFile, err := os.ReadFile(filepath.Join(repoFolder, ".solo", "tags", tag))
|
||||
if err != nil {
|
||||
return fmt.Errorf("The tag %q does not exist", tag)
|
||||
}
|
||||
re := regexp.MustCompile(`\("([^"\n]+)"\s+"([^"\n"]+)"[^\)]*\)`)
|
||||
matches := re.FindAllStringSubmatch(string(tagFile), 1)
|
||||
if len(matches) == 0 || len(matches[0]) < 3 {
|
||||
return fmt.Errorf("The tag %q is corrupted and cannot be used", tag)
|
||||
}
|
||||
branch := string(matches[0][1])
|
||||
snap := string(matches[0][2])
|
||||
if branch == "" || snap == "" {
|
||||
return fmt.Errorf("The tag %q contains invalid references and cannot be used", tag)
|
||||
}
|
||||
folderRoot := filepath.Join(repoFolder, ".solo", "tree", branch, snap, "data")
|
||||
files, _ := filepath.Glob(filepath.Join(folderRoot, "*"))
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("Invalid repository")
|
||||
}
|
||||
if !inStringSlice(files, filepath.Join(folderRoot, "main.slo")) || !inStringSlice(files, filepath.Join(folderRoot, "module.json")) {
|
||||
return fmt.Errorf("Invalid repository structure")
|
||||
}
|
||||
return os.Rename(folderRoot, filepath.Join(targetDir, repoName))
|
||||
}
|
||||
|
||||
func getSoloTarGz(u string) (string, error) {
|
||||
if !strings.HasSuffix(u, ".tar.gz") {
|
||||
return "", fmt.Errorf("Invalid repository URL")
|
||||
}
|
||||
resp, err := http.Get(u)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
f, err := os.CreateTemp("", path.Base(u))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
f.Write(body)
|
||||
return f.Name(), nil
|
||||
}
|
||||
|
||||
func unTar(tarPath, destPath string) (string, error) {
|
||||
reader, err := os.Open(tarPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer reader.Close()
|
||||
tarReader := tar.NewReader(reader)
|
||||
root := ""
|
||||
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
path := filepath.Join(destPath, header.Name)
|
||||
info := header.FileInfo()
|
||||
if info.IsDir() {
|
||||
if err = os.MkdirAll(path, info.Mode()); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if root == "" {
|
||||
root = path
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = io.Copy(file, tarReader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func unGzip(source, target string) (string, error) {
|
||||
reader, err := os.Open(source)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
archive, err := gzip.NewReader(reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer archive.Close()
|
||||
splitInd := strings.Index(source, ".gz")
|
||||
target = filepath.Join(target, filepath.Base(source)[:splitInd])
|
||||
writer, err := os.Create(target)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer writer.Close()
|
||||
|
||||
_, err = io.Copy(writer, archive)
|
||||
return target, err
|
||||
}
|
Loading…
Reference in new issue