diff options
| author | Dave Henderson <dhenderson@gmail.com> | 2020-05-20 22:56:01 -0400 |
|---|---|---|
| committer | Dave Henderson <dhenderson@gmail.com> | 2020-05-20 22:56:01 -0400 |
| commit | aa527c49e11a5c158cf87df9969b882395a735e7 (patch) | |
| tree | 41d040e7ef706b1160bcf6297e0f69b9b3078d2c /data | |
| parent | 7597dd94a53f834e67c35df51dccf90fe56b7f82 (diff) | |
Refactoring: deduplicating identical URL-parsing functions
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
Diffstat (limited to 'data')
| -rw-r--r-- | data/datasource.go | 109 | ||||
| -rw-r--r-- | data/datasource_http.go | 38 | ||||
| -rw-r--r-- | data/datasource_http_test.go | 44 | ||||
| -rw-r--r-- | data/datasource_merge.go | 7 | ||||
| -rw-r--r-- | data/datasource_test.go | 115 |
5 files changed, 11 insertions, 302 deletions
diff --git a/data/datasource.go b/data/datasource.go index 456b5a12..04cf6c8a 100644 --- a/data/datasource.go +++ b/data/datasource.go @@ -8,7 +8,6 @@ import ( "net/http" "net/url" "os" - "path" "path/filepath" "strings" @@ -101,28 +100,14 @@ func (d *Data) Cleanup() { } // NewData - constructor for Data +// Deprecated: will be replaced in future func NewData(datasourceArgs, headerArgs []string) (*Data, error) { - headers, err := parseHeaderArgs(headerArgs) + cfg := &config.Config{} + err := cfg.ParseDataSourceFlags(datasourceArgs, nil, headerArgs) if err != nil { return nil, err } - - data := &Data{ - Sources: make(map[string]*Source), - extraHeaders: headers, - } - - for _, v := range datasourceArgs { - s, err := parseSource(v) - if err != nil { - return nil, errors.Wrapf(err, "error parsing datasource") - } - s.header = headers[s.Alias] - // pop the header out of the map, so we end up with only the unreferenced ones - delete(headers, s.Alias) - - data.Sources[s.Alias] = s - } + data := FromConfig(cfg) return data, nil } @@ -242,90 +227,6 @@ func (s *Source) String() string { return fmt.Sprintf("%s=%s (%s)", s.Alias, s.URL.String(), s.mediaType) } -// parseSource creates a *Source by parsing the value provided to the -// --datasource/-d commandline flag -func parseSource(value string) (source *Source, err error) { - source = &Source{} - parts := strings.SplitN(value, "=", 2) - if len(parts) == 1 { - f := parts[0] - source.Alias = strings.SplitN(value, ".", 2)[0] - if path.Base(f) != f { - err = errors.Errorf("Invalid datasource (%s). Must provide an alias with files not in working directory", value) - return nil, err - } - source.URL, err = absFileURL(f) - if err != nil { - return nil, err - } - } else if len(parts) == 2 { - source.Alias = parts[0] - source.URL, err = parseSourceURL(parts[1]) - if err != nil { - return nil, err - } - } - - return source, nil -} - -func parseSourceURL(value string) (*url.URL, error) { - if value == "-" { - value = "stdin://" - } - value = filepath.ToSlash(value) - // handle absolute Windows paths - volName := "" - if volName = filepath.VolumeName(value); volName != "" { - // handle UNCs - if len(volName) > 2 { - value = "file:" + value - } else { - value = "file:///" + value - } - } - srcURL, err := url.Parse(value) - if err != nil { - return nil, err - } - - if volName != "" { - if strings.HasPrefix(srcURL.Path, "/") && srcURL.Path[2] == ':' { - srcURL.Path = srcURL.Path[1:] - } - } - - if !srcURL.IsAbs() { - srcURL, err = absFileURL(value) - if err != nil { - return nil, err - } - } - return srcURL, nil -} - -func absFileURL(value string) (*url.URL, error) { - cwd, err := os.Getwd() - if err != nil { - return nil, errors.Wrapf(err, "can't get working directory") - } - urlCwd := filepath.ToSlash(cwd) - baseURL := &url.URL{ - Scheme: "file", - Path: urlCwd + "/", - } - relURL, err := url.Parse(value) - if err != nil { - return nil, fmt.Errorf("can't parse value %s as URL: %w", value, err) - } - resolved := baseURL.ResolveReference(relURL) - // deal with Windows drive letters - if !strings.HasPrefix(urlCwd, "/") && resolved.Path[2] == ':' { - resolved.Path = resolved.Path[1:] - } - return resolved, nil -} - // DefineDatasource - func (d *Data) DefineDatasource(alias, value string) (string, error) { if alias == "" { @@ -334,7 +235,7 @@ func (d *Data) DefineDatasource(alias, value string) (string, error) { if d.DatasourceExists(alias) { return "", nil } - srcURL, err := parseSourceURL(value) + srcURL, err := config.ParseSourceURL(value) if err != nil { return "", err } diff --git a/data/datasource_http.go b/data/datasource_http.go index 5424fbd0..e809768e 100644 --- a/data/datasource_http.go +++ b/data/datasource_http.go @@ -5,7 +5,6 @@ import ( "mime" "net/http" "net/url" - "strings" "time" "github.com/pkg/errors" @@ -61,40 +60,3 @@ func readHTTP(source *Source, args ...string) ([]byte, error) { } return body, nil } - -func parseHeaderArgs(headerArgs []string) (map[string]http.Header, error) { - headers := make(map[string]http.Header) - for _, v := range headerArgs { - ds, name, value, err := splitHeaderArg(v) - if err != nil { - return nil, err - } - if _, ok := headers[ds]; !ok { - headers[ds] = make(http.Header) - } - headers[ds][name] = append(headers[ds][name], strings.TrimSpace(value)) - } - return headers, nil -} - -func splitHeaderArg(arg string) (datasourceAlias, name, value string, err error) { - parts := strings.SplitN(arg, "=", 2) - if len(parts) != 2 { - err = errors.Errorf("Invalid datasource-header option '%s'", arg) - return "", "", "", err - } - datasourceAlias = parts[0] - name, value, err = splitHeader(parts[1]) - return datasourceAlias, name, value, err -} - -func splitHeader(header string) (name, value string, err error) { - parts := strings.SplitN(header, ":", 2) - if len(parts) != 2 { - err = errors.Errorf("Invalid HTTP Header format '%s'", header) - return "", "", err - } - name = http.CanonicalHeaderKey(parts[0]) - value = parts[1] - return name, value, nil -} diff --git a/data/datasource_http_test.go b/data/datasource_http_test.go index f35733db..7f8515cc 100644 --- a/data/datasource_http_test.go +++ b/data/datasource_http_test.go @@ -118,50 +118,6 @@ func TestHTTPFileWithHeaders(t *testing.T) { assert.Equal(t, must(marshalObj(expected, json.Marshal)), must(marshalObj(actual, json.Marshal))) } -func TestParseHeaderArgs(t *testing.T) { - args := []string{ - "foo=Accept: application/json", - "bar=Authorization: Bearer supersecret", - } - expected := map[string]http.Header{ - "foo": { - "Accept": {jsonMimetype}, - }, - "bar": { - "Authorization": {"Bearer supersecret"}, - }, - } - parsed, err := parseHeaderArgs(args) - assert.NoError(t, err) - assert.Equal(t, expected, parsed) - - _, err = parseHeaderArgs([]string{"foo"}) - assert.Error(t, err) - - _, err = parseHeaderArgs([]string{"foo=bar"}) - assert.Error(t, err) - - args = []string{ - "foo=Accept: application/json", - "foo=Foo: bar", - "foo=foo: baz", - "foo=fOO: qux", - "bar=Authorization: Bearer supersecret", - } - expected = map[string]http.Header{ - "foo": { - "Accept": {jsonMimetype}, - "Foo": {"bar", "baz", "qux"}, - }, - "bar": { - "Authorization": {"Bearer supersecret"}, - }, - } - parsed, err = parseHeaderArgs(args) - assert.NoError(t, err) - assert.Equal(t, expected, parsed) -} - func TestBuildURL(t *testing.T) { expected := "https://example.com/index.html" base := mustParseURL(expected) diff --git a/data/datasource_merge.go b/data/datasource_merge.go index da14f24d..fa69c81f 100644 --- a/data/datasource_merge.go +++ b/data/datasource_merge.go @@ -4,6 +4,7 @@ import ( "strings" "github.com/hairyhenderson/gomplate/v3/coll" + "github.com/hairyhenderson/gomplate/v3/internal/config" "github.com/pkg/errors" ) @@ -30,10 +31,14 @@ func (d *Data) readMerge(source *Source, args ...string) ([]byte, error) { subSource, err := d.lookupSource(part) if err != nil { // maybe it's a relative filename? - subSource, err = parseSource(part + "=" + part) + u, err := config.ParseSourceURL(part) if err != nil { return nil, err } + subSource = &Source{ + Alias: part, + URL: u, + } } subSource.inherit(source) diff --git a/data/datasource_test.go b/data/datasource_test.go index 6752d9e5..62e1770e 100644 --- a/data/datasource_test.go +++ b/data/datasource_test.go @@ -4,8 +4,6 @@ import ( "fmt" "net/http" "net/url" - "os" - "path/filepath" "runtime" "strings" "testing" @@ -43,74 +41,6 @@ func TestNewData(t *testing.T) { assert.Equal(t, "blah", d.Sources["foo"].header["Accept"][0]) } -func TestParseSourceNoAlias(t *testing.T) { - s, err := parseSource("foo.json") - assert.NoError(t, err) - assert.Equal(t, "foo", s.Alias) - - _, err = parseSource("../foo.json") - assert.Error(t, err) - - _, err = parseSource("ftp://example.com/foo.yml") - assert.Error(t, err) -} - -func TestParseSourceWithAlias(t *testing.T) { - s, err := parseSource("data=foo.json") - assert.NoError(t, err) - assert.Equal(t, "data", s.Alias) - assert.Equal(t, "file", s.URL.Scheme) - assert.True(t, s.URL.IsAbs()) - - s, err = parseSource("data=/otherdir/foo.json") - assert.NoError(t, err) - assert.Equal(t, "data", s.Alias) - assert.Equal(t, "file", s.URL.Scheme) - assert.True(t, s.URL.IsAbs()) - assert.Equal(t, "/otherdir/foo.json", s.URL.Path) - - if runtime.GOOS == osWindows { - s, err = parseSource("data=foo.json") - assert.NoError(t, err) - assert.Equalf(t, byte(':'), s.URL.Path[1], "Path was %s", s.URL.Path) - - s, err = parseSource(`data=\otherdir\foo.json`) - assert.NoError(t, err) - assert.Equal(t, "data", s.Alias) - assert.Equal(t, "file", s.URL.Scheme) - assert.True(t, s.URL.IsAbs()) - assert.Equal(t, `/otherdir/foo.json`, s.URL.Path) - - s, err = parseSource("data=C:\\windowsdir\\foo.json") - assert.NoError(t, err) - assert.Equal(t, "data", s.Alias) - assert.Equal(t, "file", s.URL.Scheme) - assert.True(t, s.URL.IsAbs()) - assert.Equal(t, "C:/windowsdir/foo.json", s.URL.Path) - - s, err = parseSource("data=\\\\somehost\\share\\foo.json") - assert.NoError(t, err) - assert.Equal(t, "data", s.Alias) - assert.Equal(t, "file", s.URL.Scheme) - assert.Equal(t, "somehost", s.URL.Host) - assert.True(t, s.URL.IsAbs()) - assert.Equal(t, "/share/foo.json", s.URL.Path) - } - - s, err = parseSource("data=sftp://example.com/blahblah/foo.json") - assert.NoError(t, err) - assert.Equal(t, "data", s.Alias) - assert.Equal(t, "sftp", s.URL.Scheme) - assert.True(t, s.URL.IsAbs()) - assert.Equal(t, "/blahblah/foo.json", s.URL.Path) - - s, err = parseSource("merged=merge:./foo.yaml|http://example.com/bar.json%3Ffoo=bar") - assert.NoError(t, err) - assert.Equal(t, "merged", s.Alias) - assert.Equal(t, "merge", s.URL.Scheme) - assert.Equal(t, "./foo.yaml|http://example.com/bar.json%3Ffoo=bar", s.URL.Opaque) -} - func TestDatasource(t *testing.T) { setup := func(ext, mime string, contents []byte) *Data { fname := "foo." + ext @@ -413,51 +343,6 @@ func TestMimeTypeWithArg(t *testing.T) { } } -func TestQueryParse(t *testing.T) { - expected := &url.URL{ - Scheme: "http", - Host: "example.com", - Path: "/foo.json", - RawQuery: "bar", - } - u, err := parseSourceURL("http://example.com/foo.json?bar") - assert.NoError(t, err) - assert.EqualValues(t, expected, u) -} - -func TestAbsFileURL(t *testing.T) { - cwd, _ := os.Getwd() - // make this pass on Windows - cwd = filepath.ToSlash(cwd) - expected := &url.URL{ - Scheme: "file", - Host: "", - Path: "/tmp/foo", - } - u, err := absFileURL("/tmp/foo") - assert.NoError(t, err) - assert.EqualValues(t, expected, u) - - expected = &url.URL{ - Scheme: "file", - Host: "", - Path: cwd + "/tmp/foo", - } - u, err = absFileURL("tmp/foo") - assert.NoError(t, err) - assert.EqualValues(t, expected, u) - - expected = &url.URL{ - Scheme: "file", - Host: "", - Path: cwd + "/tmp/foo", - RawQuery: "q=p", - } - u, err = absFileURL("tmp/foo?q=p") - assert.NoError(t, err) - assert.EqualValues(t, expected, u) -} - func TestFromConfig(t *testing.T) { cfg := &config.Config{} expected := &Data{ |
