github.com/sgoings/helm@v2.0.0-alpha.2.0.20170406211108-734e92851ac3+incompatible/pkg/plugin/installer/vcs_installer.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package installer // import "k8s.io/helm/pkg/plugin/installer"
    17  
    18  import (
    19  	"os"
    20  	"sort"
    21  
    22  	"github.com/Masterminds/semver"
    23  	"github.com/Masterminds/vcs"
    24  
    25  	"k8s.io/helm/pkg/helm/helmpath"
    26  	"k8s.io/helm/pkg/plugin/cache"
    27  )
    28  
    29  // VCSInstaller installs plugins from remote a repository.
    30  type VCSInstaller struct {
    31  	Repo    vcs.Repo
    32  	Version string
    33  	base
    34  }
    35  
    36  // NewVCSInstaller creates a new VCSInstaller.
    37  func NewVCSInstaller(source, version string, home helmpath.Home) (*VCSInstaller, error) {
    38  	key, err := cache.Key(source)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	cachedpath := home.Path("cache", "plugins", key)
    43  	repo, err := vcs.NewRepo(source, cachedpath)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	i := &VCSInstaller{
    48  		Repo:    repo,
    49  		Version: version,
    50  		base:    newBase(source, home),
    51  	}
    52  	return i, err
    53  }
    54  
    55  // Install clones a remote repository and creates a symlink to the plugin directory in HELM_HOME.
    56  //
    57  // Implements Installer.
    58  func (i *VCSInstaller) Install() error {
    59  	if err := i.sync(i.Repo); err != nil {
    60  		return err
    61  	}
    62  
    63  	ref, err := i.solveVersion(i.Repo)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	if err := i.setVersion(i.Repo, ref); err != nil {
    69  		return err
    70  	}
    71  
    72  	if !isPlugin(i.Repo.LocalPath()) {
    73  		return ErrMissingMetadata
    74  	}
    75  
    76  	return i.link(i.Repo.LocalPath())
    77  }
    78  
    79  func (i *VCSInstaller) solveVersion(repo vcs.Repo) (string, error) {
    80  	if i.Version == "" {
    81  		return "", nil
    82  	}
    83  
    84  	if repo.IsReference(i.Version) {
    85  		return i.Version, nil
    86  	}
    87  
    88  	// Create the constraint first to make sure it's valid before
    89  	// working on the repo.
    90  	constraint, err := semver.NewConstraint(i.Version)
    91  	if err != nil {
    92  		return "", err
    93  	}
    94  
    95  	// Get the tags and branches (in that order)
    96  	refs, err := repo.Tags()
    97  	if err != nil {
    98  		return "", err
    99  	}
   100  	debug("found refs: %s", refs)
   101  
   102  	// Convert and filter the list to semver.Version instances
   103  	semvers := getSemVers(refs)
   104  
   105  	// Sort semver list
   106  	sort.Sort(sort.Reverse(semver.Collection(semvers)))
   107  	for _, v := range semvers {
   108  		if constraint.Check(v) {
   109  			// If the constrint passes get the original reference
   110  			ver := v.Original()
   111  			debug("setting to %s", ver)
   112  			return ver, nil
   113  		}
   114  	}
   115  	return "", nil
   116  }
   117  
   118  // setVersion attempts to checkout the version
   119  func (i *VCSInstaller) setVersion(repo vcs.Repo, ref string) error {
   120  	debug("setting version to %q", i.Version)
   121  	return repo.UpdateVersion(ref)
   122  }
   123  
   124  // sync will clone or update a remote repo.
   125  func (i *VCSInstaller) sync(repo vcs.Repo) error {
   126  	if _, err := os.Stat(repo.LocalPath()); os.IsNotExist(err) {
   127  		debug("cloning %s to %s", repo.Remote(), repo.LocalPath())
   128  		return repo.Get()
   129  	}
   130  	debug("updating %s", repo.Remote())
   131  	return repo.Update()
   132  }
   133  
   134  // Filter a list of versions to only included semantic versions. The response
   135  // is a mapping of the original version to the semantic version.
   136  func getSemVers(refs []string) []*semver.Version {
   137  	var sv []*semver.Version
   138  	for _, r := range refs {
   139  		v, err := semver.NewVersion(r)
   140  		if err == nil {
   141  			sv = append(sv, v)
   142  		}
   143  	}
   144  	return sv
   145  }