Skip to content
This repository was archived by the owner on Sep 9, 2020. It is now read-only.

allow cachedir override using env var #1234

Merged
merged 4 commits into from
Dec 8, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
validate env var DEPCACHEDIR is a valid path if set
- fs.go - Add method `IsValidPath` to check if given file path string is valid.
  Add tests as well.
- main.go - After loading cachedir from env, if it has been set, check
  validity, exit with status 1 if not. Update integration tests for this
  scenario.
  • Loading branch information
sudo-suhas committed Dec 8, 2017
commit c8f88484f39d1646ce37675bd3728927c591bf46
68 changes: 47 additions & 21 deletions cmd/dep/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,31 +65,57 @@ func TestDepCachedir(t *testing.T) {

initPath := filepath.Join("testdata", "cachedir")

testProj := integration.NewTestProject(t, initPath, wd, runMain)
defer testProj.Cleanup()
t.Run("env-cachedir", func(t *testing.T) {
t.Parallel()
testProj := integration.NewTestProject(t, initPath, wd, runMain)
defer testProj.Cleanup()

testProj.TempDir("cachedir")
cachedir := testProj.Path("cachedir")
testProj.Setenv("DEPCACHEDIR", cachedir)
testProj.TempDir("cachedir")
cachedir := testProj.Path("cachedir")
testProj.Setenv("DEPCACHEDIR", cachedir)

// Running `dep ensure` will pull in the dependency into cachedir.
err = testProj.DoRun([]string{"ensure"})
if err != nil {
// Log the error output from running `dep ensure`, could be useful.
t.Log(testProj.GetStderr())
t.Fatalf("got an unexpected error: %s", err.Error())
}
// Running `dep ensure` will pull in the dependency into cachedir.
err = testProj.DoRun([]string{"ensure"})
if err != nil {
// Log the error output from running `dep ensure`, could be useful.
t.Logf("`dep ensure` error output: \n%s", testProj.GetStderr())
t.Errorf("got an unexpected error: %s", err)
}

// Check that the cache was created in the cachedir. Our fixture has the dependency
// `github.com/sdboyer/deptest`
_, err = os.Stat(testProj.Path("cachedir", "sources", "https---github.com-sdboyer-deptest"))
if err != nil {
if os.IsNotExist(err) {
t.Fatal("Expected cachedir to have been populated but none was found")
} else {
t.Fatalf("Got unexpected error: %s", err)
// Check that the cache was created in the cachedir. Our fixture has the dependency
// `github.com/sdboyer/deptest`
_, err = os.Stat(testProj.Path("cachedir", "sources", "https---github.com-sdboyer-deptest"))
if err != nil {
if os.IsNotExist(err) {
t.Error("expected cachedir to have been populated but none was found")
} else {
t.Errorf("got an unexpected error: %s", err)
}
}
}
})
t.Run("env-invalid-cachedir", func(t *testing.T) {
t.Parallel()
testProj := integration.NewTestProject(t, initPath, wd, runMain)
defer testProj.Cleanup()

cachedir := "/invalid/path"
testProj.Setenv("DEPCACHEDIR", cachedir)
wantErr := fmt.Sprintf(
"dep: $DEPCACHEDIR set to an invalid or inaccessible path: %q", cachedir,
)

// Running `dep ensure` will pull in the dependency into cachedir.
err = testProj.DoRun([]string{"ensure"})

if err == nil {
// Log the output from running `dep ensure`, could be useful.
t.Logf("test run output: \n%s\n%s", testProj.GetStdout(), testProj.GetStderr())
t.Error("unexpected result: \n\t(GOT) nil\n\t(WNT) exit status 1")
} else if gotErr := strings.TrimSpace(testProj.GetStderr()); gotErr != wantErr {
t.Errorf("unexpected error output: \n\t(GOT) %s\n\t(WNT) %s", gotErr, wantErr)
}
})

}

// execCmd is a test.RunFunc which runs the program in another process.
Expand Down
23 changes: 15 additions & 8 deletions cmd/dep/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"text/tabwriter"

"github.com/golang/dep"
"github.com/golang/dep/internal/fs"
)

