diff --git a/README.md b/README.md index c54f298..28846f8 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,6 @@ Simple application VMs (hypervisor-based sandbox) based on Nix package manager. Uses one **read-only** /nix directory for all appvms. So creating a new appvm (but not first) is just about one minute. -Currently optimized for full screen usage (but remote-viewer has ability to resize window dynamically without change resolution). - ![appvm screenshot](screenshots/2018-07-05.png) ## Dependencies @@ -82,18 +80,8 @@ to crontab like that: ]; - environment.systemPackages = [ pkgs.chromium ]; - services.xserver.displayManager.sessionCommands = "while [ 1 ]; do ${pkgs.chromium}/bin/chromium; done &"; + services.xserver.displayManager.sessionCommands = + "while [ 1 ]; do ${pkgs.chromium}/bin/chromium; done &"; } For create new app you should add package name (search at https://nixos.org/nixos/packages.html) and path to binary (typically same as package name). - -## Defined applications (pull requests are welcome!) - -* chromium -* thunderbird -* tdesktop -* evince -* libreoffice -* wire -* torbrowser diff --git a/appvm.go b/appvm.go index a109f3d..b6fdf8d 100644 --- a/appvm.go +++ b/appvm.go @@ -390,9 +390,15 @@ func main() { stopName := kingpin.Command("stop", "Stop application").Arg("name", "Application name").Required().String() dropName := kingpin.Command("drop", "Remove application data").Arg("name", "Application name").Required().String() + generateCommand := kingpin.Command("generate", "Generate appvm definition") + generateName := generateCommand.Arg("name", "Nix package name").Required().String() + generateBin := generateCommand.Arg("bin", "Binary").Default("").String() + switch kingpin.Parse() { case "list": list(l) + case "generate": + generate(l, *generateName, *generateBin) case "start": start(l, *startName, *startVerbose) case "stop": diff --git a/generate.go b/generate.go new file mode 100644 index 0000000..3bca04a --- /dev/null +++ b/generate.go @@ -0,0 +1,93 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "strings" + + "github.com/digitalocean/go-libvirt" +) + +var template = ` +{pkgs, ...}: +{ + imports = [ + + + ]; + + services.xserver.displayManager.sessionCommands = + "while [ 1 ]; do ${pkgs.%s}/bin/%s; done &"; +} +` + +func isPackageExists(name string) bool { + cmd := exec.Command("nix-env", "-iA", name) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + return err == nil +} + +func nixPath(name string) (path string, err error) { + command := exec.Command("nix", "path-info", name) + bytes, err := command.Output() + if err != nil { + return + } + path = string(bytes) + return +} + +func generate(l *libvirt.Libvirt, name, bin string) { + if !isPackageExists(name) { + log.Println("Package pkgs."+name, "does not exists") + return + } + + path, err := nixPath(name) + if err != nil { + log.Println("Cannot find nix path") + return + } + + path = strings.TrimSpace(path) + + files, err := ioutil.ReadDir(path + "/bin/") + if err != nil { + log.Println(err) + return + } + + if bin == "" && len(files) != 1 { + fmt.Println("There's more than one binary in */bin, " + + "you should specify one of them explicitly") + fmt.Println("Files in", path+"/bin/:") + for _, f := range files { + fmt.Println("\t", f.Name()) + } + return + } + + if bin != "" { + var found bool = false + for _, f := range files { + if bin == f.Name() { + found = true + } + } + if !found { + log.Println("There's no such file in */bin") + return + } + } else { + bin = files[0].Name() + } + + realName := strings.Split(name, ".")[1] + + fmt.Printf(template, realName, bin) +}