config/module: use the raw source as part of the key
This changes the key for the storage to be the _raw_ source from the module, not the fully expanded source. Example: it'll be a relative path instead of an absolute path. This allows the ".terraform/modules" directory to be portable when moving to other machines. This was a behavior that existed in <= 0.7.2 and was broken with #8398. This amends that and adds a test to verify.
This commit is contained in:
parent
654686496c
commit
098225dc0d
|
@ -170,7 +170,7 @@ func (t *Tree) Load(s getter.Storage, mode GetMode) error {
|
||||||
|
|
||||||
// Get the directory where this module is so we can load it
|
// Get the directory where this module is so we can load it
|
||||||
key := strings.Join(path, ".")
|
key := strings.Join(path, ".")
|
||||||
key = fmt.Sprintf("root.%s-%s", key, source)
|
key = fmt.Sprintf("root.%s-%s", key, m.Source)
|
||||||
dir, ok, err := getStorage(s, key, source, mode)
|
dir, ok, err := getStorage(s, key, source, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
package module
|
package module
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-getter"
|
||||||
|
"github.com/hashicorp/terraform/config"
|
||||||
|
"github.com/hashicorp/terraform/helper/copy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTreeChild(t *testing.T) {
|
func TestTreeChild(t *testing.T) {
|
||||||
|
@ -102,6 +107,63 @@ func TestTreeLoad_duplicate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTreeLoad_copyable(t *testing.T) {
|
||||||
|
dir := tempDir(t)
|
||||||
|
storage := &getter.FolderStorage{StorageDir: dir}
|
||||||
|
cfg := testConfig(t, "basic")
|
||||||
|
tree := NewTree("", cfg)
|
||||||
|
|
||||||
|
// This should get things
|
||||||
|
if err := tree.Load(storage, GetModeGet); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tree.Loaded() {
|
||||||
|
t.Fatal("should be loaded")
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should no longer error
|
||||||
|
if err := tree.Load(storage, GetModeNone); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we copy the directory, this COPIES symlink values, and
|
||||||
|
// doesn't create symlinks themselves. That is important.
|
||||||
|
dir2 := tempDir(t)
|
||||||
|
os.RemoveAll(dir2)
|
||||||
|
defer os.RemoveAll(dir2)
|
||||||
|
if err := copy.CopyDir(dir, dir2); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now copy the configuration
|
||||||
|
cfgDir := tempDir(t)
|
||||||
|
os.RemoveAll(cfgDir)
|
||||||
|
defer os.RemoveAll(cfgDir)
|
||||||
|
if err := copy.CopyDir(cfg.Dir, cfgDir); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
cfg, err := config.LoadDir(cfgDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tree := NewTree("", cfg)
|
||||||
|
storage := &getter.FolderStorage{StorageDir: dir2}
|
||||||
|
|
||||||
|
// This should not error since we already got it!
|
||||||
|
if err := tree.Load(storage, GetModeNone); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tree.Loaded() {
|
||||||
|
t.Fatal("should be loaded")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTreeLoad_parentRef(t *testing.T) {
|
func TestTreeLoad_parentRef(t *testing.T) {
|
||||||
storage := testStorage(t)
|
storage := testStorage(t)
|
||||||
tree := NewTree("", testConfig(t, "basic-parent"))
|
tree := NewTree("", testConfig(t, "basic-parent"))
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
package copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// From: https://gist.github.com/m4ng0squ4sh/92462b38df26839a3ca324697c8cba04
|
||||||
|
|
||||||
|
// CopyFile copies the contents of the file named src to the file named
|
||||||
|
// by dst. The file will be created if it does not already exist. If the
|
||||||
|
// destination file exists, all it's contents will be replaced by the contents
|
||||||
|
// of the source file. The file mode will be copied from the source and
|
||||||
|
// the copied data is synced/flushed to stable storage.
|
||||||
|
func CopyFile(src, dst string) (err error) {
|
||||||
|
in, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer in.Close()
|
||||||
|
|
||||||
|
out, err := os.Create(dst)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if e := out.Close(); e != nil {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = io.Copy(out, in)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = out.Sync()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
si, err := os.Stat(src)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = os.Chmod(dst, si.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyDir recursively copies a directory tree, attempting to preserve permissions.
|
||||||
|
// Source directory must exist, destination directory must *not* exist.
|
||||||
|
// Symlinks are ignored and skipped.
|
||||||
|
func CopyDir(src string, dst string) (err error) {
|
||||||
|
src = filepath.Clean(src)
|
||||||
|
dst = filepath.Clean(dst)
|
||||||
|
|
||||||
|
si, err := os.Stat(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !si.IsDir() {
|
||||||
|
return fmt.Errorf("source is not a directory")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = os.Stat(dst)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("destination already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.MkdirAll(dst, si.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entries, err := ioutil.ReadDir(src)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
srcPath := filepath.Join(src, entry.Name())
|
||||||
|
dstPath := filepath.Join(dst, entry.Name())
|
||||||
|
|
||||||
|
// If the entry is a symlink, we copy the contents
|
||||||
|
for entry.Mode()&os.ModeSymlink != 0 {
|
||||||
|
target, err := os.Readlink(srcPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err = os.Stat(target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.IsDir() {
|
||||||
|
err = CopyDir(srcPath, dstPath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = CopyFile(srcPath, dstPath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in New Issue