Repository: goreleaser/nfpm (go)

Issue:
Bad rights on created subdirectories
### What happened?

When I package a RPM, subdirectories has `root:root` even if I set `file_info.owner` and `file_info.group` to `apache`

When using `type: tree`, all files and subdirectories are `root:root` instead of `apache:apache`

### How can we reproduce this?

* Create following file structure : 
  * `A/B/C.txt`
  * `X/Y/Z.txt`

* Create `my-package.yaml` :
```yaml
name: my-package
arch: "all"
platform: "linux"
version_schema: "none"
version: "1.0.0"
release: "1"
section: "default"
priority: "optional"
maintainer: "kduret"
description: |
  This is a test package.
  Commit: my-commit-hash
vendor: "kduret"
homepage: "https://www.google.com"
license: "Apache-2.0"

contents:
  - src: "./A/"
    dst: "/usr/share/A"
    type: tree
    file_info:
      mode: 0644
      owner: "apache"
      group: "apache"

  - src: "./B"
    dst: "/usr/share/B"
    file_info:
      mode: 0644
      owner: "apache"
      group: "apache"
```

* run following nfpm command : `nfpm package --config my-package.yaml --packager rpm`
* Install `httpd` to create apache user : `dnf install httpd`
* Install generated rpm : `rpm -Uvh my-package-1.0.0-1.rpm`

* Received result :
  * all directories and files in `/usr/share/A` are `root:root`
  * all directories in `/usr/share/B` are `root:root`
  * all files in `/usr/share/B` are `apache:apache`

* Expected result :
  * all directories and files in `/usr/share/A` are `apache:apache`
  * all directories and files in `/usr/share/B` are `apache:apache`

### nfpm version

```bash
# nfpm --version
       _____ ____  __  __
 _ __ |  ___|  _ \|  \/  |
| '_ \| |_  | |_) | |\/| |
| | | |  _| |  __/| |  | |
|_| |_|_|   |_|   |_|  |_|
nfpm: a simple and 0-dependencies deb, rpm, apk and arch linux packager written in Go
https://nfpm.goreleaser.com

GitVersion:    2.33.1
GitCommit:     bb6d0b9839c71ebd5d9d9bc0cf4088b3b933dc09
GitTreeState:  false
BuildDate:     2023-09-22T02:48:09Z
BuiltBy:       goreleaser
GoVersion:     go1.21.1
Compiler:      gc
ModuleSum:     h1:EkdAzZyVhAI9JC1vjmjjbmnNzyH1J6Cu4JCsA7YcQuc=
Platform:      linux/amd64
```


### 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

* I have not tested with deb packages
* Same issue with nfpm version 2.29.0

Pull request description:
fix: use parent owner/group on typedir
closes #738

