blob: 7c3190c27f1af19685263e8c6b898c0ab41745c4 [file] [log] [blame]
// 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/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()) {
if _, err := targetAtDefaultVersion(mgr, *target); err == nil {
// Target with default version is already installed.
continue
}
if cl.verbose {
fmt.Fprintf(jirix.Stdout(), "Updating %s %s from %q to %s\n", ip.qname, target, target.Version(), vi)
}
target.SetVersion(vi.Default())
err := mgr.Install(jirix, ip.db, root, *target)
logResult(jirix, "Update", mgr, *target, 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
}
d := root.Abs(jirix)
err := s.AssertDirExists(d).
Run("chmod", "-R", "u+w", d).
RemoveAll(d).
Done()
fmt.Fprintf(jirix.Stdout(), "Cleanup: -rm-all: ")
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)
}
}