Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions deb/deb.go
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,11 @@ type controlData struct {
}

func writeControl(w io.Writer, data controlData) error {
tmpl := template.New("control")
return writeTemplate("control", controlTemplate, w, data)
}

func writeTemplate(name, t string, w io.Writer, data interface{}) error {
tmpl := template.New(name)
tmpl.Funcs(template.FuncMap{
"join": func(strs []string) string {
return strings.Trim(strings.Join(strs, ", "), " ")
Expand Down Expand Up @@ -806,5 +810,5 @@ func writeControl(w io.Writer, data controlData) error {
return result
},
})
return template.Must(tmpl.Parse(controlTemplate)).Execute(w, data)
return template.Must(tmpl.Parse(t)).Execute(w, data)
}
161 changes: 161 additions & 0 deletions deb/deb_meta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package deb

import (
"bytes"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"fmt"
"io"
"path/filepath"
"strings"
"time"

"github.com/goreleaser/nfpm/v2"
"github.com/goreleaser/nfpm/v2/internal/sign"
)

const debChangesTemplate = `
{{- /* Mandatory fields */ -}}
Format: 1.8
Date: {{.Date}}
Source: {{.Info.Name}}
Binary: {{.Info.Deb.Metadata.Binary}}
Architecture: {{ if ne .Info.Platform "linux"}}{{ .Info.Platform }}-{{ end }}{{.Info.Arch}}
Version: {{ if .Info.Epoch}}{{ .Info.Epoch }}:{{ end }}{{.Info.Version}}
{{- if .Info.Prerelease}}~{{ .Info.Prerelease }}{{- end }}
{{- if .Info.VersionMetadata}}+{{ .Info.VersionMetadata }}{{- end }}
{{- if .Info.Release}}-{{ .Info.Release }}{{- end }}
Distribution: {{.Info.Deb.Metadata.Distribution}}
{{- if .Info.Deb.Metadata.Urgency }}
Urgency: {{.Info.Deb.Metadata.Urgency}}
{{- end }}
Maintainer: {{.Info.Maintainer}}
{{- if .Info.Deb.Metadata.ChangedBy }}
Changed-By: {{.Info.Deb.Metadata.ChangedBy}}
{{- end }}
Description: {{ multiline .Info.Description }}
{{- range $key, $value := .Info.Deb.Metadata.Fields }}
{{- if $value }}
{{$key}}: {{$value}}
{{- end }}
{{- end }}
Changes:
{{range .Changes}} {{.}}{{end}}
Checksums-Sha256:
{{range .Files}} {{ .Sha256Sum }} {{.Size}} {{.Name}}{{end}}
Checksums-Sha1:
{{range .Files}} {{ .Sha1Sum }} {{.Size}} {{.Name}}{{end}}
Files:
{{range .Files}} {{ .Md5Sum }} {{.Size}} {{.Section}} {{.Priority}} {{.Name}}{{end}}

`

type changesData struct {
Date string
Info *nfpm.Info
Changes []string
Files []changesFileData
}

type changesFileData struct {
Name string
Size int
Section string
Priority string
Md5Sum string
Sha1Sum string
Sha256Sum string
}

var now = time.Now

func (d *Deb) ConventionalMetadataFileName(info *nfpm.Info) string {
target := info.Target

if target == "" {
target = d.ConventionalFileName(info)
}

return strings.Replace(target, ".deb", ".changes", 1)
}

func (d *Deb) PackageMetadata(metaInfo *nfpm.MetaInfo, w io.Writer) error {
data, err := createChanges(metaInfo)
if err != nil {
return err
}

if metaInfo.Info.Deb.Signature.KeyFile == "" {
_, err = w.Write(data.Bytes())
return err
}

signedData, err := signChanges(data, metaInfo.Info)
if err != nil {
return err
}

_, err = w.Write(signedData)
return err
}

func createChanges(info *nfpm.MetaInfo) (*bytes.Buffer, error) {
data, err := prepareChangesData(info)
if err != nil {
return nil, err
}

buf := new(bytes.Buffer)

if err := writeTemplate("changes", debChangesTemplate, buf, data); err != nil {
return nil, err
}

return buf, nil
}

func prepareChangesData(meta *nfpm.MetaInfo) (*changesData, error) {
info := meta.Info

_, err := meta.Package.Seek(0, io.SeekStart)
if err != nil {
return nil, err
}

buf := new(bytes.Buffer)

_, err = buf.ReadFrom(meta.Package)
if err != nil {
return nil, err
}

return &changesData{
Date: now().Format(time.RFC1123Z),
Info: info,
Changes: []string{
fmt.Sprintf("%s (%s) %s; urgency=%s\n * Package created with nFPM",
info.Name, info.Version, info.Deb.Metadata.Distribution, info.Deb.Metadata.Urgency),
},
Files: []changesFileData{
{
Name: filepath.Base(info.Target),
Size: buf.Len(),
Section: info.Section,
Priority: info.Priority,
Md5Sum: fmt.Sprintf("%x", md5.Sum(buf.Bytes())),
Sha1Sum: fmt.Sprintf("%x", sha1.Sum(buf.Bytes())),
Sha256Sum: fmt.Sprintf("%x", sha256.Sum256(buf.Bytes())),
},
},
}, nil
}

func signChanges(data *bytes.Buffer, info *nfpm.Info) ([]byte, error) {
signConfig := info.Deb.Signature
signature, err := sign.PGPClearSignWithKeyID(data, signConfig.KeyFile, signConfig.KeyPassphrase, signConfig.KeyID)
if err != nil {
return nil, &nfpm.ErrSigningFailure{Err: err}
}
return signature, nil
}
110 changes: 110 additions & 0 deletions deb/deb_meta_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package deb

import (
"bytes"
"os"
"testing"
"time"

"github.com/goreleaser/nfpm/v2"
"github.com/goreleaser/nfpm/v2/internal/sign"
"github.com/stretchr/testify/require"
)

func fakeTime() time.Time {
t, _ := time.Parse(time.RFC1123Z, "Mon, 30 Jan 2023 08:36:31 +0300")
return t
}

func TestMetaFilename(t *testing.T) {
info := exampleInfo()

require.Equal(t, "foo_1.0.0_amd64.changes", Default.ConventionalMetadataFileName(info))
}

func TestMetaFilenameTarget(t *testing.T) {
info := exampleInfo()
info.Target = "bar_1.0.0_amd64.deb"

require.Equal(t, "bar_1.0.0_amd64.changes", Default.ConventionalMetadataFileName(info))
}

func TestMetaFields(t *testing.T) {
now = fakeTime

var w bytes.Buffer
pkg := bytes.NewReader([]byte{1, 2, 3})
info := nfpm.WithDefaults(&nfpm.Info{
Name: "foo",
Description: "Foo does things",
Priority: "extra",
Maintainer: "Carlos A Becker <pkg@carlosbecker.com>",
Version: "v1.0.0",
Section: "default",
Homepage: "http://carlosbecker.com",
EnableMetadata: true,
Overridables: nfpm.Overridables{
Deb: nfpm.Deb{
Metadata: nfpm.DebMetadata{
Binary: "foo",
Distribution: "unstable",
Urgency: "medium",
ChangedBy: "Carlos A Becker <pkg@carlosbecker.com>",
Fields: map[string]string{
"Bugs": "https://github.com/goreleaser/nfpm/issues",
"Empty": "",
},
},
},
},
})
info.Target = Default.ConventionalFileName(info)

require.NoError(t, Default.PackageMetadata(&nfpm.MetaInfo{
Info: info,
Package: pkg,
}, &w))
golden := "testdata/changes.golden"
if *update {
require.NoError(t, os.WriteFile(golden, w.Bytes(), 0o600))
}
bts, err := os.ReadFile(golden) //nolint:gosec
require.NoError(t, err)
require.Equal(t, string(bts), w.String())
}

func TestMetaSignature(t *testing.T) {
info := exampleInfo()
info.Target = Default.ConventionalFileName(info)
info.Deb.Signature.KeyFile = "../internal/sign/testdata/privkey.asc"
info.Deb.Signature.KeyPassphrase = "hunter2"

var w bytes.Buffer
pkg := bytes.NewReader([]byte{1, 2, 3})

require.NoError(t, Default.PackageMetadata(&nfpm.MetaInfo{
Info: info,
Package: pkg,
}, &w))

_, err := sign.PGPReadMessage(w.Bytes(), "../internal/sign/testdata/pubkey.asc")
require.NoError(t, err)
}

func TestMetaSignatureError(t *testing.T) {
now = fakeTime
info := exampleInfo()
info.Target = Default.ConventionalFileName(info)
info.Deb.Signature.KeyFile = "/does/not/exist"

var w bytes.Buffer
pkg := bytes.NewReader([]byte{1, 2, 3})
err := Default.PackageMetadata(&nfpm.MetaInfo{
Info: info,
Package: pkg,
}, &w)
require.Error(t, err)

var expectedError *nfpm.ErrSigningFailure
require.ErrorAs(t, err, &expectedError)
}
22 changes: 22 additions & 0 deletions deb/testdata/changes.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Format: 1.8
Date: Mon, 30 Jan 2023 08:36:31 +0300
Source: foo
Binary: foo
Architecture: amd64
Version: 1.0.0
Distribution: unstable
Urgency: medium
Maintainer: Carlos A Becker <pkg@carlosbecker.com>
Changed-By: Carlos A Becker <pkg@carlosbecker.com>
Description: Foo does things
Bugs: https://github.com/goreleaser/nfpm/issues
Changes:
foo (1.0.0) unstable; urgency=medium
* Package created with nFPM
Checksums-Sha256:
039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81 3 foo_1.0.0_amd64.deb
Checksums-Sha1:
7037807198c22a7d2b0807371d763779a84fdfcf 3 foo_1.0.0_amd64.deb
Files:
5289df737df57326fcdd22597afb1fac 3 default extra foo_1.0.0_amd64.deb

30 changes: 30 additions & 0 deletions internal/cmd/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"errors"
"fmt"
"io"
"os"
"path"
"path/filepath"
Expand Down Expand Up @@ -113,5 +114,34 @@ func doPackage(configPath, target, packager string) error {
}

fmt.Printf("created package: %s\n", target)

meta, supports := pkg.(nfpm.PackagerWithMetadata)
if !supports || !info.EnableMetadata {
return nil
}

return doPackageMeta(meta, f, info)
}

func doPackageMeta(pkgMeta nfpm.PackagerWithMetadata, p io.ReadSeeker, info *nfpm.Info) error {
target := pkgMeta.ConventionalMetadataFileName(info)

f, err := os.Create(target)
if err != nil {
return err
}
defer f.Close()

metaInfo := &nfpm.MetaInfo{
Info: info,
Package: p,
}

if err := pkgMeta.PackageMetadata(metaInfo, f); err != nil {
_ = os.Remove(target)
return err
}

fmt.Printf("created package metadata: %s\n", target)
return f.Close()
}
Loading