summaryrefslogtreecommitdiff
path: root/data.go
diff options
context:
space:
mode:
authorDave Henderson <dhenderson@gmail.com>2016-01-24 20:07:36 -0500
committerDave Henderson <dhenderson@gmail.com>2016-05-19 16:38:04 -0400
commitcb5774a31d2ac883db87f27fe2942b8ea7975b70 (patch)
tree29e5a83b603d9f9b0756a048deef1d8af8ea7e5d /data.go
parentcc70da900865809abd2affdd0bbb426bedbbcfde (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.go180
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
+}