218 lines
4.7 KiB
Go
218 lines
4.7 KiB
Go
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_run_path, err := filepath.Abs(filepath.Join(instance, "exec", "bin", "bnd-run"))
|
|
|
|
contents := "#!/usr/bin/env bash\nexec " + bnd_run_path + " -i " + instance + " -t " + target + " -w $PWD " + program + " $@\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")
|
|
}
|
|
}
|