Skip to content
This repository has been archived by the owner on Mar 24, 2023. It is now read-only.

copy, not symlink, local files #844

Merged
merged 2 commits into from
Feb 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pkg/specs/apptype/determine_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/replicatedhq/ship/pkg/constants"
"github.com/replicatedhq/ship/pkg/specs/githubclient"
"github.com/replicatedhq/ship/pkg/specs/gogetter"
"github.com/replicatedhq/ship/pkg/specs/localgetter"
"github.com/replicatedhq/ship/pkg/state"
"github.com/replicatedhq/ship/pkg/util"
errors2 "github.com/replicatedhq/ship/pkg/util/errors"
Expand Down Expand Up @@ -86,6 +87,11 @@ func (r *inspector) DetermineApplicationType(ctx context.Context, upstream strin
return r.determineTypeFromContents(ctx, upstream, githubClient)
}

if localgetter.IsLocalFile(&r.fs, upstream) {
fetcher := localgetter.LocalGetter{Logger: r.logger, FS: r.fs}
return r.determineTypeFromContents(ctx, upstream, &fetcher)
}

upstream, subdir, isSingleFile := gogetter.UntreeGithub(upstream)
if !isSingleFile {
isSingleFile = gogetter.IsShipYaml(upstream)
Expand Down
6 changes: 3 additions & 3 deletions pkg/specs/gogetter/go_getter.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ func (g *GoGetter) GetFiles(ctx context.Context, upstream, savePath string) (str
}

if g.IsSingleFile {
debug.Log("event", "gogetter.GetSingleFile", "upstream", upstream, "savePath", savePath)
return g.GetSingleFile(ctx, upstream, savePath)
debug.Log("event", "gogetter.getSingleFile", "upstream", upstream, "savePath", savePath)
return g.getSingleFile(ctx, upstream, savePath)
}

err = getter.GetAny(savePath, upstream)
Expand Down Expand Up @@ -65,7 +65,7 @@ func (g *GoGetter) GetFiles(ctx context.Context, upstream, savePath string) (str
return filepath.Join(savePath, g.Subdir), nil
}

func (g *GoGetter) GetSingleFile(ctx context.Context, upstream, savePath string) (string, error) {
func (g *GoGetter) getSingleFile(ctx context.Context, upstream, savePath string) (string, error) {
tmpDir := filepath.Join(constants.ShipPathInternalTmp, "gogetter-file")

err := getter.GetAny(tmpDir, upstream)
Expand Down
96 changes: 96 additions & 0 deletions pkg/specs/localgetter/local_getter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package localgetter

import (
"context"
"os"
"path/filepath"

"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/pkg/errors"
"github.com/spf13/afero"
)

type LocalGetter struct {
Logger log.Logger
FS afero.Afero
}

func (g *LocalGetter) GetFiles(ctx context.Context, upstream, savePath string) (string, error) {
debug := level.Debug(g.Logger)
debug.Log("event", "localgetter.GetFiles", "upstream", upstream, "savePath", savePath)

err := g.copyDir(ctx, upstream, savePath)
if err != nil {
return "", errors.Wrap(err, "copy files")
}
return savePath, nil
}

func (g *LocalGetter) copyDir(ctx context.Context, upstream, savePath string) error {
isDir, err := g.FS.IsDir(upstream)
if err != nil {
return errors.Wrapf(err, "check if %s is dir", upstream)
}
if !isDir {
// copy a single file
return g.copyFile(ctx, upstream, savePath, os.FileMode(777))
}

files, err := g.FS.ReadDir(upstream)
if err != nil {
return errors.Wrapf(err, "read files in dir %s", upstream)
}

for _, file := range files {
loopFile := filepath.Join(upstream, file.Name())
loopDest := filepath.Join(savePath, file.Name())
if file.IsDir() {
err = g.FS.MkdirAll(loopDest, file.Mode())
if err != nil {
return errors.Wrapf(err, "create dest dir %s", loopDest)
}

err = g.copyDir(ctx, loopFile, loopDest)
if err != nil {
return errors.Wrapf(err, "copy dir %s", file.Name())
}
} else {
err = g.copyFile(ctx, loopFile, loopDest, file.Mode())
if err != nil {
return errors.Wrapf(err, "copy file %s", file.Name())
}
}
}
return nil
}

func (g *LocalGetter) copyFile(ctx context.Context, upstream, savePath string, mode os.FileMode) error {
saveDir := filepath.Dir(savePath)
exists, err := g.FS.Exists(saveDir)
if err != nil {
return errors.Wrapf(err, "determine if path %s exists", saveDir)
}
if !exists {
err = g.FS.MkdirAll(saveDir, os.ModePerm)
if err != nil {
return errors.Wrapf(err, "create dest dir %s", saveDir)
}
}

contents, err := g.FS.ReadFile(upstream)
if err != nil {
return errors.Wrapf(err, "read %s file contents", upstream)
}

err = g.FS.WriteFile(savePath, contents, mode)
return errors.Wrapf(err, "write %s file contents", savePath)
}

func IsLocalFile(FS *afero.Afero, upstream string) bool {
exists, err := FS.Exists(upstream)
if err != nil {
return false
}
return exists
}
145 changes: 145 additions & 0 deletions pkg/specs/localgetter/local_getter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package localgetter

import (
"context"
"os"
"path/filepath"
"testing"

"github.com/go-kit/kit/log"
"github.com/spf13/afero"
"github.com/stretchr/testify/require"
)

func TestLocalGetter_copyDir(t *testing.T) {
type file struct {
contents []byte
path string
}
tests := []struct {
name string
upstream string
savePath string
inFiles []file
outFiles []file
wantErr bool
}{
{
name: "single file",
upstream: "/upstream/file",
savePath: "/save/file",
inFiles: []file{
{
contents: []byte("hello world"),
path: "/upstream/file",
},
},
outFiles: []file{
{
contents: []byte("hello world"),
path: "/upstream/file",
},
{
contents: []byte("hello world"),
path: "/save/file",
},
},
},
{
name: "single file in dir",
upstream: "/upstream/dir",
savePath: "/save/dir",
inFiles: []file{
{
contents: []byte("hello world"),
path: "/upstream/dir/file",
},
},
outFiles: []file{
{
contents: []byte("hello world"),
path: "/upstream/dir/file",
},
{
contents: []byte("hello world"),
path: "/save/dir/file",
},
},
},
{
name: "file plus subdirs",
upstream: "/upstream/",
savePath: "/save/",
inFiles: []file{
{
contents: []byte("hello world"),
path: "/upstream/dir/file",
},
{
contents: []byte("abc xyz"),
path: "/upstream/dir2/file",
},
{
contents: []byte("123456789"),
path: "/upstream/file",
},
},
outFiles: []file{
{
contents: []byte("hello world"),
path: "/upstream/dir/file",
},
{
contents: []byte("abc xyz"),
path: "/upstream/dir2/file",
},
{
contents: []byte("123456789"),
path: "/upstream/file",
},
{
contents: []byte("hello world"),
path: "/save/dir/file",
},
{
contents: []byte("abc xyz"),
path: "/save/dir2/file",
},
{
contents: []byte("123456789"),
path: "/save/file",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := require.New(t)

mmFs := afero.Afero{Fs: afero.NewMemMapFs()}

g := &LocalGetter{
Logger: log.NewNopLogger(),
FS: mmFs,
}

for _, file := range tt.inFiles {
req.NoError(mmFs.MkdirAll(filepath.Dir(file.path), os.ModePerm))
req.NoError(mmFs.WriteFile(file.path, file.contents, os.ModePerm))
}

err := g.copyDir(context.Background(), tt.upstream, tt.savePath)
if tt.wantErr {
req.Error(err)
} else {
req.NoError(err)
}

for _, file := range tt.outFiles {
contents, err := mmFs.ReadFile(file.path)
req.NoError(err)
req.Equal(file.contents, contents, "expected equal contents: expected %q, got %q", string(file.contents), string(contents))
}
})
}
}