github.com/Datadog/cnab-go@v0.3.3-beta1.0.20191007143216-bba4b7e723d0/bundle/loader/loader.go (about)

     1  package loader
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"net/url"
     8  	"os"
     9  
    10  	"github.com/deislabs/cnab-go/bundle"
    11  )
    12  
    13  // BundleLoader provides an interface for loading a bundle
    14  type BundleLoader interface {
    15  	// Load a bundle from a local file
    16  	Load(source string) (*bundle.Bundle, error)
    17  	// Load a bundle from raw data
    18  	LoadData(data []byte) (*bundle.Bundle, error)
    19  }
    20  
    21  // Loader loads a bundle manifest (bundle.json)
    22  type Loader struct{}
    23  
    24  // New creates a loader for bundle files.
    25  //TODO: remove if unnecessary
    26  func New() BundleLoader {
    27  	return &Loader{}
    28  }
    29  
    30  func NewLoader() *Loader {
    31  	return &Loader{}
    32  }
    33  
    34  // Load loads the given bundle.
    35  func (l *Loader) Load(filename string) (*bundle.Bundle, error) {
    36  	b := &bundle.Bundle{}
    37  	data, err := loadData(filename)
    38  	if err != nil {
    39  		return b, err
    40  	}
    41  	return l.LoadData(data)
    42  }
    43  
    44  // LoadData loads a Bundle from the given data.
    45  //
    46  // This loads a JSON bundle file into a *bundle.Bundle.
    47  func (l *Loader) LoadData(data []byte) (*bundle.Bundle, error) {
    48  	return bundle.Unmarshal(data)
    49  }
    50  
    51  // loadData is a utility method that loads a file either off of the FS (if it exists) or via a remote HTTP GET.
    52  //
    53  // If bundleFile exists on disk, this will return that file. Otherwise, it will attempt to parse the
    54  // file name as a URL and request it as an HTTP GET request.
    55  func loadData(bundleFile string) ([]byte, error) {
    56  	if isLocalReference(bundleFile) {
    57  		return ioutil.ReadFile(bundleFile)
    58  	}
    59  
    60  	if u, err := url.ParseRequestURI(bundleFile); err != nil {
    61  		// The error emitted by ParseRequestURI is icky.
    62  		return []byte{}, fmt.Errorf("bundle %q not found", bundleFile)
    63  	} else if u.Scheme == "file" {
    64  		// What do we do if someone passes a `file:///` URL in? Is `file` inferred
    65  		// if no protocol is specified?
    66  		return []byte{}, fmt.Errorf("bundle %q not found", bundleFile)
    67  	}
    68  
    69  	response, err := http.Get(bundleFile)
    70  	if err != nil {
    71  		return []byte{}, fmt.Errorf("cannot download bundle file: %v", err)
    72  	}
    73  	defer response.Body.Close()
    74  
    75  	return ioutil.ReadAll(response.Body)
    76  }
    77  
    78  func isLocalReference(file string) bool {
    79  	_, err := os.Stat(file)
    80  	return err == nil
    81  }