github.com/replicatedhq/ship@v0.55.0/pkg/specs/gogetter/go_getter.go (about)

     1  package gogetter
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"path"
     8  	"path/filepath"
     9  
    10  	"github.com/go-kit/kit/log"
    11  	"github.com/go-kit/kit/log/level"
    12  	getter "github.com/hashicorp/go-getter"
    13  	"github.com/pkg/errors"
    14  	"github.com/replicatedhq/ship/pkg/constants"
    15  	"github.com/replicatedhq/ship/pkg/util"
    16  	errors2 "github.com/replicatedhq/ship/pkg/util/errors"
    17  	"github.com/spf13/afero"
    18  )
    19  
    20  type GoGetter struct {
    21  	Logger       log.Logger
    22  	FS           afero.Afero
    23  	Subdir       string
    24  	IsSingleFile bool
    25  }
    26  
    27  // TODO figure out how to copy files from host into afero filesystem for testing, or how to force go-getter to fetch into afero
    28  func (g *GoGetter) GetFiles(ctx context.Context, upstream, savePath string) (string, error) {
    29  	debug := level.Debug(g.Logger)
    30  	debug.Log("event", "gogetter.GetFiles", "upstream", upstream, "savePath", savePath)
    31  
    32  	// Remove the directory because go-getter wants to create it
    33  	err := g.FS.RemoveAll(savePath)
    34  	if err != nil {
    35  		return "", errors.Wrap(err, "remove dir")
    36  	}
    37  
    38  	if g.IsSingleFile {
    39  		debug.Log("event", "gogetter.getSingleFile", "upstream", upstream, "savePath", savePath)
    40  		return g.getSingleFile(ctx, upstream, savePath)
    41  	}
    42  
    43  	err = getter.GetAny(savePath, upstream)
    44  	if err != nil {
    45  		return "", errors2.FetchFilesError{Message: err.Error()}
    46  	}
    47  
    48  	// check if the upstream is a local file - if it is, we shouldn't remove the .git directory
    49  	fileDetector := getter.FileDetector{}
    50  	if _, foundFile, err := fileDetector.Detect(upstream, savePath); !foundFile || err != nil {
    51  		// if there is a `.git` directory, remove it - it's dynamic and will break the content hash used by `ship update`
    52  		gitPresent, err := g.FS.Exists(path.Join(savePath, ".git"))
    53  		if err != nil {
    54  			return "", errors.Wrap(err, "check for .git directory")
    55  		}
    56  		if gitPresent {
    57  			err := g.FS.RemoveAll(path.Join(savePath, ".git"))
    58  			if err != nil {
    59  				return "", errors.Wrap(err, "remove .git directory")
    60  			}
    61  		}
    62  		debug.Log("event", "gitPresent.check", "gitPresent", gitPresent)
    63  	}
    64  
    65  	return filepath.Join(savePath, g.Subdir), nil
    66  }
    67  
    68  func (g *GoGetter) getSingleFile(ctx context.Context, upstream, savePath string) (string, error) {
    69  	tmpDir := filepath.Join(constants.ShipPathInternalTmp, "gogetter-file")
    70  
    71  	err := getter.GetAny(tmpDir, upstream)
    72  	if err != nil {
    73  		return "", errors2.FetchFilesError{Message: err.Error()}
    74  	}
    75  	defer g.FS.RemoveAll(tmpDir) // nolint: errcheck
    76  
    77  	err = g.FS.MkdirAll(filepath.Dir(filepath.Join(savePath, g.Subdir)), os.FileMode(0777))
    78  	if err != nil {
    79  		return "", errors.Wrap(err, "make path to move file to")
    80  	}
    81  
    82  	err = g.FS.Rename(filepath.Join(tmpDir, g.Subdir), filepath.Join(savePath, g.Subdir))
    83  	if err != nil {
    84  		return "", errors.Wrap(err, "move downloaded file to destination")
    85  	}
    86  
    87  	return savePath, nil
    88  }
    89  
    90  func IsGoGettable(path string) bool {
    91  	_, err := getter.Detect(path, "", getter.Detectors)
    92  	return err == nil
    93  }
    94  
    95  // if this path is a github path of the form `github.com/OWNER/REPO/tree/REF/SUBDIR` or `github.com/OWNER/REPO/SUBDIR`,
    96  // change it to the go-getter form of `github.com/OWNER/REPO?ref=REF//` with a default ref of master and return a subdir of SUBDIR
    97  // otherwise return the unmodified path
    98  // the final param is whether the github URL is a blob (and thus a single file)
    99  func UntreeGithub(path string) (string, string, bool) {
   100  	githubURL, err := util.ParseGithubURL(path, "master")
   101  	if err != nil {
   102  		return path, "", false
   103  	}
   104  	return fmt.Sprintf("github.com/%s/%s?ref=%s//", githubURL.Owner, githubURL.Repo, githubURL.Ref), githubURL.Subdir, githubURL.IsBlob
   105  }
   106  
   107  func IsShipYaml(path string) bool {
   108  	base := filepath.Base(path)
   109  	return base == "ship.yaml" || base == "ship.yml"
   110  }