github.com/ijc/docker-app@v0.6.1-0.20181012090447-c7ca8bc483fb/loader/loader.go (about) 1 package loader 2 3 import ( 4 "io" 5 "io/ioutil" 6 "net/http" 7 "os" 8 "strings" 9 10 "github.com/docker/app/types" 11 "github.com/docker/docker/pkg/archive" 12 "github.com/pkg/errors" 13 ) 14 15 // LoadFromURL loads a docker app from an URL that should return a single-file app. 16 func LoadFromURL(url string, ops ...func(*types.App) error) (*types.App, error) { 17 resp, err := http.Get(url) 18 if err != nil { 19 return nil, errors.Wrap(err, "failed to download "+url) 20 } 21 if resp.Body != nil { 22 defer resp.Body.Close() 23 } 24 if resp.StatusCode != 200 { 25 return nil, errors.Errorf("failed to download %s: %s", url, resp.Status) 26 } 27 return LoadFromSingleFile(url, resp.Body, ops...) 28 } 29 30 // LoadFromSingleFile loads a docker app from a single-file format (as a reader) 31 func LoadFromSingleFile(path string, r io.Reader, ops ...func(*types.App) error) (*types.App, error) { 32 data, err := ioutil.ReadAll(r) 33 if err != nil { 34 return nil, errors.Wrap(err, "error reading single-file") 35 } 36 parts := strings.Split(string(data), types.SingleFileSeparator) 37 if len(parts) != 3 { 38 return nil, errors.Errorf("malformed single-file application: expected 3 documents, got %d", len(parts)) 39 } 40 // 0. is metadata 41 metadata := strings.NewReader(parts[0]) 42 // 1. is compose 43 compose := strings.NewReader(parts[1]) 44 // 2. is settings 45 setting := strings.NewReader(parts[2]) 46 appOps := append([]func(*types.App) error{ 47 types.WithComposes(compose), 48 types.WithSettings(setting), 49 types.Metadata(metadata), 50 }, ops...) 51 return types.NewApp(path, appOps...) 52 } 53 54 // LoadFromDirectory loads a docker app from a directory 55 func LoadFromDirectory(path string, ops ...func(*types.App) error) (*types.App, error) { 56 return types.NewAppFromDefaultFiles(path, ops...) 57 } 58 59 // LoadFromTar loads a docker app from a tarball 60 func LoadFromTar(tar string, ops ...func(*types.App) error) (*types.App, error) { 61 f, err := os.Open(tar) 62 if err != nil { 63 return nil, errors.Wrap(err, "cannot load app from tar") 64 } 65 defer f.Close() 66 appOps := append(ops, types.WithPath(tar)) 67 return LoadFromTarReader(f, appOps...) 68 } 69 70 // LoadFromTarReader loads a docker app from a tarball reader 71 func LoadFromTarReader(r io.Reader, ops ...func(*types.App) error) (*types.App, error) { 72 dir, err := ioutil.TempDir("", "load-from-tar") 73 if err != nil { 74 return nil, errors.Wrap(err, "cannot load app from tar") 75 } 76 if err := archive.Untar(r, dir, &archive.TarOptions{ 77 NoLchown: true, 78 }); err != nil { 79 originalErr := errors.Wrap(err, "cannot load app from tar") 80 if err := os.RemoveAll(dir); err != nil { 81 return nil, errors.Wrapf(originalErr, "cannot remove temporary folder : %s", err.Error()) 82 } 83 return nil, originalErr 84 } 85 appOps := append([]func(*types.App) error{ 86 types.WithCleanup(func() { 87 os.RemoveAll(dir) 88 }), 89 }, ops...) 90 return LoadFromDirectory(dir, appOps...) 91 }