github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/internal/packager/extract.go (about)

     1  package packager
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/docker/app/internal"
    11  	"github.com/docker/app/internal/validator"
    12  	"github.com/docker/app/loader"
    13  	"github.com/docker/app/types"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  // findApp looks for an app in CWD or subdirs
    18  func findApp(cwd string) (string, error) {
    19  	if strings.HasSuffix(cwd, internal.AppExtension) {
    20  		return cwd, nil
    21  	}
    22  	content, err := ioutil.ReadDir(cwd)
    23  	if err != nil {
    24  		return "", errors.Wrap(err, "failed to read current working directory")
    25  	}
    26  	hit := ""
    27  	for _, c := range content {
    28  		if strings.HasSuffix(c.Name(), internal.AppExtension) {
    29  			if hit != "" {
    30  				return "", fmt.Errorf("multiple applications found in current directory, specify the application name on the command line")
    31  			}
    32  			hit = c.Name()
    33  		}
    34  	}
    35  	if hit == "" {
    36  		return "", fmt.Errorf("no application found in current directory")
    37  	}
    38  	return filepath.Join(cwd, hit), nil
    39  }
    40  
    41  // Extract extracts the app content if argument is an archive, or does nothing if a dir.
    42  // It returns source file, effective app name, and cleanup function
    43  // If appname is empty, it looks into cwd, and all subdirs for a single matching .dockerapp
    44  // If nothing is found, it looks for an image and loads it
    45  func Extract(name string, ops ...func(*types.App) error) (*types.App, error) {
    46  	if name == "" {
    47  		cwd, err := os.Getwd()
    48  		if err != nil {
    49  			return nil, errors.Wrap(err, "cannot resolve current working directory")
    50  		}
    51  		if name, err = findApp(cwd); err != nil {
    52  			return nil, err
    53  		}
    54  	}
    55  	if name == "." {
    56  		var err error
    57  		if name, err = os.Getwd(); err != nil {
    58  			return nil, errors.Wrap(err, "cannot resolve current working directory")
    59  		}
    60  	}
    61  	ops = append(ops, types.WithName(name))
    62  	appname := internal.DirNameFromAppName(name)
    63  	s, err := os.Stat(appname)
    64  	if err != nil {
    65  		return nil, errors.Wrapf(err, "cannot locate application %q in filesystem", name)
    66  	}
    67  	if s.IsDir() {
    68  		v := validator.NewValidatorWithDefaults()
    69  		err := v.Validate(filepath.Join(appname, internal.ComposeFileName))
    70  		if err != nil {
    71  			return nil, err
    72  		}
    73  
    74  		// directory: already decompressed
    75  		appOpts := append(ops,
    76  			types.WithPath(appname),
    77  			types.WithSource(types.AppSourceSplit),
    78  		)
    79  		return loader.LoadFromDirectory(appname, appOpts...)
    80  	}
    81  	// not a dir: a tarball package, extract that in a temp dir
    82  	app, err := loader.LoadFromTar(appname, ops...)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	app.Source = types.AppSourceArchive
    87  	return app, nil
    88  }