var (
Expand Down Expand Up @@ -158,31 +159,37 @@ func (c *Config) Run() int {
for _, cmd := range commands {
if cmd.Name() == cmdName {
// Build flag set with global flags in there.
fs := flag.NewFlagSet(cmdName, flag.ContinueOnError)
fs.SetOutput(c.Stderr)
verbose := fs.Bool("v", false, "enable verbose logging")
flags := flag.NewFlagSet(cmdName, flag.ContinueOnError)
flags.SetOutput(c.Stderr)
verbose := flags.Bool("v", false, "enable verbose logging")

// Register the subcommand flags in there, too.
cmd.Register(fs)
cmd.Register(flags)

// Override the usage text to something nicer.
resetUsage(errLogger, fs, cmdName, cmd.Args(), cmd.LongHelp())
resetUsage(errLogger, flags, cmdName, cmd.Args(), cmd.LongHelp())

if printCommandHelp {
fs.Usage()
flags.Usage()
return errorExitCode
}

// Parse the flags the user gave us.
// flag package automatically prints usage and error message in err != nil
// or if '-h' flag provided
if err := fs.Parse(c.Args[2:]); err != nil {
if err := flags.Parse(c.Args[2:]); err != nil {
return errorExitCode
}

// Cachedir is loaded from env if present. `$GOPATH/pkg/dep` is used as the
// fallback cache location.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"default" is better than "fallback" here.

cachedir := getEnv(c.Env, "DEPCACHEDIR")
if cachedir != "" && !fs.IsValidPath(cachedir) {
errLogger.Printf(
"dep: $DEPCACHEDIR set to an invalid or inaccessible path: %q\n", cachedir,
)
return errorExitCode
}

// Set up dep context.
ctx := &dep.Ctx{
Expand All @@ -197,7 +204,7 @@ func (c *Config) Run() int {
ctx.SetPaths(c.WorkingDir, GOPATHS...)

// Run the command with the post-flag-processing args.
if err := cmd.Run(ctx, fs.Args()); err != nil {
if err := cmd.Run(ctx, flags.Args()); err != nil {
errLogger.Printf("%v\n", err)
return errorExitCode
}
Expand Down
18 changes: 18 additions & 0 deletions internal/fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,24 @@ func cloneSymlink(sl, dst string) error {
return os.Symlink(resolved, dst)
}

// IsValidPath checks if the given string is a valid path.
func IsValidPath(fp string) bool {
// See https://stackoverflow.com/questions/35231846/golang-check-if-string-is-valid-path
// Check if file/dir already exists
if _, err := os.Stat(fp); err == nil {
return true
}

// Attempt to create it
var d []byte
if err := ioutil.WriteFile(fp, d, 0644); err == nil {
os.Remove(fp) // And delete it
return true
}

return false
}

// IsDir determines is the path given is a directory or not.
func IsDir(name string) (bool, error) {
fi, err := os.Stat(name)
Expand Down
41 changes: 41 additions & 0 deletions internal/fs/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,47 @@ func setupInaccessibleDir(t *testing.T, op func(dir string) error) func() {
return cleanup
}

func TestIsValidPath(t *testing.T) {
wd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

var dn string

cleanup := setupInaccessibleDir(t, func(dir string) error {
dn = filepath.Join(dir, "dir")
return os.Mkdir(dn, 0777)
})
defer cleanup()

tests := map[string]bool{
wd: true,
filepath.Join(wd, "testdata"): true,
filepath.Join(wd, "main.go"): true,
filepath.Join(wd, "this_file_does_not_exist.thing"): true,
dn: false,
"": false,
"/invalid/path": false,
}

if runtime.GOOS == "windows" {
// This test doesn't work on Microsoft Windows because
// of the differences in how file permissions are
// implemented. For this to work, the directory where
// the directory exists should be inaccessible.
delete(tests, dn)
}

for fp, want := range tests {
got := IsValidPath(fp)

if got != want {
t.Fatalf("expected %t for %s, got %t", want, fp, got)
}
}
}

func TestIsRegular(t *testing.T) {
wd, err := os.Getwd()
if err != nil {
Expand Down