Commit f1a08adb authored by Johan Lyheden's avatar Johan Lyheden

Update to comply with linter rules and gofmt

parent d43d5ab4
......@@ -16,188 +16,192 @@ limitations under the License.
package installer // import "k8s.io/helm/pkg/plugin/installer"
import (
"k8s.io/helm/pkg/helm/helmpath"
"path/filepath"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/plugin/cache"
"compress/gzip"
"archive/tar"
"io"
"os"
"fmt"
"strings"
"bytes"
"regexp"
"archive/tar"
"bytes"
"compress/gzip"
"fmt"
"io"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/plugin/cache"
"os"
"path/filepath"
"regexp"
"strings"
)
type HttpInstaller struct {
CacheDir string
PluginName string
base
extractor Extractor
getter getter.Getter
// HTTPInstaller installs plugins from an archive served by a web server.
type HTTPInstaller struct {
CacheDir string
PluginName string
base
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 {
Extract(buffer *bytes.Buffer, targetDir string) error
Extract(buffer *bytes.Buffer, targetDir string) error
}
var Extractors = map[string]Extractor {
".tar.gz": &TarGzExtractor{},
".tgz": &TarGzExtractor{},
// Extractors contains a map of suffixes and matching implementations of extractor to return
var Extractors = map[string]Extractor{
".tar.gz": &TarGzExtractor{},
".tgz": &TarGzExtractor{},
}
// NewExtractor creates a new extractor matching the source file name
func NewExtractor(source string) (Extractor, error) {
for suffix, extractor := range Extractors {
if strings.HasSuffix(source, suffix) {
return extractor, nil
}
}
return nil, fmt.Errorf("no extractor implemented yet for %s", source)
for suffix, extractor := range Extractors {
if strings.HasSuffix(source, suffix) {
return extractor, nil
}
}
return nil, fmt.Errorf("no extractor implemented yet for %s", source)
}
// NewHttpInstaller creates a new HttpInstaller.
func NewHttpInstaller(source string, home helmpath.Home) (*HttpInstaller, error) {
key, err := cache.Key(source)
if err != nil {
return nil, err
}
extractor, err := NewExtractor(source)
if err != nil {
return nil, err
}
getConstructor, err := getter.ByScheme("http", environment.EnvSettings{})
if err != nil {
return nil, err
}
get, err := getConstructor.New(source,"", "", "")
if err != nil {
return nil, err
}
i := &HttpInstaller{
CacheDir: home.Path("cache", "plugins", key),
PluginName: stripPluginName(filepath.Base(source)),
base: newBase(source, home),
extractor: extractor,
getter: get,
}
return i, nil
// NewHTTPInstaller creates a new HttpInstaller.
func NewHTTPInstaller(source string, home helmpath.Home) (*HTTPInstaller, error) {
key, err := cache.Key(source)
if err != nil {
return nil, err
}
extractor, err := NewExtractor(source)
if err != nil {
return nil, err
}
getConstructor, err := getter.ByScheme("http", environment.EnvSettings{})
if err != nil {
return nil, err
}
get, err := getConstructor.New(source, "", "", "")
if err != nil {
return nil, err
}
i := &HTTPInstaller{
CacheDir: home.Path("cache", "plugins", key),
PluginName: stripPluginName(filepath.Base(source)),
base: newBase(source, home),
extractor: extractor,
getter: get,
}
return i, nil
}
// helper that relies on some sort of convention for plugin name (plugin-name-<version>)
func stripPluginName(name string) string {
var strippedName string
for suffix := range Extractors {
if strings.HasSuffix(name, suffix) {
strippedName = strings.TrimSuffix(name, suffix)
break
}
}
re := regexp.MustCompile(`(.*)-[0-9]+\..*`)
return re.ReplaceAllString(strippedName, `$1`)
var strippedName string
for suffix := range Extractors {
if strings.HasSuffix(name, suffix) {
strippedName = strings.TrimSuffix(name, suffix)
break
}
}
re := regexp.MustCompile(`(.*)-[0-9]+\..*`)
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.
func (i *HttpInstaller) Install() error {
func (i *HTTPInstaller) Install() error {
pluginData, err := i.getter.Get(i.Source)
if err != nil {
return err
}
pluginData, err := i.getter.Get(i.Source)
if err != nil {
return err
}
err = i.extractor.Extract(pluginData, i.CacheDir)
if err != nil {
return err
}
err = i.extractor.Extract(pluginData, i.CacheDir)
if err != nil {
return err
}
if !isPlugin(i.CacheDir) {
return ErrMissingMetadata
}
if !isPlugin(i.CacheDir) {
return ErrMissingMetadata
}
src, err := filepath.Abs(i.CacheDir)
if err != nil {
return err
}
src, err := filepath.Abs(i.CacheDir)
if err != nil {
return err
}
return i.link(src)
return i.link(src)
}
// Update updates a local repository
// Not implemented for now since tarball most likely will be packaged by version
func (i *HttpInstaller) Update() error {
return fmt.Errorf("method Update() not implemented for HttpInstaller")
func (i *HTTPInstaller) Update() error {
return fmt.Errorf("method Update() not implemented for HttpInstaller")
}
// Override link because we want to use HttpInstaller.Path() not base.Path()
func (i *HttpInstaller) link(from string) error {
debug("symlinking %s to %s", from, i.Path())
return os.Symlink(from, i.Path())
func (i *HTTPInstaller) link(from string) error {
debug("symlinking %s to %s", from, i.Path())
return os.Symlink(from, i.Path())
}
// Override Path() because we want to join on the plugin name not the file name
func (i HttpInstaller) Path() string {
if i.base.Source == "" {
return ""
}
return filepath.Join(i.base.HelmHome.Plugins(), i.PluginName)
// Path is overridden because we want to join on the plugin name not the file name
func (i HTTPInstaller) Path() string {
if i.base.Source == "" {
return ""
}
return filepath.Join(i.base.HelmHome.Plugins(), i.PluginName)
}
// Extracts tar.gz archive
// Extract extracts compressed archives
//
// Implements Extractor.
func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error {
uncompressedStream, err := gzip.NewReader(buffer)
if err != nil {
return err
}
tarReader := tar.NewReader(uncompressedStream)
os.MkdirAll(targetDir, 0755)
for true {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
path := filepath.Join(targetDir, header.Name)
switch header.Typeflag {
case tar.TypeDir:
if err := os.Mkdir(path, 0755); err != nil {
return err
}
case tar.TypeReg:
outFile, err := os.Create(path)
if err != nil {
return err
}
defer outFile.Close()
if _, err := io.Copy(outFile, tarReader); err != nil {
return err
}
default:
return fmt.Errorf("unknown type: %s in %s", header.Typeflag, header.Name)
}
}
return nil
}
\ No newline at end of file
uncompressedStream, err := gzip.NewReader(buffer)
if err != nil {
return err
}
tarReader := tar.NewReader(uncompressedStream)
os.MkdirAll(targetDir, 0755)
for true {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
path := filepath.Join(targetDir, header.Name)
switch header.Typeflag {
case tar.TypeDir:
if err := os.Mkdir(path, 0755); err != nil {
return err
}
case tar.TypeReg:
outFile, err := os.Create(path)
if err != nil {
return err
}
defer outFile.Close()
if _, err := io.Copy(outFile, tarReader); err != nil {
return err
}
default:
return fmt.Errorf("unknown type: %b in %s", header.Typeflag, header.Name)
}
}
return nil
}
......@@ -16,88 +16,88 @@ limitations under the License.
package installer // import "k8s.io/helm/pkg/plugin/installer"
import (
"testing"
"io/ioutil"
"os"
"k8s.io/helm/pkg/helm/helmpath"
"bytes"
"encoding/base64"
"bytes"
"encoding/base64"
"io/ioutil"
"k8s.io/helm/pkg/helm/helmpath"
"os"
"testing"
)
var _ Installer = new(HttpInstaller)
var _ Installer = new(HTTPInstaller)
// Fake http client
type TestHttpGetter struct {
MockResponse *bytes.Buffer
type TestHTTPGetter struct {
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
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) {
if stripPluginName("fake-plugin-0.0.1.tar.gz") != "fake-plugin" {
t.Errorf("name does not match expected value")
}
if stripPluginName("fake-plugin-0.0.1.tgz") != "fake-plugin" {
t.Errorf("name does not match expected value")
}
if stripPluginName("fake-plugin.tgz") != "fake-plugin" {
t.Errorf("name does not match expected value")
}
if stripPluginName("fake-plugin.tar.gz") != "fake-plugin" {
t.Errorf("name does not match expected value")
}
if stripPluginName("fake-plugin-0.0.1.tar.gz") != "fake-plugin" {
t.Errorf("name does not match expected value")
}
if stripPluginName("fake-plugin-0.0.1.tgz") != "fake-plugin" {
t.Errorf("name does not match expected value")
}
if stripPluginName("fake-plugin.tgz") != "fake-plugin" {
t.Errorf("name does not match expected value")
}
if stripPluginName("fake-plugin.tar.gz") != "fake-plugin" {
t.Errorf("name does not match expected value")
}
}
func TestHttpInstaller(t *testing.T) {
source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz"
hh, err := ioutil.TempDir("", "helm-home-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(hh)
home := helmpath.Home(hh)
if err := os.MkdirAll(home.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", home.Plugins(), err)
}
i, err := NewForSource(source, "0.0.1", home)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
// ensure a HttpInstaller was returned
httpInstaller, ok := i.(*HttpInstaller)
if !ok {
t.Error("expected a HttpInstaller")
}
// inject fake http client responding with minimal plugin tarball
mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64)
if err != nil {
t.Fatalf("Could not decode fake tgz plugin: %s", err)
}
httpInstaller.getter = &TestHttpGetter{
MockResponse: bytes.NewBuffer(mockTgz),
}
// install the plugin
if err := Install(i); err != nil {
t.Error(err)
}
if i.Path() != home.Path("plugins", "fake-plugin") {
t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path())
}
// Install again to test plugin exists error
if err := Install(i); err == nil {
t.Error("expected error for plugin exists, got none")
} else if err.Error() != "plugin already exists" {
t.Errorf("expected error for plugin exists, got (%v)", err)
}
}
\ No newline at end of file
func TestHTTPInstaller(t *testing.T) {
source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz"
hh, err := ioutil.TempDir("", "helm-home-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(hh)
home := helmpath.Home(hh)
if err := os.MkdirAll(home.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", home.Plugins(), err)
}
i, err := NewForSource(source, "0.0.1", home)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
// ensure a HttpInstaller was returned
httpInstaller, ok := i.(*HTTPInstaller)
if !ok {
t.Error("expected a HttpInstaller")
}
// inject fake http client responding with minimal plugin tarball
mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64)
if err != nil {
t.Fatalf("Could not decode fake tgz plugin: %s", err)
}
httpInstaller.getter = &TestHTTPGetter{
MockResponse: bytes.NewBuffer(mockTgz),
}
// install the plugin
if err := Install(i); err != nil {
t.Error(err)
}
if i.Path() != home.Path("plugins", "fake-plugin") {
t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path())
}
// Install again to test plugin exists error
if err := Install(i); err == nil {
t.Error("expected error for plugin exists, got none")
} else if err.Error() != "plugin already exists" {
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
if isLocalReference(source) {
return NewLocalInstaller(source, home)
} else if isRemoteHttpArchive(source) {
return NewHttpInstaller(source, home)
} else if isRemoteHTTPArchive(source) {
return NewHTTPInstaller(source, home)
}
return NewVCSInstaller(source, version, home)
}
......@@ -90,10 +90,10 @@ func isLocalReference(source string) bool {
return err == nil
}
// isRemoteHttpArchive checks if the source is a http/https url and is an archive
func isRemoteHttpArchive(source string) bool {
// isRemoteHTTPArchive checks if the source is a http/https url and is an archive
func isRemoteHTTPArchive(source string) bool {
if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") {
for suffix, _ := range Extractors {
for suffix := range Extractors {
if strings.HasSuffix(source, suffix) {
return true
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment