package main import ( "fmt" "os" "sort" "strings" "time" ) // wxch-agent modules list | install | remove // // The same installing the control page does, for the installer and for people on the machine. Nothing is installed by // default: the owner picks what this machine offers. func cliModules(args []string) int { cfg := loadNodeConfig() cat, err := loadCatalog() if err != nil { fmt.Fprintln(os.Stderr, err) return 1 } usage := func() int { fmt.Fprintln(os.Stderr, "usage: wxch-agent modules list | install | remove ") fmt.Fprintln(os.Stderr, "capabilities:", strings.Join(cat.IDs(), ", ")) return 2 } if len(args) == 0 { return usage() } switch args[0] { case "list": st := readModuleState(cfg) for _, id := range cat.IDs() { cp, _ := cat.Capability(id) mark := " " if _, ok := st.Installed[id]; ok { mark = "✓ " } fmt.Printf("%s%-18s models %5.1f GB memory ~%2.0f GB %s\n", mark, id, float64(cp.ModelBytes())/1e9, float64(cp.MemBytes)/1e9, cp.Title.Get("en")) } all := cat.Sizes(cat.IDs()) fmt.Printf("\neverything: %.1f GB (models %.1f + engines %.1f); folder %s\n", float64(all.Total())/1e9, float64(all.Models)/1e9, float64(all.Engines)/1e9, modulesDir(cfg)) return 0 case "install", "remove": ids := args[1:] if len(ids) == 0 { return usage() } if len(ids) == 1 && ids[0] == "all" { ids = cat.IDs() } sort.Strings(ids) for _, id := range ids { if _, ok := cat.Capability(id); !ok { fmt.Fprintf(os.Stderr, "unknown capability %q\n", id) return usage() } } if args[0] == "install" { s := cat.Sizes(ids) fmt.Printf("installing %s: about %.1f GB (models %.1f + engine %.1f)\n", strings.Join(ids, ", "), float64(s.Total())/1e9, float64(s.Models)/1e9, float64(s.Engines)/1e9) } fail := 0 for _, id := range ids { if args[0] == "remove" { if err := moduleManager.Remove(cfg, id); err != nil { fmt.Fprintf(os.Stderr, "%s: %v\n", id, err) fail++ } else { fmt.Println("removed", id) } continue } if _, ok := readModuleState(cfg).Installed[id]; ok { fmt.Println(id, "is already installed") continue } if err := moduleManager.Install(cfg, id); err != nil { fmt.Fprintf(os.Stderr, "%s: %v\n", id, err) fail++ continue } if err := waitModuleTask(id); err != nil { fmt.Fprintf(os.Stderr, "%s: %v\n", id, err) fail++ continue } fmt.Println("installed", id) } if fail > 0 { return 1 } return 0 } return usage() } // waitModuleTask prints progress until the background install of id has finished. func waitModuleTask(id string) error { last := "" for { time.Sleep(2 * time.Second) moduleManager.mu.Lock() b, l := moduleManager.busy, moduleManager.last[id] var line string if b != nil && b.ID == id { line = b.Status if b.Total > 0 && b.Done > 0 { line = fmt.Sprintf("%s %.1f / %.1f GB", b.Status, float64(b.Done)/1e9, float64(b.Total)/1e9) } } moduleManager.mu.Unlock() if line != "" { if line != last && (last == "" || !strings.HasPrefix(line, "downloading") || !strings.HasPrefix(last, "downloading") || time.Now().Unix()%15 == 0) { fmt.Println(" ", line) } last = line continue } if l != nil && l.Err != "" { return fmt.Errorf("%s", l.Err) } return nil } }