Patch:
diff --git a/files/files.go b/files/files.go
index 6b3b898..955939a 100644
--- a/files/files.go
+++ b/files/files.go
@@ -471,7 +471,13 @@ func addTree(
 
 		destination := filepath.Join(tree.Destination, relPath)
 
-		c := &Content{}
+		c := &Content{
+			FileInfo: &ContentFileInfo{},
+		}
+		if tree.FileInfo != nil {
+			c.FileInfo.Owner = tree.FileInfo.Owner
+			c.FileInfo.Group = tree.FileInfo.Group
+		}
 
 		switch {
 		case d.IsDir():
@@ -482,28 +488,22 @@ func addTree(
 
 			c.Type = TypeDir
 			c.Destination = NormalizeAbsoluteDirPath(destination)
-			c.FileInfo = &ContentFileInfo{
-				Owner: "root",
-				Group: "root",
-				Mode:  info.Mode() &^ umask,
-				MTime: info.ModTime(),
-			}
+			c.FileInfo.Mode = info.Mode() &^ umask
+			c.FileInfo.MTime = info.ModTime()
 		case d.Type()&os.ModeSymlink != 0:
 			linkDestination, err := os.Readlink(path)
 			if err != nil {
 				return err
 			}
 
+			c.Type = TypeSymlink
 			c.Source = filepath.ToSlash(strings.TrimPrefix(linkDestination, filepath.VolumeName(linkDestination)))
 			c.Destination = NormalizeAbsoluteFilePath(destination)
-			c.Type = TypeSymlink
 		default:
+			c.Type = TypeFile
 			c.Source = path
 			c.Destination = NormalizeAbsoluteFilePath(destination)
-			c.Type = TypeFile
-			c.FileInfo = &ContentFileInfo{
-				Mode: d.Type() &^ umask,
-			}
+			c.FileInfo.Mode = d.Type() &^ umask
 		}
 
 		all[c.Destination] = c.WithFileInfoDefaults(umask, mtime)
diff --git a/go.mod b/go.mod
index 07021fb..4922a2f 100644
--- a/go.mod
+++ b/go.mod
@@ -69,9 +69,9 @@ require (
 	github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
 	github.com/xanzy/ssh-agent v0.3.3 // indirect
 	gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
-	golang.org/x/crypto v0.14.0 // indirect
+	golang.org/x/crypto v0.17.0 // indirect
 	golang.org/x/net v0.17.0 // indirect
-	golang.org/x/sys v0.13.0 // indirect
-	golang.org/x/text v0.13.0 // indirect
+	golang.org/x/sys v0.15.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
 	gopkg.in/warnings.v0 v0.1.2 // indirect
 )
diff --git a/go.sum b/go.sum
index 75b617c..fb223e4 100644
--- a/go.sum
+++ b/go.sum
@@ -178,8 +178,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
 golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
 golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
-golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
-golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
+golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
 golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8=
 golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
@@ -216,14 +216,14 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
-golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
-golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
+golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -231,8 +231,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=


Test patch:
diff --git a/files/files_test.go b/files/files_test.go
index 0c2378f..6442296 100644
--- a/files/files_test.go
+++ b/files/files_test.go
@@ -751,6 +751,76 @@ func TestRelevantFiles(t *testing.T) {
 	})
 }
 
+func TestTreeOwner(t *testing.T) {
+	results, err := files.PrepareForPackager(
+		files.Contents{
+			{
+				Source:      filepath.Join("testdata", "tree"),
+				Destination: "/base",
+				Type:        files.TypeTree,
+				FileInfo: &files.ContentFileInfo{
+					Owner: "goreleaser",
+					Group: "goreleaser",
+					MTime: mtime,
+				},
+			},
+		},
+		0,
+		"",
+		false,
+		mtime,
+	)
+	require.NoError(t, err)
+
+	for _, f := range results {
+		require.Equal(t, "goreleaser", f.FileInfo.Owner, f.Destination)
+		require.Equal(t, "goreleaser", f.FileInfo.Group, f.Destination)
+	}
+
+	require.Equal(t, files.Contents{
+		{
+			Source:      "",
+			Destination: "/base/",
+			Type:        files.TypeDir,
+		},
+		{
+			Source:      "",
+			Destination: "/base/files/",
+			Type:        files.TypeDir,
+		},
+		{
+			Source:      filepath.Join("testdata", "tree", "files", "a"),
+			Destination: "/base/files/a",
+			Type:        files.TypeFile,
+		},
+		{
+			Source:      "",
+			Destination: "/base/files/b/",
+			Type:        files.TypeDir,
+		},
+		{
+			Source:      filepath.Join("testdata", "tree", "files", "b", "c"),
+			Destination: "/base/files/b/c",
+			Type:        files.TypeFile,
+		},
+		{
+			Source:      "",
+			Destination: "/base/symlinks/",
+			Type:        files.TypeDir,
+		},
+		{
+			Source:      "/etc/foo",
+			Destination: "/base/symlinks/link1",
+			Type:        files.TypeSymlink,
+		},
+		{
+			Source:      "../files/a",
+			Destination: "/base/symlinks/link2",
+			Type:        files.TypeSymlink,
+		},
+	}, withoutFileInfo(results))
+}
+
 func TestTree(t *testing.T) {
 	results, err := files.PrepareForPackager(
 		files.Contents{