depsfile: Don't panic when lock file is unreadable
Previously we were expecting that the *hcl.File would always be non-nil, even in error cases. That isn't always true, so now we'll be more robust about it and explicitly return an empty locks object in that case, along with the error diagnostics. In particular this avoids a panic in a strange situation where the user created a directory where the lock file would normally go. There's no meaning to such a directory, so it would always be a mistake and so now we'll return an error message about it, rather than panicking as before. The error message for the situation where the lock file is a directory is currently not very specific, but since it's HCL responsible for generating that message we can't really fix that at this layer. Perhaps in future we can change HCL to have a specialized error message for that particular error situation, but for the sake of this commit the goal is only to stop the panic and return a normal error message.
This commit is contained in:
parent
c412935d63
commit
21d6fb5a37
|
@ -59,6 +59,12 @@ func loadLocks(loadParse func(*hclparse.Parser) (*hcl.File, hcl.Diagnostics)) (*
|
|||
f, hclDiags := loadParse(parser)
|
||||
ret.sources = parser.Sources()
|
||||
diags = diags.Append(hclDiags)
|
||||
if f == nil {
|
||||
// If we encountered an error loading the file then those errors
|
||||
// should already be in diags from the above, but the file might
|
||||
// also be nil itself and so we can't decode from it.
|
||||
return ret, diags
|
||||
}
|
||||
|
||||
moreDiags := decodeLocksFromHCL(ret, f.Body)
|
||||
diags = diags.Append(moreDiags)
|
||||
|
|
|
@ -159,6 +159,45 @@ func TestLoadLocksFromFile(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestLoadLocksFromFileAbsent(t *testing.T) {
|
||||
t.Run("lock file is a directory", func(t *testing.T) {
|
||||
// This can never happen when Terraform is the one generating the
|
||||
// lock file, but might arise if the user makes a directory with the
|
||||
// lock file's name for some reason. (There is no actual reason to do
|
||||
// so, so that would always be a mistake.)
|
||||
locks, diags := LoadLocksFromFile("testdata")
|
||||
if len(locks.providers) != 0 {
|
||||
t.Errorf("returned locks has providers; expected empty locks")
|
||||
}
|
||||
if !diags.HasErrors() {
|
||||
t.Fatalf("LoadLocksFromFile succeeded; want error")
|
||||
}
|
||||
// This is a generic error message from HCL itself, so upgrading HCL
|
||||
// in future might cause a different error message here.
|
||||
want := `Failed to read file: The configuration file "testdata" could not be read.`
|
||||
got := diags.Err().Error()
|
||||
if got != want {
|
||||
t.Errorf("wrong error message\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
})
|
||||
t.Run("lock file doesn't exist", func(t *testing.T) {
|
||||
locks, diags := LoadLocksFromFile("testdata/nonexist.hcl")
|
||||
if len(locks.providers) != 0 {
|
||||
t.Errorf("returned locks has providers; expected empty locks")
|
||||
}
|
||||
if !diags.HasErrors() {
|
||||
t.Fatalf("LoadLocksFromFile succeeded; want error")
|
||||
}
|
||||
// This is a generic error message from HCL itself, so upgrading HCL
|
||||
// in future might cause a different error message here.
|
||||
want := `Failed to read file: The configuration file "testdata/nonexist.hcl" could not be read.`
|
||||
got := diags.Err().Error()
|
||||
if got != want {
|
||||
t.Errorf("wrong error message\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSaveLocksToFile(t *testing.T) {
|
||||
locks := NewLocks()
|
||||
|
||||
|
|
Loading…
Reference in New Issue