diff options
| author | Dave Henderson <dhenderson@gmail.com> | 2016-01-24 20:07:36 -0500 |
|---|---|---|
| committer | Dave Henderson <dhenderson@gmail.com> | 2016-05-19 16:38:04 -0400 |
| commit | cb5774a31d2ac883db87f27fe2942b8ea7975b70 (patch) | |
| tree | 29e5a83b603d9f9b0756a048deef1d8af8ea7e5d /data.go | |
| parent | cc70da900865809abd2affdd0bbb426bedbbcfde (diff) | |
New datasource function - works for JSON files
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
Diffstat (limited to 'data.go')
| -rw-r--r-- | data.go | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/data.go b/data.go new file mode 100644 index 00000000..b053faa8 --- /dev/null +++ b/data.go @@ -0,0 +1,180 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "mime" + "net/url" + "os" + "path" + "path/filepath" + "strings" + + "github.com/blang/vfs" +) + +func init() { + // Add some types we want to be able to handle which can be missing by default + mime.AddExtensionType(".json", "application/json") + mime.AddExtensionType(".yml", "application/yaml") + mime.AddExtensionType(".yaml", "application/yaml") +} + +// Data - +type Data struct { + Sources map[string]*Source + cache map[string][]byte +} + +// NewData - constructor for Data +func NewData(datasourceArgs []string) *Data { + sources := make(map[string]*Source) + for _, v := range datasourceArgs { + s, err := ParseSource(v) + if err != nil { + log.Fatalf("error parsing datasource %v", err) + return nil + } + sources[s.Alias] = s + } + return &Data{ + Sources: sources, + } +} + +// Source - a data source +type Source struct { + Alias string + URL *url.URL + Ext string + Type string + FS vfs.Filesystem +} + +// NewSource - builds a &Source +func NewSource(alias string, URL *url.URL) (s *Source) { + ext := filepath.Ext(URL.Path) + + var t string + if ext != "" { + t = mime.TypeByExtension(ext) + } + + s = &Source{ + Alias: alias, + URL: URL, + Ext: ext, + Type: t, + } + return +} + +// String is the method to format the flag's value, part of the flag.Value interface. +// The String method's output will be used in diagnostics. +func (s *Source) String() string { + return fmt.Sprintf("%s=%s (%s)", s.Alias, s.URL.String(), s.Type) +} + +// ParseSource - +func ParseSource(value string) (*Source, error) { + var ( + alias string + srcURL *url.URL + ) + parts := strings.SplitN(value, "=", 2) + if len(parts) == 1 { + f := parts[0] + alias = strings.SplitN(value, ".", 2)[0] + if path.Base(f) != f { + err := fmt.Errorf("Invalid datasource (%s). Must provide an alias with files not in working directory.", value) + return nil, err + } + srcURL = absURL(f) + } else if len(parts) == 2 { + alias = parts[0] + var err error + srcURL, err = url.Parse(parts[1]) + if err != nil { + return nil, err + } + + if !srcURL.IsAbs() { + srcURL = absURL(parts[1]) + } + } + + s := NewSource(alias, srcURL) + return s, nil +} + +func absURL(value string) *url.URL { + cwd, err := os.Getwd() + if err != nil { + log.Fatalf("Can't get working directory: %s", err) + } + baseURL := &url.URL{ + Scheme: "file", + Path: cwd + "/", + } + relURL := &url.URL{ + Path: value, + } + return baseURL.ResolveReference(relURL) +} + +// Datasource - +func (d *Data) Datasource(alias string) map[string]interface{} { + source := d.Sources[alias] + b, err := d.ReadSource(source.FS, source) + if err != nil { + log.Fatalf("Couldn't read datasource '%s': %#v", alias, err) + } + if source.Type == "application/json" { + ty := &TypeConv{} + return ty.JSON(string(b)) + } + log.Fatalf("Datasources of type %s not yet supported", source.Type) + return nil +} + +// ReadSource - +func (d *Data) ReadSource(fs vfs.Filesystem, source *Source) ([]byte, error) { + if d.cache == nil { + d.cache = make(map[string][]byte) + } + cached, ok := d.cache[source.Alias] + if ok { + return cached, nil + } + if source.URL.Scheme == "file" { + if fs == nil { + fs = vfs.OS() + source.FS = fs + } + + // make sure we can access the file + _, err := fs.Stat(source.URL.Path) + if err != nil { + log.Fatalf("Can't stat %s: %#v", source.URL.Path, err) + return nil, err + } + + f, err := fs.OpenFile(source.URL.Path, os.O_RDWR, 0) + if err != nil { + log.Fatalf("Can't open %s: %#v", source.URL.Path, err) + return nil, err + } + + b, err := ioutil.ReadAll(f) + if err != nil { + log.Fatalf("Can't read %s: %#v", source.URL.Path, err) + return nil, err + } + d.cache[source.Alias] = b + return b, nil + } + + log.Fatalf("Datasources with scheme %s not yet supported", source.URL.Scheme) + return nil, nil +} |
