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 }