Repository: goreleaser/nfpm (go)

Issue:
archlinux packager does not support folders for configs
### What happened?

Tried to create archpackage with the following configuration and failed:

```yaml
$ cat foo.yaml 
name: test

contents:
- src: etc/foo
  dst: /etc/foo
  type: config
```

```sh
mkdir -p etc/foo
touch etc/foo/foo.yml
```

### How can we reproduce this?

```
$ nfpm package --target . --config foo.yaml --packager archlinux
using archlinux packager...
read etc/foo: is a directory
```

Though debian is OK:

```
$ nfpm package --target . --config foo.yaml --packager deb
using deb packager...
DEPRECATION WARNING: Leaving the 'maintainer' field unset will not be allowed in a future version
created package: test_0.0.0~rc0_amd64.deb
```

### nfpm version

```bash
nfpm version nfpm version v2.20.0
```


### Search

- [X] I did search for other open and closed issues before opening this.

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct

### Additional context

_No response_

Pull request description:
Allow using directories as contents in archlinux packager
This PR allows using directories in the contents when using the archlinux packager. It also adds acceptance tests for all the packagers so that no one misses this use case in the future.

Fixes #564 

Patch:
diff --git a/arch/arch.go b/arch/arch.go
index e724fc1..1d90f41 100644
--- a/arch/arch.go
+++ b/arch/arch.go
@@ -9,6 +9,7 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"io/fs"
 	"os"
 	"path/filepath"
 	"strconv"
