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