Update to comply with linter rules and gofmt

pull/3041/head
Johan Lyheden 7 years ago
parent d43d5ab452
commit f1a08adb41

@ -16,188 +16,192 @@ limitations under the License.
package installer // import "k8s.io/helm/pkg/plugin/installer" package installer // import "k8s.io/helm/pkg/plugin/installer"
import ( import (
"k8s.io/helm/pkg/helm/helmpath" "archive/tar"
"path/filepath" "bytes"
"k8s.io/helm/pkg/getter" "compress/gzip"
"k8s.io/helm/pkg/helm/environment" "fmt"
"k8s.io/helm/pkg/plugin/cache" "io"
"compress/gzip" "k8s.io/helm/pkg/getter"
"archive/tar" "k8s.io/helm/pkg/helm/environment"
"io" "k8s.io/helm/pkg/helm/helmpath"
"os" "k8s.io/helm/pkg/plugin/cache"
"fmt" "os"
"strings" "path/filepath"
"bytes" "regexp"
"regexp" "strings"
) )
type HttpInstaller struct { // HTTPInstaller installs plugins from an archive served by a web server.
CacheDir string type HTTPInstaller struct {
PluginName string CacheDir string
base PluginName string
extractor Extractor base
getter getter.Getter extractor Extractor
getter getter.Getter
} }
type TarGzExtractor struct {} // TarGzExtractor extracts gzip compressed tar archives
type TarGzExtractor struct{}
// Extractor provides an interface for extracting archives
type Extractor interface { type Extractor interface {
Extract(buffer *bytes.Buffer, targetDir string) error Extract(buffer *bytes.Buffer, targetDir string) error
} }
var Extractors = map[string]Extractor { // Extractors contains a map of suffixes and matching implementations of extractor to return
".tar.gz": &TarGzExtractor{}, var Extractors = map[string]Extractor{
".tgz": &TarGzExtractor{}, ".tar.gz": &TarGzExtractor{},
".tgz": &TarGzExtractor{},
} }
// NewExtractor creates a new extractor matching the source file name // NewExtractor creates a new extractor matching the source file name
func NewExtractor(source string) (Extractor, error) { func NewExtractor(source string) (Extractor, error) {
for suffix, extractor := range Extractors { for suffix, extractor := range Extractors {
if strings.HasSuffix(source, suffix) { if strings.HasSuffix(source, suffix) {
return extractor, nil return extractor, nil
} }
} }
return nil, fmt.Errorf("no extractor implemented yet for %s", source) return nil, fmt.Errorf("no extractor implemented yet for %s", source)
} }
// NewHttpInstaller creates a new HttpInstaller. // NewHTTPInstaller creates a new HttpInstaller.
func NewHttpInstaller(source string, home helmpath.Home) (*HttpInstaller, error) { func NewHTTPInstaller(source string, home helmpath.Home) (*HTTPInstaller, error) {
key, err := cache.Key(source) key, err := cache.Key(source)
if err != nil { if err != nil {
return nil, err return nil, err
} }
extractor, err := NewExtractor(source) extractor, err := NewExtractor(source)
if err != nil { if err != nil {
return nil, err return nil, err
} }
getConstructor, err := getter.ByScheme("http", environment.EnvSettings{}) getConstructor, err := getter.ByScheme("http", environment.EnvSettings{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
get, err := getConstructor.New(source,"", "", "") get, err := getConstructor.New(source, "", "", "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
i := &HttpInstaller{ i := &HTTPInstaller{
CacheDir: home.Path("cache", "plugins", key), CacheDir: home.Path("cache", "plugins", key),
PluginName: stripPluginName(filepath.Base(source)), PluginName: stripPluginName(filepath.Base(source)),
base: newBase(source, home), base: newBase(source, home),
extractor: extractor, extractor: extractor,
getter: get, getter: get,
} }
return i, nil return i, nil
} }
// helper that relies on some sort of convention for plugin name (plugin-name-<version>) // helper that relies on some sort of convention for plugin name (plugin-name-<version>)
func stripPluginName(name string) string { func stripPluginName(name string) string {
var strippedName string var strippedName string
for suffix := range Extractors { for suffix := range Extractors {
if strings.HasSuffix(name, suffix) { if strings.HasSuffix(name, suffix) {
strippedName = strings.TrimSuffix(name, suffix) strippedName = strings.TrimSuffix(name, suffix)
break break
} }
} }
re := regexp.MustCompile(`(.*)-[0-9]+\..*`) re := regexp.MustCompile(`(.*)-[0-9]+\..*`)
return re.ReplaceAllString(strippedName, `$1`) return re.ReplaceAllString(strippedName, `$1`)
} }
// Install() downloads and extracts the tarball into the cache directory and creates a symlink to the plugin directory in $HELM_HOME. // Install downloads and extracts the tarball into the cache directory and creates a symlink to the plugin directory in $HELM_HOME.
// //
// Implements Installer. // Implements Installer.
func (i *HttpInstaller) Install() error { func (i *HTTPInstaller) Install() error {
pluginData, err := i.getter.Get(i.Source) pluginData, err := i.getter.Get(i.Source)
if err != nil { if err != nil {
return err return err
} }
err = i.extractor.Extract(pluginData, i.CacheDir) err = i.extractor.Extract(pluginData, i.CacheDir)
if err != nil { if err != nil {
return err return err
} }
if !isPlugin(i.CacheDir) { if !isPlugin(i.CacheDir) {
return ErrMissingMetadata return ErrMissingMetadata
} }
src, err := filepath.Abs(i.CacheDir) src, err := filepath.Abs(i.CacheDir)
if err != nil { if err != nil {
return err return err
} }
return i.link(src) return i.link(src)
} }
// Update updates a local repository // Update updates a local repository
// Not implemented for now since tarball most likely will be packaged by version // Not implemented for now since tarball most likely will be packaged by version
func (i *HttpInstaller) Update() error { func (i *HTTPInstaller) Update() error {
return fmt.Errorf("method Update() not implemented for HttpInstaller") return fmt.Errorf("method Update() not implemented for HttpInstaller")
} }
// Override link because we want to use HttpInstaller.Path() not base.Path() // Override link because we want to use HttpInstaller.Path() not base.Path()
func (i *HttpInstaller) link(from string) error { func (i *HTTPInstaller) link(from string) error {
debug("symlinking %s to %s", from, i.Path()) debug("symlinking %s to %s", from, i.Path())
return os.Symlink(from, i.Path()) return os.Symlink(from, i.Path())
} }
// Override Path() because we want to join on the plugin name not the file name // Path is overridden because we want to join on the plugin name not the file name
func (i HttpInstaller) Path() string { func (i HTTPInstaller) Path() string {
if i.base.Source == "" { if i.base.Source == "" {
return "" return ""
} }
return filepath.Join(i.base.HelmHome.Plugins(), i.PluginName) return filepath.Join(i.base.HelmHome.Plugins(), i.PluginName)
} }
// Extracts tar.gz archive // Extract extracts compressed archives
// //
// Implements Extractor. // Implements Extractor.
func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error { func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error {
uncompressedStream, err := gzip.NewReader(buffer) uncompressedStream, err := gzip.NewReader(buffer)
if err != nil { if err != nil {
return err return err
} }
tarReader := tar.NewReader(uncompressedStream) tarReader := tar.NewReader(uncompressedStream)
os.MkdirAll(targetDir, 0755) os.MkdirAll(targetDir, 0755)
for true { for true {
header, err := tarReader.Next() header, err := tarReader.Next()
if err == io.EOF { if err == io.EOF {
break break
} }
if err != nil { if err != nil {
return err return err
} }
path := filepath.Join(targetDir, header.Name) path := filepath.Join(targetDir, header.Name)
switch header.Typeflag { switch header.Typeflag {
case tar.TypeDir: case tar.TypeDir:
if err := os.Mkdir(path, 0755); err != nil { if err := os.Mkdir(path, 0755); err != nil {
return err return err
} }
case tar.TypeReg: case tar.TypeReg:
outFile, err := os.Create(path) outFile, err := os.Create(path)
if err != nil { if err != nil {
return err return err
} }
defer outFile.Close() defer outFile.Close()
if _, err := io.Copy(outFile, tarReader); err != nil { if _, err := io.Copy(outFile, tarReader); err != nil {
return err return err
} }
default: default:
return fmt.Errorf("unknown type: %s in %s", header.Typeflag, header.Name) return fmt.Errorf("unknown type: %b in %s", header.Typeflag, header.Name)
} }
} }
return nil return nil
} }

@ -16,88 +16,88 @@ limitations under the License.
package installer // import "k8s.io/helm/pkg/plugin/installer" package installer // import "k8s.io/helm/pkg/plugin/installer"
import ( import (
"testing" "bytes"
"io/ioutil" "encoding/base64"
"os" "io/ioutil"
"k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/helm/helmpath"
"bytes" "os"
"encoding/base64" "testing"
) )
var _ Installer = new(HttpInstaller) var _ Installer = new(HTTPInstaller)
// Fake http client // Fake http client
type TestHttpGetter struct { type TestHTTPGetter struct {
MockResponse *bytes.Buffer MockResponse *bytes.Buffer
} }
func (t *TestHttpGetter) Get(href string) (*bytes.Buffer, error) { return t.MockResponse, nil } func (t *TestHTTPGetter) Get(href string) (*bytes.Buffer, error) { return t.MockResponse, nil }
// Fake plugin tarball data // Fake plugin tarball data
var fakePluginB64 = "H4sIAKRj51kAA+3UX0vCUBgGcC9jn+Iwuk3Peza3GeyiUlJQkcogCOzgli7dJm4TvYk+a5+k479UqquUCJ/fLs549sLO2TnvWnJa9aXnjwujYdYLovxMhsPcfnHOLdNkOXthM/IVQQYjg2yyLLJ4kXGhLp5j0z3P41tZksqxmspL3B/O+j/XtZu1y8rdYzkOZRCxduKPk53ny6Wwz/GfIIf1As8lxzGJSmoHNLJZphKHG4YpTCE0wVk3DULfpSJ3DMMqkj3P5JfMYLdX1Vr9Ie/5E5cstcdC8K04iGLX5HaJuKpWL17F0TCIBi5pf/0pjtLhun5j3f9v6r7wfnI/H0eNp9d1/5P6Gez0vzo7wsoxfrAZbTny/o9k6J8z/VkO/LPlWdC1iVpbEEcq5nmeJ13LEtmbV0k2r2PrOs9PuuNglC5rL1Y5S/syXRQmutaNw1BGnnp8Wq3UG51WvX1da3bKtZtCN/R09DwAAAAAAAAAAAAAAAAAAADAb30AoMczDwAoAAA=" var fakePluginB64 = "H4sIAKRj51kAA+3UX0vCUBgGcC9jn+Iwuk3Peza3GeyiUlJQkcogCOzgli7dJm4TvYk+a5+k479UqquUCJ/fLs549sLO2TnvWnJa9aXnjwujYdYLovxMhsPcfnHOLdNkOXthM/IVQQYjg2yyLLJ4kXGhLp5j0z3P41tZksqxmspL3B/O+j/XtZu1y8rdYzkOZRCxduKPk53ny6Wwz/GfIIf1As8lxzGJSmoHNLJZphKHG4YpTCE0wVk3DULfpSJ3DMMqkj3P5JfMYLdX1Vr9Ie/5E5cstcdC8K04iGLX5HaJuKpWL17F0TCIBi5pf/0pjtLhun5j3f9v6r7wfnI/H0eNp9d1/5P6Gez0vzo7wsoxfrAZbTny/o9k6J8z/VkO/LPlWdC1iVpbEEcq5nmeJ13LEtmbV0k2r2PrOs9PuuNglC5rL1Y5S/syXRQmutaNw1BGnnp8Wq3UG51WvX1da3bKtZtCN/R09DwAAAAAAAAAAAAAAAAAAADAb30AoMczDwAoAAA="
func TestStripName(t *testing.T) { func TestStripName(t *testing.T) {
if stripPluginName("fake-plugin-0.0.1.tar.gz") != "fake-plugin" { if stripPluginName("fake-plugin-0.0.1.tar.gz") != "fake-plugin" {
t.Errorf("name does not match expected value") t.Errorf("name does not match expected value")
} }
if stripPluginName("fake-plugin-0.0.1.tgz") != "fake-plugin" { if stripPluginName("fake-plugin-0.0.1.tgz") != "fake-plugin" {
t.Errorf("name does not match expected value") t.Errorf("name does not match expected value")
} }
if stripPluginName("fake-plugin.tgz") != "fake-plugin" { if stripPluginName("fake-plugin.tgz") != "fake-plugin" {
t.Errorf("name does not match expected value") t.Errorf("name does not match expected value")
} }
if stripPluginName("fake-plugin.tar.gz") != "fake-plugin" { if stripPluginName("fake-plugin.tar.gz") != "fake-plugin" {
t.Errorf("name does not match expected value") t.Errorf("name does not match expected value")
} }
} }
func TestHttpInstaller(t *testing.T) { func TestHTTPInstaller(t *testing.T) {
source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz" source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz"
hh, err := ioutil.TempDir("", "helm-home-") hh, err := ioutil.TempDir("", "helm-home-")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(hh) defer os.RemoveAll(hh)
home := helmpath.Home(hh) home := helmpath.Home(hh)
if err := os.MkdirAll(home.Plugins(), 0755); err != nil { if err := os.MkdirAll(home.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", home.Plugins(), err) t.Fatalf("Could not create %s: %s", home.Plugins(), err)
} }
i, err := NewForSource(source, "0.0.1", home) i, err := NewForSource(source, "0.0.1", home)
if err != nil { if err != nil {
t.Errorf("unexpected error: %s", err) t.Errorf("unexpected error: %s", err)
} }
// ensure a HttpInstaller was returned // ensure a HttpInstaller was returned
httpInstaller, ok := i.(*HttpInstaller) httpInstaller, ok := i.(*HTTPInstaller)
if !ok { if !ok {
t.Error("expected a HttpInstaller") t.Error("expected a HttpInstaller")
} }
// inject fake http client responding with minimal plugin tarball // inject fake http client responding with minimal plugin tarball
mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64)
if err != nil { if err != nil {
t.Fatalf("Could not decode fake tgz plugin: %s", err) t.Fatalf("Could not decode fake tgz plugin: %s", err)
} }
httpInstaller.getter = &TestHttpGetter{ httpInstaller.getter = &TestHTTPGetter{
MockResponse: bytes.NewBuffer(mockTgz), MockResponse: bytes.NewBuffer(mockTgz),
} }
// install the plugin // install the plugin
if err := Install(i); err != nil { if err := Install(i); err != nil {
t.Error(err) t.Error(err)
} }
if i.Path() != home.Path("plugins", "fake-plugin") { if i.Path() != home.Path("plugins", "fake-plugin") {
t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path()) t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path())
} }
// Install again to test plugin exists error // Install again to test plugin exists error
if err := Install(i); err == nil { if err := Install(i); err == nil {
t.Error("expected error for plugin exists, got none") t.Error("expected error for plugin exists, got none")
} else if err.Error() != "plugin already exists" { } else if err.Error() != "plugin already exists" {
t.Errorf("expected error for plugin exists, got (%v)", err) t.Errorf("expected error for plugin exists, got (%v)", err)
} }
} }

@ -69,8 +69,8 @@ func NewForSource(source, version string, home helmpath.Home) (Installer, error)
// Check if source is a local directory // Check if source is a local directory
if isLocalReference(source) { if isLocalReference(source) {
return NewLocalInstaller(source, home) return NewLocalInstaller(source, home)
} else if isRemoteHttpArchive(source) { } else if isRemoteHTTPArchive(source) {
return NewHttpInstaller(source, home) return NewHTTPInstaller(source, home)
} }
return NewVCSInstaller(source, version, home) return NewVCSInstaller(source, version, home)
} }
@ -90,10 +90,10 @@ func isLocalReference(source string) bool {
return err == nil return err == nil
} }
// isRemoteHttpArchive checks if the source is a http/https url and is an archive // isRemoteHTTPArchive checks if the source is a http/https url and is an archive
func isRemoteHttpArchive(source string) bool { func isRemoteHTTPArchive(source string) bool {
if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") { if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") {
for suffix, _ := range Extractors { for suffix := range Extractors {
if strings.HasSuffix(source, suffix) { if strings.HasSuffix(source, suffix) {
return true return true
} }

Loading…
Cancel
Save