@@ -159,11 +160,60 @@ func createFilesInTar(info *nfpm.Info, tw *tar.Writer) ([]MtreeEntry, int64, err
 	var entries []MtreeEntry
 	var totalSize int64
 
+	var contents []*files.Content
+
 	for _, content := range info.Contents {
 		if content.Packager != "" && content.Packager != packagerName {
 			continue
 		}
 
+		switch content.Type {
+		case "dir", "symlink":
+			contents = append(contents, content)
+			continue
+		}
+
+		fi, err := os.Stat(content.Source)
+		if err != nil {
+			return nil, 0, err
+		}
+
+		if fi.IsDir() {
+			err = filepath.WalkDir(content.Source, func(path string, d fs.DirEntry, err error) error {
+				if err != nil {
+					return err
+				}
+
+				relPath := strings.TrimPrefix(path, content.Source)
+
+				if d.IsDir() {
+					return nil
+				}
+
+				c := &files.Content{
+					Source:      path,
+					Destination: filepath.Join(content.Destination, relPath),
+					FileInfo: &files.ContentFileInfo{
+						Mode: d.Type(),
+					},
+				}
+
+				if d.Type()&os.ModeSymlink != 0 {
+					c.Type = "symlink"
+				}
+
+				contents = append(contents, c)
+				return nil
+			})
+			if err != nil {
+				return nil, 0, err
+			}
+		} else {
+			contents = append(contents, content)
+		}
+	}
+
+	for _, content := range contents {
 		path := normalizePath(content.Destination)
 
 		switch content.Type {
diff --git a/go.mod b/go.mod
index 08f3ae1..0fed103 100644
--- a/go.mod
+++ b/go.mod
@@ -26,7 +26,7 @@ require (
 require (
 	github.com/cavaliergopher/cpio v1.0.1
 	github.com/google/go-cmp v0.5.9
-	github.com/klauspost/compress v1.15.11
+	github.com/klauspost/compress v1.15.12
 	github.com/pkg/errors v0.9.1
 )
 
diff --git a/go.sum b/go.sum
index d417101..24e96b7 100644
--- a/go.sum
+++ b/go.sum
@@ -90,8 +90,8 @@ github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT
 github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o=
 github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
-github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
+github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
+github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
 github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
 github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=


Test patch:
diff --git a/arch/arch_test.go b/arch/arch_test.go
index 5ba9f9c..63da2be 100644
--- a/arch/arch_test.go
+++ b/arch/arch_test.go
@@ -61,6 +61,10 @@ func exampleInfo() *nfpm.Info {
 					Destination: "/etc/fake/fake-link.conf",
 					Type:        "symlink",
 				},
+				{
+					Source:      "../testdata/something",
+					Destination: "/etc/something",
+				},
 			},
 			Scripts: nfpm.Scripts{
 				PreInstall:  "../testdata/scripts/preinstall.sh",
diff --git a/testdata/acceptance/apk.dockerfile b/testdata/acceptance/apk.dockerfile
index e234fbc..06ea3fd 100644
--- a/testdata/acceptance/apk.dockerfile
+++ b/testdata/acceptance/apk.dockerfile
@@ -48,6 +48,11 @@ RUN test -f /usr/share/whatever/folder/folder2/file2
 RUN test -d /var/log/whatever
 RUN test -d /usr/share/foo
 RUN test -d /usr/foo/bar/something
+RUN test -d /etc/something
+RUN test -f /etc/something/a
+RUN test -f /etc/something/b
+RUN test -d /etc/something/c
+RUN test -f /etc/something/c/d
 RUN test $(stat -c %a /usr/sbin/fake) -eq 4755
 RUN test -f /tmp/preinstall-proof
 RUN test -f /tmp/postinstall-proof
diff --git a/testdata/acceptance/archlinux.dockerfile b/testdata/acceptance/archlinux.dockerfile
index 75e5ab8..987e3ac 100644
--- a/testdata/acceptance/archlinux.dockerfile
+++ b/testdata/acceptance/archlinux.dockerfile
@@ -51,6 +51,11 @@ RUN test -f /usr/share/whatever/folder/folder2/file2
 RUN test -d /var/log/whatever
 RUN test -d /usr/share/foo
 RUN test -d /usr/foo/bar/something
+RUN test -d /etc/something
+RUN test -f /etc/something/a
+RUN test -f /etc/something/b
+RUN test -d /etc/something/c
+RUN test -f /etc/something/c/d
 RUN test $(stat -c %a /usr/bin/fake) -eq 4755
 RUN test -f /tmp/preinstall-proof
 RUN test -f /tmp/postinstall-proof
diff --git a/testdata/acceptance/core.complex.yaml b/testdata/acceptance/core.complex.yaml
index 6e302ed..4ad9179 100644
--- a/testdata/acceptance/core.complex.yaml
+++ b/testdata/acceptance/core.complex.yaml
@@ -27,6 +27,8 @@ contents:
 - src: ./testdata/whatever.conf
   dst: /etc/foo/whatever.conf
   type: config
+- src: ./testdata/something
+  dst: /etc/something
 - src: ./testdata/fake
   dst: /usr/sbin/fake
   packager: deb
diff --git a/testdata/acceptance/deb.dockerfile b/testdata/acceptance/deb.dockerfile
index fca374a..3a99139 100644
--- a/testdata/acceptance/deb.dockerfile
+++ b/testdata/acceptance/deb.dockerfile
@@ -51,6 +51,11 @@ RUN test -f /usr/share/whatever/folder/folder2/file2
 RUN test -d /var/log/whatever
 RUN test -d /usr/share/foo
 RUN test -d /usr/foo/bar/something
+RUN test -d /etc/something
+RUN test -f /etc/something/a
+RUN test -f /etc/something/b
+RUN test -d /etc/something/c
+RUN test -f /etc/something/c/d
 RUN test $(stat -c %a /usr/sbin/fake) -eq 4755
 RUN test -f /tmp/preinstall-proof
 RUN test -f /tmp/postinstall-proof
diff --git a/testdata/acceptance/rpm.dockerfile b/testdata/acceptance/rpm.dockerfile
index 6a23f20..d009580 100644
--- a/testdata/acceptance/rpm.dockerfile
+++ b/testdata/acceptance/rpm.dockerfile
@@ -50,6 +50,11 @@ RUN test -f /usr/share/whatever/folder/folder2/file2
 RUN test -d /var/log/whatever
 RUN test -d /usr/share/foo
 RUN test -d /usr/foo/bar/something
+RUN test -d /etc/something
+RUN test -f /etc/something/a
+RUN test -f /etc/something/b
+RUN test -d /etc/something/c
+RUN test -f /etc/something/c/d
 RUN test $(stat -c %a /usr/sbin/fake) -eq 4755
 RUN test -f /tmp/preinstall-proof
 RUN test -f /tmp/postinstall-proof
diff --git a/testdata/something/a b/testdata/something/a
new file mode 100644
index 0000000..2e65efe
--- /dev/null
+++ b/testdata/something/a
@@ -0,0 +1,1 @@
+a
\ No newline at end of file
diff --git a/testdata/something/b b/testdata/something/b
new file mode 100644
index 0000000..63d8dbd
--- /dev/null
+++ b/testdata/something/b
@@ -0,0 +1,1 @@
+b
\ No newline at end of file
diff --git a/testdata/something/c/d b/testdata/something/c/d
new file mode 100644
index 0000000..c59d9b6
--- /dev/null
+++ b/testdata/something/c/d
@@ -0,0 +1,1 @@
+d
\ No newline at end of file