mirror of
https://github.com/goreleaser/nfpm
synced 2024-05-21 19:36:11 +02:00
Compare commits
50 Commits
Author | SHA1 | Date | |
---|---|---|---|
dependabot[bot] | 745b0f59d9 | ||
dependabot[bot] | 96b0d10688 | ||
caarlos0 | ba2bebd36d | ||
Carlos Alexandro Becker | ffb033ce70 | ||
caarlos0 | 5bb11f8f91 | ||
Carlos Alexandro Becker | 8377f70ac5 | ||
Carlos Alexandro Becker | 8643a66fc2 | ||
caarlos0 | 00cc3d861b | ||
Weston Schmidt | bc5c3bd876 | ||
Carlos Alexandro Becker | 45cc1deaf5 | ||
dependabot[bot] | 8d3515b77c | ||
dependabot[bot] | 690e88b030 | ||
dependabot[bot] | d78518b84a | ||
dependabot[bot] | 3ee9df5f08 | ||
dependabot[bot] | b381d5144d | ||
Carlos Alexandro Becker | 409b51628a | ||
dependabot[bot] | ccfa2f4b18 | ||
dependabot[bot] | 311860860c | ||
dependabot[bot] | 53815fbb5c | ||
Carlos Alexandro Becker | 157bd8dfd7 | ||
Carlos Alexandro Becker | 4e7be8063b | ||
caarlos0 | cee170f7a9 | ||
Carlos Alexandro Becker | 190ce19eca | ||
Carlos Alexandro Becker | a5cccefbf3 | ||
Carlos Alexandro Becker | 19f864b2d4 | ||
Carlos Alexandro Becker | 2118e9a218 | ||
Yaroslav | 1667ef9585 | ||
dependabot[bot] | 04298aca7a | ||
dependabot[bot] | a5376659a9 | ||
Carlos Alexandro Becker | 507ad79260 | ||
Carlos Alexandro Becker | 2bfa63a13f | ||
caarlos0 | 7761491ab4 | ||
Carlos Alexandro Becker | 7b3fb8b759 | ||
Carlos Alexandro Becker | ba8a7568e0 | ||
Yan Song Liu | ad0161768d | ||
Carlos Alexandro Becker | 29c8a210fe | ||
dependabot[bot] | 4a7322bba1 | ||
dependabot[bot] | b447c50c27 | ||
dependabot[bot] | f2711813ee | ||
dependabot[bot] | ebf76648f6 | ||
dependabot[bot] | cb456b40e7 | ||
nickajacks1 | d0d7c60d34 | ||
dependabot[bot] | 0b1bc17d46 | ||
dependabot[bot] | 41c6debf36 | ||
dependabot[bot] | c3a8e2d185 | ||
dependabot[bot] | ac5e97005a | ||
dependabot[bot] | 69660e6db1 | ||
dependabot[bot] | e0761b58cb | ||
dependabot[bot] | 0000c30be9 | ||
caarlos0 | 277ad52f54 |
|
@ -13,6 +13,7 @@ on:
|
|||
- "Dockerfile"
|
||||
- ".github/workflows/build.yml"
|
||||
- "testdata/**"
|
||||
- ".goreleaser.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "go.*"
|
||||
|
@ -20,7 +21,8 @@ on:
|
|||
- "Taskfile.yml"
|
||||
- "Dockerfile"
|
||||
- ".github/workflows/build.yml"
|
||||
- "testdata/"
|
||||
- "testdata/**"
|
||||
- ".goreleaser.yml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
@ -47,7 +49,7 @@ jobs:
|
|||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
- uses: arduino/setup-task@v1
|
||||
- uses: arduino/setup-task@v2
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: setup-tparse
|
||||
|
@ -55,7 +57,7 @@ jobs:
|
|||
- run: task setup
|
||||
- name: test
|
||||
run: ./scripts/test.sh test ${{ matrix.os }}
|
||||
- uses: codecov/codecov-action@v3
|
||||
- uses: codecov/codecov-action@v4
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
@ -63,7 +65,7 @@ jobs:
|
|||
acceptance-tests:
|
||||
strategy:
|
||||
matrix:
|
||||
pkgFormat: [deb, rpm, apk, archlinux]
|
||||
pkgFormat: [deb, rpm, apk, archlinux, ipk]
|
||||
pkgPlatform: [amd64, arm64, 386, ppc64le, armv6, armv7, s390x]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
|
@ -74,7 +76,7 @@ jobs:
|
|||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
- uses: arduino/setup-task@v1
|
||||
- uses: arduino/setup-task@v2
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
|
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v25
|
||||
- uses: cachix/install-nix-action@V27
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
github_access_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
- uses: arduino/setup-task@v1
|
||||
- uses: arduino/setup-task@v2
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- run: "go install github.com/santhosh-tekuri/jsonschema/cmd/jv@latest"
|
||||
|
|
|
@ -18,4 +18,4 @@ jobs:
|
|||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
- uses: golangci/golangci-lint-action@v3
|
||||
- uses: golangci/golangci-lint-action@v6
|
||||
|
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
needs: goreleaser
|
||||
steps:
|
||||
- uses: benc-uk/workflow-dispatch@v121
|
||||
- uses: benc-uk/workflow-dispatch@v1.2.3
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ secrets.GH_PAT }}
|
||||
|
@ -31,14 +31,14 @@ jobs:
|
|||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
- uses: arduino/setup-task@v1
|
||||
- uses: arduino/setup-task@v2
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: sigstore/cosign-installer@v3.3.0
|
||||
- uses: anchore/sbom-action/download-syft@v0.15.7
|
||||
- uses: sigstore/cosign-installer@v3.5.0
|
||||
- uses: anchore/sbom-action/download-syft@v0.16.0
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- uses: cachix/install-nix-action@v25
|
||||
- uses: cachix/install-nix-action@V27
|
||||
with:
|
||||
github_access_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- run: task setup
|
||||
|
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
- uses: arduino/setup-task@v1
|
||||
- uses: arduino/setup-task@v2
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: setup-tparse
|
||||
|
@ -45,13 +45,13 @@ jobs:
|
|||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
- uses: arduino/setup-task@v1
|
||||
- uses: arduino/setup-task@v2
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- shell: bash
|
||||
run: |
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v3
|
||||
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
|
||||
with:
|
||||
path: dist/
|
||||
key: ${{ env.sha_short }}
|
||||
|
@ -63,13 +63,13 @@ jobs:
|
|||
steps:
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: arduino/setup-task@v1
|
||||
- uses: arduino/setup-task@v2
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- shell: bash
|
||||
run: |
|
||||
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v3
|
||||
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
|
||||
with:
|
||||
path: dist/
|
||||
key: ${{ env.sha_short }}
|
||||
|
|
|
@ -24,6 +24,7 @@ builds:
|
|||
- amd64
|
||||
- arm64
|
||||
- ppc64le
|
||||
- s390x
|
||||
mod_timestamp: "{{ .CommitTimestamp }}"
|
||||
flags:
|
||||
- -trimpath
|
||||
|
@ -146,7 +147,7 @@ winget:
|
|||
branch: "nfpm-{{.Version}}"
|
||||
pull_request:
|
||||
enabled: true
|
||||
draft: true
|
||||
draft: false
|
||||
check_boxes: true
|
||||
base:
|
||||
owner: microsoft
|
||||
|
|
|
@ -9,7 +9,7 @@ By participating to this project, you agree to abide our [code of conduct](https
|
|||
Prerequisites:
|
||||
|
||||
- [Task](https://taskfile.dev/#/installation)
|
||||
- [Go 1.19+](https://golang.org/doc/install)
|
||||
- [Go 1.21+](https://golang.org/doc/install)
|
||||
- [Docker](https://www.docker.com/)
|
||||
- `gpg` (probably already installed on your system)
|
||||
|
||||
|
@ -38,6 +38,16 @@ If on the ARM tests you are seeing `standard_init_linux.go:211: exec user proces
|
|||
sudo docker run --rm --privileged hypriot/qemu-register
|
||||
```
|
||||
|
||||
### A note about Docker multi-arch builds
|
||||
|
||||
If you want to properly run the Docker tests, or run `goreleaser release
|
||||
--snapshot` locally, you might need to setup Docker for it.
|
||||
You can do so by running:
|
||||
|
||||
```sh
|
||||
task docker:setup
|
||||
```
|
||||
|
||||
## Test your change
|
||||
|
||||
You can create a branch for your changes and try to build from the source as you go:
|
||||
|
|
16
Taskfile.yml
16
Taskfile.yml
|
@ -17,6 +17,11 @@ tasks:
|
|||
cmds:
|
||||
- go mod tidy
|
||||
|
||||
docker:setup:
|
||||
desc: Setup Docker for multi-arch image builds
|
||||
cmds:
|
||||
- docker run --privileged --rm tonistiigi/binfmt --install all
|
||||
|
||||
build:
|
||||
desc: Build the binary
|
||||
sources:
|
||||
|
@ -169,3 +174,14 @@ tasks:
|
|||
- git tag {{.NEXT}}
|
||||
- echo {{.NEXT}}
|
||||
- git push origin --tags
|
||||
|
||||
nix:flake:update-vendor:
|
||||
desc: update default flake package vendor hash
|
||||
cmds:
|
||||
- bash ./scripts/nix-update-flake.sh
|
||||
generates:
|
||||
- flake.nix
|
||||
sources:
|
||||
- flake.lock
|
||||
- go.mod
|
||||
- go.sum
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
_ "github.com/goreleaser/nfpm/v2/apk"
|
||||
_ "github.com/goreleaser/nfpm/v2/arch"
|
||||
_ "github.com/goreleaser/nfpm/v2/deb"
|
||||
_ "github.com/goreleaser/nfpm/v2/ipk"
|
||||
_ "github.com/goreleaser/nfpm/v2/rpm"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -23,6 +24,7 @@ import (
|
|||
var formatArchs = map[string][]string{
|
||||
"apk": {"amd64", "arm64", "386", "ppc64le", "armv6", "armv7", "s390x"},
|
||||
"deb": {"amd64", "arm64", "ppc64le", "armv7", "s390x"},
|
||||
"ipk": {"x86_64", "aarch64_generic"},
|
||||
"rpm": {"amd64", "arm64", "ppc64le"},
|
||||
"archlinux": {"amd64"},
|
||||
}
|
||||
|
@ -202,6 +204,7 @@ func TestRPMSpecific(t *testing.T) {
|
|||
testNames := []string{
|
||||
"release",
|
||||
"directories",
|
||||
"verify",
|
||||
}
|
||||
for _, name := range testNames {
|
||||
for _, arch := range formatArchs[format] {
|
||||
|
@ -260,6 +263,38 @@ func TestDebSpecific(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIPKSpecific(t *testing.T) {
|
||||
t.Parallel()
|
||||
format := "ipk"
|
||||
testNames := []string{
|
||||
"alternatives",
|
||||
"conflicts",
|
||||
"predepends",
|
||||
}
|
||||
for _, name := range testNames {
|
||||
for _, arch := range formatArchs[format] {
|
||||
func(t *testing.T, testName, testArch string) {
|
||||
t.Run(fmt.Sprintf("%s/%s/%s", format, testArch, testName), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if testArch == "ppc64le" && os.Getenv("NO_TEST_PPC64LE") == "true" {
|
||||
t.Skip("ppc64le arch not supported in pipeline")
|
||||
}
|
||||
accept(t, acceptParms{
|
||||
Name: fmt.Sprintf("%s_%s", testName, testArch),
|
||||
Conf: fmt.Sprintf("%s.%s.yaml", format, testName),
|
||||
Format: format,
|
||||
Docker: dockerParams{
|
||||
File: fmt.Sprintf("%s.dockerfile", format),
|
||||
Target: testName,
|
||||
Arch: testArch,
|
||||
},
|
||||
})
|
||||
})
|
||||
}(t, name, arch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPMSign(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, os := range []string{"centos9", "centos8", "fedora34", "fedora36", "fedora38"} {
|
||||
|
|
47
apk/apk.go
47
apk/apk.go
|
@ -88,16 +88,7 @@ type Apk struct{}
|
|||
|
||||
func (a *Apk) ConventionalFileName(info *nfpm.Info) string {
|
||||
info = ensureValidArch(info)
|
||||
version := info.Version
|
||||
|
||||
if info.Prerelease != "" {
|
||||
version += "_" + info.Prerelease
|
||||
}
|
||||
|
||||
if info.Release != "" {
|
||||
version += "_p" + info.Release
|
||||
}
|
||||
|
||||
version := pkgver(info)
|
||||
return fmt.Sprintf("%s_%s_%s.apk", info.Name, version, info.Arch)
|
||||
}
|
||||
|
||||
|
@ -290,7 +281,10 @@ func createSignatureBuilder(digest []byte, info *nfpm.Info) func(*tar.Writer) er
|
|||
return errNoKeyAddress
|
||||
}
|
||||
|
||||
keyname = addr.Address + ".rsa.pub"
|
||||
keyname = addr.Address
|
||||
}
|
||||
if !strings.HasSuffix(keyname, ".rsa.pub") {
|
||||
keyname += ".rsa.pub"
|
||||
}
|
||||
|
||||
// In principle apk supports RSA signatures over SHA256/512 keys, but in
|
||||
|
@ -469,9 +463,7 @@ func copyToTarAndDigest(file *files.Content, tw *tar.Writer, sizep *int64) error
|
|||
const controlTemplate = `
|
||||
{{- /* Mandatory fields */ -}}
|
||||
pkgname = {{.Info.Name}}
|
||||
pkgver = {{.Info.Version}}
|
||||
{{- if .Info.Prerelease}}{{ .Info.Prerelease }}{{- end }}
|
||||
{{- if .Info.Release}}-{{ .Info.Release }}{{- end }}
|
||||
pkgver = {{ pkgver .Info }}
|
||||
arch = {{.Info.Arch}}
|
||||
size = {{.InstalledSize}}
|
||||
pkgdesc = {{multiline .Info.Description}}
|
||||
|
@ -509,6 +501,33 @@ func writeControl(w io.Writer, data controlData) error {
|
|||
ret := strings.ReplaceAll(strs, "\n", "\n ")
|
||||
return strings.Trim(ret, " \n")
|
||||
},
|
||||
"pkgver": pkgver,
|
||||
})
|
||||
return template.Must(tmpl.Parse(controlTemplate)).Execute(w, data)
|
||||
}
|
||||
|
||||
func pkgver(info *nfpm.Info) string {
|
||||
version := info.Version
|
||||
|
||||
if info.Prerelease != "" {
|
||||
version += "_" + info.Prerelease
|
||||
}
|
||||
|
||||
if rel := info.Release; rel != "" {
|
||||
if !strings.HasPrefix(rel, "r") {
|
||||
rel = "r" + rel
|
||||
}
|
||||
version += "-" + rel
|
||||
}
|
||||
if meta := info.VersionMetadata; meta != "" {
|
||||
if !strings.HasPrefix(meta, "p") &&
|
||||
!strings.HasPrefix(meta, "cvs") &&
|
||||
!strings.HasPrefix(meta, "svn") &&
|
||||
!strings.HasPrefix(meta, "git") &&
|
||||
!strings.HasPrefix(meta, "hg") {
|
||||
meta = "p" + meta
|
||||
}
|
||||
version += "-" + meta
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
|
|
@ -315,6 +315,28 @@ func TestControl(t *testing.T) {
|
|||
require.Equal(t, string(bts), w.String())
|
||||
}
|
||||
|
||||
func TestSignatureName(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.APK.Signature.KeyFile = "../internal/sign/testdata/rsa.priv"
|
||||
info.APK.Signature.KeyName = "testkey"
|
||||
info.APK.Signature.KeyPassphrase = "hunter2"
|
||||
err := nfpm.PrepareForPackager(info, "apk")
|
||||
require.NoError(t, err)
|
||||
|
||||
digest := sha1.New().Sum(nil) // nolint:gosec
|
||||
|
||||
var signatureTarGz bytes.Buffer
|
||||
tw := tar.NewWriter(&signatureTarGz)
|
||||
require.NoError(t, createSignatureBuilder(digest, info)(tw))
|
||||
|
||||
signature := extractFromTar(t, signatureTarGz.Bytes(), ".SIGN.RSA.testkey.rsa.pub")
|
||||
err = sign.RSAVerifySHA1Digest(digest, signature, "../internal/sign/testdata/rsa.pub")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = Default.Package(info, io.Discard)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSignature(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.APK.Signature.KeyFile = "../internal/sign/testdata/rsa.priv"
|
||||
|
@ -477,12 +499,16 @@ func TestAPKConventionalFileName(t *testing.T) {
|
|||
Expect: "default_1.2.3_x86_64.apk",
|
||||
},
|
||||
{
|
||||
Arch: "386", Version: "1.2.3", Prerelease: "git",
|
||||
Expect: "default_1.2.3_git_x86.apk",
|
||||
Arch: "386", Version: "1.2.3", Meta: "git",
|
||||
Expect: "default_1.2.3-git_x86.apk",
|
||||
},
|
||||
{
|
||||
Arch: "386", Version: "1.2.3", Meta: "1", Release: "10",
|
||||
Expect: "default_1.2.3-r10-p1_x86.apk",
|
||||
},
|
||||
{
|
||||
Arch: "386", Version: "1.2.3", Prerelease: "git", Release: "1",
|
||||
Expect: "default_1.2.3_git_p1_x86.apk",
|
||||
Expect: "default_1.2.3_git-r1_x86.apk",
|
||||
},
|
||||
{
|
||||
Arch: "all", Version: "1.2.3",
|
||||
|
@ -490,7 +516,11 @@ func TestAPKConventionalFileName(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Arch: "386", Version: "1.2.3", Release: "1", Prerelease: "beta1",
|
||||
Expect: "default_1.2.3_beta1_p1_x86.apk",
|
||||
Expect: "default_1.2.3_beta1-r1_x86.apk",
|
||||
},
|
||||
{
|
||||
Arch: "amd64", Version: "1.2.3a", Prerelease: "alpha1", Release: "47", Meta: "git-aaaccc",
|
||||
Expect: "default_1.2.3a_alpha1-r47-git-aaaccc_x86_64.apk",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pkgname = foo
|
||||
pkgver = 1.0.0beta1-r1
|
||||
pkgver = 1.0.0_beta1-r1
|
||||
arch = amd64
|
||||
size = 10
|
||||
pkgdesc = Foo does things
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pkgname = foo
|
||||
pkgver = 1.0.0beta1-r1
|
||||
pkgver = 1.0.0_beta1-r1
|
||||
arch = amd64
|
||||
size = 12345
|
||||
pkgdesc = Foo does things
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pkgname = foo
|
||||
pkgver = 1.0.0beta1-r1
|
||||
pkgver = 1.0.0_beta1-r1
|
||||
arch = amd64
|
||||
size = 12345
|
||||
pkgdesc = Foo does things
|
||||
|
|
|
@ -33,7 +33,7 @@ func main() {
|
|||
|
||||
func buildVersion(version, commit, date, builtBy, treeState string) goversion.Info {
|
||||
return goversion.GetVersionInfo(
|
||||
goversion.WithAppDetails("nfpm", "a simple and 0-dependencies deb, rpm, apk and arch linux packager written in Go", website),
|
||||
goversion.WithAppDetails("nfpm", "a simple and 0-dependencies apk, arch linux, deb, ipk, and rpm packager written in Go", website),
|
||||
goversion.WithASCIIName(asciiArt),
|
||||
func(i *goversion.Info) {
|
||||
if commit != "" {
|
||||
|
|
|
@ -279,6 +279,8 @@ contents:
|
|||
`))
|
||||
err := dec.Decode(&config)
|
||||
require.NoError(t, err)
|
||||
errs := make(chan error, 10)
|
||||
t.Cleanup(func() { close(errs) })
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
|
@ -291,10 +293,14 @@ contents:
|
|||
false,
|
||||
mtime,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
errs <- err
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
require.NoError(t, <-errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollision(t *testing.T) {
|
||||
|
|
31
flake.lock
31
flake.lock
|
@ -5,11 +5,11 @@
|
|||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1701680307,
|
||||
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -20,11 +20,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1703438236,
|
||||
"narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=",
|
||||
"lastModified": 1711703276,
|
||||
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b",
|
||||
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -37,24 +37,7 @@
|
|||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"staging": "staging"
|
||||
}
|
||||
},
|
||||
"staging": {
|
||||
"locked": {
|
||||
"lastModified": 1703777495,
|
||||
"narHash": "sha256-ISkNWa58+6Uk/nQ47omTETrV+yhKFbnU/wR9n+3ux8g=",
|
||||
"owner": "caarlos0",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e1d1738a056a052aedb6560c240b2749af33fee0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "caarlos0",
|
||||
"ref": "wip",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
staging.url = "github:caarlos0/nixpkgs/wip";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
outputs = { nixpkgs, staging, flake-utils, ... }:
|
||||
outputs = { nixpkgs, flake-utils, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
staging-pkgs = staging.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
packages.default = pkgs.buildGoModule {
|
||||
|
@ -17,7 +15,7 @@
|
|||
src = ./.;
|
||||
ldflags = [ "-s" "-w" "-X main.version=dev" "-X main.builtBy=flake" ];
|
||||
doCheck = false;
|
||||
vendorHash = "sha256-P9jSQG6EyVGMZKtThy8Q7Y/pV7mbMl2eGrylea0VHRc=";
|
||||
vendorHash = "sha256-g57tLk2+WWcdG0COqkQD7eLYG0TdC0RnlhLF6Qt4woY=";
|
||||
};
|
||||
|
||||
devShells.default = pkgs.mkShell {
|
||||
|
@ -25,6 +23,7 @@
|
|||
go
|
||||
go-task
|
||||
gofumpt
|
||||
nix-prefetch
|
||||
];
|
||||
shellHook = "go mod tidy";
|
||||
};
|
||||
|
|
35
go.mod
35
go.mod
|
@ -1,6 +1,6 @@
|
|||
module github.com/goreleaser/nfpm/v2
|
||||
|
||||
go 1.19
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0
|
||||
|
@ -9,25 +9,26 @@ require (
|
|||
github.com/ProtonMail/go-crypto v1.0.0
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.1
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||
github.com/caarlos0/go-rpmutils v0.2.1-0.20240105125627-01185134a559
|
||||
github.com/caarlos0/go-version v0.1.1
|
||||
github.com/google/rpmpack v0.5.0
|
||||
github.com/goreleaser/chglog v0.5.0
|
||||
github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a
|
||||
github.com/goreleaser/chglog v0.6.1
|
||||
github.com/goreleaser/fileglob v1.3.0
|
||||
github.com/invopop/jsonschema v0.12.0
|
||||
github.com/klauspost/compress v1.17.5
|
||||
github.com/klauspost/compress v1.17.8
|
||||
github.com/klauspost/pgzip v1.2.6
|
||||
github.com/muesli/mango-cobra v1.2.0
|
||||
github.com/muesli/roff v0.1.0
|
||||
github.com/sassoftware/go-rpmutils v0.4.0
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/ulikunitz/xz v0.5.11
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/ulikunitz/xz v0.5.12
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8
|
||||
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/DataDog/zstd v1.5.5 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
|
@ -35,17 +36,17 @@ require (
|
|||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/cavaliergopher/cpio v1.0.1 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cloudflare/circl v1.3.8 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.5.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.11.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.12.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/uuid v1.4.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
|
@ -60,19 +61,19 @@ require (
|
|||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/skeema/knownhosts v1.2.1 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/skeema/knownhosts v1.2.2 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
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.17.0 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/tools v0.16.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
|
116
go.sum
116
go.sum
|
@ -2,6 +2,8 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
|||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
|
||||
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
|
||||
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
|
||||
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
|
@ -12,7 +14,6 @@ github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBa
|
|||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
|
||||
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
|
||||
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
|
@ -21,7 +22,9 @@ github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0k
|
|||
github.com/ProtonMail/gopenpgp/v2 v2.7.1 h1:Awsg7MPc2gD3I7IFac2qE3Gdls0lZW8SzrFZ3k1oz0s=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.1/go.mod h1:/BU5gfAVwqyd8EfC3Eu7zmuhwYQpKs+cGD8M//iiaxs=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
||||
|
@ -30,8 +33,6 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU
|
|||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/caarlos0/go-rpmutils v0.2.1-0.20240105125627-01185134a559 h1:5TPRjT2njvPKzXUcrcg6Dt+JPzQF+M5K7xb5V1Nwteg=
|
||||
github.com/caarlos0/go-rpmutils v0.2.1-0.20240105125627-01185134a559/go.mod h1:sUS7SdlihaphHRYa/Uu4haxl9zL6DLGrFjoTsurEYOw=
|
||||
github.com/caarlos0/go-version v0.1.1 h1:1bikKHkGGVIIxqCmufhSSs3hpBScgHGacrvsi8FuIfc=
|
||||
github.com/caarlos0/go-version v0.1.1/go.mod h1:Ze5Qx4TsBBi5FyrSKVg1Ibc44KGV/llAaKGp86oTwZ0=
|
||||
github.com/caarlos0/testfs v0.4.4 h1:3PHvzHi5Lt+g332CiShwS8ogTgS3HjrmzZxCm6JCDr8=
|
||||
|
@ -40,8 +41,8 @@ github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7a
|
|||
github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc=
|
||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
|
||||
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
|
@ -50,30 +51,36 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
|
||||
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
|
||||
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
|
||||
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/rpmpack v0.5.0 h1:L16KZ3QvkFGpYhmp23iQip+mx1X39foEsqszjMNBm8A=
|
||||
github.com/google/rpmpack v0.5.0/go.mod h1:uqVAUVQLq8UY2hCDfmJ/+rtO3aw7qyhc90rCVEabEfI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a h1:JJBdjSfqSy3mnDT0940ASQFghwcZ4y4cb6ttjAoXqwE=
|
||||
github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a/go.mod h1:uqVAUVQLq8UY2hCDfmJ/+rtO3aw7qyhc90rCVEabEfI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||
github.com/goreleaser/chglog v0.5.0 h1:Sk6BMIpx8+vpAf8KyPit34OgWui8c7nKTMHhYx88jJ4=
|
||||
github.com/goreleaser/chglog v0.5.0/go.mod h1:Ri46M3lrMuv76FHszs3vtABR8J8k1w9JHYAzxeeOl28=
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/goreleaser/chglog v0.6.1 h1:NZKiX8l0FTQPRzBgKST7knvNZmZ04f7PEGkN2wInfhE=
|
||||
github.com/goreleaser/chglog v0.6.1/go.mod h1:Bnnfo07jMZkaAb0uRNASMZyOsX6ROW6X1qbXqN3guUo=
|
||||
github.com/goreleaser/fileglob v1.3.0 h1:/X6J7U8lbDpQtBvGcwwPS6OpzkNVlVEsFUVRx9+k+7I=
|
||||
github.com/goreleaser/fileglob v1.3.0/go.mod h1:Jx6BoXv3mbYkEzwm9THo7xbr5egkAraxkGorbJb4RxU=
|
||||
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
|
||||
|
@ -89,18 +96,20 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
|
|||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.5 h1:d4vBd+7CHydUqpFBgUEKkSdtSugf9YFmSkvUYPquI5E=
|
||||
github.com/klauspost/compress v1.17.5/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
|
@ -120,6 +129,7 @@ github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i
|
|||
github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8=
|
||||
github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
|
@ -127,20 +137,25 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg=
|
||||
github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
|
||||
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||
github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU=
|
||||
github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w=
|
||||
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
|
||||
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
|
||||
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
|
||||
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
|
||||
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
|
@ -150,11 +165,10 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
|
@ -164,29 +178,22 @@ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMx
|
|||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/YjuiKhqhGlOCwlIV8SqqGh8=
|
||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
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.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
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=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
|
@ -194,14 +201,14 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
|||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -215,14 +222,15 @@ 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.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.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.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
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=
|
||||
|
@ -230,28 +238,24 @@ 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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.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=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
|
||||
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -21,7 +21,7 @@ func newDocsCmd() *docsCmd {
|
|||
Hidden: true,
|
||||
Args: cobra.NoArgs,
|
||||
ValidArgsFunction: cobra.NoFileCompletions,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(*cobra.Command, []string) error {
|
||||
root.cmd.Root().DisableAutoGenTag = true
|
||||
return doc.GenMarkdownTreeCustom(root.cmd.Root(), "www/docs/cmd", func(_ string) string {
|
||||
return ""
|
||||
|
|
|
@ -23,7 +23,7 @@ func newManCmd() *manCmd {
|
|||
Hidden: true,
|
||||
Args: cobra.NoArgs,
|
||||
ValidArgsFunction: cobra.NoFileCompletions,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(*cobra.Command, []string) error {
|
||||
manPage, err := mcobra.NewManPage(1, root.cmd.Root())
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/goreleaser/nfpm/v2"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -28,7 +29,7 @@ func newPackageCmd() *packageCmd {
|
|||
SilenceErrors: true,
|
||||
Args: cobra.NoArgs,
|
||||
ValidArgsFunction: cobra.NoFileCompletions,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(*cobra.Command, []string) error {
|
||||
return doPackage(root.config, root.target, root.packager)
|
||||
},
|
||||
}
|
||||
|
@ -37,9 +38,12 @@ func newPackageCmd() *packageCmd {
|
|||
_ = cmd.MarkFlagFilename("config", "yaml", "yml")
|
||||
cmd.Flags().StringVarP(&root.target, "target", "t", "", "where to save the generated package (filename, folder or empty for current folder)")
|
||||
_ = cmd.MarkFlagFilename("target")
|
||||
cmd.Flags().StringVarP(&root.packager, "packager", "p", "", "which packager implementation to use [apk|deb|rpm|archlinux]")
|
||||
_ = cmd.RegisterFlagCompletionFunc("packager", cobra.FixedCompletions(
|
||||
[]string{"apk", "deb", "rpm", "archlinux"},
|
||||
|
||||
pkgs := nfpm.Enumerate()
|
||||
|
||||
cmd.Flags().StringVarP(&root.packager, "packager", "p", "",
|
||||
fmt.Sprintf("which packager implementation to use [%s]", strings.Join(pkgs, "|")))
|
||||
_ = cmd.RegisterFlagCompletionFunc("packager", cobra.FixedCompletions(pkgs,
|
||||
cobra.ShellCompDirectiveNoFileComp,
|
||||
))
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
_ "github.com/goreleaser/nfpm/v2/apk" // apk packager
|
||||
_ "github.com/goreleaser/nfpm/v2/arch" // archlinux packager
|
||||
_ "github.com/goreleaser/nfpm/v2/deb" // deb packager
|
||||
_ "github.com/goreleaser/nfpm/v2/ipk" // ipk packager
|
||||
_ "github.com/goreleaser/nfpm/v2/rpm" // rpm packager
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -35,8 +36,8 @@ func newRootCmd(version goversion.Info, exit func(int)) *rootCmd {
|
|||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "nfpm",
|
||||
Short: "Packages apps on RPM, Deb, APK and Arch Linux formats based on a YAML configuration file",
|
||||
Long: `nFPM is a simple and 0-dependencies deb, rpm, apk and arch linux packager written in Go.`,
|
||||
Short: "Packages apps on RPM, Deb, APK, Arch Linux, and ipk formats based on a YAML configuration file",
|
||||
Long: `nFPM is a simple and 0-dependencies apk, arch, deb, ipk and rpm linux packager written in Go.`,
|
||||
Version: version.String(),
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
|
|
|
@ -26,7 +26,7 @@ func newSchemaCmd() *schemaCmd {
|
|||
SilenceErrors: true,
|
||||
Args: cobra.NoArgs,
|
||||
ValidArgsFunction: cobra.NoFileCompletions,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(*cobra.Command, []string) error {
|
||||
schema := jsonschema.Reflect(&nfpm.Config{})
|
||||
schema.Description = "nFPM configuration definition file"
|
||||
bts, err := json.MarshalIndent(schema, " ", " ")
|
||||
|
|
|
@ -20,6 +20,11 @@ var (
|
|||
errNoRSAKey = errors.New("key is not an RSA key")
|
||||
)
|
||||
|
||||
const (
|
||||
PKCS1PrivkeyPreamble = "RSA PRIVATE KEY"
|
||||
PKCS8PrivkeyPreamble = "PRIVATE KEY"
|
||||
)
|
||||
|
||||
// RSASignSHA1Digest signs the provided SHA1 message digest. The key file
|
||||
// must be in the PEM format and can either be encrypted or not.
|
||||
func RSASignSHA1Digest(sha1Digest []byte, keyFile, passphrase string) ([]byte, error) {
|
||||
|
@ -53,9 +58,26 @@ func RSASignSHA1Digest(sha1Digest []byte, keyFile, passphrase string) ([]byte, e
|
|||
blockData = decryptedBlockData
|
||||
}
|
||||
|
||||
priv, err := x509.ParsePKCS1PrivateKey(blockData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse PKCS1 private key: %w", err)
|
||||
var priv crypto.Signer
|
||||
|
||||
switch block.Type {
|
||||
case PKCS1PrivkeyPreamble:
|
||||
priv, err = x509.ParsePKCS1PrivateKey(blockData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse PKCS#1 private key: %w", err)
|
||||
}
|
||||
case PKCS8PrivkeyPreamble:
|
||||
privAny, err := x509.ParsePKCS8PrivateKey(blockData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse PKCS#8 private key: %w", err)
|
||||
}
|
||||
privTmp, ok := privAny.(crypto.Signer)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot sign with given private key")
|
||||
}
|
||||
priv = privTmp
|
||||
default:
|
||||
return nil, fmt.Errorf(`key type "%v" is not supported`, block.Type)
|
||||
}
|
||||
|
||||
signature, err := priv.Sign(rand.Reader, sha1Digest, crypto.SHA1)
|
||||
|
|
|
@ -17,8 +17,9 @@ func TestRSASignAndVerify(t *testing.T) {
|
|||
pubKey string
|
||||
passphrase string
|
||||
}{
|
||||
{"unprotected", "testdata/rsa_unprotected.priv", "testdata/rsa_unprotected.pub", ""},
|
||||
{"protected", "testdata/rsa.priv", "testdata/rsa.pub", pass},
|
||||
{"unprotected pkcs1", "testdata/rsa_unprotected.priv", "testdata/rsa_unprotected.pub", ""},
|
||||
{"protected pkcs1", "testdata/rsa.priv", "testdata/rsa.pub", pass},
|
||||
{"unprotected pkcs8", "testdata/rsa_pkcs8.priv", "testdata/rsa_pkcs8.pub", ""},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
|
@ -54,18 +55,39 @@ func TestInvalidHash(t *testing.T) {
|
|||
func TestRSAVerifyWrongKey(t *testing.T) {
|
||||
digest := sha1.New().Sum(nil) // nolint:gosec
|
||||
|
||||
sig, err := rsaSign(bytes.NewReader(digest), "testdata/rsa_unprotected.priv", "")
|
||||
require.NoError(t, err)
|
||||
testCases := []struct {
|
||||
name string
|
||||
privKey string
|
||||
pubKey string
|
||||
}{
|
||||
{"pkcs1", "testdata/rsa_unprotected.priv", "testdata/rsa_unprotected.pub"},
|
||||
{"pkcs8", "testdata/rsa_pkcs8.priv", "testdata/rsa_pkcs8.pub"},
|
||||
}
|
||||
|
||||
err = RSAVerifySHA1Digest(digest, sig, "testdata/rsa.pub")
|
||||
require.EqualError(t, err, "verify PKCS1v15 signature: crypto/rsa: verification error")
|
||||
for _, testCase := range testCases {
|
||||
sig, err := rsaSign(bytes.NewReader(digest), testCase.privKey, "")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = RSAVerifySHA1Digest(digest, sig, testCase.pubKey)
|
||||
require.EqualError(t, err, "verify PKCS1v15 signature: crypto/rsa: verification error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRSAVerifyWrongSignature(t *testing.T) {
|
||||
digest := sha1.New().Sum(nil) // nolint:gosec
|
||||
|
||||
err := RSAVerifySHA1Digest(digest, []byte{}, "testdata/rsa.pub")
|
||||
require.EqualError(t, err, "verify PKCS1v15 signature: crypto/rsa: verification error")
|
||||
testCases := []struct {
|
||||
name string
|
||||
pubKey string
|
||||
}{
|
||||
{"pkcs1", "testdata/rsa.pub"},
|
||||
{"pkcs8", "testdata/rsa_pkcs8.pub"},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
err := RSAVerifySHA1Digest(digest, []byte{}, testCase.pubKey)
|
||||
require.EqualError(t, err, "verify PKCS1v15 signature: crypto/rsa: verification error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRSAVerifyWrongPublicKeyFormat(t *testing.T) {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbfacH7+FQJmKF
|
||||
2gadVTUGceI/Edjo0RDHG9Y9xLlA1VJ+HppgHGDYkek+kqLRSwcqKJ8g58M8hYRK
|
||||
saOAa2OnMfgQ+B0qg191i7VwNrCm4YxgbP1t0z1QWUYX4G97hV+wS7MUFVz8+2H1
|
||||
2I4aKw3iNoBINIKlDJgVgxvR4v85Ly4sEFT7PNl7xEE7sxIOiDMv/EL+M4HXrdx7
|
||||
OCE4IcwyCyJFmBcSoc/qbTO87LDE/K4EBR0Lte/IJApid3u1gwfliOEeyCKVh1JH
|
||||
AMNJ7s5RjpuW6XJMNMba+CyUTDiGmnbbxvEGvb6trJfDUHd2ChsD+3HR2qx4lNQA
|
||||
epdUrQsdAgMBAAECggEAMvw3qhTTUlJwTWZtZeuukw4uP3dOWxqBWrcBJ70ESWak
|
||||
MG68bnn5FyWhuCrIznQuuGDSQgsEI5FiPxWPhNutPN/TH2H7KG525K+s2GGj3EgF
|
||||
WzrGDdZlZj4ulYpJazh6l1GmShKCVLOyODDzJWn94h/F4b/s3xkTVN/tPO6NWcNJ
|
||||
MHUM8wYXtUP4jqfJvWljJPFrzKZBRVnB9PV+VtZRtX880VnMwQ76CjC8fLbaJQRT
|
||||
XXDLl12FkULWQzJieQr8XJLhb8hLSytBovbqbO24NbMjGFx1hxHdwyziceDPtu04
|
||||
4R11Zi/YK4DOYi7wrQfxuqyquHH0lAPK648b60HBMwKBgQD2mYzqCq11qHKjrKLV
|
||||
AR3ufemcN40b7PjcxpXccaNzEzkBaWlRlqhdhO/naLXKHM97hNotji002/whANx5
|
||||
0MYcjdo+VnYT/OYmxexVbsLjFsV0B9LOY1zrSyBAxxyjlSTdjBslOXMDtDnPKpZQ
|
||||
ydjqFqlrpAZNXuOjBtaRVcC7pwKBgQDj24740wfDnuzbOKxcaTzBLf+Ak7aNI3xz
|
||||
E8e9A2yOUBWhnpmi0fwiws5IE0ghqJBWrjdrwjna+B9Gs6HKMyTNatCYh8SdjxgQ
|
||||
JivJ3jrKVrP8ixojz/cuNDXC6KJEHvklaLARMO6BPSaB88oR425Y0BZcw2XBNuU/
|
||||
JS1YGCLLmwKBgCFWiPJrFyA88aKnCCx7xiwj4Z049V69HrfaMRBoXIyGIMLMGWzq
|
||||
TUC3ZCeIxGrakkJEp6pY+kuXIfLkRupBC0d49fRPhA8XtZWwVE8Idlh1D6SsGhfE
|
||||
3x8APRAE2x5SX3WEJ3dU2PO7PcWAIGozn5umDKl8t01mcqfrmL51NWUpAoGAVDtf
|
||||
EAbbMOq4PpYlyYexyOwbLsnsSyKaJ+RhCzOP1tAuHvAFdZZQsfz3ytct7BtnOFPw
|
||||
8un6/0KINVfEcH4VlcZt1GUkPuaeC6JAv8BiVVhV8v7tK93+T1tHoITlL2+PxM99
|
||||
fu1qzeXwLUwVICXGLhjGm4Y0QIftmTlCGPXbLw8CgYBDiihffbawacxp79CZJUyd
|
||||
DFvVvCLgwu1K9JRyykxyVPOZAcS/7x5IzRhpQdy51A5xG4WjBkNghGNosbnSaiFr
|
||||
cCzEtKiNHefbSNUd5T3w8NO97y26BmtylyUrx+qIGr5XWHYFUFmgAmErqFVRLheT
|
||||
4E9lCp7uSkx2AlbSgs+ugQ==
|
||||
-----END PRIVATE KEY-----
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA232nB+/hUCZihdoGnVU1
|
||||
BnHiPxHY6NEQxxvWPcS5QNVSfh6aYBxg2JHpPpKi0UsHKiifIOfDPIWESrGjgGtj
|
||||
pzH4EPgdKoNfdYu1cDawpuGMYGz9bdM9UFlGF+Bve4VfsEuzFBVc/Pth9diOGisN
|
||||
4jaASDSCpQyYFYMb0eL/OS8uLBBU+zzZe8RBO7MSDogzL/xC/jOB163cezghOCHM
|
||||
MgsiRZgXEqHP6m0zvOywxPyuBAUdC7XvyCQKYnd7tYMH5YjhHsgilYdSRwDDSe7O
|
||||
UY6blulyTDTG2vgslEw4hpp228bxBr2+rayXw1B3dgobA/tx0dqseJTUAHqXVK0L
|
||||
HQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
|
@ -0,0 +1,512 @@
|
|||
// Package ipk implements nfpm.Packager providing .ipk bindings.
|
||||
//
|
||||
// IPK is a package format used by the opkg package manager, which is very
|
||||
// similar to the Debian package format. Generally, the package format is
|
||||
// stripped down and simplified compared to the Debian package format.
|
||||
// Yocto/OpenEmbedded/OpenWRT uses the IPK format for its package management.
|
||||
package ipk
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/goreleaser/nfpm/v2"
|
||||
"github.com/goreleaser/nfpm/v2/deprecation"
|
||||
"github.com/goreleaser/nfpm/v2/files"
|
||||
"github.com/goreleaser/nfpm/v2/internal/modtime"
|
||||
)
|
||||
|
||||
const packagerName = "ipk"
|
||||
|
||||
// nolint: gochecknoinits
|
||||
func init() {
|
||||
nfpm.RegisterPackager(packagerName, Default)
|
||||
}
|
||||
|
||||
// nolint: gochecknoglobals
|
||||
var archToIPK = map[string]string{
|
||||
// all --> all
|
||||
"386": "i386",
|
||||
"amd64": "x86_64",
|
||||
"arm64": "arm64",
|
||||
"arm5": "armel",
|
||||
"arm6": "armhf",
|
||||
"arm7": "armhf",
|
||||
"mips64le": "mips64el",
|
||||
"mipsle": "mipsel",
|
||||
"ppc64le": "ppc64el",
|
||||
"s390": "s390x",
|
||||
}
|
||||
|
||||
func ensureValidArch(info *nfpm.Info) *nfpm.Info {
|
||||
if info.IPK.Arch != "" {
|
||||
info.Arch = info.IPK.Arch
|
||||
} else if arch, ok := archToIPK[info.Arch]; ok {
|
||||
info.Arch = arch
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
// Default ipk packager.
|
||||
// nolint: gochecknoglobals
|
||||
var Default = &IPK{}
|
||||
|
||||
// IPK is a ipk packager implementation.
|
||||
type IPK struct{}
|
||||
|
||||
// ConventionalFileName returns a file name according
|
||||
// to the conventions for ipk packages. Ipk packages generally follow
|
||||
// the conventions set by debian. See:
|
||||
// https://manpages.debian.org/buster/dpkg-dev/dpkg-name.1.en.html
|
||||
func (*IPK) ConventionalFileName(info *nfpm.Info) string {
|
||||
info = ensureValidArch(info)
|
||||
|
||||
version := info.Version
|
||||
if info.Prerelease != "" {
|
||||
version += "~" + info.Prerelease
|
||||
}
|
||||
|
||||
if info.VersionMetadata != "" {
|
||||
version += "+" + info.VersionMetadata
|
||||
}
|
||||
|
||||
if info.Release != "" {
|
||||
version += "-" + info.Release
|
||||
}
|
||||
|
||||
// package_version_architecture.package-type
|
||||
return fmt.Sprintf("%s_%s_%s.ipk", info.Name, version, info.Arch)
|
||||
}
|
||||
|
||||
// ConventionalExtension returns the file name conventionally used for IPK packages
|
||||
func (*IPK) ConventionalExtension() string {
|
||||
return ".ipk"
|
||||
}
|
||||
|
||||
// SetPackagerDefaults sets the default values for the IPK packager.
|
||||
func (*IPK) SetPackagerDefaults(info *nfpm.Info) {
|
||||
// Priority should be set on all packages per:
|
||||
// https://www.debian.org/doc/debian-policy/ch-archive.html#priorities
|
||||
// "optional" seems to be the safe/sane default here
|
||||
if info.Priority == "" {
|
||||
info.Priority = "optional"
|
||||
}
|
||||
|
||||
// The safe thing here feels like defaulting to something like below.
|
||||
// That will prevent existing configs from breaking anyway... Wondering
|
||||
// if in the long run we should be more strict about this and error when
|
||||
// not set?
|
||||
if strings.TrimSpace(info.Maintainer) == "" {
|
||||
deprecation.Println("Leaving the 'maintainer' field unset will not be allowed in a future version")
|
||||
info.Maintainer = "Unset Maintainer <unset@localhost>"
|
||||
}
|
||||
}
|
||||
|
||||
// Package writes a new ipk package to the given writer using the given info.
|
||||
func (d *IPK) Package(info *nfpm.Info, ipk io.Writer) error {
|
||||
info = ensureValidArch(info)
|
||||
|
||||
if err := nfpm.PrepareForPackager(info, packagerName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set up some ipk specific defaults
|
||||
d.SetPackagerDefaults(info)
|
||||
|
||||
// Strip out any custom fields that are disallowed.
|
||||
stripDisallowedFields(info)
|
||||
|
||||
contents, err := newTGZ("ipk",
|
||||
func(tw *tar.Writer) error {
|
||||
return createIPK(info, tw)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = ipk.Write(contents)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// createIPK creates a new ipk package using the given tar writer and info.
|
||||
func createIPK(info *nfpm.Info, ipk *tar.Writer) error {
|
||||
var installSize int64
|
||||
|
||||
data, err := newTGZ("data.tar.gz",
|
||||
func(tw *tar.Writer) error {
|
||||
var err error
|
||||
installSize, err = populateDataTar(info, tw)
|
||||
return err
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
control, err := newTGZ("control.tar.gz",
|
||||
func(tw *tar.Writer) error {
|
||||
return populateControlTar(info, tw, installSize)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mtime := modtime.Get(info.MTime)
|
||||
|
||||
if err := writeToFile(ipk, "debian-binary", []byte("2.0\n"), mtime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := writeToFile(ipk, "control.tar.gz", control, mtime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := writeToFile(ipk, "data.tar.gz", data, mtime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// populateDataTar populates the data tarball with the files specified in the info.
|
||||
func populateDataTar(info *nfpm.Info, tw *tar.Writer) (instSize int64, err error) {
|
||||
// create files and implicit directories
|
||||
for _, file := range info.Contents {
|
||||
var size int64
|
||||
|
||||
switch file.Type {
|
||||
case files.TypeDir, files.TypeImplicitDir:
|
||||
err = tw.WriteHeader(
|
||||
&tar.Header{
|
||||
Name: files.AsExplicitRelativePath(file.Destination),
|
||||
Typeflag: tar.TypeDir,
|
||||
Format: tar.FormatGNU,
|
||||
ModTime: modtime.Get(info.MTime),
|
||||
Mode: int64(file.FileInfo.Mode),
|
||||
Uname: file.FileInfo.Owner,
|
||||
Gname: file.FileInfo.Group,
|
||||
})
|
||||
case files.TypeSymlink:
|
||||
err = tw.WriteHeader(
|
||||
&tar.Header{
|
||||
Name: files.AsExplicitRelativePath(file.Destination),
|
||||
Typeflag: tar.TypeSymlink,
|
||||
Format: tar.FormatGNU,
|
||||
ModTime: modtime.Get(info.MTime),
|
||||
Linkname: file.Source,
|
||||
})
|
||||
case files.TypeFile, files.TypeTree, files.TypeConfig, files.TypeConfigNoReplace:
|
||||
size, err = writeFile(tw, file)
|
||||
default:
|
||||
// ignore everything else
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
instSize += size
|
||||
}
|
||||
|
||||
return instSize, nil
|
||||
}
|
||||
|
||||
// getScripts returns the scripts for the given info.
|
||||
func getScripts(info *nfpm.Info, mtime time.Time) []files.Content {
|
||||
return []files.Content{
|
||||
{
|
||||
Destination: "preinst",
|
||||
Source: info.Scripts.PreInstall,
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
Mode: 0o755,
|
||||
MTime: mtime,
|
||||
},
|
||||
}, {
|
||||
Destination: "postinst",
|
||||
Source: info.Scripts.PostInstall,
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
Mode: 0o755,
|
||||
MTime: mtime,
|
||||
},
|
||||
}, {
|
||||
Destination: "prerm",
|
||||
Source: info.Scripts.PreRemove,
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
Mode: 0o755,
|
||||
MTime: mtime,
|
||||
},
|
||||
}, {
|
||||
Destination: "postrm",
|
||||
Source: info.Scripts.PostRemove,
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
Mode: 0o755,
|
||||
MTime: mtime,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// populateControlTar populates the control tarball with the control files defined
|
||||
// in the info.
|
||||
func populateControlTar(info *nfpm.Info, out *tar.Writer, instSize int64) error {
|
||||
var body bytes.Buffer
|
||||
|
||||
cd := controlData{
|
||||
Info: info,
|
||||
InstalledSize: instSize / 1024,
|
||||
}
|
||||
|
||||
if err := renderControl(&body, cd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mtime := modtime.Get(info.MTime)
|
||||
if err := writeToFile(out, "./control", body.Bytes(), mtime); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeToFile(out, "./conffiles", conffiles(info), mtime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scripts := getScripts(info, mtime)
|
||||
for _, file := range scripts {
|
||||
if file.Source != "" {
|
||||
if _, err := writeFile(out, &file); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// conffiles returns the conffiles file bytes for the given info.
|
||||
func conffiles(info *nfpm.Info) []byte {
|
||||
// nolint: prealloc
|
||||
var confs []string
|
||||
for _, file := range info.Contents {
|
||||
switch file.Type {
|
||||
case files.TypeConfig, files.TypeConfigNoReplace:
|
||||
confs = append(confs, files.NormalizeAbsoluteFilePath(file.Destination))
|
||||
}
|
||||
}
|
||||
return []byte(strings.Join(confs, "\n") + "\n")
|
||||
}
|
||||
|
||||
// The ipk format is not formally defined, but it is similar to the deb format.
|
||||
// The two sources that were used to create this template are:
|
||||
// - https://git.yoctoproject.org/opkg/
|
||||
// - https://github.com/openwrt/opkg-lede
|
||||
//
|
||||
// Supported Fields
|
||||
//
|
||||
// R = Required
|
||||
// O = Optional
|
||||
// e = Extra
|
||||
// - = Not Supported/Ignored/Extra
|
||||
//
|
||||
//
|
||||
// OpenWRT Yocto
|
||||
// | |
|
||||
// | Field | W | Y | Status |
|
||||
// |----------------|---|---|--------|
|
||||
// | ABIVersion | O | - | âś“
|
||||
// | Alternatives | O | - | âś“
|
||||
// | Architecture | R | R | âś“
|
||||
// | Auto-Installed | O | O | âś“
|
||||
// | Conffiles | O | O | not needed since config files are listed in .conffiles
|
||||
// | Conflicts | O | O | âś“
|
||||
// | Depends | R | R | âś“
|
||||
// | Description | R | R | âś“
|
||||
// | Essential | O | O | âś“
|
||||
// | Filename | - | - | an opkg field, not a package field
|
||||
// | Homepage | e | e | âś“
|
||||
// | Installed-Size | O | O | âś“
|
||||
// | Installed-Time | - | - | an opkg field, not a package field
|
||||
// | License | e | e | âś“
|
||||
// | Maintainer | R | R | âś“
|
||||
// | MD5sum | - | - | insecure, not supported
|
||||
// | Package | R | R | âś“
|
||||
// | Pre-Depends | e | O | âś“
|
||||
// | Priority | R | R | âś“
|
||||
// | Provides | O | O | âś“
|
||||
// | Recommends | O | O | âś“
|
||||
// | Replaces | O | O | âś“
|
||||
// | Section | O | O | âś“
|
||||
// | SHA256sum | - | - | an opkg field, not a package field
|
||||
// | Size | - | - | an opkg field, not a package field
|
||||
// | Source | - | - | use the Fields field
|
||||
// | Status | - | - | an opkg state, not a package field
|
||||
// | Suggests | O | O | âś“
|
||||
// | Tags | O | O | âś“
|
||||
// | Vendor | e | e | âś“
|
||||
// | Version | R | R | âś“
|
||||
//
|
||||
// If any values in user supplied Fields are found to be duplicates of the above
|
||||
// fields, they will be stripped out.
|
||||
|
||||
// nolint: gochecknoglobals
|
||||
var controlFields = []string{
|
||||
"ABIVersion",
|
||||
"Alternatives",
|
||||
"Architecture",
|
||||
"Auto-Installed",
|
||||
"Conffiles",
|
||||
"Conflicts",
|
||||
"Depends",
|
||||
"Description",
|
||||
"Essential",
|
||||
"Filename",
|
||||
"Homepage",
|
||||
"Installed-Size",
|
||||
"Installed-Time",
|
||||
"License",
|
||||
"Maintainer",
|
||||
"MD5sum",
|
||||
"Package",
|
||||
"Pre-Depends",
|
||||
"Priority",
|
||||
"Provides",
|
||||
"Recommends",
|
||||
"Replaces",
|
||||
"Section",
|
||||
"SHA256sum",
|
||||
"Size",
|
||||
// "Source", Allowed
|
||||
"Status",
|
||||
"Suggests",
|
||||
"Tags",
|
||||
"Vendor",
|
||||
"Version",
|
||||
}
|
||||
|
||||
// stripDisallowedFields strips out any fields that are disallowed in the ipk
|
||||
// format, ignoring case.
|
||||
func stripDisallowedFields(info *nfpm.Info) {
|
||||
for key := range info.IPK.Fields {
|
||||
for _, disallowed := range controlFields {
|
||||
if strings.EqualFold(key, disallowed) {
|
||||
delete(info.IPK.Fields, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const controlTemplate = `
|
||||
{{- /* Mandatory fields */ -}}
|
||||
Architecture: {{.Info.Arch}}
|
||||
Description: {{multiline .Info.Description}}
|
||||
Maintainer: {{.Info.Maintainer}}
|
||||
Package: {{.Info.Name}}
|
||||
Priority: {{.Info.Priority}}
|
||||
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 }}
|
||||
{{- /* Optional fields */ -}}
|
||||
{{- if .Info.IPK.ABIVersion}}
|
||||
ABIVersion: {{.Info.IPK.ABIVersion}}
|
||||
{{- end}}
|
||||
{{- if .Info.IPK.Alternatives}}
|
||||
Alternatives: {{ range $index, $element := .Info.IPK.Alternatives }}{{ if $index }}, {{end}}{{ $element.Priority }}:{{ $element.LinkName}}:{{ $element.Target}}{{- end }}
|
||||
{{- end}}
|
||||
{{- if .Info.IPK.AutoInstalled}}
|
||||
Auto-Installed: yes
|
||||
{{- end }}
|
||||
{{- with .Info.Conflicts}}
|
||||
Conflicts: {{join .}}
|
||||
{{- end }}
|
||||
{{- with .Info.Depends}}
|
||||
Depends: {{join .}}
|
||||
{{- end }}
|
||||
{{- if .Info.IPK.Essential}}
|
||||
Essential: yes
|
||||
{{- end }}
|
||||
{{- if .Info.Homepage}}
|
||||
Homepage: {{.Info.Homepage}}
|
||||
{{- end }}
|
||||
{{- if .Info.License}}
|
||||
License: {{.Info.License}}
|
||||
{{- end }}
|
||||
{{- if .InstalledSize }}
|
||||
Installed-Size: {{.InstalledSize}}
|
||||
{{- end }}
|
||||
{{- with .Info.IPK.Predepends}}
|
||||
Pre-Depends: {{join .}}
|
||||
{{- end }}
|
||||
{{- with nonEmpty .Info.Provides}}
|
||||
Provides: {{join .}}
|
||||
{{- end }}
|
||||
{{- with .Info.Recommends}}
|
||||
Recommends: {{join .}}
|
||||
{{- end }}
|
||||
{{- with .Info.Replaces}}
|
||||
Replaces: {{join .}}
|
||||
{{- end }}
|
||||
{{- if .Info.Section}}
|
||||
Section: {{.Info.Section}}
|
||||
{{- end }}
|
||||
{{- with .Info.Suggests}}
|
||||
Suggests: {{join .}}
|
||||
{{- end }}
|
||||
{{- with .Info.IPK.Tags}}
|
||||
Tags: {{join .}}
|
||||
{{- end }}
|
||||
{{- if .Info.Vendor}}
|
||||
Vendor: {{.Info.Vendor}}
|
||||
{{- end }}
|
||||
{{- range $key, $value := .Info.IPK.Fields }}
|
||||
{{- if $value }}
|
||||
{{$key}}: {{$value}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
type controlData struct {
|
||||
Info *nfpm.Info
|
||||
InstalledSize int64
|
||||
}
|
||||
|
||||
func renderControl(w io.Writer, data controlData) error {
|
||||
tmpl := template.New("control")
|
||||
tmpl.Funcs(template.FuncMap{
|
||||
"join": func(strs []string) string {
|
||||
return strings.Trim(strings.Join(strs, ", "), " ")
|
||||
},
|
||||
"multiline": func(strs string) string {
|
||||
var b strings.Builder
|
||||
s := bufio.NewScanner(strings.NewReader(strings.TrimSpace(strs)))
|
||||
s.Scan()
|
||||
b.Write(bytes.TrimSpace(s.Bytes()))
|
||||
for s.Scan() {
|
||||
b.WriteString("\n ")
|
||||
l := bytes.TrimSpace(s.Bytes())
|
||||
if len(l) == 0 {
|
||||
b.WriteByte('.')
|
||||
} else {
|
||||
b.Write(l)
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
},
|
||||
"nonEmpty": func(strs []string) []string {
|
||||
var result []string
|
||||
for _, s := range strs {
|
||||
s := strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
result = append(result, s)
|
||||
}
|
||||
return result
|
||||
},
|
||||
})
|
||||
return template.Must(tmpl.Parse(controlTemplate)).Execute(w, data)
|
||||
}
|
|
@ -0,0 +1,1035 @@
|
|||
package ipk
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/goreleaser/nfpm/v2"
|
||||
"github.com/goreleaser/nfpm/v2/files"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// nolint: gochecknoglobals
|
||||
var update = flag.Bool("update", false, "update .golden files")
|
||||
|
||||
func exampleInfo() *nfpm.Info {
|
||||
return nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "foo",
|
||||
Arch: "amd64",
|
||||
Description: "Foo does things",
|
||||
Priority: "extra",
|
||||
Maintainer: "Carlos A Becker <pkg@carlosbecker.com>",
|
||||
Version: "v1.0.0",
|
||||
Section: "default",
|
||||
Homepage: "http://carlosbecker.com",
|
||||
Vendor: "nope",
|
||||
Overridables: nfpm.Overridables{
|
||||
Depends: []string{
|
||||
"bash",
|
||||
},
|
||||
Recommends: []string{
|
||||
"git",
|
||||
},
|
||||
Suggests: []string{
|
||||
"bash",
|
||||
},
|
||||
Replaces: []string{
|
||||
"svn",
|
||||
},
|
||||
Provides: []string{
|
||||
"bzr",
|
||||
},
|
||||
Conflicts: []string{
|
||||
"zsh",
|
||||
},
|
||||
Contents: []*files.Content{
|
||||
{
|
||||
Source: "../testdata/fake",
|
||||
Destination: "/usr/bin/fake",
|
||||
},
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: "/usr/share/doc/fake/fake.txt",
|
||||
},
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: "/etc/fake/fake.conf",
|
||||
Type: files.TypeConfig,
|
||||
},
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: "/etc/fake/fake2.conf",
|
||||
Type: files.TypeConfigNoReplace,
|
||||
},
|
||||
{
|
||||
Destination: "/var/log/whatever",
|
||||
Type: files.TypeDir,
|
||||
},
|
||||
{
|
||||
Destination: "/usr/share/whatever",
|
||||
Type: files.TypeDir,
|
||||
},
|
||||
},
|
||||
IPK: nfpm.IPK{
|
||||
Predepends: []string{"less"},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestConventionalExtension(t *testing.T) {
|
||||
require.Equal(t, ".ipk", Default.ConventionalExtension())
|
||||
}
|
||||
|
||||
func TestIPK(t *testing.T) {
|
||||
for _, arch := range []string{"386", "amd64"} {
|
||||
arch := arch
|
||||
t.Run(arch, func(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.Arch = arch
|
||||
err := Default.Package(info, io.Discard)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPKPlatform(t *testing.T) {
|
||||
f, err := os.CreateTemp(t.TempDir(), "test*.deb")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { require.NoError(t, f.Close()) })
|
||||
info := exampleInfo()
|
||||
info.Platform = "darwin"
|
||||
err = Default.Package(info, f)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func extractIPKArchitecture(deb *bytes.Buffer) string {
|
||||
for _, s := range strings.Split(deb.String(), "\n") {
|
||||
if strings.Contains(s, "Architecture: ") {
|
||||
return strings.TrimPrefix(s, "Architecture: ")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func splitIPKArchitecture(deb *bytes.Buffer) (string, string) {
|
||||
a := extractIPKArchitecture(deb)
|
||||
if strings.Contains(a, "-") {
|
||||
f := strings.Split(a, "-")
|
||||
return f[0], f[1]
|
||||
}
|
||||
return "linux", a
|
||||
}
|
||||
|
||||
func TestIPKOS(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
var buf bytes.Buffer
|
||||
err := renderControl(&buf, controlData{info, 0})
|
||||
require.NoError(t, err)
|
||||
o, _ := splitIPKArchitecture(&buf)
|
||||
require.Equal(t, "linux", o)
|
||||
}
|
||||
|
||||
func TestIPKArch(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
var buf bytes.Buffer
|
||||
err := renderControl(&buf, controlData{info, 0})
|
||||
require.NoError(t, err)
|
||||
_, a := splitIPKArchitecture(&buf)
|
||||
require.Equal(t, "amd64", a)
|
||||
}
|
||||
|
||||
func extractIPKVersion(deb *bytes.Buffer) string {
|
||||
for _, s := range strings.Split(deb.String(), "\n") {
|
||||
if strings.Contains(s, "Version: ") {
|
||||
return strings.TrimPrefix(s, "Version: ")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func TestIPKVersionWithDash(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.Version = "1.0.0-beta"
|
||||
err := Default.Package(info, io.Discard)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestIPKVersion(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.Version = "1.0.0" //nolint:golint,goconst
|
||||
var buf bytes.Buffer
|
||||
err := renderControl(&buf, controlData{info, 0})
|
||||
require.NoError(t, err)
|
||||
v := extractIPKVersion(&buf)
|
||||
require.Equal(t, "1.0.0", v)
|
||||
}
|
||||
|
||||
func TestIPKVersionWithRelease(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.Version = "1.0.0" //nolint:golint,goconst
|
||||
info.Release = "1"
|
||||
var buf bytes.Buffer
|
||||
err := renderControl(&buf, controlData{info, 0})
|
||||
require.NoError(t, err)
|
||||
v := extractIPKVersion(&buf)
|
||||
require.Equal(t, "1.0.0-1", v)
|
||||
}
|
||||
|
||||
func TestIPKVersionWithPrerelease(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
info := exampleInfo()
|
||||
info.Version = "1.0.0" //nolint:golint,goconst
|
||||
info.Prerelease = "1"
|
||||
err := renderControl(&buf, controlData{info, 0})
|
||||
require.NoError(t, err)
|
||||
v := extractIPKVersion(&buf)
|
||||
require.Equal(t, "1.0.0~1", v)
|
||||
}
|
||||
|
||||
func TestIPKVersionWithReleaseAndPrerelease(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
info := exampleInfo()
|
||||
info.Version = "1.0.0" //nolint:golint,goconst
|
||||
info.Release = "2"
|
||||
info.Prerelease = "rc1" //nolint:golint,goconst
|
||||
err := renderControl(&buf, controlData{info, 0})
|
||||
require.NoError(t, err)
|
||||
v := extractIPKVersion(&buf)
|
||||
require.Equal(t, "1.0.0~rc1-2", v)
|
||||
}
|
||||
|
||||
func TestIPKVersionWithVersionMetadata(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
info := exampleInfo()
|
||||
info.Version = "1.0.0+meta" //nolint:golint,goconst
|
||||
info.VersionMetadata = ""
|
||||
err := renderControl(&buf, controlData{info, 0})
|
||||
require.NoError(t, err)
|
||||
v := extractIPKVersion(&buf)
|
||||
require.Equal(t, "1.0.0+meta", v)
|
||||
|
||||
buf.Reset()
|
||||
|
||||
info.Version = "1.0.0" //nolint:golint,goconst
|
||||
info.VersionMetadata = "meta"
|
||||
err = renderControl(&buf, controlData{info, 0})
|
||||
require.NoError(t, err)
|
||||
v = extractIPKVersion(&buf)
|
||||
require.Equal(t, "1.0.0+meta", v)
|
||||
|
||||
buf.Reset()
|
||||
|
||||
info.Version = "1.0.0+foo" //nolint:golint,goconst
|
||||
info.Prerelease = "alpha"
|
||||
info.VersionMetadata = "meta"
|
||||
err = renderControl(&buf, controlData{nfpm.WithDefaults(info), 0})
|
||||
require.NoError(t, err)
|
||||
v = extractIPKVersion(&buf)
|
||||
require.Equal(t, "1.0.0~alpha+meta", v)
|
||||
}
|
||||
|
||||
func TestControl(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
require.NoError(t, renderControl(&w, controlData{
|
||||
Info: exampleInfo(),
|
||||
InstalledSize: 10,
|
||||
}))
|
||||
golden := "testdata/control.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 TestNoJoinsControl(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
require.NoError(t, renderControl(&w, controlData{
|
||||
Info: nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "foo",
|
||||
Arch: "amd64",
|
||||
Description: "Foo does things",
|
||||
Priority: "extra",
|
||||
Maintainer: "Carlos A Becker <pkg@carlosbecker.com>",
|
||||
Version: "v1.0.0",
|
||||
Section: "default",
|
||||
Homepage: "http://carlosbecker.com",
|
||||
Vendor: "nope",
|
||||
Overridables: nfpm.Overridables{
|
||||
Depends: []string{},
|
||||
Recommends: []string{},
|
||||
Suggests: []string{},
|
||||
Replaces: []string{},
|
||||
Provides: []string{},
|
||||
Conflicts: []string{},
|
||||
Contents: []*files.Content{},
|
||||
},
|
||||
}),
|
||||
InstalledSize: 10,
|
||||
}))
|
||||
golden := "testdata/control2.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 TestVersionControl(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
require.NoError(t, renderControl(&w, controlData{
|
||||
Info: nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "foo",
|
||||
Arch: "amd64",
|
||||
Description: "Foo does things",
|
||||
Priority: "extra",
|
||||
Maintainer: "Carlos A Becker <pkg@carlosbecker.com>",
|
||||
Version: "v1.0.0-beta+meta",
|
||||
Release: "2",
|
||||
Section: "default",
|
||||
Homepage: "http://carlosbecker.com",
|
||||
Vendor: "nope",
|
||||
Overridables: nfpm.Overridables{
|
||||
Depends: []string{},
|
||||
Recommends: []string{},
|
||||
Suggests: []string{},
|
||||
Replaces: []string{},
|
||||
Provides: []string{},
|
||||
Conflicts: []string{},
|
||||
Contents: []*files.Content{},
|
||||
},
|
||||
}),
|
||||
InstalledSize: 10,
|
||||
}))
|
||||
golden := "testdata/control4.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 TestIPKFileDoesNotExist(t *testing.T) {
|
||||
abs, err := filepath.Abs("../testdata/whatever.confzzz")
|
||||
require.NoError(t, err)
|
||||
err = Default.Package(
|
||||
nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "foo",
|
||||
Arch: "amd64",
|
||||
Description: "Foo does things",
|
||||
Priority: "extra",
|
||||
Maintainer: "Carlos A Becker <pkg@carlosbecker.com>",
|
||||
Version: "1.0.0",
|
||||
Section: "default",
|
||||
Homepage: "http://carlosbecker.com",
|
||||
Vendor: "nope",
|
||||
Overridables: nfpm.Overridables{
|
||||
Depends: []string{
|
||||
"bash",
|
||||
},
|
||||
Contents: []*files.Content{
|
||||
{
|
||||
Source: "../testdata/fake",
|
||||
Destination: "/usr/bin/fake",
|
||||
},
|
||||
{
|
||||
Source: "../testdata/whatever.confzzz",
|
||||
Destination: "/etc/fake/fake.conf",
|
||||
Type: files.TypeConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
io.Discard,
|
||||
)
|
||||
require.EqualError(t, err, fmt.Sprintf("matching \"%s\": file does not exist", filepath.ToSlash(abs)))
|
||||
}
|
||||
|
||||
func TestIPKNoFiles(t *testing.T) {
|
||||
err := Default.Package(
|
||||
nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "foo",
|
||||
Arch: "amd64",
|
||||
Description: "Foo does things",
|
||||
Priority: "extra",
|
||||
Maintainer: "Carlos A Becker <pkg@carlosbecker.com>",
|
||||
Version: "1.0.0",
|
||||
Section: "default",
|
||||
Homepage: "http://carlosbecker.com",
|
||||
Vendor: "nope",
|
||||
Overridables: nfpm.Overridables{
|
||||
Depends: []string{
|
||||
"bash",
|
||||
},
|
||||
},
|
||||
}),
|
||||
io.Discard,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestIPKNoInfo(t *testing.T) {
|
||||
err := Default.Package(nfpm.WithDefaults(&nfpm.Info{}), io.Discard)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestConffiles(t *testing.T) {
|
||||
info := nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "minimal",
|
||||
Arch: "arm64",
|
||||
Description: "Minimal does nothing",
|
||||
Priority: "extra",
|
||||
Version: "1.0.0",
|
||||
Section: "default",
|
||||
Maintainer: "maintainer",
|
||||
Overridables: nfpm.Overridables{
|
||||
Contents: []*files.Content{
|
||||
{
|
||||
Source: "../testdata/fake",
|
||||
Destination: "/etc/fake",
|
||||
Type: files.TypeConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
err := nfpm.PrepareForPackager(info, packagerName)
|
||||
require.NoError(t, err)
|
||||
out := conffiles(info)
|
||||
require.Equal(t, "/etc/fake\n", string(out), "should have a trailing empty line")
|
||||
}
|
||||
|
||||
func TestMinimalFields(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
require.NoError(t, renderControl(&w, controlData{
|
||||
Info: nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "minimal",
|
||||
Arch: "arm64",
|
||||
Description: "Minimal does nothing",
|
||||
Priority: "extra",
|
||||
Version: "1.0.0",
|
||||
Maintainer: "maintainer",
|
||||
}),
|
||||
}))
|
||||
golden := "testdata/minimal.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 TestIPKEpoch(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
require.NoError(t, renderControl(&w, controlData{
|
||||
Info: nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "withepoch",
|
||||
Arch: "arm64",
|
||||
Description: "Has an epoch added to it's version",
|
||||
Priority: "extra",
|
||||
Epoch: "2",
|
||||
Version: "1.0.0",
|
||||
Section: "default",
|
||||
}),
|
||||
}))
|
||||
golden := "testdata/withepoch.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 TestMultilineFields(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
require.NoError(t, renderControl(&w, controlData{
|
||||
Info: nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "multiline",
|
||||
Arch: "riscv64",
|
||||
Description: "This field is a\nmultiline field\n\nthat should work.",
|
||||
Priority: "extra",
|
||||
Version: "1.0.0",
|
||||
Maintainer: "someone",
|
||||
}),
|
||||
}))
|
||||
golden := "testdata/multiline.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 TestIPKConventionalFileName(t *testing.T) {
|
||||
info := &nfpm.Info{
|
||||
Name: "testpkg",
|
||||
Arch: "all",
|
||||
Maintainer: "maintainer",
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
Version string
|
||||
Release string
|
||||
Prerelease string
|
||||
Expected string
|
||||
Metadata string
|
||||
}{
|
||||
{
|
||||
Version: "1.2.3", Release: "", Prerelease: "", Metadata: "",
|
||||
Expected: fmt.Sprintf("%s_1.2.3_%s.ipk", info.Name, info.Arch),
|
||||
},
|
||||
{
|
||||
Version: "1.2.3", Release: "4", Prerelease: "", Metadata: "",
|
||||
Expected: fmt.Sprintf("%s_1.2.3-4_%s.ipk", info.Name, info.Arch),
|
||||
},
|
||||
{
|
||||
Version: "1.2.3", Release: "4", Prerelease: "5", Metadata: "",
|
||||
Expected: fmt.Sprintf("%s_1.2.3~5-4_%s.ipk", info.Name, info.Arch),
|
||||
},
|
||||
{
|
||||
Version: "1.2.3", Release: "", Prerelease: "5", Metadata: "",
|
||||
Expected: fmt.Sprintf("%s_1.2.3~5_%s.ipk", info.Name, info.Arch),
|
||||
},
|
||||
{
|
||||
Version: "1.2.3", Release: "1", Prerelease: "5", Metadata: "git",
|
||||
Expected: fmt.Sprintf("%s_1.2.3~5+git-1_%s.ipk", info.Name, info.Arch),
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
info.Version = testCase.Version
|
||||
info.Release = testCase.Release
|
||||
info.Prerelease = testCase.Prerelease
|
||||
info.VersionMetadata = testCase.Metadata
|
||||
|
||||
require.Equal(t, testCase.Expected, Default.ConventionalFileName(info))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSymlink(t *testing.T) {
|
||||
var (
|
||||
configFilePath = "/usr/share/doc/fake/fake.txt"
|
||||
symlink = "/path/to/symlink"
|
||||
symlinkTarget = configFilePath
|
||||
)
|
||||
|
||||
info := &nfpm.Info{
|
||||
Name: "symlink-in-files",
|
||||
Arch: "amd64",
|
||||
Description: "This package's config references a file via symlink.",
|
||||
Version: "1.0.0",
|
||||
Maintainer: "maintainer",
|
||||
Overridables: nfpm.Overridables{
|
||||
Contents: []*files.Content{
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: configFilePath,
|
||||
},
|
||||
{
|
||||
Source: symlinkTarget,
|
||||
Destination: symlink,
|
||||
Type: files.TypeSymlink,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err := nfpm.PrepareForPackager(info, packagerName)
|
||||
require.NoError(t, err)
|
||||
|
||||
var buf bytes.Buffer
|
||||
tarball := tar.NewWriter(&buf)
|
||||
_, err = populateDataTar(info, tarball)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, tarball.Close())
|
||||
|
||||
packagedSymlinkHeader := extractFileHeaderFromTar(t, buf.Bytes(), symlink)
|
||||
|
||||
require.Equal(t, symlink, path.Join("/", packagedSymlinkHeader.Name)) // nolint:gosec
|
||||
require.Equal(t, uint8(tar.TypeSymlink), packagedSymlinkHeader.Typeflag)
|
||||
require.Equal(t, symlinkTarget, packagedSymlinkHeader.Linkname)
|
||||
}
|
||||
|
||||
func TestEnsureRelativePrefixInTarballs(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.Contents = []*files.Content{
|
||||
{
|
||||
Source: "/symlink/to/fake.txt",
|
||||
Destination: "/usr/share/doc/fake/fake.txt",
|
||||
Type: files.TypeSymlink,
|
||||
},
|
||||
}
|
||||
info.Changelog = "../testdata/changelog.yaml"
|
||||
err := nfpm.PrepareForPackager(info, packagerName)
|
||||
require.NoError(t, err)
|
||||
|
||||
var dataBuf bytes.Buffer
|
||||
dataTarball := tar.NewWriter(&dataBuf)
|
||||
instSize, err := populateDataTar(info, dataTarball)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, dataTarball.Close())
|
||||
testRelativePathPrefixInTar(t, dataBuf.Bytes())
|
||||
|
||||
var controlBuf bytes.Buffer
|
||||
controlTarball := tar.NewWriter(&controlBuf)
|
||||
err = populateControlTar(info, controlTarball, instSize)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, controlTarball.Close())
|
||||
testRelativePathPrefixInTar(t, controlBuf.Bytes())
|
||||
}
|
||||
|
||||
func TestDirectories(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.Contents = []*files.Content{
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: "/etc/foo/file",
|
||||
},
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: "/etc/bar/file",
|
||||
},
|
||||
{
|
||||
Destination: "/etc/bar",
|
||||
Type: files.TypeDir,
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
Owner: "test",
|
||||
Mode: 0o700,
|
||||
},
|
||||
},
|
||||
{
|
||||
Destination: "/etc/baz",
|
||||
Type: files.TypeDir,
|
||||
},
|
||||
{
|
||||
Destination: "/usr/lib/something/somethingelse",
|
||||
Type: files.TypeDir,
|
||||
},
|
||||
}
|
||||
|
||||
require.NoError(t, nfpm.PrepareForPackager(info, packagerName))
|
||||
|
||||
var dataBuf bytes.Buffer
|
||||
tarball := tar.NewWriter(&dataBuf)
|
||||
_, err := populateDataTar(info, tarball)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, tarball.Close())
|
||||
|
||||
dataTarball := dataBuf.Bytes()
|
||||
|
||||
require.Equal(t, []string{
|
||||
"./etc/",
|
||||
"./etc/bar/",
|
||||
"./etc/bar/file",
|
||||
"./etc/baz/",
|
||||
"./etc/foo/",
|
||||
"./etc/foo/file",
|
||||
"./usr/",
|
||||
"./usr/lib/",
|
||||
"./usr/lib/something/",
|
||||
"./usr/lib/something/somethingelse/",
|
||||
}, getTree(t, dataBuf.Bytes()))
|
||||
|
||||
// for ipk all implicit or explicit directories are created in the tarball
|
||||
h := extractFileHeaderFromTar(t, dataTarball, "/etc")
|
||||
require.Equal(t, h.Typeflag, byte(tar.TypeDir))
|
||||
h = extractFileHeaderFromTar(t, dataTarball, "/etc/foo")
|
||||
require.Equal(t, h.Typeflag, byte(tar.TypeDir))
|
||||
h = extractFileHeaderFromTar(t, dataTarball, "/etc/bar")
|
||||
require.Equal(t, h.Typeflag, byte(tar.TypeDir))
|
||||
require.Equal(t, int64(0o700), h.Mode)
|
||||
require.Equal(t, "test", h.Uname)
|
||||
h = extractFileHeaderFromTar(t, dataTarball, "/etc/baz")
|
||||
require.Equal(t, h.Typeflag, byte(tar.TypeDir))
|
||||
|
||||
h = extractFileHeaderFromTar(t, dataTarball, "/usr")
|
||||
require.Equal(t, h.Typeflag, byte(tar.TypeDir))
|
||||
h = extractFileHeaderFromTar(t, dataTarball, "/usr/lib")
|
||||
require.Equal(t, h.Typeflag, byte(tar.TypeDir))
|
||||
h = extractFileHeaderFromTar(t, dataTarball, "/usr/lib/something")
|
||||
require.Equal(t, h.Typeflag, byte(tar.TypeDir))
|
||||
h = extractFileHeaderFromTar(t, dataTarball, "/usr/lib/something/somethingelse")
|
||||
require.Equal(t, h.Typeflag, byte(tar.TypeDir))
|
||||
}
|
||||
|
||||
func TestNoDuplicateContents(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.Contents = []*files.Content{
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: "/etc/foo/file",
|
||||
},
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: "/etc/foo/file2",
|
||||
},
|
||||
{
|
||||
Destination: "/etc/foo",
|
||||
Type: files.TypeDir,
|
||||
},
|
||||
{
|
||||
Destination: "/etc/baz",
|
||||
Type: files.TypeDir,
|
||||
},
|
||||
}
|
||||
|
||||
require.NoError(t, nfpm.PrepareForPackager(info, packagerName))
|
||||
|
||||
var dataBuf bytes.Buffer
|
||||
tarball := tar.NewWriter(&dataBuf)
|
||||
_, err := populateDataTar(info, tarball)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, tarball.Close())
|
||||
|
||||
exists := map[string]bool{}
|
||||
|
||||
tr := tar.NewReader(bytes.NewReader(dataBuf.Bytes()))
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break // End of archive
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
_, ok := exists[hdr.Name]
|
||||
if ok {
|
||||
t.Fatalf("%s exists more than once in tarball", hdr.Name)
|
||||
}
|
||||
|
||||
exists[hdr.Name] = true
|
||||
}
|
||||
}
|
||||
|
||||
func testRelativePathPrefixInTar(tb testing.TB, tarFile []byte) {
|
||||
tb.Helper()
|
||||
|
||||
tr := tar.NewReader(bytes.NewReader(tarFile))
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break // End of archive
|
||||
}
|
||||
require.NoError(tb, err)
|
||||
require.True(tb, strings.HasPrefix(hdr.Name, "./"), "%s does not start with './'", hdr.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisableGlobbing(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.DisableGlobbing = true
|
||||
info.Contents = []*files.Content{
|
||||
{
|
||||
Source: "../testdata/{file}[",
|
||||
Destination: "/test/{file}[",
|
||||
},
|
||||
}
|
||||
require.NoError(t, nfpm.PrepareForPackager(info, packagerName))
|
||||
|
||||
var dataBuf bytes.Buffer
|
||||
tarball := tar.NewWriter(&dataBuf)
|
||||
_, err := populateDataTar(info, tarball)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, tarball.Close())
|
||||
|
||||
expectedContent, err := os.ReadFile("../testdata/{file}[")
|
||||
require.NoError(t, err)
|
||||
|
||||
actualContent := extractFileFromTar(t, dataBuf.Bytes(), "/test/{file}[")
|
||||
|
||||
require.Equal(t, expectedContent, actualContent)
|
||||
}
|
||||
|
||||
func TestNoDuplicateAutocreatedDirectories(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.DisableGlobbing = true
|
||||
info.Contents = []*files.Content{
|
||||
{
|
||||
Source: "../testdata/fake",
|
||||
Destination: "/etc/foo/bar",
|
||||
},
|
||||
{
|
||||
Type: files.TypeDir,
|
||||
Destination: "/etc/foo",
|
||||
},
|
||||
}
|
||||
require.NoError(t, nfpm.PrepareForPackager(info, packagerName))
|
||||
|
||||
expected := map[string]bool{
|
||||
"./etc/": true,
|
||||
"./etc/foo/": true,
|
||||
"./etc/foo/bar": true,
|
||||
}
|
||||
|
||||
var dataBuf bytes.Buffer
|
||||
tarball := tar.NewWriter(&dataBuf)
|
||||
_, err := populateDataTar(info, tarball)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, tarball.Close())
|
||||
|
||||
contents := tarContents(t, dataBuf.Bytes())
|
||||
|
||||
if len(expected) != len(contents) {
|
||||
t.Fatalf("contents has %d entries instead of %d: %#v", len(contents), len(expected), contents)
|
||||
}
|
||||
|
||||
for _, entry := range contents {
|
||||
if !expected[entry] {
|
||||
t.Fatalf("unexpected content: %q", entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoDuplicateDirectories(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.DisableGlobbing = true
|
||||
info.Contents = []*files.Content{
|
||||
{
|
||||
Type: files.TypeDir,
|
||||
Destination: "/etc/foo",
|
||||
},
|
||||
{
|
||||
Type: files.TypeDir,
|
||||
Destination: "/etc/foo/",
|
||||
},
|
||||
}
|
||||
require.Error(t, nfpm.PrepareForPackager(info, packagerName))
|
||||
}
|
||||
|
||||
func TestIgnoreUnrelatedFiles(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.Contents = files.Contents{
|
||||
{
|
||||
Source: "../testdata/fake",
|
||||
Destination: "/usr/bin/fake",
|
||||
Packager: "rpm",
|
||||
},
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: "/usr/share/doc/fake/fake.txt",
|
||||
Type: files.TypeRPMLicence,
|
||||
},
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: "/etc/fake/fake.conf",
|
||||
Type: files.TypeRPMLicense,
|
||||
},
|
||||
{
|
||||
Source: "../testdata/whatever.conf",
|
||||
Destination: "/etc/fake/fake2.conf",
|
||||
Type: files.TypeRPMReadme,
|
||||
},
|
||||
{
|
||||
Destination: "/var/log/whatever",
|
||||
Type: files.TypeRPMDoc,
|
||||
},
|
||||
}
|
||||
|
||||
require.NoError(t, nfpm.PrepareForPackager(info, packagerName))
|
||||
|
||||
var dataBuf bytes.Buffer
|
||||
tarball := tar.NewWriter(&dataBuf)
|
||||
_, err := populateDataTar(info, tarball)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, tarball.Close())
|
||||
|
||||
contents := tarContents(t, dataBuf.Bytes())
|
||||
require.Empty(t, contents)
|
||||
}
|
||||
|
||||
func TestEmptyButRequiredIPKFields(t *testing.T) {
|
||||
item := nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "foo",
|
||||
Version: "v1.0.0",
|
||||
})
|
||||
Default.SetPackagerDefaults(item)
|
||||
|
||||
require.Equal(t, "optional", item.Priority)
|
||||
require.Equal(t, "Unset Maintainer <unset@localhost>", item.Maintainer)
|
||||
|
||||
var deb bytes.Buffer
|
||||
err := Default.Package(item, &deb)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestArches(t *testing.T) {
|
||||
for k := range archToIPK {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.Arch = k
|
||||
info = ensureValidArch(info)
|
||||
require.Equal(t, archToIPK[k], info.Arch)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("override", func(t *testing.T) {
|
||||
info := exampleInfo()
|
||||
info.IPK.Arch = "foo64"
|
||||
info = ensureValidArch(info)
|
||||
require.Equal(t, "foo64", info.Arch)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFields(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
require.NoError(t, renderControl(&w, controlData{
|
||||
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",
|
||||
Overridables: nfpm.Overridables{
|
||||
IPK: nfpm.IPK{
|
||||
Fields: map[string]string{
|
||||
"Bugs": "https://github.com/goreleaser/nfpm/issues",
|
||||
"Empty": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
InstalledSize: 10,
|
||||
}))
|
||||
golden := "testdata/control3.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 TestMost(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
require.NoError(t, renderControl(&w, controlData{
|
||||
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",
|
||||
License: "MIT",
|
||||
Homepage: "http://carlosbecker.com",
|
||||
Overridables: nfpm.Overridables{
|
||||
IPK: nfpm.IPK{
|
||||
ABIVersion: "1",
|
||||
AutoInstalled: true,
|
||||
Essential: true,
|
||||
Fields: map[string]string{
|
||||
"Bugs": "https://github.com/goreleaser/nfpm/issues",
|
||||
"Empty": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
InstalledSize: 10,
|
||||
}))
|
||||
golden := "testdata/control_most.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 TestGlob(t *testing.T) {
|
||||
require.NoError(t, Default.Package(nfpm.WithDefaults(&nfpm.Info{
|
||||
Name: "nfpm-repro",
|
||||
Version: "1.0.0",
|
||||
Maintainer: "asdfasdf",
|
||||
|
||||
Overridables: nfpm.Overridables{
|
||||
Contents: files.Contents{
|
||||
{
|
||||
Destination: "/usr/share/nfpm-repro",
|
||||
Source: "../files/*",
|
||||
},
|
||||
},
|
||||
},
|
||||
}), io.Discard))
|
||||
}
|
||||
|
||||
func TestBadProvides(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
info := exampleInfo()
|
||||
info.Provides = []string{" "}
|
||||
require.NoError(t, renderControl(&w, controlData{
|
||||
Info: nfpm.WithDefaults(info),
|
||||
}))
|
||||
golden := "testdata/bad_provides.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 Test_stripDisallowedFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
info *nfpm.Info
|
||||
expect map[string]string
|
||||
}{
|
||||
{
|
||||
description: "",
|
||||
info: &nfpm.Info{
|
||||
Overridables: nfpm.Overridables{
|
||||
IPK: nfpm.IPK{
|
||||
ABIVersion: "1",
|
||||
AutoInstalled: true,
|
||||
Essential: true,
|
||||
Fields: map[string]string{
|
||||
"Bugs": "https://github.com/goreleaser/nfpm/issues",
|
||||
"Empty": "",
|
||||
"Conffiles": "removed",
|
||||
"Filename": "removed",
|
||||
"Installed-Time": "removed",
|
||||
"MD5sum": "removed",
|
||||
"SHA256sum": "removed",
|
||||
"Size": "removed",
|
||||
"size": "removed",
|
||||
"Status": "removed",
|
||||
"Source": "ok",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: map[string]string{
|
||||
"Bugs": "https://github.com/goreleaser/nfpm/issues",
|
||||
"Empty": "",
|
||||
"Source": "ok",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
stripDisallowedFields(tc.info)
|
||||
|
||||
assert.Equal(tc.expect, tc.info.Overridables.IPK.Fields)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package ipk
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/goreleaser/nfpm/v2/files"
|
||||
)
|
||||
|
||||
// newTGZ creates a new tar.gz archive with the given name and populates it
|
||||
// with the given function.
|
||||
//
|
||||
// The function returns the bytes of the archive, its size and an error if any.
|
||||
func newTGZ(name string, populate func(*tar.Writer) error) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
gz := gzip.NewWriter(&buf)
|
||||
tarball := tar.NewWriter(gz)
|
||||
|
||||
// the writers are properly closed later, this is just in case that we error out
|
||||
defer gz.Close() // nolint: errcheck
|
||||
defer tarball.Close() // nolint: errcheck
|
||||
|
||||
if err := populate(tarball); err != nil {
|
||||
return nil, fmt.Errorf("cannot populate '%s': %w", name, err)
|
||||
}
|
||||
|
||||
if err := tarball.Close(); err != nil {
|
||||
return nil, fmt.Errorf("cannot close '%s': %w", name, err)
|
||||
}
|
||||
|
||||
if err := gz.Close(); err != nil {
|
||||
return nil, fmt.Errorf("cannot close '%s': %w", name, err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// writeFile writes a file from the filesystem to the tarball.
|
||||
func writeFile(out *tar.Writer, file *files.Content) (int64, error) {
|
||||
f, err := os.OpenFile(file.Source, os.O_RDONLY, 0o600) //nolint:gosec
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("could not open file %s to read and include in the archive: %w", file.Source, err)
|
||||
}
|
||||
defer f.Close() // nolint: errcheck
|
||||
|
||||
header, err := tar.FileInfoHeader(file, file.Source)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
content, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
size := int64(len(content))
|
||||
|
||||
// tar.FileInfoHeader only uses file.Mode().Perm() which masks the mode with
|
||||
// 0o777 which we don't want because we want to be able to set the suid bit.
|
||||
header.Mode = int64(file.Mode())
|
||||
header.Format = tar.FormatGNU
|
||||
header.Name = files.AsExplicitRelativePath(file.Destination)
|
||||
header.Size = size
|
||||
header.Uname = file.FileInfo.Owner
|
||||
header.Gname = file.FileInfo.Group
|
||||
if err := out.WriteHeader(header); err != nil {
|
||||
return 0, fmt.Errorf("cannot write tar header for file %s to archive: %w", file.Source, err)
|
||||
}
|
||||
|
||||
n, err := out.Write(content)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%s: failed to copy: %w", file.Source, err)
|
||||
}
|
||||
|
||||
if int64(n) != size {
|
||||
return 0, fmt.Errorf("%s: failed to copy: expected %d bytes, copied %d", file.Source, size, n)
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// writeToFile writes a file to the tarball where the contents are an array of bytes.
|
||||
func writeToFile(out *tar.Writer, filename string, content []byte, mtime time.Time) error {
|
||||
header := tar.Header{
|
||||
Name: files.AsExplicitRelativePath(filename),
|
||||
Size: int64(len(content)),
|
||||
Mode: 0o644,
|
||||
ModTime: mtime,
|
||||
Typeflag: tar.TypeReg,
|
||||
Format: tar.FormatGNU,
|
||||
}
|
||||
|
||||
if err := out.WriteHeader(&header); err != nil {
|
||||
return fmt.Errorf("cannot write file header %s to archive: %w", header.Name, err)
|
||||
}
|
||||
|
||||
_, err := out.Write(content)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot write file %s payload: %w", header.Name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
package ipk
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"io"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_newTGZ(t *testing.T) {
|
||||
unknownErr := errors.New("unknown error")
|
||||
|
||||
tests := []struct {
|
||||
description string
|
||||
name string
|
||||
populate func(*tar.Writer) error
|
||||
file string
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
description: "simple",
|
||||
name: "simple.tar",
|
||||
populate: func(tw *tar.Writer) error {
|
||||
return writeToFile(tw, "simple.txt", []byte("hello, world"), time.Now())
|
||||
},
|
||||
file: "./simple.txt",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
got, err := newTGZ(tc.name, tc.populate)
|
||||
|
||||
if tc.expectedErr == nil {
|
||||
require.NoError(err)
|
||||
require.NotNil(got)
|
||||
|
||||
gz, err := gzip.NewReader(bytes.NewReader(got))
|
||||
require.NoError(err)
|
||||
require.NotNil(gz)
|
||||
defer gz.Close() // nolint: errcheck
|
||||
|
||||
assert.True(tarContains(t, gz, tc.file))
|
||||
return
|
||||
}
|
||||
|
||||
require.Error(err)
|
||||
if !errors.Is(tc.expectedErr, unknownErr) {
|
||||
assert.ErrorIs(err, tc.expectedErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func extractFileFromTar(tb testing.TB, tarFile []byte, filename string) []byte {
|
||||
tb.Helper()
|
||||
|
||||
tr := tar.NewReader(bytes.NewReader(tarFile))
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break // End of archive
|
||||
}
|
||||
require.NoError(tb, err)
|
||||
|
||||
if path.Join("/", hdr.Name) != path.Join("/", filename) {
|
||||
continue
|
||||
}
|
||||
|
||||
fileContents, err := io.ReadAll(tr)
|
||||
require.NoError(tb, err)
|
||||
|
||||
return fileContents
|
||||
}
|
||||
|
||||
tb.Fatalf("file %q does not exist in tar", filename)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tarContains(tb testing.TB, r io.Reader, filename string) bool {
|
||||
tb.Helper()
|
||||
|
||||
tr := tar.NewReader(r)
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break // End of archive
|
||||
}
|
||||
require.NoError(tb, err)
|
||||
|
||||
if path.Join("/", hdr.Name) == path.Join("/", filename) { // nolint:gosec
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func tarContents(tb testing.TB, tarFile []byte) []string {
|
||||
tb.Helper()
|
||||
|
||||
contents := []string{}
|
||||
|
||||
tr := tar.NewReader(bytes.NewReader(tarFile))
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break // End of archive
|
||||
}
|
||||
require.NoError(tb, err)
|
||||
|
||||
contents = append(contents, hdr.Name)
|
||||
}
|
||||
|
||||
return contents
|
||||
}
|
||||
|
||||
func getTree(tb testing.TB, tarFile []byte) []string {
|
||||
tb.Helper()
|
||||
|
||||
var result []string
|
||||
tr := tar.NewReader(bytes.NewReader(tarFile))
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break // End of archive
|
||||
}
|
||||
require.NoError(tb, err)
|
||||
|
||||
result = append(result, hdr.Name)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func extractFileHeaderFromTar(tb testing.TB, tarFile []byte, filename string) *tar.Header {
|
||||
tb.Helper()
|
||||
|
||||
tr := tar.NewReader(bytes.NewReader(tarFile))
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break // End of archive
|
||||
}
|
||||
require.NoError(tb, err)
|
||||
|
||||
if path.Join("/", hdr.Name) != path.Join("/", filename) { // nolint:gosec
|
||||
continue
|
||||
}
|
||||
|
||||
return hdr
|
||||
}
|
||||
|
||||
tb.Fatalf("file %q does not exist in tar", filename)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
Architecture: amd64
|
||||
Description: Foo does things
|
||||
Maintainer: Carlos A Becker <pkg@carlosbecker.com>
|
||||
Package: foo
|
||||
Priority: extra
|
||||
Version: 1.0.0
|
||||
Conflicts: zsh
|
||||
Depends: bash
|
||||
Homepage: http://carlosbecker.com
|
||||
Pre-Depends: less
|
||||
Recommends: git
|
||||
Replaces: svn
|
||||
Section: default
|
||||
Suggests: bash
|
||||
Vendor: nope
|
|
@ -0,0 +1,17 @@
|
|||
Architecture: amd64
|
||||
Description: Foo does things
|
||||
Maintainer: Carlos A Becker <pkg@carlosbecker.com>
|
||||
Package: foo
|
||||
Priority: extra
|
||||
Version: 1.0.0
|
||||
Conflicts: zsh
|
||||
Depends: bash
|
||||
Homepage: http://carlosbecker.com
|
||||
Installed-Size: 10
|
||||
Pre-Depends: less
|
||||
Provides: bzr
|
||||
Recommends: git
|
||||
Replaces: svn
|
||||
Section: default
|
||||
Suggests: bash
|
||||
Vendor: nope
|
|
@ -0,0 +1,10 @@
|
|||
Architecture: amd64
|
||||
Description: Foo does things
|
||||
Maintainer: Carlos A Becker <pkg@carlosbecker.com>
|
||||
Package: foo
|
||||
Priority: extra
|
||||
Version: 1.0.0
|
||||
Homepage: http://carlosbecker.com
|
||||
Installed-Size: 10
|
||||
Section: default
|
||||
Vendor: nope
|
|
@ -0,0 +1,10 @@
|
|||
Architecture: amd64
|
||||
Description: Foo does things
|
||||
Maintainer: Carlos A Becker <pkg@carlosbecker.com>
|
||||
Package: foo
|
||||
Priority: extra
|
||||
Version: 1.0.0
|
||||
Homepage: http://carlosbecker.com
|
||||
Installed-Size: 10
|
||||
Section: default
|
||||
Bugs: https://github.com/goreleaser/nfpm/issues
|
|
@ -0,0 +1,10 @@
|
|||
Architecture: amd64
|
||||
Description: Foo does things
|
||||
Maintainer: Carlos A Becker <pkg@carlosbecker.com>
|
||||
Package: foo
|
||||
Priority: extra
|
||||
Version: 1.0.0~beta+meta-2
|
||||
Homepage: http://carlosbecker.com
|
||||
Installed-Size: 10
|
||||
Section: default
|
||||
Vendor: nope
|
|
@ -0,0 +1,14 @@
|
|||
Architecture: amd64
|
||||
Description: Foo does things
|
||||
Maintainer: Carlos A Becker <pkg@carlosbecker.com>
|
||||
Package: foo
|
||||
Priority: extra
|
||||
Version: 1.0.0
|
||||
ABIVersion: 1
|
||||
Auto-Installed: yes
|
||||
Essential: yes
|
||||
Homepage: http://carlosbecker.com
|
||||
License: MIT
|
||||
Installed-Size: 10
|
||||
Section: default
|
||||
Bugs: https://github.com/goreleaser/nfpm/issues
|
|
@ -0,0 +1,6 @@
|
|||
Architecture: arm64
|
||||
Description: Minimal does nothing
|
||||
Maintainer: maintainer
|
||||
Package: minimal
|
||||
Priority: extra
|
||||
Version: 1.0.0
|
|
@ -0,0 +1,9 @@
|
|||
Architecture: riscv64
|
||||
Description: This field is a
|
||||
multiline field
|
||||
.
|
||||
that should work.
|
||||
Maintainer: someone
|
||||
Package: multiline
|
||||
Priority: extra
|
||||
Version: 1.0.0
|
|
@ -0,0 +1,4 @@
|
|||
Template: templates/lala
|
||||
Type: string
|
||||
Description: Set lala for templates.
|
||||
For the test purpose this templates.golden is created.
|
|
@ -0,0 +1,7 @@
|
|||
Architecture: arm64
|
||||
Description: Has an epoch added to it's version
|
||||
Maintainer:
|
||||
Package: withepoch
|
||||
Priority: extra
|
||||
Version: 2:1.0.0
|
||||
Section: default
|
47
nfpm.go
47
nfpm.go
|
@ -8,6 +8,7 @@ import (
|
|||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -59,6 +60,22 @@ func Get(format string) (Packager, error) {
|
|||
return p, nil
|
||||
}
|
||||
|
||||
// Enumerate lists the available packagers
|
||||
func Enumerate() []string {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
list := make([]string, 0, len(packagers))
|
||||
for key := range packagers {
|
||||
if key != "" {
|
||||
list = append(list, key)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(list)
|
||||
return list
|
||||
}
|
||||
|
||||
// Parse decodes YAML data from an io.Reader into a configuration struct.
|
||||
func Parse(in io.Reader) (config Config, err error) {
|
||||
return ParseWithEnvMapping(in, os.Getenv)
|
||||
|
@ -252,6 +269,15 @@ func (c *Config) expandEnvVars() {
|
|||
c.Info.Deb.Fields[k] = os.Expand(v, c.envMappingFunc)
|
||||
}
|
||||
c.Info.Deb.Predepends = c.expandEnvVarsStringSlice(c.Info.Deb.Predepends)
|
||||
|
||||
// IPK specific
|
||||
for k, v := range c.Info.IPK.Fields {
|
||||
c.Info.IPK.Fields[k] = os.Expand(v, c.envMappingFunc)
|
||||
}
|
||||
c.Info.IPK.Predepends = c.expandEnvVarsStringSlice(c.Info.IPK.Predepends)
|
||||
|
||||
// RPM specific
|
||||
c.Info.RPM.Packager = os.Expand(c.RPM.Packager, c.envMappingFunc)
|
||||
}
|
||||
|
||||
// Info contains information about a single package.
|
||||
|
@ -332,6 +358,7 @@ type Overridables struct {
|
|||
Deb Deb `yaml:"deb,omitempty" json:"deb,omitempty" jsonschema:"title=deb-specific settings"`
|
||||
APK APK `yaml:"apk,omitempty" json:"apk,omitempty" jsonschema:"title=apk-specific settings"`
|
||||
ArchLinux ArchLinux `yaml:"archlinux,omitempty" json:"archlinux,omitempty" jsonschema:"title=archlinux-specific settings"`
|
||||
IPK IPK `yaml:"ipk,omitempty" json:"ipk,omitempty" jsonschema:"title=ipk-specific settings"`
|
||||
}
|
||||
|
||||
type ArchLinux struct {
|
||||
|
@ -362,6 +389,7 @@ type RPM struct {
|
|||
type RPMScripts struct {
|
||||
PreTrans string `yaml:"pretrans,omitempty" json:"pretrans,omitempty" jsonschema:"title=pretrans script"`
|
||||
PostTrans string `yaml:"posttrans,omitempty" json:"posttrans,omitempty" jsonschema:"title=posttrans script"`
|
||||
Verify string `yaml:"verify,omitempty" json:"verify,omitempty" jsonschema:"title=verify script"`
|
||||
}
|
||||
|
||||
type PackageSignature struct {
|
||||
|
@ -439,6 +467,25 @@ type DebScripts struct {
|
|||
Config string `yaml:"config,omitempty" json:"config,omitempty" jsonschema:"title=config"`
|
||||
}
|
||||
|
||||
// IPK is custom configs that are only available on deb packages.
|
||||
type IPK struct {
|
||||
ABIVersion string `yaml:"abi_version,omitempty" json:"abi_version,omitempty" jsonschema:"title=abi version"`
|
||||
Alternatives []IPKAlternative `yaml:"alternatives,omitempty" json:"alternatives,omitempty" jsonschema:"title=alternatives"`
|
||||
Arch string `yaml:"arch,omitempty" json:"arch,omitempty" jsonschema:"title=architecture in deb nomenclature"`
|
||||
AutoInstalled bool `yaml:"auto_installed,omitempty" json:"auto_installed,omitempty" jsonschema:"title=auto installed,default=false"`
|
||||
Essential bool `yaml:"essential,omitempty" json:"essential,omitempty" jsonschema:"title=whether package is essential,default=false"`
|
||||
Fields map[string]string `yaml:"fields,omitempty" json:"fields,omitempty" jsonschema:"title=fields"`
|
||||
Predepends []string `yaml:"predepends,omitempty" json:"predepends,omitempty" jsonschema:"title=predepends directive,example=nfpm"`
|
||||
Tags []string `yaml:"tags,omitempty" json:"tags,omitempty" jsonschema:"title=tags"`
|
||||
}
|
||||
|
||||
// IPKAlternative represents an alternative for an IPK package.
|
||||
type IPKAlternative struct {
|
||||
Priority int `yaml:"priority,omitempty" json:"priority,omitempty" jsonschema:"title=priority"`
|
||||
Target string `yaml:"target,omitempty" json:"target,omitempty" jsonschema:"title=target"`
|
||||
LinkName string `yaml:"link_name,omitempty" json:"link_name,omitempty" jsonschema:"title=link name"`
|
||||
}
|
||||
|
||||
// Scripts contains information about maintainer scripts for packages.
|
||||
type Scripts struct {
|
||||
PreInstall string `yaml:"preinstall,omitempty" json:"preinstall,omitempty" jsonschema:"title=pre install"`
|
||||
|
|
|
@ -17,6 +17,12 @@ import (
|
|||
|
||||
var mtime = time.Date(2023, 11, 5, 23, 15, 17, 0, time.UTC)
|
||||
|
||||
func TestEnumerate(t *testing.T) {
|
||||
nfpm.RegisterPackager("deb", nil)
|
||||
result := nfpm.Enumerate()
|
||||
require.NotEmpty(t, result)
|
||||
}
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
format := "TestRegister"
|
||||
pkgr := &fakePackager{}
|
||||
|
@ -299,6 +305,7 @@ func TestParseFile(t *testing.T) {
|
|||
nfpm.RegisterPackager("deb", &fakePackager{})
|
||||
nfpm.RegisterPackager("rpm", &fakePackager{})
|
||||
nfpm.RegisterPackager("apk", &fakePackager{})
|
||||
nfpm.RegisterPackager("ipk", &fakePackager{})
|
||||
_, err = parseAndValidate("./testdata/overrides.yaml")
|
||||
require.NoError(t, err)
|
||||
_, err = parseAndValidate("./testdata/doesnotexist.yaml")
|
||||
|
|
17
rpm/rpm.go
17
rpm/rpm.go
|
@ -208,8 +208,13 @@ func buildRPMMeta(info *nfpm.Info) (*rpmpack.RPMMetaData, error) {
|
|||
if info.RPM.Compression == "" {
|
||||
info.RPM.Compression = "gzip:-1"
|
||||
}
|
||||
if epoch, err = strconv.ParseUint(defaultTo(info.Epoch, "0"), 10, 32); err != nil {
|
||||
return nil, err
|
||||
|
||||
if info.Epoch == "" {
|
||||
epoch = uint64(rpmpack.NoEpoch)
|
||||
} else {
|
||||
if epoch, err = strconv.ParseUint(info.Epoch, 10, 32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if provides, err = toRelation(info.Provides); err != nil {
|
||||
return nil, err
|
||||
|
@ -342,6 +347,14 @@ func addScriptFiles(info *nfpm.Info, rpm *rpmpack.RPM) error {
|
|||
rpm.AddPosttrans(string(data))
|
||||
}
|
||||
|
||||
if info.RPM.Scripts.Verify != "" {
|
||||
data, err := os.ReadFile(info.RPM.Scripts.Verify)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rpm.AddVerifyScript(string(data))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -12,12 +12,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
"github.com/caarlos0/go-rpmutils"
|
||||
"github.com/caarlos0/go-rpmutils/cpio"
|
||||
"github.com/goreleaser/chglog"
|
||||
"github.com/goreleaser/nfpm/v2"
|
||||
"github.com/goreleaser/nfpm/v2/files"
|
||||
"github.com/goreleaser/nfpm/v2/internal/sign"
|
||||
"github.com/sassoftware/go-rpmutils"
|
||||
"github.com/sassoftware/go-rpmutils/cpio"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -29,6 +29,8 @@ func exampleInfo() *nfpm.Info {
|
|||
Priority: "extra",
|
||||
Maintainer: "Carlos A Becker <pkg@carlosbecker.com>",
|
||||
Version: "1.0.0",
|
||||
Release: "1",
|
||||
Epoch: "0",
|
||||
Section: "default",
|
||||
Homepage: "http://carlosbecker.com",
|
||||
Vendor: "nope",
|
||||
|
@ -78,10 +80,12 @@ func exampleInfo() *nfpm.Info {
|
|||
PostRemove: "../testdata/scripts/postremove.sh",
|
||||
},
|
||||
RPM: nfpm.RPM{
|
||||
Group: "foo",
|
||||
Prefixes: []string{"/opt"},
|
||||
Scripts: nfpm.RPMScripts{
|
||||
PreTrans: "../testdata/scripts/pretrans.sh",
|
||||
PostTrans: "../testdata/scripts/posttrans.sh",
|
||||
Verify: "../testdata/scripts/verify.sh",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -133,7 +137,7 @@ func TestRPM(t *testing.T) {
|
|||
|
||||
group, err := rpm.Header.GetString(rpmutils.GROUP)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "", group)
|
||||
require.Equal(t, "foo", group)
|
||||
|
||||
summary, err := rpm.Header.GetString(rpmutils.SUMMARY)
|
||||
require.NoError(t, err)
|
||||
|
@ -144,6 +148,60 @@ func TestRPM(t *testing.T) {
|
|||
require.Equal(t, "Foo does things", description)
|
||||
}
|
||||
|
||||
func TestRPMMandatoryFieldsOnly(t *testing.T) {
|
||||
f, err := os.CreateTemp(t.TempDir(), "test.rpm")
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, Default.Package(&nfpm.Info{
|
||||
Name: "foo",
|
||||
Arch: "amd64",
|
||||
Version: "1.2",
|
||||
Release: "1",
|
||||
Description: "summary\nfoo bar\nlong description",
|
||||
License: "MIT",
|
||||
}, f))
|
||||
|
||||
file, err := os.OpenFile(f.Name(), os.O_RDONLY, 0o600) //nolint:gosec
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
f.Close()
|
||||
file.Close()
|
||||
err = os.Remove(file.Name())
|
||||
require.NoError(t, err)
|
||||
}()
|
||||
rpm, err := rpmutils.ReadRpm(file)
|
||||
require.NoError(t, err)
|
||||
|
||||
os, err := rpm.Header.GetString(rpmutils.OS)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "linux", os)
|
||||
|
||||
arch, err := rpm.Header.GetString(rpmutils.ARCH)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, archToRPM["amd64"], arch)
|
||||
|
||||
version, err := rpm.Header.GetString(rpmutils.VERSION)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "1.2", version)
|
||||
|
||||
release, err := rpm.Header.GetString(rpmutils.RELEASE)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "1", release)
|
||||
|
||||
_, err = rpm.Header.Get(rpmutils.EPOCH)
|
||||
require.Error(t, err, "epoch should not be set")
|
||||
|
||||
_, err = rpm.Header.GetString(rpmutils.GROUP)
|
||||
require.Error(t, err, "group should not be set")
|
||||
|
||||
summary, err := rpm.Header.GetString(rpmutils.SUMMARY)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "summary", summary)
|
||||
|
||||
description, err := rpm.Header.GetString(rpmutils.DESCRIPTION)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "summary\nfoo bar\nlong description", description)
|
||||
}
|
||||
|
||||
func TestRPMPlatform(t *testing.T) {
|
||||
f, err := os.CreateTemp(t.TempDir(), "test*.rpm")
|
||||
require.NoError(t, err)
|
||||
|
@ -481,6 +539,13 @@ echo "Pretrans" > /dev/null
|
|||
|
||||
echo "Posttrans" > /dev/null
|
||||
`, data, "Posttrans script does not match")
|
||||
|
||||
data, err = rpm.Header.GetString(rpmutils.VERIFYSCRIPT)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, `#!/bin/bash
|
||||
|
||||
echo "Verify" > /dev/null
|
||||
`, data, "Verify script does not match")
|
||||
}
|
||||
|
||||
func TestRPMFileDoesNotExist(t *testing.T) {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
NEW_HASH="$(nix-prefetch \
|
||||
--option extra-experimental-features flakes \
|
||||
'{ sha256 }: (builtins.getFlake (toString ./.)).packages.x86_64-linux.default.goModules.overrideAttrs (_: { vendorSha256 = sha256; })')"
|
||||
|
||||
sed -i "s|vendorHash = \".*\"|vendorHash = \"${NEW_HASH}\"|" ./flake.nix
|
|
@ -100,7 +100,7 @@ RUN command -v zsh
|
|||
|
||||
# ---- env-var-version test ----
|
||||
FROM min AS env-var-version
|
||||
ENV EXPECTVER="foo-1.0.00.1.b1 description:"
|
||||
ENV EXPECTVER="foo-1.0.0_0.1.b1-git.abcdefgh description:"
|
||||
RUN apk info foo | grep "foo-" | grep " description:" > found
|
||||
RUN export FOUND_VER="$(cat found)" && \
|
||||
echo "Expected: '${EXPECTVER}' :: Found: '${FOUND_VER}'" && \
|
||||
|
|
|
@ -62,6 +62,12 @@ contents:
|
|||
file_info:
|
||||
mode: 04755
|
||||
|
||||
- packager: ipk
|
||||
src: ./testdata/fake
|
||||
dst: /usr/bin/fake2
|
||||
file_info:
|
||||
mode: 04755
|
||||
|
||||
scripts:
|
||||
preinstall: ./testdata/acceptance/scripts/preinstall.sh
|
||||
postinstall: ./testdata/acceptance/scripts/postinstall.sh
|
||||
|
@ -72,6 +78,7 @@ rpm:
|
|||
scripts:
|
||||
pretrans: ./testdata/acceptance/scripts/pretrans.sh
|
||||
posttrans: ./testdata/acceptance/scripts/posttrans.sh
|
||||
verify: ./testdata/acceptance/scripts/verify.sh
|
||||
apk:
|
||||
scripts:
|
||||
preupgrade: ./testdata/acceptance/scripts/preupgrade.sh
|
||||
|
|
|
@ -49,3 +49,10 @@ overrides:
|
|||
scripts:
|
||||
postinstall: ./testdata/acceptance/scripts/postinstall.sh
|
||||
preremove: ./testdata/acceptance/scripts/preremove.sh
|
||||
ipk:
|
||||
depends:
|
||||
- bash
|
||||
- fish
|
||||
scripts:
|
||||
postinstall: ./testdata/acceptance/scripts/postinstall.sh
|
||||
preremove: ./testdata/acceptance/scripts/preremove.sh
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,18 @@
|
|||
name: "foo"
|
||||
arch: "all"
|
||||
platform: "linux"
|
||||
version: "v1.0.0"
|
||||
maintainer: "John Doe <john@example.com>"
|
||||
description: Foo conflicts dummy
|
||||
contents:
|
||||
- src: ./testdata/fake
|
||||
dst: /usr/bin/fake
|
||||
ipk:
|
||||
alternatives:
|
||||
- priority: 100
|
||||
target: /usr/bin/fake
|
||||
link_name: /usr/bin/bar
|
||||
|
||||
- link_name: /usr/bin/baz
|
||||
target: /usr/bin/fake
|
||||
priority: 200
|
|
@ -0,0 +1,8 @@
|
|||
name: "foo"
|
||||
arch: "all"
|
||||
platform: "linux"
|
||||
version: "v1.0.0"
|
||||
maintainer: "John Doe <john@example.com>"
|
||||
description: Foo conflicts dummy
|
||||
conflicts:
|
||||
- dummy
|
|
@ -0,0 +1,172 @@
|
|||
FROM openwrt/rootfs AS test_base
|
||||
ARG package
|
||||
#ARG CACHEBUST=1
|
||||
RUN mkdir -p /var/lock && \
|
||||
mkdir -p /var/run && \
|
||||
mkdir -p /tmp
|
||||
RUN echo "${package}"
|
||||
COPY ${package} /tmp/foo.ipk
|
||||
|
||||
# ---- minimal test ----
|
||||
FROM test_base AS min
|
||||
RUN opkg install /tmp/foo.ipk
|
||||
|
||||
|
||||
# ---- symlink test ----
|
||||
FROM min AS symlink
|
||||
RUN ls -l /path/to/symlink | grep "/path/to/symlink -> /etc/foo/whatever.conf"
|
||||
|
||||
|
||||
# ---- simple test ----
|
||||
FROM min AS simple
|
||||
RUN test -e /usr/bin/fake
|
||||
RUN test -f /etc/foo/whatever.conf
|
||||
RUN echo wat >> /etc/foo/whatever.conf
|
||||
RUN opkg remove foo
|
||||
RUN test -f /etc/foo/whatever.conf
|
||||
RUN test ! -f /usr/bin/fake
|
||||
|
||||
|
||||
# ---- no-glob test ----
|
||||
FROM min AS no-glob
|
||||
RUN test -d /usr/share/whatever/
|
||||
RUN test -f /usr/share/whatever/file1
|
||||
RUN test -f /usr/share/whatever/file2
|
||||
RUN test -d /usr/share/whatever/folder2
|
||||
RUN test -f /usr/share/whatever/folder2/file1
|
||||
RUN test -f /usr/share/whatever/folder2/file2
|
||||
|
||||
|
||||
# ---- complex test ----
|
||||
FROM test_base AS complex
|
||||
RUN opkg install coreutils-stat
|
||||
RUN test "$(opkg status fish)" = ""
|
||||
RUN opkg install /tmp/foo.ipk > install.log
|
||||
RUN opkg depends foo | grep "bash"
|
||||
RUN cat install.log | grep "package foo suggests installing zsh"
|
||||
RUN test "$(opkg status fish)" != ""
|
||||
RUN opkg info foo | grep "Provides: fake"
|
||||
RUN test -e /usr/bin/fake
|
||||
RUN test -f /etc/foo/whatever.conf
|
||||
RUN test -d /usr/share/whatever/
|
||||
RUN test -d /usr/share/whatever/folder
|
||||
RUN test -f /usr/share/whatever/folder/file1
|
||||
RUN test -f /usr/share/whatever/folder/file2
|
||||
RUN test -d /usr/share/whatever/folder/folder2
|
||||
RUN test -f /usr/share/whatever/folder/folder2/file1
|
||||
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/fake2) -eq 4755
|
||||
RUN test -f /tmp/preinstall-proof
|
||||
RUN test -f /tmp/postinstall-proof
|
||||
RUN test ! -f /tmp/preremove-proof
|
||||
RUN test ! -f /tmp/postremove-proof
|
||||
RUN echo wat >> /etc/foo/whatever.conf
|
||||
RUN opkg remove foo
|
||||
RUN test -f /etc/foo/whatever.conf
|
||||
RUN test ! -f /usr/bin/fake
|
||||
RUN test ! -f /usr/bin/fake2
|
||||
RUN test -f /tmp/preremove-proof
|
||||
RUN test -f /tmp/postremove-proof
|
||||
|
||||
# ---- overrides test ----
|
||||
FROM min AS overrides
|
||||
RUN test -e /usr/bin/fake
|
||||
RUN test -f /etc/foo/whatever.conf
|
||||
RUN test ! -f /tmp/preinstall-proof
|
||||
RUN test -f /tmp/postinstall-proof
|
||||
RUN test ! -f /tmp/preremove-proof
|
||||
RUN test ! -f /tmp/postremove-proof
|
||||
RUN echo wat >> /etc/foo/whatever.conf
|
||||
RUN opkg remove foo
|
||||
RUN test -f /etc/foo/whatever.conf
|
||||
RUN test ! -f /usr/bin/fake
|
||||
RUN test -f /tmp/preremove-proof
|
||||
RUN test ! -f /tmp/postremove-proof
|
||||
|
||||
# ---- meta test ----
|
||||
FROM test_base AS meta
|
||||
RUN opkg install /tmp/foo.ipk
|
||||
RUN command -v zsh
|
||||
|
||||
# ---- env-var-version test ----
|
||||
FROM min AS env-var-version
|
||||
ENV EXPECTVER="Version: 1.0.0~0.1.b1+git.abcdefgh"
|
||||
RUN opkg info foo | grep "Version" > found
|
||||
RUN export FOUND_VER="$(cat found)" && \
|
||||
echo "Expected: '${EXPECTVER}' :: Found: '${FOUND_VER}'" && \
|
||||
test "${FOUND_VER}" = "${EXPECTVER}"
|
||||
|
||||
# ---- changelog test ----
|
||||
FROM test_base AS withchangelog
|
||||
|
||||
# ---- signed test ----
|
||||
FROM test_base AS signed
|
||||
|
||||
# ----- IPK Specific Tests -----
|
||||
|
||||
# ---- alternatives test ----
|
||||
FROM test_base AS alternatives
|
||||
RUN test ! -e /usr/bin/foo
|
||||
RUN test ! -e /usr/bin/bar
|
||||
RUN test ! -e /usr/bin/baz
|
||||
RUN opkg install /tmp/foo.ipk
|
||||
RUN test -e /usr/bin/fake
|
||||
RUN test -e /usr/bin/bar
|
||||
RUN test -e /usr/bin/baz
|
||||
|
||||
# ---- conflicts test ----
|
||||
FROM test_base AS conflicts
|
||||
COPY dummy.ipk /tmp/dummy.ipk
|
||||
# install dummy package
|
||||
RUN opkg install /tmp/dummy.ipk
|
||||
# make sure foo can't be installed
|
||||
RUN opkg install /tmp/foo.ipk 2>&1 | grep "Cannot install package foo"
|
||||
# make sure foo can be installed if dummy is not installed
|
||||
RUN opkg remove dummy
|
||||
RUN opkg install /tmp/foo.ipk
|
||||
|
||||
# ---- predepends test ----
|
||||
FROM test_base AS predepends
|
||||
COPY dummy.ipk /tmp/dummy.ipk
|
||||
RUN opkg install /tmp/foo.ipk 2>&1 | grep "cannot find dependency dummy for foo"
|
||||
RUN opkg install /tmp/dummy.ipk
|
||||
RUN opkg install /tmp/foo.ipk
|
||||
|
||||
|
||||
# ---- upgrade test ----
|
||||
FROM test_base AS upgrade
|
||||
ARG oldpackage
|
||||
RUN echo "${oldpackage}"
|
||||
COPY ${oldpackage} /tmp/old_foo.ipk
|
||||
RUN opkg install /tmp/old_foo.ipk
|
||||
|
||||
RUN test -f /tmp/preinstall-proof
|
||||
RUN cat /tmp/preinstall-proof | grep "Install"
|
||||
|
||||
RUN test -f /tmp/postinstall-proof
|
||||
RUN cat /tmp/postinstall-proof | grep "Install"
|
||||
|
||||
# The upgrade process doesn't allow a local upgrade.
|
||||
RUN opkg install /tmp/foo.ipk
|
||||
|
||||
RUN test -f /tmp/preremove-proof
|
||||
RUN cat /tmp/preremove-proof | grep "Upgrade"
|
||||
|
||||
RUN test -f /tmp/postremove-proof
|
||||
RUN cat /tmp/postremove-proof | grep "Upgrade"
|
||||
|
||||
RUN test -f /tmp/preinstall-proof
|
||||
RUN cat /tmp/preinstall-proof | grep "Upgrade"
|
||||
|
||||
# The upgrade process doesn't allow a local upgrade,
|
||||
# so the following test will fail.
|
||||
#RUN test -d /tmp/postinstall-proof
|
||||
#RUN cat /tmp/postinstall-proof | grep "Upgrade"
|
|
@ -0,0 +1,9 @@
|
|||
name: "foo"
|
||||
arch: "all"
|
||||
platform: "linux"
|
||||
version: "v1.0.0"
|
||||
maintainer: "John Doe <john@example.com>"
|
||||
description: Foo breaks dummy
|
||||
ipk:
|
||||
predepends:
|
||||
- dummy
|
|
@ -220,3 +220,9 @@ RUN test ! -f /etc/bar/file
|
|||
RUN test -d /etc/foo
|
||||
RUN test ! -d /etc/bar
|
||||
RUN test ! -d /etc/baz
|
||||
|
||||
# ---- verify test ----
|
||||
FROM min as verify
|
||||
RUN rpm -V foo
|
||||
RUN rm /tmp/postinstall-proof
|
||||
RUN ! rpm -V foo
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
name: "foo"
|
||||
arch: "${BUILD_ARCH}"
|
||||
platform: "linux"
|
||||
version: "v1.2.3"
|
||||
maintainer: "Foo Bar"
|
||||
release: "4"
|
||||
description: |
|
||||
Foo bar
|
||||
Multiple lines
|
||||
vendor: "foobar"
|
||||
homepage: "https://foobar.org"
|
||||
license: "MIT"
|
||||
contents:
|
||||
- src: ./testdata/fake
|
||||
dst: /etc/foo/file
|
||||
scripts:
|
||||
postinstall: ./testdata/acceptance/scripts/postinstall.sh
|
||||
rpm:
|
||||
scripts:
|
||||
verify: ./testdata/acceptance/scripts/verify.sh
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
test -e /tmp/postinstall-proof
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "Verify" > /dev/null
|
|
@ -1,10 +1,10 @@
|
|||
# nfpm
|
||||
|
||||
Packages apps on RPM, Deb, APK and Arch Linux formats based on a YAML configuration file
|
||||
Packages apps on RPM, Deb, APK, Arch Linux, and ipk formats based on a YAML configuration file
|
||||
|
||||
## Synopsis
|
||||
|
||||
nFPM is a simple and 0-dependencies deb, rpm, apk and arch linux packager written in Go.
|
||||
nFPM is a simple and 0-dependencies apk, arch, deb, ipk and rpm linux packager written in Go.
|
||||
|
||||
## Options
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ See each sub-command's help for details on how to use the generated script.
|
|||
|
||||
## See also
|
||||
|
||||
* [nfpm](/cmd/nfpm/) - Packages apps on RPM, Deb, APK and Arch Linux formats based on a YAML configuration file
|
||||
* [nfpm](/cmd/nfpm/) - Packages apps on RPM, Deb, APK, Arch Linux, and ipk formats based on a YAML configuration file
|
||||
* [nfpm completion bash](/cmd/nfpm_completion_bash/) - Generate the autocompletion script for bash
|
||||
* [nfpm completion fish](/cmd/nfpm_completion_fish/) - Generate the autocompletion script for fish
|
||||
* [nfpm completion powershell](/cmd/nfpm_completion_powershell/) - Generate the autocompletion script for powershell
|
||||
|
|
|
@ -15,5 +15,5 @@ nfpm init [flags]
|
|||
|
||||
## See also
|
||||
|
||||
* [nfpm](/cmd/nfpm/) - Packages apps on RPM, Deb, APK and Arch Linux formats based on a YAML configuration file
|
||||
* [nfpm](/cmd/nfpm/) - Packages apps on RPM, Deb, APK, Arch Linux, and ipk formats based on a YAML configuration file
|
||||
|
||||
|
|
|
@ -15,5 +15,5 @@ nfpm jsonschema [flags]
|
|||
|
||||
## See also
|
||||
|
||||
* [nfpm](/cmd/nfpm/) - Packages apps on RPM, Deb, APK and Arch Linux formats based on a YAML configuration file
|
||||
* [nfpm](/cmd/nfpm/) - Packages apps on RPM, Deb, APK, Arch Linux, and ipk formats based on a YAML configuration file
|
||||
|
||||
|
|
|
@ -11,11 +11,11 @@ nfpm package [flags]
|
|||
```
|
||||
-f, --config string config file to be used (default "nfpm.yaml")
|
||||
-h, --help help for package
|
||||
-p, --packager string which packager implementation to use [apk|deb|rpm|archlinux]
|
||||
-p, --packager string which packager implementation to use [apk|archlinux|deb|ipk|rpm]
|
||||
-t, --target string where to save the generated package (filename, folder or empty for current folder)
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
* [nfpm](/cmd/nfpm/) - Packages apps on RPM, Deb, APK and Arch Linux formats based on a YAML configuration file
|
||||
* [nfpm](/cmd/nfpm/) - Packages apps on RPM, Deb, APK, Arch Linux, and ipk formats based on a YAML configuration file
|
||||
|
||||
|
|
|
@ -322,6 +322,8 @@ rpm:
|
|||
pretrans: ./scripts/pretrans.sh
|
||||
# The posttrans script runs after all RPM package transactions / stages.
|
||||
posttrans: ./scripts/posttrans.sh
|
||||
# The verify script runs when verifying packages using `rpm -V`.
|
||||
verify: ./scripts/verify.sh
|
||||
|
||||
# The package group. This option is deprecated by most distros
|
||||
# but required by old distros like CentOS 5 / EL 5 and earlier.
|
||||
|
|
|
@ -1 +1 @@
|
|||
v2.35.2
|
||||
v2.37.1
|
||||
|
|
|
@ -192,6 +192,10 @@
|
|||
"$ref": "#/$defs/ArchLinux",
|
||||
"title": "archlinux-specific settings"
|
||||
},
|
||||
"ipk": {
|
||||
"$ref": "#/$defs/IPK",
|
||||
"title": "ipk-specific settings"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "package name"
|
||||
|
@ -563,6 +567,79 @@
|
|||
"additionalProperties": false,
|
||||
"type": "object"
|
||||
},
|
||||
"IPK": {
|
||||
"properties": {
|
||||
"abi_version": {
|
||||
"type": "string",
|
||||
"title": "abi version"
|
||||
},
|
||||
"alternatives": {
|
||||
"items": {
|
||||
"$ref": "#/$defs/IPKAlternative"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "alternatives"
|
||||
},
|
||||
"arch": {
|
||||
"type": "string",
|
||||
"title": "architecture in deb nomenclature"
|
||||
},
|
||||
"auto_installed": {
|
||||
"type": "boolean",
|
||||
"title": "auto installed",
|
||||
"default": false
|
||||
},
|
||||
"essential": {
|
||||
"type": "boolean",
|
||||
"title": "whether package is essential",
|
||||
"default": false
|
||||
},
|
||||
"fields": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object",
|
||||
"title": "fields"
|
||||
},
|
||||
"predepends": {
|
||||
"items": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"nfpm"
|
||||
]
|
||||
},
|
||||
"type": "array",
|
||||
"title": "predepends directive"
|
||||
},
|
||||
"tags": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "tags"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object"
|
||||
},
|
||||
"IPKAlternative": {
|
||||
"properties": {
|
||||
"priority": {
|
||||
"type": "integer",
|
||||
"title": "priority"
|
||||
},
|
||||
"target": {
|
||||
"type": "string",
|
||||
"title": "target"
|
||||
},
|
||||
"link_name": {
|
||||
"type": "string",
|
||||
"title": "link name"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object"
|
||||
},
|
||||
"Overridables": {
|
||||
"properties": {
|
||||
"replaces": {
|
||||
|
@ -655,6 +732,10 @@
|
|||
"archlinux": {
|
||||
"$ref": "#/$defs/ArchLinux",
|
||||
"title": "archlinux-specific settings"
|
||||
},
|
||||
"ipk": {
|
||||
"$ref": "#/$defs/IPK",
|
||||
"title": "ipk-specific settings"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
@ -719,6 +800,10 @@
|
|||
"posttrans": {
|
||||
"type": "string",
|
||||
"title": "posttrans script"
|
||||
},
|
||||
"verify": {
|
||||
"type": "string",
|
||||
"title": "verify script"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
|
Loading…
Reference in New Issue