v.io/jiri@v0.0.0-20160715023856-abfb8b131290/profiles/profiles.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 profiles and its subdirectoris implement support for managing external
     6  // sofware dependencies. They offer a balance between providing no support at
     7  // all and a full blown package manager. A profile is a named collection of
     8  // software required for a given system component or application. The name of
     9  // the profile refers to all of the required software, which may a single
    10  // library or a collection of libraries or SDKs. Profiles thus refer to
    11  // uncompiled source code that needs to be compiled for a specific "target".
    12  // Targets represent compiled code and consist of:
    13  //
    14  // 1. An 'architecture' that refers to the CPU to be generate code for.
    15  //
    16  // 2. An 'operating system' that refers to the operating system to generate
    17  // code for.
    18  //
    19  // 3. An 'environment' which is a set of environment variables to use when
    20  // compiling and using the profile.
    21  //
    22  // Targets provide the essential support for cross compilation.
    23  //
    24  // The profiles package provides the data types to support its sub-packages,
    25  // including a database format (in XML) that is used to store the state of
    26  // the currently installed profiles.
    27  //
    28  // The profilesmanager sub-package provides a registry for profile
    29  // implementations to register themselves (by calling manager.Register
    30  // from an init function for example).
    31  //
    32  // The profilesreader sub-package provides support for reading the profiles
    33  // database and performing common operations on it.
    34  // profiles/commandline provides an easy to use command line environment for
    35  // tools that need to read and/or write profiles.
    36  //
    37  // The profilescmdline sub-package provides support for implementing
    38  // command line clients that implement profile installation and for
    39  // reading profile information. It also provides support for invoking
    40  // sub-commands to manage families of profiles which uses the notion
    41  // of a 'qualified' profile name where the profile name includes a prefix
    42  // (separated by InstallSeparator) which identifies the sub-command responsible
    43  // for managing that profile.
    44  //
    45  // The profilesutil sub-package provides some utility routines intended
    46  // for use by profile implementers.
    47  //
    48  // Profiles may be installed, updated or removed. When doing so, the name of
    49  // the profile is required, but the other components of the target are optional
    50  // and will default to the values of the system that the commands are run on
    51  // (so-called native builds). These operations are defined by the
    52  // profiles/manager.Manager interface.
    53  package profiles
    54  
    55  import (
    56  	"flag"
    57  	"strings"
    58  
    59  	"v.io/jiri"
    60  )
    61  
    62  // InstallerSeparator is the string used to separate the installer
    63  // and profile name for qualified profile names.
    64  const InstallerSeparator = ":"
    65  
    66  // Profile represents an installed profile and its associated targets.
    67  type Profile struct {
    68  	name, root, installer string
    69  	targets               Targets
    70  }
    71  
    72  func clean(n string) string {
    73  	return strings.TrimRight(strings.TrimLeft(n, InstallerSeparator), InstallerSeparator)
    74  }
    75  
    76  // SplitProfileName returns the installer and profile name in the
    77  // case where the name is qualified (see QualifiedProfileName) or just
    78  // the profile name if it is not so qualified.
    79  func SplitProfileName(name string) (string, string) {
    80  	if pos := strings.Index(name, InstallerSeparator); pos >= 0 {
    81  		return name[:pos], name[pos+len(InstallerSeparator):]
    82  	}
    83  	return "", name
    84  }
    85  
    86  // QualifiedProfileName returns the name of a profile qualified by
    87  // the name of its installer, if any. If the installer is "myproject"
    88  // and the profile name is "bar" then then returned string is
    89  // "myproject" + InstallerSeparator + "bar". If the installer is not
    90  // specified then the unqualified name, without InstallerSeparator is returned.
    91  // If the supplied name is already qualified then the existing qualifier
    92  // will be removed and the supplied one used instead.
    93  // Any leading colons in name will be stripped.
    94  func QualifiedProfileName(installer, name string) string {
    95  	name = clean(name)
    96  	installer = clean(installer)
    97  	if installer != "" {
    98  		// Strip any existing installer.
    99  		_, n := SplitProfileName(name)
   100  		return installer + InstallerSeparator + n
   101  	}
   102  	return name
   103  }
   104  
   105  // Name returns the qualified name of this profile.
   106  func (p *Profile) Name() string {
   107  	return QualifiedProfileName(p.installer, p.name)
   108  }
   109  
   110  // Root returns the directory, relative to the jiri root, that this
   111  // profile is installed at.
   112  func (p *Profile) Root() string {
   113  	return p.root
   114  }
   115  
   116  // Targets returns the currently installed set of targets for this profile.
   117  // Note that Targets is ordered by architecture, operating system and
   118  // descending versions.
   119  func (p *Profile) Targets() Targets {
   120  	r := make(Targets, len(p.targets), len(p.targets))
   121  	for i, t := range p.targets {
   122  		tmp := *t
   123  		r[i] = &tmp
   124  	}
   125  	return r
   126  }
   127  
   128  type Action int
   129  
   130  const (
   131  	Install Action = iota
   132  	Uninstall
   133  )
   134  
   135  // Manager is the interface that must be implemented in order to
   136  // manage (i.e. install/uninstall) and describe a profile.
   137  type Manager interface {
   138  	// Name returns the unqualified name of this profile.
   139  	Name() string
   140  
   141  	// Installer returns the installer for this profile.
   142  	Installer() string
   143  
   144  	// Info returns an informative description of the profile.
   145  	Info() string
   146  
   147  	// VersionInfo returns the VersionInfo instance for this profile.
   148  	VersionInfo() *VersionInfo
   149  
   150  	// String returns a string representation of the profile, conventionally
   151  	// this is its qualified name and version.
   152  	String() string
   153  
   154  	// AddFlags allows the profile manager to add profile specific flags
   155  	// to the supplied FlagSet for the specified Action.
   156  	// They should be named <profile-name>.<flag>.
   157  	AddFlags(*flag.FlagSet, Action)
   158  
   159  	// OSPackages returns the set of operating system packages required by the
   160  	// specified profile and target.
   161  	OSPackages(jirix *jiri.X, pdb *DB, root jiri.RelPath, target Target) ([]string, error)
   162  
   163  	// Install installs the profile for the specified build target.
   164  	Install(jirix *jiri.X, pdb *DB, root jiri.RelPath, target Target) error
   165  
   166  	// Uninstall uninstalls the profile for the specified build target.
   167  	Uninstall(jirix *jiri.X, pdb *DB, root jiri.RelPath, target Target) error
   168  }