Unverified Commit de5af147 authored by bryanl's avatar bryanl
Browse files

import component from a http URL


Signed-off-by: default avatarbryanl <bryanliles@gmail.com>
parent 68d8f751
......@@ -17,7 +17,11 @@ package actions
import (
"bytes"
"io"
"mime"
"net/http"
"os"
"path"
"path/filepath"
"strings"
......@@ -70,8 +74,80 @@ func NewImport(m map[string]interface{}) (*Import, error) {
// Run runs the import process.
func (i *Import) Run() error {
if i.path == "" {
return errors.New("filename is required")
return errors.New("path is required")
}
if strings.HasPrefix(i.path, "http") {
return i.handleURL()
}
return i.handleLocal()
}
func (i *Import) handleURL() error {
resp, err := http.Get(i.path)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return errors.Errorf("unable to download %s: %s", i.path, resp.Status)
}
dir, err := afero.TempDir(i.app.Fs(), "", "")
if err != nil {
return err
}
defer i.app.Fs().RemoveAll(dir)
filename, err := extractFilename(resp)
if err != nil {
return err
}
path := filepath.Join(dir, filename)
f, err := i.app.Fs().Create(path)
if err != nil {
return err
}
_, err = io.Copy(f, resp.Body)
if err != nil {
return err
}
if err := f.Close(); err != nil {
return err
}
return i.importFile(path)
}
func extractFilename(resp *http.Response) (string, error) {
filename := resp.Request.URL.Path
cd := resp.Header.Get("Content-Disposition")
if cd != "" {
if _, params, err := mime.ParseMediaType(cd); err == nil {
filename = params["filename"]
}
}
if filename == "" || strings.HasSuffix(filename, "/") || strings.Contains(filename, "\x00") {
return "", errors.New("unable to find name for file")
}
filename = filepath.Base(path.Clean("/" + filename))
if filename == "" || filename == "." || filename == "/" {
return "", errors.New("unable to find name for file in path")
}
return filename, nil
}
func (i *Import) handleLocal() error {
pathFi, err := i.app.Fs().Stat(i.path)
if err != nil {
if os.IsNotExist(err) {
......
......@@ -16,7 +16,12 @@
package actions
import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/mock"
......@@ -27,6 +32,43 @@ import (
"github.com/stretchr/testify/require"
)
func TestImport_http(t *testing.T) {
withApp(t, func(appMock *amocks.App) {
f, err := os.Open(filepath.Join("testdata", "import", "file.yaml"))
require.NoError(t, err)
defer f.Close()
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Disposition", `attachment; filename="manifest.yaml"`)
http.ServeContent(w, r, "file.yaml", time.Time{}, f)
}))
defer ts.Close()
module := "/"
in := map[string]interface{}{
OptionApp: appMock,
OptionModule: module,
OptionPath: ts.URL,
}
a, err := NewImport(in)
require.NoError(t, err)
cm := &cmocks.Manager{}
cm.On("CreateComponent", mock.Anything, "/manifest", "",
params.Params{}, prototype.YAML).Return("/", nil)
a.cm = cm
err = a.Run()
require.NoError(t, err)
cm.AssertExpectations(t)
})
}
func TestImport_file(t *testing.T) {
withApp(t, func(appMock *amocks.App) {
module := "/"
......
......@@ -46,7 +46,7 @@ var importCmd = &cobra.Command{
func init() {
RootCmd.AddCommand(importCmd)
importCmd.Flags().StringP(flagFilename, shortFilename, "", "Filename or directory for component to import")
importCmd.Flags().StringP(flagFilename, shortFilename, "", "Filename, directory, or URL for component to import")
viper.BindPFlag(vImportFilename, importCmd.Flags().Lookup(flagFilename))
importCmd.Flags().String(flagModule, "", "Component module")
viper.BindPFlag(vImportModule, importCmd.Flags().Lookup(flagModule))
......
......@@ -85,7 +85,10 @@ func (cc *componentCreator) Create(name, text string, params param.Params, templ
}
if exists {
return "", errors.Errorf("component with name '%s' already exists", name)
if module == "" {
module = "/"
}
return "", errors.Errorf("component with name %q in module %q already exists", name, module)
}
log.Infof("Writing component at '%s'", componentPath)
......
......@@ -13,7 +13,7 @@ ks import [flags]
### Options
```
-f, --filename string Filename or directory for component to import
-f, --filename string Filename, directory, or URL for component to import
-h, --help help for import
--module string Component module
```
......
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