github.com/rohankumardubey/draft-classic@v0.16.0/pkg/plugin/installer/vcs_installer.go (about)

     1  package installer
     2  
     3  import (
     4  	"os"
     5  	"sort"
     6  
     7  	"github.com/Masterminds/semver"
     8  	"github.com/Masterminds/vcs"
     9  	"k8s.io/helm/pkg/plugin/cache"
    10  
    11  	"github.com/Azure/draft/pkg/draft/draftpath"
    12  	"github.com/Azure/draft/pkg/plugin"
    13  )
    14  
    15  //VCSInstaller installs plugins from a remote repository
    16  type VCSInstaller struct {
    17  	Repo    vcs.Repo
    18  	Version string
    19  	base
    20  }
    21  
    22  // NewVCSInstaller creates a new VCSInstaller.
    23  func NewVCSInstaller(source, version string, home draftpath.Home) (*VCSInstaller, error) {
    24  	// create a system safe cache key
    25  	key, err := cache.Key(source)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	cachedpath := home.Path("cache", "plugins", key)
    30  	repo, err := vcs.NewRepo(source, cachedpath)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	i := &VCSInstaller{
    36  		Repo:    repo,
    37  		Version: version,
    38  		base:    newBase(source, home),
    39  	}
    40  	return i, err
    41  }
    42  
    43  // Install clones a remote repository and creates a symlink to the plugin directory in DRAFT_HOME
    44  //
    45  // Implements Installer
    46  func (i *VCSInstaller) Install() error {
    47  	if err := i.sync(i.Repo); err != nil {
    48  		return err
    49  	}
    50  
    51  	ref, err := i.solveVersion(i.Repo)
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	if ref != "" {
    57  		if err := i.setVersion(i.Repo, ref); err != nil {
    58  			return err
    59  		}
    60  	}
    61  
    62  	if !isPlugin(i.Repo.LocalPath()) {
    63  		return plugin.ErrMissingMetadata
    64  	}
    65  
    66  	return i.link(i.Repo.LocalPath())
    67  }
    68  
    69  // Update updates a remote repository
    70  func (i *VCSInstaller) Update() error {
    71  	debug("updating %s", i.Repo.Remote())
    72  	if i.Repo.IsDirty() {
    73  		return plugin.ErrRepoDirty
    74  	}
    75  	if err := i.Repo.Update(); err != nil {
    76  		return err
    77  	}
    78  	if !isPlugin(i.Repo.LocalPath()) {
    79  		return plugin.ErrMissingMetadata
    80  	}
    81  	return nil
    82  }
    83  
    84  func existingVCSRepo(location string, home draftpath.Home) (Installer, error) {
    85  	repo, err := vcs.NewRepo("", location)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	i := &VCSInstaller{
    90  		Repo: repo,
    91  		base: newBase(repo.Remote(), home),
    92  	}
    93  
    94  	return i, err
    95  }
    96  
    97  // Filter a list of versions to only included semantic versions. The response
    98  // is a mapping of the original version to the semantic version.
    99  func getSemVers(refs []string) []*semver.Version {
   100  	var sv []*semver.Version
   101  	for _, r := range refs {
   102  		if v, err := semver.NewVersion(r); err == nil {
   103  			sv = append(sv, v)
   104  		}
   105  	}
   106  	return sv
   107  }
   108  
   109  // setVersion attempts to checkout the version
   110  func (i *VCSInstaller) setVersion(repo vcs.Repo, ref string) error {
   111  	debug("setting version to %q", i.Version)
   112  	return repo.UpdateVersion(ref)
   113  }
   114  
   115  func (i *VCSInstaller) solveVersion(repo vcs.Repo) (string, error) {
   116  	if i.Version == "" {
   117  		return "", nil
   118  	}
   119  
   120  	if repo.IsReference(i.Version) {
   121  		return i.Version, nil
   122  	}
   123  
   124  	// Create the constraint first to make sure it's valid before
   125  	// working on the repo.
   126  	constraint, err := semver.NewConstraint(i.Version)
   127  	if err != nil {
   128  		return "", err
   129  	}
   130  
   131  	// Get the tags
   132  	refs, err := repo.Tags()
   133  	if err != nil {
   134  		return "", err
   135  	}
   136  	debug("found refs: %s", refs)
   137  
   138  	// Convert and filter the list to semver.Version instances
   139  	semvers := getSemVers(refs)
   140  
   141  	// Sort semver list
   142  	sort.Sort(sort.Reverse(semver.Collection(semvers)))
   143  	for _, v := range semvers {
   144  		if constraint.Check(v) {
   145  			// If the constraint passes get the original reference
   146  			ver := v.Original()
   147  			debug("setting to %s", ver)
   148  			return ver, nil
   149  		}
   150  	}
   151  
   152  	return "", plugin.ErrVersionDoesNotExist
   153  }
   154  
   155  // sync will clone or update a remote repo.
   156  func (i *VCSInstaller) sync(repo vcs.Repo) error {
   157  
   158  	if _, err := os.Stat(repo.LocalPath()); os.IsNotExist(err) {
   159  		debug("cloning %s to %s", repo.Remote(), repo.LocalPath())
   160  		return repo.Get()
   161  	}
   162  	debug("updating %s", repo.Remote())
   163  	return repo.Update()
   164  }