diff --git a/Makefile b/Makefile index 79218661..d7e552cf 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ pull_test_imgs: .PHONY: pull_test_imgs test: pull_test_imgs - go test $(TEST_OPTIONS) -v -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.out $(SOURCE_FILES) -run $(TEST_PATTERN) -timeout=5m + go test $(TEST_OPTIONS) -v -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.out $(SOURCE_FILES) -run $(TEST_PATTERN) -timeout=25m .PHONY: test cover: test diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 280b5730..f7c32407 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,22 @@ 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() + + slurp, _ := ioutil.ReadAll(stderr) + if len(slurp) > 0 { + t.Log("stderr:", string(slurp)) + } + slurp, _ = ioutil.ReadAll(stdout) + if len(slurp) > 0 { + t.Log("stdout:", string(slurp)) + } + require.NoError(t, err) + err = cmd.Wait() require.NoError(t, err) } diff --git a/acceptance/testdata/release.rpm.dockerfile b/acceptance/testdata/release.rpm.dockerfile index 17a0ba19..dc200f22 100644 --- a/acceptance/testdata/release.rpm.dockerfile +++ b/acceptance/testdata/release.rpm.dockerfile @@ -7,4 +7,4 @@ RUN test -f /etc/foo/whatever.conf RUN echo wat >> /etc/foo/whatever.conf RUN rpm -e foo RUN test -f /etc/foo/whatever.conf.rpmsave -RUN test ! -f /usr/local/bin/fake +RUN test ! -f /usr/local/bin/fake \ No newline at end of file diff --git a/acceptance/testdata/rpm.complex.dockerfile b/acceptance/testdata/rpm.complex.dockerfile index e7db0c72..e42426f2 100644 --- a/acceptance/testdata/rpm.complex.dockerfile +++ b/acceptance/testdata/rpm.complex.dockerfile @@ -23,4 +23,4 @@ RUN test ! -f /usr/local/bin/fake RUN test -f /tmp/preremove-proof RUN test -f /tmp/postremove-proof RUN test ! -d /var/log/whatever -RUN test ! -d /usr/share/foo +RUN test ! -d /usr/share/foo \ No newline at end of file diff --git a/acceptance/testdata/rpm.dockerfile b/acceptance/testdata/rpm.dockerfile index 17a0ba19..dc200f22 100644 --- a/acceptance/testdata/rpm.dockerfile +++ b/acceptance/testdata/rpm.dockerfile @@ -7,4 +7,4 @@ RUN test -f /etc/foo/whatever.conf RUN echo wat >> /etc/foo/whatever.conf RUN rpm -e foo RUN test -f /etc/foo/whatever.conf.rpmsave -RUN test ! -f /usr/local/bin/fake +RUN test ! -f /usr/local/bin/fake \ No newline at end of file diff --git a/acceptance/testdata/rpm.min.dockerfile b/acceptance/testdata/rpm.min.dockerfile index b7b21cb4..6cbcd767 100644 --- a/acceptance/testdata/rpm.min.dockerfile +++ b/acceptance/testdata/rpm.min.dockerfile @@ -2,4 +2,4 @@ FROM fedora ARG package COPY ${package} /tmp/foo.rpm RUN rpm -ivh /tmp/foo.rpm -RUN rpm -e foo +RUN rpm -e foo \ No newline at end of file diff --git a/acceptance/testdata/rpm.overrides.dockerfile b/acceptance/testdata/rpm.overrides.dockerfile index eba42f99..43ca85c8 100644 --- a/acceptance/testdata/rpm.overrides.dockerfile +++ b/acceptance/testdata/rpm.overrides.dockerfile @@ -19,4 +19,4 @@ RUN rpm -e foo RUN test -f /etc/foo/whatever.conf.rpmsave RUN test ! -f /usr/local/bin/fake RUN test ! -f /tmp/preremove-proof -RUN test -f /tmp/postremove-proof +RUN test -f /tmp/postremove-proof \ No newline at end of file diff --git a/go.mod b/go.mod index a4758cc4..f55d041c 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 323884a9..5d5e27ee 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 7b1e1ba7..c38e693b 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) @@ -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 }