Skip to content

Commit

Permalink
Don't cache mainfiles, just set modtime (magefile#173)
Browse files Browse the repository at this point in the history
Remove caching of mainfiles, instead just recreate it each time and set the modtime to be old.  This fixes a problem where we can't move the file to a different drive (seen in magefile#172 )
  • Loading branch information
natefinch authored Sep 19, 2018
1 parent 4a81047 commit 8c5bce8
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 71 deletions.
83 changes: 19 additions & 64 deletions mage/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,13 @@ func Invoke(inv Invocation) int {
}

main := filepath.Join(inv.Dir, mainfile)
mainhash, err := GenerateMainfile(main, inv.CacheDir, info)
err = GenerateMainfile(main, inv.CacheDir, info)
if err != nil {
log.Println("Error:", err)
return 1
}
if !inv.Keep {
defer moveMainToCache(inv.CacheDir, main, mainhash)
defer os.RemoveAll(main)
}
files = append(files, main)
if err := Compile(inv.Dir, inv.GoCmd, exePath, files, inv.Debug, inv.Stderr, inv.Stdout); err != nil {
Expand All @@ -351,7 +351,7 @@ func Invoke(inv Invocation) int {
// move aside this file before we run the compiled version, in case the
// compiled file screws things up. Yes this doubles up with the above
// defer, that's ok.
moveMainToCache(inv.CacheDir, main, mainhash)
os.RemoveAll(main)
} else {
debug.Print("keeping mainfile")
}
Expand Down Expand Up @@ -517,16 +517,14 @@ func cachedMainfile(cachedir, hash string) string {
// GenerateMainfile generates the mage mainfile at path. Because go build's
// cache cares about modtimes, we squirrel away our mainfiles in the cachedir
// and move them back as needed.
func GenerateMainfile(path, cachedir string, info *parse.PkgInfo) (hash string, _ error) {
func GenerateMainfile(path, cachedir string, info *parse.PkgInfo) error {
debug.Println("Creating mainfile at", path)
mainfiles := filepath.Join(cachedir, mainfileSubdir)
if err := os.MkdirAll(mainfiles, 0700); err != nil {
return "", fmt.Errorf("failed to create path for mainfiles at %s: %v", mainfiles, err)
}
buf := &bytes.Buffer{}
hasher := sha1.New()
w := io.MultiWriter(buf, hasher)

f, err := os.Create(path)
if err != nil {
return fmt.Errorf("error creating generated mainfile: %v", err)
}
defer f.Close()
data := data{
Description: info.Description,
Funcs: info.Funcs,
Expand All @@ -537,63 +535,20 @@ func GenerateMainfile(path, cachedir string, info *parse.PkgInfo) (hash string,

data.DefaultError = info.DefaultIsError

if err := output.Execute(w, data); err != nil {
return "", fmt.Errorf("can't execute mainfile template: %v", err)
}

hash = fmt.Sprintf("%x", hasher.Sum(nil))
cachedMain := filepath.Join(mainfiles, hash)
if useExistingMain(cachedMain, path, hash) {
info, err := os.Stat(path)
if err != nil {
debug.Println("mainfile modtime:", info.ModTime())
}
return hash, nil
}
debug.Println("writing new file at", path)
if err := ioutil.WriteFile(path, buf.Bytes(), 0600); err != nil {
return "", fmt.Errorf("can't write mainfile: %v", err)
}
return hash, nil
}

func useExistingMain(cachedMain, path, hash string) bool {
err := os.Rename(cachedMain, path)
if err == nil {
debug.Println("using cached mainfile from cachedir")
return true
}
if os.IsNotExist(err) {
debug.Println("file does not exist at", cachedMain)
} else {
debug.Printf("error copying cached mainfile from %s to %s: %v", cachedMain, path, err)
if err := output.Execute(f, data); err != nil {
return fmt.Errorf("can't execute mainfile template: %v", err)
}
// ok, no cached file, try to open the file at the target (happens if
// the user ran with -keep)
f, err := os.Open(path)
if os.IsNotExist(err) {
return false
if err := f.Close(); err != nil {
return fmt.Errorf("error closing generated mainfile: %v", err)
}
if err != nil {
debug.Printf("error opening existing mainfile at %s: %v", path, err)
return false
// we set an old modtime on the generated mainfile so that the go tool
// won't think it has changed more recently than the compiled binary.
longAgo := time.Now().Add(-time.Hour * 24 * 365 * 10)
if err := os.Chtimes(path, longAgo, longAgo); err != nil {
return fmt.Errorf("error setting old modtime on generated mainfile: %v", err)
}
defer f.Close()
debug.Println("mainfile already exists at", path)
existing := sha1.New()
_, err = io.Copy(existing, f)
if err != nil {
debug.Println("error hashing existing file:", err)
return false
}

if hash == fmt.Sprintf("%x", existing.Sum(nil)) {
// same contents on disk, use those
debug.Println("mainfile is the same as generated, using existing file")
return true
}
debug.Println("existing file has different contents")
return false
return nil
}

// ExeName reports the executable filename that this version of Mage would
Expand Down
7 changes: 0 additions & 7 deletions mage/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -785,13 +785,6 @@ func TestClean(t *testing.T) {
if len(names) != 0 {
t.Errorf("expected '-clean' to remove files from CACHE_DIR, but still have %v", names)
}
infos, err = ioutil.ReadDir(filepath.Join(mg.CacheDir(), mainfileSubdir))
if err != nil {
t.Error("issue reading directory:", err)
}
if len(infos) > 0 {
t.Fatalf("%d files left in mainfile subdir", len(infos))
}
}

func TestGoCmd(t *testing.T) {
Expand Down

0 comments on commit 8c5bce8

Please sign in to comment.