Repository: goreleaser/nfpm
Pull request #79 (2019-10-03 22:46:25)

feat: provide more field support for rpms
New RPM fields
---
* Description
* OS <= info.Platform
* Licence
* URL <= info.Homepage
* Vendor
* Packager <= info.Maintainer
* Provides
* Require <= info.Depends
* Obsolete <= info.Replaces
* Suggests
* Conflicts

Fixes
---
* RPM Compression types are supported again
* RPM Config files are supported again
  * `rpmpack` supports all the rpm file types, so we could extend this more latter

Closes: #71 #54 

caarlos0: LGTM so far :D 
djgilcrease: Should be all good now
codecov-io: # [Codecov](https://codecov.io/gh/goreleaser/nfpm/pull/79?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@7a174b2`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `78.75%`.

[![Impacted file tree graph](https://codecov.io/gh/goreleaser/nfpm/pull/79/graphs/tree.svg?width=650&token=9QKGIxn7wg&height=150&src=pr)](https://codecov.io/gh/goreleaser/nfpm/pull/79?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master      #79   +/-   ##
=========================================
  Coverage          ?   71.09%           
=========================================
  Files             ?        5           
  Lines             ?      467           
  Branches          ?        0           
=========================================
  Hits              ?      332           
  Misses            ?       84           
  Partials          ?       51
```


| [Impacted Files](https://codecov.io/gh/goreleaser/nfpm/pull/79?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [rpm/rpm.go](https://codecov.io/gh/goreleaser/nfpm/pull/79/diff?src=pr&el=tree#diff-cnBtL3JwbS5nbw==) | `71.63% <78.75%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/goreleaser/nfpm/pull/79?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/goreleaser/nfpm/pull/79?src=pr&el=footer). Last update [7a174b2...12f49a7](https://codecov.io/gh/goreleaser/nfpm/pull/79?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

caarlos0: awesome, thanks!

Patch:
diff --git a/Makefile b/Makefile
index 7921866..76472b2 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,7 @@ fmt:
 .PHONY: fmt
 
 lint: check
-	./bin/golangci-lint run --disable godox --enable-all ./...
+	./bin/golangci-lint run --disable wsl --disable godox --enable-all ./...
 .PHONY: check
 
 ci: build lint test
diff --git a/go.mod b/go.mod
index a4758cc..f55d041 100644
--- a/go.mod
+++ b/go.mod
@@ -17,7 +17,7 @@ require (
 	github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b
 	github.com/stretchr/testify v1.4.0
 	github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
-	golang.org/x/crypto v0.0.0-20190909091759-094676da4a83 // indirect
+	golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc // indirect
 	gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
 	gopkg.in/yaml.v2 v2.2.4
 )
diff --git a/go.sum b/go.sum
index 323884a..5d5e27e 100644
--- a/go.sum
+++ b/go.sum
@@ -41,8 +41,8 @@ github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4A
 github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
 github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190909091759-094676da4a83 h1:mgAKeshyNqWKdENOnQsg+8dRTwZFIwFaO3HNl52sweA=
-golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4=
+golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/rpm/rpm.go b/rpm/rpm.go
index 243f4b4..c38e693 100644
--- a/rpm/rpm.go
+++ b/rpm/rpm.go
@@ -42,24 +42,24 @@ func ensureValidArch(info nfpm.Info) nfpm.Info {
 
 // Package writes a new RPM package to the given writer using the given info
 func (*RPM) Package(info nfpm.Info, w io.Writer) error {
+	var (
+		err  error
+		meta *rpmpack.RPMMetaData
+		rpm  *rpmpack.RPM
+	)
 	info = ensureValidArch(info)
-	err := nfpm.Validate(info)
-	if err != nil {
+	if err = nfpm.Validate(info); err != nil {
 		return err
 	}
 
-	vInfo := strings.SplitN(info.Version, "-", 1)
-	vInfo = append(vInfo, "")
-	rpm, err := rpmpack.NewRPM(rpmpack.RPMMetaData{
-		Name:    info.Name,
-		Version: vInfo[0],
-		Release: vInfo[1],
-		Arch:    info.Arch,
-	})
-	if err != nil {
+	if meta, err = buildRPMMeta(info); err != nil {
+		return err
+	}
+	if rpm, err = rpmpack.NewRPM(*meta); err != nil {
 		return err
 	}
 
+	addEmptyDirsRPM(info, rpm)
 	if err = createFilesInsideRPM(info, rpm); err != nil {
 		return err
 	}
@@ -75,6 +75,65 @@ func (*RPM) Package(info nfpm.Info, w io.Writer) error {
 	return nil
 }
 
+func buildRPMMeta(info nfpm.Info) (*rpmpack.RPMMetaData, error) {
+	var (
+		err error
+		provides,
+		depends,
+		replaces,
+		suggests,
+		conflicts rpmpack.Relations
+	)
+	vInfo := strings.SplitN(info.Version, "-", 2)
+	vInfo = append(vInfo, info.RPM.Release)
+
+	if provides, err = toRelation(info.Provides); err != nil {
+		return nil, err
+	}
+	if depends, err = toRelation(info.Depends); err != nil {
+		return nil, err
+	}
+	if replaces, err = toRelation(info.Replaces); err != nil {
+		return nil, err
+	}
+	if suggests, err = toRelation(info.Suggests); err != nil {
+		return nil, err
+	}
+	if conflicts, err = toRelation(info.Conflicts); err != nil {
+		return nil, err
+	}
+
+	return &rpmpack.RPMMetaData{
+		Name:        info.Name,
+		Description: info.Description,
+		Version:     vInfo[0],
+		Release:     vInfo[1],
+		Arch:        info.Arch,
+		OS:          info.Platform,
+		Licence:     info.License,
+		URL:         info.Homepage,
+		Vendor:      info.Vendor,
+		Packager:    info.Maintainer,
+		Provides:    provides,
+		Requires:    depends,
+		Obsoletes:   replaces,
+		Suggests:    suggests,
+		Conflicts:   conflicts,
+		Compressor:  info.RPM.Compression,
+	}, nil
+}
+
+func toRelation(items []string) (rpmpack.Relations, error) {
+	relations := make(rpmpack.Relations, 0)
+	for idx := range items {
+		if err := relations.Set(items[idx]); err != nil {
+			return nil, err
+		}
+	}
+
+	return relations, nil
+}
+
 func addScriptFiles(info nfpm.Info, rpm *rpmpack.RPM) error {
 	if info.Scripts.PreInstall != "" {
 		data, err := ioutil.ReadFile(info.Scripts.PreInstall)
@@ -101,7 +160,7 @@ func addScriptFiles(info nfpm.Info, rpm *rpmpack.RPM) error {
 	}
 
 	if info.Scripts.PostRemove != "" {
-		data, err := ioutil.ReadFile(info.Scripts.PostInstall)
+		data, err := ioutil.ReadFile(info.Scripts.PostRemove)
 		if err != nil {
 			return err
 		}
@@ -111,28 +170,45 @@ func addScriptFiles(info nfpm.Info, rpm *rpmpack.RPM) error {
 	return nil
 }
 
+func addEmptyDirsRPM(info nfpm.Info, rpm *rpmpack.RPM) {
+	for _, dir := range info.EmptyFolders {
+		rpm.AddFile(
+			rpmpack.RPMFile{
+				Name: dir,
+				Mode: uint(1 | 040000),
+			})
+	}
+}
+
 func createFilesInsideRPM(info nfpm.Info, rpm *rpmpack.RPM) error {
-	for _, files := range []map[string]string{
-		info.Files,
-		info.ConfigFiles,
-	} {
+	copy := func(files map[string]string, config bool) error {
 		for srcglob, dstroot := range files {
 			globbed, err := glob.Glob(srcglob, dstroot)
 			if err != nil {
 				return err
 			}
 			for src, dst := range globbed {
-				err := copyToRPM(rpm, src, dst)
+				err := copyToRPM(rpm, src, dst, config)
 				if err != nil {
 					return err
 				}
 			}
 		}
+
+		return nil
+	}
+	err := copy(info.Files, false)
+	if err != nil {
+		return err
+	}
+	err = copy(info.ConfigFiles, true)
+	if err != nil {
+		return err
 	}
 	return nil
 }
 
-func copyToRPM(rpm *rpmpack.RPM, src, dst string) error {
+func copyToRPM(rpm *rpmpack.RPM, src, dst string, config bool) error {
 	file, err := os.OpenFile(src, os.O_RDONLY, 0600) //nolint:gosec
 	if err != nil {
 		return errors.Wrap(err, "could not add file to the archive")
@@ -152,12 +228,17 @@ func copyToRPM(rpm *rpmpack.RPM, src, dst string) error {
 		return err
 	}
 
-	rpm.AddFile(
-		rpmpack.RPMFile{
-			Name: dst,
-			Body: data,
-			Mode: uint(info.Mode()),
-		})
+	rpmFile := rpmpack.RPMFile{
+		Name: dst,
+		Body: data,
+		Mode: uint(info.Mode()),
+	}
+
+	if config {
+		rpmFile.Type = rpmpack.ConfigFile
+	}
+
+	rpm.AddFile(rpmFile)
 
 	return nil
 }


Test patch:
diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go
index 280b573..ac64994 100644
--- a/acceptance/acceptance_test.go
+++ b/acceptance/acceptance_test.go
@@ -2,6 +2,7 @@ package acceptance
 
 import (
 	"fmt"
+	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -21,7 +22,7 @@ var formats = []string{"deb", "rpm"}
 func TestSimple(t *testing.T) {
 	for _, format := range formats {
 		format := format
-		t.Run("amd64", func(t *testing.T) {
+		t.Run(fmt.Sprintf("amd64-%s", format), func(t *testing.T) {
 			t.Parallel()
 			accept(t, acceptParms{
 				Name:       fmt.Sprintf("simple_%s", format),
@@ -30,7 +31,7 @@ func TestSimple(t *testing.T) {
 				Dockerfile: fmt.Sprintf("%s.dockerfile", format),
 			})
 		})
-		t.Run("i386", func(t *testing.T) {
+		t.Run(fmt.Sprintf("i386-%s", format), func(t *testing.T) {
 			t.Parallel()
 			accept(t, acceptParms{
 				Name:       fmt.Sprintf("simple_%s_386", format),
@@ -39,7 +40,7 @@ func TestSimple(t *testing.T) {
 				Dockerfile: fmt.Sprintf("%s.386.dockerfile", format),
 			})
 		})
-		t.Run("ppc64le", func(t *testing.T) {
+		t.Run(fmt.Sprintf("ppc64le-%s", format), func(t *testing.T) {
 			t.Skip("for some reason travis fails to run those")
 			t.Parallel()
 			accept(t, acceptParms{
@@ -49,7 +50,7 @@ func TestSimple(t *testing.T) {
 				Dockerfile: fmt.Sprintf("%s.ppc64le.dockerfile", format),
 			})
 		})
-		t.Run("arm64", func(t *testing.T) {
+		t.Run(fmt.Sprintf("arm64-%s", format), func(t *testing.T) {
 			t.Parallel()
 			accept(t, acceptParms{
 				Name:       fmt.Sprintf("simple_%s_arm64", format),
@@ -64,7 +65,7 @@ func TestSimple(t *testing.T) {
 func TestComplex(t *testing.T) {
 	for _, format := range formats {
 		format := format
-		t.Run("amd64", func(t *testing.T) {
+		t.Run(fmt.Sprintf("amd64-%s", format), func(t *testing.T) {
 			t.Parallel()
 			accept(t, acceptParms{
 				Name:       fmt.Sprintf("complex_%s", format),
@@ -73,7 +74,7 @@ func TestComplex(t *testing.T) {
 				Dockerfile: fmt.Sprintf("%s.complex.dockerfile", format),
 			})
 		})
-		t.Run("i386", func(t *testing.T) {
+		t.Run(fmt.Sprintf("i386-%s", format), func(t *testing.T) {
 			t.Parallel()
 			accept(t, acceptParms{
 				Name:       fmt.Sprintf("complex_%s_386", format),
@@ -85,10 +86,10 @@ func TestComplex(t *testing.T) {
 	}
 }
 
-func TestComplexOverridesDeb(t *testing.T) {
+func TestComplexOverrides(t *testing.T) {
 	for _, format := range formats {
 		format := format
-		t.Run("amd64", func(t *testing.T) {
+		t.Run(fmt.Sprintf("amd64-%s", format), func(t *testing.T) {
 			t.Parallel()
 			accept(t, acceptParms{
 				Name:       fmt.Sprintf("overrides_%s", format),
@@ -100,10 +101,10 @@ func TestComplexOverridesDeb(t *testing.T) {
 	}
 }
 
-func TestMinDeb(t *testing.T) {
+func TestMin(t *testing.T) {
 	for _, format := range formats {
 		format := format
-		t.Run("amd64", func(t *testing.T) {
+		t.Run(fmt.Sprintf("amd64-%s", format), func(t *testing.T) {
 			t.Parallel()
 			accept(t, acceptParms{
 				Name:       fmt.Sprintf("min_%s", format),
@@ -186,8 +187,27 @@ func accept(t *testing.T, params acceptParms) {
 		".",
 	)
 	cmd.Dir = "./testdata"
+	stdout, err := cmd.StdoutPipe()
+	require.NoError(t, err)
+	stderr, err := cmd.StderrPipe()
+	require.NoError(t, err)
 	t.Log("will exec:", cmd.Args)
-	bts, err := cmd.CombinedOutput()
-	t.Log("output:", string(bts))
+	err = cmd.Start()
+	require.NoError(t, err)
+
+	var slurp []byte
+	slurp, err = ioutil.ReadAll(stderr)
+	if len(slurp) > 0 {
+		t.Log("stderr:", string(slurp))
+	}
+	require.NoError(t, err)
+
+	slurp, err = ioutil.ReadAll(stdout)
+	if len(slurp) > 0 {
+		t.Log("stdout:", string(slurp))
+	}
+	require.NoError(t, err)
+
+	err = cmd.Wait()
 	require.NoError(t, err)
 }