feat(install.go): experimental package installation
This commit is contained in:
parent
a7651c5b0b
commit
1c947f1e38
3 changed files with 540 additions and 0 deletions
218
install.go
Normal file
218
install.go
Normal file
|
@ -0,0 +1,218 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/mholt/archiver/v4"
|
||||
)
|
||||
|
||||
func installMap(conn net.Conn, instance string, objmap map[string]interface{}) error {
|
||||
package_path, has := objmap["path"]
|
||||
if !has {
|
||||
return errors.New("a path is required")
|
||||
}
|
||||
|
||||
return install(conn, instance, package_path.(string))
|
||||
}
|
||||
|
||||
func install(conn net.Conn, instance string, package_path string) error {
|
||||
|
||||
unpack_path, err := filepath.Abs(filepath.Join("/tmp", "boundaries"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exists, _ := path_exists(unpack_path); exists {
|
||||
err = os.RemoveAll(unpack_path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
package_path, err = filepath.Abs(package_path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fsys, err := archiver.FileSystem(nil, package_path, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.CopyFS(unpack_path, fsys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dir, _, err := find_infofile(unpack_path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info_path := filepath.Join(dir, "boundaries.json")
|
||||
|
||||
infofile_content, err := os.ReadFile(info_path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var info map[string]interface{}
|
||||
err = json.Unmarshal(infofile_content, &info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
package_name, has := info["name"]
|
||||
if !has {
|
||||
return errors.New("infofile does not contain name field")
|
||||
}
|
||||
|
||||
package_path, err = filepath.Abs(filepath.Join(instance, "apps", package_name.(string)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exists, _ := path_exists(package_path); exists {
|
||||
err := remove(conn, instance, package_name.(string), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = os.CopyFS(package_path, os.DirFS(dir))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(filepath.Join(instance, "var", package_name.(string)), 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
commands, has := info["command"]
|
||||
if !has {
|
||||
return errors.New("infofile does not contain command field")
|
||||
}
|
||||
|
||||
targets := make(map[string]string)
|
||||
|
||||
for target, command := range commands.(map[string]interface{}) {
|
||||
if target == "install" {
|
||||
return_code, err := run_command(conn, command.(string), package_path, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if return_code != 0 {
|
||||
return errors.New("install script failed")
|
||||
}
|
||||
}
|
||||
targets[target] = command.(string)
|
||||
}
|
||||
|
||||
if _, has := targets["run"]; !has {
|
||||
return errors.New("run target not found")
|
||||
}
|
||||
|
||||
bin_files, has := info["bin"]
|
||||
if has {
|
||||
install_wrapped_bin, has := info["wrap_bin"]
|
||||
if !has {
|
||||
install_wrapped_bin = true
|
||||
}
|
||||
switch bin_files.(type) {
|
||||
case string:
|
||||
if install_wrapped_bin.(bool) {
|
||||
err = install_bin(instance, bin_files.(string), "run", package_name.(string))
|
||||
} else {
|
||||
err = install_unwrapped_bin(instance, bin_files.(string), filepath.Join(package_path, targets["run"]))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case map[string]interface{}:
|
||||
for target, path := range bin_files.(map[string]interface{}) {
|
||||
if install_wrapped_bin.(bool) {
|
||||
err = install_bin(instance, path.(string), target, package_name.(string))
|
||||
} else {
|
||||
err = install_unwrapped_bin(instance, path.(string), filepath.Join(package_path, targets[target]))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errors.New("unknown type for bin")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func install_bin(instance string, path string, target string, program string) error {
|
||||
bin_path, err := filepath.Abs(filepath.Join(instance, "exec", "bin", path))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists, err := path_exists(bin_path); exists && err == nil {
|
||||
err = os.Remove(bin_path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
bnd_send_cmd_path, err := filepath.Abs(filepath.Join(instance, "exec", "bin", "bnd-send-cmd"))
|
||||
|
||||
contents := "#!/usr/bin/env bash\n" + bnd_send_cmd_path + " " + instance + " \"{\\\"command\\\": \\\"run\\\", \\\"package\\\": \\\"" + program + "\\\", \\\"workdir\\\": \\\"$PWD\\\", \\\"arguments\\\": \\\"$@\\\"}\"\n"
|
||||
|
||||
err = os.WriteFile(bin_path, []byte(contents), 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func install_unwrapped_bin(instance string, path string, source string) error {
|
||||
bin_path, err := filepath.Abs(filepath.Join(instance, "exec", "bin", path))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists, err := path_exists(bin_path); exists && err == nil {
|
||||
err = os.Remove(bin_path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
os.Symlink(source, bin_path)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func find_infofile(source string) (string, string, error) {
|
||||
|
||||
var found_file string = ""
|
||||
var found_dir string = ""
|
||||
|
||||
fs.WalkDir(os.DirFS(source), ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dir, file := filepath.Split(filepath.Join(source, path))
|
||||
if file == "boundaries.json" {
|
||||
found_file = file
|
||||
found_dir = dir
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if found_dir != "" && found_file != "" {
|
||||
return found_dir, found_file, nil
|
||||
} else {
|
||||
return "", "", errors.New("no infofile found")
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue