| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package profilescmdline |
| |
| import ( |
| "fmt" |
| "strings" |
| |
| "v.io/jiri" |
| "v.io/jiri/profiles" |
| "v.io/jiri/profiles/profilesmanager" |
| "v.io/jiri/runutil" |
| ) |
| |
| // profileManager is implemented for both in-process and sub-command |
| // implemented profiles. |
| type profileManager interface { |
| install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error |
| uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error |
| update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error |
| cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error |
| mgrName() string |
| } |
| |
| func newProfileManager(name string, db *profiles.DB) profileManager { |
| installer, profile := profiles.SplitProfileName(name) |
| installer = strings.TrimSpace(installer) |
| if len(installer) == 0 || installer == profileInstaller { |
| return &inproc{installer, profile, name, db} |
| } |
| return &subcommand{installer, profile, name, db} |
| } |
| |
| type inproc struct { |
| installer, name, qname string |
| db *profiles.DB |
| } |
| |
| func (ip *inproc) mgrName() string { |
| return ip.qname |
| } |
| |
| func (ip *inproc) install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error { |
| mgr := profilesmanager.LookupManager(ip.qname) |
| if mgr == nil { |
| return fmt.Errorf("profile %v is not available via this installer %q", ip.qname, ip.installer) |
| } |
| def, err := targetAtDefaultVersion(mgr, cl.target) |
| if err != nil { |
| return err |
| } |
| err = mgr.Install(jirix, ip.db, root, def) |
| logResult(jirix, "Install", mgr, def, err) |
| return err |
| } |
| |
| func (ip *inproc) uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error { |
| profile := ip.db.LookupProfile(ip.installer, ip.name) |
| if profile == nil { |
| fmt.Fprintf(jirix.Stdout(), "%s is not installed\n", ip.qname) |
| return nil |
| } |
| mgr := profilesmanager.LookupManager(ip.qname) |
| var targets []*profiles.Target |
| if cl.allTargets { |
| targets = profile.Targets() |
| } else { |
| def, err := targetAtDefaultVersion(mgr, cl.target) |
| if err != nil { |
| return err |
| } |
| targets = []*profiles.Target{&def} |
| } |
| for _, target := range targets { |
| if err := mgr.Uninstall(jirix, ip.db, root, *target); err != nil { |
| logResult(jirix, "Uninstall", mgr, *target, err) |
| return err |
| } |
| logResult(jirix, "Uninstall", mgr, *target, nil) |
| } |
| return nil |
| } |
| |
| func (ip *inproc) update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error { |
| profile := ip.db.LookupProfile(ip.installer, ip.name) |
| if profile == nil { |
| // silently ignore uninstalled profile. |
| return nil |
| } |
| mgr := profilesmanager.LookupManager(ip.qname) |
| vi := mgr.VersionInfo() |
| for _, target := range profile.Targets() { |
| if vi.IsTargetOlderThanDefault(target.Version()) { |
| // Check if default target is already installed. |
| defTarget := *target |
| defTarget.SetVersion(vi.Default()) |
| if profiles.FindTarget(profile.Targets(), &defTarget) != nil { |
| // Default target is already installed. Skip. |
| continue |
| } |
| if cl.verbose { |
| fmt.Fprintf(jirix.Stdout(), "Updating %s %s from %q to %s\n", ip.qname, target, target.Version(), vi) |
| } |
| err := mgr.Install(jirix, ip.db, root, defTarget) |
| logResult(jirix, "Update", mgr, defTarget, err) |
| if err != nil { |
| return err |
| } |
| } else { |
| if cl.verbose { |
| fmt.Fprintf(jirix.Stdout(), "%s %s at %q is up to date(%s)\n", ip.qname, target, target.Version(), vi) |
| } |
| } |
| } |
| return nil |
| } |
| |
| func cleanupGC(jirix *jiri.X, db *profiles.DB, root jiri.RelPath, verbose bool, name string) error { |
| mgr := profilesmanager.LookupManager(name) |
| if mgr == nil { |
| fmt.Fprintf(jirix.Stderr(), "%s is not linked into this binary\n", name) |
| return nil |
| } |
| vi := mgr.VersionInfo() |
| installer, profileName := profiles.SplitProfileName(name) |
| profile := db.LookupProfile(installer, profileName) |
| for _, target := range profile.Targets() { |
| if vi.IsTargetOlderThanDefault(target.Version()) { |
| err := mgr.Uninstall(jirix, db, root, *target) |
| logResult(jirix, "Cleanup: -gc", mgr, *target, err) |
| if err != nil { |
| return err |
| } |
| } |
| } |
| return nil |
| } |
| |
| func cleanupRmAll(jirix *jiri.X, db *profiles.DB, root jiri.RelPath) error { |
| s := jirix.NewSeq() |
| if err := s.AssertFileExists(db.Path()).Remove(db.Path()).Done(); err != nil && !runutil.IsNotExist(err) { |
| return err |
| } else { |
| if err := s.AssertDirExists(db.Path()).RemoveAll(db.Path()).Done(); err != nil && !runutil.IsNotExist(err) { |
| return err |
| } |
| } |
| d := root.Abs(jirix) |
| err := s.AssertDirExists(d). |
| Run("chmod", "-R", "u+w", d). |
| RemoveAll(d). |
| Done() |
| if err == nil || runutil.IsNotExist(err) { |
| fmt.Fprintf(jirix.Stdout(), "success\n") |
| return nil |
| } else { |
| fmt.Fprintf(jirix.Stdout(), "%v\n", err) |
| } |
| return err |
| } |
| |
| func (ip *inproc) cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error { |
| if cl.gc { |
| if cl.verbose { |
| fmt.Fprintf(jirix.Stdout(), "Removing targets older than the default version for %s\n", ip.qname) |
| } |
| if err := cleanupGC(jirix, ip.db, root, cl.verbose, ip.qname); err != nil { |
| return fmt.Errorf("gc: %v", err) |
| } |
| } |
| if cl.rmAll { |
| if cl.verbose { |
| fmt.Fprintf(jirix.Stdout(), "Removing profile manifest and all profile output files\n") |
| } |
| if err := cleanupRmAll(jirix, ip.db, root); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| type subcommand struct { |
| installer, profile, qname string |
| db *profiles.DB |
| } |
| |
| func (sc *subcommand) mgrName() string { |
| return sc.qname |
| } |
| |
| func (sc *subcommand) run(jirix *jiri.X, verb string, args []string) error { |
| cl := []string{"profile-" + sc.installer, verb} |
| cl = append(cl, args...) |
| cl = append(cl, sc.qname) |
| return jirix.NewSeq().Capture(jirix.Stdout(), jirix.Stderr()).Last("jiri", cl...) |
| } |
| |
| func (sc *subcommand) install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error { |
| return sc.run(jirix, "install", cl.args()) |
| } |
| |
| func (sc *subcommand) uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error { |
| return sc.run(jirix, "uninstall", cl.args()) |
| } |
| |
| func (sc *subcommand) update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error { |
| return sc.run(jirix, "update", cl.args()) |
| } |
| |
| func (sc *subcommand) cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error { |
| return sc.run(jirix, "cleanup", cl.args()) |
| } |
| |
| func logResult(jirix *jiri.X, action string, mgr profiles.Manager, target profiles.Target, err error) { |
| fmt.Fprintf(jirix.Stdout(), "%s: %s %s: ", action, profiles.QualifiedProfileName(mgr.Installer(), mgr.Name()), target) |
| if err == nil { |
| fmt.Fprintf(jirix.Stdout(), "success\n") |
| } else { |
| fmt.Fprintf(jirix.Stdout(), "%v\n", err) |
| } |
| } |