Repository: gruntwork-io/terragrunt (language: go)

Issue:
Documentation: Multiple Includes example syntax I think is incorrect.
## Describe the bug

I was trying to replicate the example that is documented here...

https://github.com/gruntwork-io/terragrunt/blob/9f5b3f55309c0bfe7ff174898adaf8682b4c47f7/docs/_docs/04_reference/config-blocks-and-attributes.md?plain=1#L546


## Steps To Reproduce

There is a reference to a `/region.hcl` file but there is no details as to what the contents are.  I tried a standard `tfvars` type format...

```hcl
region = "production"
```

but I got this error...

```
]$ tg init
ERRO[0000] Error: Unsupported argument

ERRO[0000]   on /Users/greg/workspace/terragrunt/multiple-includes-example/region.hcl line 1:
ERRO[0000]    1: region = "production"
ERRO[0000]
ERRO[0000] An argument named "region" is not expected here.

ERRO[0000] /Users/greg/workspace/terragrunt/multiple-includes-example/region.hcl:1,1-7: Unsupported argument; An argument named "region" is not expected here.
ERRO[0000] Unable to determine underlying exit code, so Terragrunt will exit with error code 1
```

Shouldn't the syntax use a 'include.locals" or a "include.inputs". ?



Discussion / hints:

Fix patch:
diff --git a/docs/_docs/04_reference/config-blocks-and-attributes.md b/docs/_docs/04_reference/config-blocks-and-attributes.md
index 0c2a93b93e..1ab21109e8 100644
--- a/docs/_docs/04_reference/config-blocks-and-attributes.md
+++ b/docs/_docs/04_reference/config-blocks-and-attributes.md
@@ -430,6 +430,7 @@ Example with S3:
 # .
 # ├── terragrunt.hcl
 # └── child
+#     ├── main.tf
 #     └── terragrunt.hcl
 #
 # And the following is defined in the root terragrunt.hcl config that is included in the child, the state file for the
@@ -437,6 +438,7 @@ Example with S3:
 #
 # Note that since we are not using any of the skip args, this will automatically create the S3 bucket
 # "my-terraform-state" and DynamoDB table "my-lock-table" if it does not already exist.
+# terragrunt.hcl
 remote_state {
   backend = "s3"
   config = {
@@ -447,6 +449,16 @@ remote_state {
     dynamodb_table = "my-lock-table"
   }
 }
+
+# child/terragrunt.hcl
+include "root" {
+  path   = find_in_parent_folders()
+}
+
+# child/main.tf
+terraform {
+  backend "s3" {}
+}
 ```
 
 Example with GCS:
@@ -461,6 +473,7 @@ Example with GCS:
 # .
 # ├── terragrunt.hcl
 # └── child
+#     ├── main.tf
 #     └── terragrunt.hcl
 #
 # And the following is defined in the root terragrunt.hcl config that is included in the child, the state file for the
@@ -468,6 +481,8 @@ Example with GCS:
 #
 # Note that since we are not using any of the skip args, this will automatically create the GCS bucket
 # "my-terraform-state" if it does not already exist.
+
+# terragrunt.hcl
 remote_state {
   backend = "gcs"
 
@@ -483,6 +498,16 @@ remote_state {
     }
   }
 }
+
+# child/terragrunt.hcl
+include "root" {
+  path   = find_in_parent_folders()
+}
+
+# child/main.tf
+terraform {
+  backend "gcs" {}
+}
 ```
 
 
@@ -532,7 +557,22 @@ _Single include_
 # .
 # ├── terragrunt.hcl
 # └── child
+#     ├── main.tf
 #     └── terragrunt.hcl
+
+# terragrunt.hcl
+remote_state {
+  backend = "s3"
+  config = {
+    bucket         = "my-terraform-state"
+    key            = "${path_relative_to_include()}/terraform.tfstate"
+    region         = "us-east-1"
+    encrypt        = true
+    dynamodb_table = "my-lock-table"
+  }
+}
+
+# child/terragrunt.hcl
 include "root" {
   path   = find_in_parent_folders()
   expose = true
@@ -541,6 +581,11 @@ include "root" {
 inputs = {
   remote_state_config = include.root.remote_state
 }
+
+# child/main.tf
+terraform {
+  backend "s3" {}
+}
 ```
 
 _Multiple includes_
@@ -554,6 +599,25 @@ _Multiple includes_
 # ├── region.hcl
 # └── child
 #     └── terragrunt.hcl
+
+# terragrunt.hcl
+remote_state {
+  backend = "s3"
+  config = {
+    bucket         = "my-terraform-state"
+    key            = "${path_relative_to_include()}/terraform.tfstate"
+    region         = "us-east-1"
+    encrypt        = true
+    dynamodb_table = "my-lock-table"
+  }
+}
+
+# region.hcl
+locals {
+  region = "production"
+}
+
+# child/terragrunt.hcl
 include "remote_state" {
   path   = find_in_parent_folders()
   expose = true
@@ -567,7 +631,12 @@ include "region" {
 
 inputs = {
   remote_state_config = include.remote_state.remote_state
-  region              = include.region.region
+  region              = include.region.locals.region
+}
+
+# child/main.tf
+terraform {
+  backend "s3" {}
 }
 ```
 
diff --git a/util/locks.go b/util/locks.go
index 458f56f0b7..a7811c5e96 100644
--- a/util/locks.go
+++ b/util/locks.go
@@ -17,23 +17,22 @@ func NewKeyLocks() *KeyLocks {
 
 // Lock acquires the lock for the given key.
 func (kl *KeyLocks) Lock(key string) {
-	kl.ensureLock(key)
-	kl.locks[key].Lock()
+	kl.masterLock.Lock()
+	lock, ok := kl.locks[key]
+	if !ok {
+		lock = &sync.Mutex{}
+		kl.locks[key] = lock
+	}
+	kl.masterLock.Unlock()
+	lock.Lock()
 }
 
 // Unlock releases the lock for the given key.
 func (kl *KeyLocks) Unlock(key string) {
-	if lock, ok := kl.locks[key]; ok {
-		lock.Unlock()
-	}
-}
-
-// ensureLock checks if a lock exists for the key, and if not, creates one.
-func (kl *KeyLocks) ensureLock(key string) {
 	kl.masterLock.Lock()
 	defer kl.masterLock.Unlock()
 
-	if _, ok := kl.locks[key]; !ok {
-		kl.locks[key] = new(sync.Mutex)
+	if lock, ok := kl.locks[key]; ok {
+		lock.Unlock()
 	}
 }


Test patch: