github.com/vanadium-archive/go.jiri@v0.0.0-20160715023856-abfb8b131290/profiles/profilescmdline/profile_manager.go (about)

     1  // Copyright 2015 The Vanadium Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package profilescmdline
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"fmt"
    11  	"sort"
    12  	"strings"
    13  
    14  	"v.io/jiri"
    15  	"v.io/jiri/profiles"
    16  	"v.io/jiri/profiles/profilesmanager"
    17  	"v.io/jiri/profiles/profilesutil"
    18  	"v.io/jiri/runutil"
    19  )
    20  
    21  // profileManager is implemented for both in-process and sub-command
    22  // implemented profiles.
    23  type profileManager interface {
    24  	packageCmds(jirix *jiri.X, cl *packagesFlagValues, root jiri.RelPath) ([][]string, error)
    25  	install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error
    26  	uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error
    27  	update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error
    28  	cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error
    29  	mgrName() string
    30  }
    31  
    32  func newProfileManager(name string, db *profiles.DB) profileManager {
    33  	installer, profile := profiles.SplitProfileName(name)
    34  	installer = strings.TrimSpace(installer)
    35  	if len(installer) == 0 || installer == profileInstaller {
    36  		return &inproc{installer, profile, name, db}
    37  	}
    38  	return &subcommand{installer, profile, name, db}
    39  }
    40  
    41  type inproc struct {
    42  	installer, name, qname string
    43  	db                     *profiles.DB
    44  }
    45  
    46  func (ip *inproc) mgrName() string {
    47  	return ip.qname
    48  }
    49  
    50  func (ip *inproc) packageCmds(jirix *jiri.X, cl *packagesFlagValues, root jiri.RelPath) ([][]string, error) {
    51  	mgr := profilesmanager.LookupManager(ip.qname)
    52  	if mgr == nil {
    53  		return nil, fmt.Errorf("profile %v is not available via this installer %q", ip.qname, ip.installer)
    54  	}
    55  	def, err := targetAtDefaultVersion(mgr, cl.target)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	needed, err := mgr.OSPackages(jirix, ip.db, root, def)
    60  	if err != nil {
    61  		return nil, fmt.Errorf("Failed to obtain packages for %v %v: %v", ip.name, cl.target, err)
    62  	}
    63  	if !cl.allPackages {
    64  		if missing, err := profilesutil.MissingOSPackages(jirix, needed); err != nil {
    65  			return nil, fmt.Errorf("Failed to obtain missing packages for %v %v: %v", ip.name, cl.target, err)
    66  		} else {
    67  			needed = missing
    68  		}
    69  	}
    70  	// Dedup & sort.
    71  	deduped := []string{}
    72  	m := map[string]bool{}
    73  	for _, n := range needed {
    74  		if !m[n] {
    75  			m[n] = true
    76  			deduped = append(deduped, n)
    77  		}
    78  	}
    79  	sort.Strings(deduped)
    80  	return profilesutil.OSPackageInstallCommands(jirix, deduped), nil
    81  }
    82  
    83  func (ip *inproc) install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error {
    84  	mgr := profilesmanager.LookupManager(ip.qname)
    85  	if mgr == nil {
    86  		return fmt.Errorf("profile %v is not available via this installer %q", ip.qname, ip.installer)
    87  	}
    88  	def, err := targetAtDefaultVersion(mgr, cl.target)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	err = mgr.Install(jirix, ip.db, root, def)
    93  	logResult(jirix, "Install", mgr, def, err)
    94  	return err
    95  }
    96  
    97  func (ip *inproc) uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error {
    98  	profile := ip.db.LookupProfile(ip.installer, ip.name)
    99  	if profile == nil {
   100  		fmt.Fprintf(jirix.Stdout(), "%s is not installed\n", ip.qname)
   101  		return nil
   102  	}
   103  	mgr := profilesmanager.LookupManager(ip.qname)
   104  	var targets []*profiles.Target
   105  	if cl.allTargets {
   106  		targets = profile.Targets()
   107  	} else {
   108  		def, err := targetAtDefaultVersion(mgr, cl.target)
   109  		if err != nil {
   110  			return err
   111  		}
   112  		targets = []*profiles.Target{&def}
   113  	}
   114  	for _, target := range targets {
   115  		if err := mgr.Uninstall(jirix, ip.db, root, *target); err != nil {
   116  			logResult(jirix, "Uninstall", mgr, *target, err)
   117  			return err
   118  		}
   119  		logResult(jirix, "Uninstall", mgr, *target, nil)
   120  	}
   121  	return nil
   122  }
   123  
   124  func (ip *inproc) update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error {
   125  	profile := ip.db.LookupProfile(ip.installer, ip.name)
   126  	if profile == nil {
   127  		// silently ignore uninstalled profile.
   128  		return nil
   129  	}
   130  	mgr := profilesmanager.LookupManager(ip.qname)
   131  	vi := mgr.VersionInfo()
   132  	for _, target := range profile.Targets() {
   133  		if vi.IsTargetOlderThanDefault(target.Version()) {
   134  			// Check if default target is already installed.
   135  			defTarget := *target
   136  			defTarget.SetVersion(vi.Default())
   137  			if profiles.FindTarget(profile.Targets(), &defTarget) != nil {
   138  				// Default target is already installed.  Skip.
   139  				continue
   140  			}
   141  			if cl.verbose {
   142  				fmt.Fprintf(jirix.Stdout(), "Updating %s %s from %q to %s\n", ip.qname, target, target.Version(), vi)
   143  			}
   144  			err := mgr.Install(jirix, ip.db, root, defTarget)
   145  			logResult(jirix, "Update", mgr, defTarget, err)
   146  			if err != nil {
   147  				return err
   148  			}
   149  		} else {
   150  			if cl.verbose {
   151  				fmt.Fprintf(jirix.Stdout(), "%s %s at %q is up to date(%s)\n", ip.qname, target, target.Version(), vi)
   152  			}
   153  		}
   154  	}
   155  	return nil
   156  }
   157  
   158  func cleanupGC(jirix *jiri.X, db *profiles.DB, root jiri.RelPath, verbose bool, name string) error {
   159  	mgr := profilesmanager.LookupManager(name)
   160  	if mgr == nil {
   161  		fmt.Fprintf(jirix.Stderr(), "%s is not linked into this binary\n", name)
   162  		return nil
   163  	}
   164  	vi := mgr.VersionInfo()
   165  	installer, profileName := profiles.SplitProfileName(name)
   166  	profile := db.LookupProfile(installer, profileName)
   167  	for _, target := range profile.Targets() {
   168  		if vi.IsTargetOlderThanDefault(target.Version()) {
   169  			err := mgr.Uninstall(jirix, db, root, *target)
   170  			logResult(jirix, "Cleanup: -gc", mgr, *target, err)
   171  			if err != nil {
   172  				return err
   173  			}
   174  		}
   175  	}
   176  	return nil
   177  }
   178  
   179  func cleanupRmAll(jirix *jiri.X, db *profiles.DB, root jiri.RelPath) error {
   180  	s := jirix.NewSeq()
   181  	if err := s.AssertFileExists(db.Path()).Remove(db.Path()).Done(); err != nil && !runutil.IsNotExist(err) {
   182  		return err
   183  	} else {
   184  		if err := s.AssertDirExists(db.Path()).RemoveAll(db.Path()).Done(); err != nil && !runutil.IsNotExist(err) {
   185  			return err
   186  		}
   187  	}
   188  	d := root.Abs(jirix)
   189  	err := s.AssertDirExists(d).
   190  		Run("chmod", "-R", "u+w", d).
   191  		RemoveAll(d).
   192  		Done()
   193  	if err == nil || runutil.IsNotExist(err) {
   194  		fmt.Fprintf(jirix.Stdout(), "success\n")
   195  		return nil
   196  	} else {
   197  		fmt.Fprintf(jirix.Stdout(), "%v\n", err)
   198  	}
   199  	return err
   200  }
   201  
   202  func (ip *inproc) cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error {
   203  	if cl.gc {
   204  		if cl.verbose {
   205  			fmt.Fprintf(jirix.Stdout(), "Removing targets older than the default version for %s\n", ip.qname)
   206  		}
   207  		if err := cleanupGC(jirix, ip.db, root, cl.verbose, ip.qname); err != nil {
   208  			return fmt.Errorf("gc: %v", err)
   209  		}
   210  	}
   211  	if cl.rmAll {
   212  		if cl.verbose {
   213  			fmt.Fprintf(jirix.Stdout(), "Removing profile manifest and all profile output files\n")
   214  		}
   215  		if err := cleanupRmAll(jirix, ip.db, root); err != nil {
   216  			return err
   217  		}
   218  	}
   219  	return nil
   220  }
   221  
   222  type subcommand struct {
   223  	installer, profile, qname string
   224  	db                        *profiles.DB
   225  }
   226  
   227  func (sc *subcommand) mgrName() string {
   228  	return sc.qname
   229  }
   230  
   231  func (sc *subcommand) run(jirix *jiri.X, verb string, args []string) error {
   232  	cl := []string{"profile-" + sc.installer, verb}
   233  	cl = append(cl, args...)
   234  	cl = append(cl, sc.qname)
   235  	return jirix.NewSeq().Capture(jirix.Stdout(), jirix.Stderr()).Last("jiri", cl...)
   236  }
   237  
   238  func (sc *subcommand) packageCmds(jirix *jiri.X, cl *packagesFlagValues, root jiri.RelPath) ([][]string, error) {
   239  	cmd := []string{"profile-" + sc.installer, "os-packages"}
   240  	cmd = append(cmd, cl.args()...)
   241  	cmd = append(cmd, sc.qname)
   242  	var out bytes.Buffer
   243  	if err := jirix.NewSeq().Capture(&out, jirix.Stderr()).Last("jiri", cmd...); err != nil {
   244  		return nil, err
   245  	}
   246  	scanner := bufio.NewScanner(&out)
   247  	cmds := make([][]string, 0, 5)
   248  	for scanner.Scan() {
   249  		cmds = append(cmds, strings.Split(scanner.Text(), " "))
   250  	}
   251  	return cmds, nil
   252  }
   253  
   254  func (sc *subcommand) install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error {
   255  	return sc.run(jirix, "install", cl.args())
   256  }
   257  
   258  func (sc *subcommand) uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error {
   259  	return sc.run(jirix, "uninstall", cl.args())
   260  }
   261  
   262  func (sc *subcommand) update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error {
   263  	return sc.run(jirix, "update", cl.args())
   264  }
   265  
   266  func (sc *subcommand) cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error {
   267  	return sc.run(jirix, "cleanup", cl.args())
   268  }
   269  
   270  func logResult(jirix *jiri.X, action string, mgr profiles.Manager, target profiles.Target, err error) {
   271  	fmt.Fprintf(jirix.Stdout(), "%s: %s %s: ", action, profiles.QualifiedProfileName(mgr.Installer(), mgr.Name()), target)
   272  	if err == nil {
   273  		fmt.Fprintf(jirix.Stdout(), "success\n")
   274  	} else {
   275  		fmt.Fprintf(jirix.Stdout(), "%v\n", err)
   276  	}
   277  }