1
1
Fork 0
mirror of https://github.com/goreleaser/nfpm synced 2024-05-21 19:36:11 +02:00

Compare commits

...

50 Commits

Author SHA1 Message Date
dependabot[bot] 745b0f59d9
--- (#824)
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-21 09:24:49 -03:00
dependabot[bot] 96b0d10688
chore(deps): bump cachix/install-nix-action from 26 to 27 (#823)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 26 to 27.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v26...V27)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 10:01:22 -03:00
caarlos0 ba2bebd36d docs: update cmd docs 2024-05-09 12:37:07 +00:00
Carlos Alexandro Becker ffb033ce70
fix: move mod back to go 1.21
refs #820

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2024-05-09 09:29:19 -03:00
caarlos0 5bb11f8f91 docs: update cmd docs 2024-05-09 01:29:40 +00:00
Carlos Alexandro Becker 8377f70ac5
test: test enumarate
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2024-05-08 22:15:16 -03:00
Carlos Alexandro Becker 8643a66fc2
chore(deps): update go-rpmutils (#814)
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2024-05-08 16:06:49 -03:00
caarlos0 00cc3d861b docs: update cmd docs 2024-05-08 19:03:20 +00:00
Weston Schmidt bc5c3bd876
feat: support for ipk packages (#818)
Implements #507.

* Adds ipk support for keywords used by OpenWRT and Yocto.
* MD5sum is explicitly excluded due to insecurity.
* SHA256Sum excluded due packages not being individually signed,
  instead, the feed of packages is checksummed and signed externally.
* Adds code to nfpm package to automatically enumerate the supported
  packaging types where possible.
2024-05-08 16:02:39 -03:00
Carlos Alexandro Becker 45cc1deaf5
chore(deps): update go-rpmutils
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2024-05-07 14:10:56 -03:00
dependabot[bot] 8d3515b77c
chore(deps): bump golangci/golangci-lint-action from 5 to 6 (#819)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 5 to 6.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-07 09:13:13 -03:00
dependabot[bot] 690e88b030
chore(deps): bump anchore/sbom-action from 0.15.10 to 0.15.11 (#817)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.10 to 0.15.11.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.15.10...v0.15.11)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 08:48:08 -03:00
dependabot[bot] d78518b84a
chore(deps): bump golangci/golangci-lint-action from 4 to 5 (#816)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 4 to 5.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-25 10:11:04 -03:00
dependabot[bot] 3ee9df5f08
feat(deps): bump golang.org/x/net from 0.22.0 to 0.23.0 (#815)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-19 15:25:33 -03:00
dependabot[bot] b381d5144d
feat(deps): bump github.com/goreleaser/chglog from 0.5.0 to 0.6.0 (#813) 2024-04-18 11:30:39 -03:00
Carlos Alexandro Becker 409b51628a
feat(rpm): properly handle optional fields (#809)
closes  #619

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2024-04-15 08:02:58 -03:00
dependabot[bot] ccfa2f4b18
chore(deps): bump sigstore/cosign-installer from 3.4.0 to 3.5.0 (#812) 2024-04-12 13:10:20 +00:00
dependabot[bot] 311860860c
feat(deps): bump github.com/klauspost/compress from 1.17.7 to 1.17.8 (#811)
Bumps [github.com/klauspost/compress](https://github.com/klauspost/compress) from 1.17.7 to 1.17.8.
- [Release notes](https://github.com/klauspost/compress/releases)
- [Changelog](https://github.com/klauspost/compress/blob/master/.goreleaser.yml)
- [Commits](https://github.com/klauspost/compress/compare/v1.17.7...v1.17.8)

---
updated-dependencies:
- dependency-name: github.com/klauspost/compress
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-10 08:56:29 -03:00
dependabot[bot] 53815fbb5c
feat(deps): bump github.com/ulikunitz/xz from 0.5.11 to 0.5.12 (#810)
Bumps [github.com/ulikunitz/xz](https://github.com/ulikunitz/xz) from 0.5.11 to 0.5.12.
- [Commits](https://github.com/ulikunitz/xz/compare/v0.5.11...v0.5.12)

---
updated-dependencies:
- dependency-name: github.com/ulikunitz/xz
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-04 09:37:03 -03:00
Carlos Alexandro Becker 157bd8dfd7
build: fix workflow-dispatch deleted tag 2024-04-01 11:59:05 -03:00
Carlos Alexandro Becker 4e7be8063b
build: do not draft winget pr 2024-04-01 11:59:05 -03:00
caarlos0 cee170f7a9 docs: update cmd docs 2024-04-01 14:58:14 +00:00
Carlos Alexandro Becker 190ce19eca
build: instructions regarding binfmt 2024-04-01 11:17:12 -03:00
Carlos Alexandro Becker a5cccefbf3
build(nix): update flake 2024-04-01 11:06:02 -03:00
Carlos Alexandro Becker 19f864b2d4
build: fix s390x build
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2024-04-01 10:57:50 -03:00
Carlos Alexandro Becker 2118e9a218
fix(apk): always append .rsa.pub to key name (#808) 2024-03-30 09:36:14 -03:00
Yaroslav 1667ef9585
feat: support PKCS8 keys for APK signing (#804)
* support PKCS8 keys for APK signing

Call correct parsing function for given RSA key depending on its PEM
header. So we can use both PKCS1 and PKCS8 keys to sign APK files.

Fixes https://github.com/goreleaser/nfpm/issues/799

* fix golangci-lint warnings
2024-03-27 10:28:44 -03:00
dependabot[bot] 04298aca7a
chore(deps): bump anchore/sbom-action from 0.15.9 to 0.15.10 (#807)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.9 to 0.15.10.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.15.9...v0.15.10)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-27 10:26:51 -03:00
dependabot[bot] a5376659a9
chore(deps): bump actions/cache from 4.0.1 to 4.0.2 (#803)
Bumps [actions/cache](https://github.com/actions/cache) from 4.0.1 to 4.0.2.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](ab5e6d0c87...0c45773b62)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 08:56:08 -03:00
Carlos Alexandro Becker 507ad79260
build: use s390x in filename
refs #802

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2024-03-19 10:23:56 -03:00
Carlos Alexandro Becker 2bfa63a13f
test: fix apk integration test
refs #794
2024-03-19 10:20:45 -03:00
caarlos0 7761491ab4 docs: update cmd docs 2024-03-19 13:15:25 +00:00
Carlos Alexandro Becker 7b3fb8b759
fix: lint issues 2024-03-19 10:14:49 -03:00
Carlos Alexandro Becker ba8a7568e0
ci: trigger build on goreleaser config changes 2024-03-19 10:04:27 -03:00
Yan Song Liu ad0161768d
feat: release for s390x (#802)
Signed-off-by: Yan Song Liu <lysliu@cn.ibm.com>
2024-03-19 10:02:26 -03:00
Carlos Alexandro Becker 29c8a210fe
fix(apk): conventional name template (#794)
* fix(apk): conventional name template

closes #793

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: pkginfo

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2024-03-11 09:05:47 -03:00
dependabot[bot] 4a7322bba1
chore(deps): bump anchore/sbom-action from 0.15.8 to 0.15.9 (#796)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.8 to 0.15.9.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.15.8...v0.15.9)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-08 13:19:06 -03:00
dependabot[bot] b447c50c27
chore(deps): bump cachix/install-nix-action from 25 to 26 (#797)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 25 to 26.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v25...v26)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-08 13:18:54 -03:00
dependabot[bot] f2711813ee
feat(deps): bump github.com/stretchr/testify from 1.8.4 to 1.9.0 (#792)
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.4 to 1.9.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.4...v1.9.0)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-04 08:55:55 -03:00
dependabot[bot] ebf76648f6
chore(deps): bump actions/cache from 4.0.0 to 4.0.1 (#791)
* chore(deps): bump actions/cache from 4.0.0 to 4.0.1

Bumps [actions/cache](https://github.com/actions/cache) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](13aacd865c...ab5e6d0c87)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Apply suggestions from code review

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2024-03-01 09:59:33 -03:00
dependabot[bot] cb456b40e7
feat(deps): bump github.com/klauspost/compress from 1.17.6 to 1.17.7 (#789)
Bumps [github.com/klauspost/compress](https://github.com/klauspost/compress) from 1.17.6 to 1.17.7.
- [Release notes](https://github.com/klauspost/compress/releases)
- [Changelog](https://github.com/klauspost/compress/blob/master/.goreleaser.yml)
- [Commits](https://github.com/klauspost/compress/compare/v1.17.6...v1.17.7)

---
updated-dependencies:
- dependency-name: github.com/klauspost/compress
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-22 10:03:28 -03:00
nickajacks1 d0d7c60d34
feat(rpm): add support for verify scriptlet (#788)
Co-authored-by: Nicholas Jackson <nicholas.jackson@zii.aero>
2024-02-21 20:13:30 -03:00
dependabot[bot] 0b1bc17d46
feat(deps): bump github.com/google/rpmpack from 0.5.0 to 0.6.0 (#787)
Bumps [github.com/google/rpmpack](https://github.com/google/rpmpack) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/google/rpmpack/releases)
- [Commits](https://github.com/google/rpmpack/compare/v0.5...v0.6.0)

---
updated-dependencies:
- dependency-name: github.com/google/rpmpack
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-16 07:41:13 -03:00
dependabot[bot] 41c6debf36
chore(deps): bump golangci/golangci-lint-action from 3 to 4 (#786)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3 to 4.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-12 08:50:29 -03:00
dependabot[bot] c3a8e2d185
chore(deps): bump arduino/setup-task from 1 to 2 (#784)
Bumps [arduino/setup-task](https://github.com/arduino/setup-task) from 1 to 2.
- [Release notes](https://github.com/arduino/setup-task/releases)
- [Commits](https://github.com/arduino/setup-task/compare/v1...v2)

---
updated-dependencies:
- dependency-name: arduino/setup-task
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-07 08:53:15 -03:00
dependabot[bot] ac5e97005a
feat(deps): bump github.com/klauspost/compress from 1.17.5 to 1.17.6 (#783)
Bumps [github.com/klauspost/compress](https://github.com/klauspost/compress) from 1.17.5 to 1.17.6.
- [Release notes](https://github.com/klauspost/compress/releases)
- [Changelog](https://github.com/klauspost/compress/blob/master/.goreleaser.yml)
- [Commits](https://github.com/klauspost/compress/compare/v1.17.5...v1.17.6)

---
updated-dependencies:
- dependency-name: github.com/klauspost/compress
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-06 08:01:25 -03:00
dependabot[bot] 69660e6db1
chore(deps): bump anchore/sbom-action from 0.15.7 to 0.15.8 (#780) 2024-02-01 14:47:12 +00:00
dependabot[bot] e0761b58cb
chore(deps): bump codecov/codecov-action from 3 to 4 (#781) 2024-02-01 14:41:29 +00:00
dependabot[bot] 0000c30be9
chore(deps): bump sigstore/cosign-installer from 3.3.0 to 3.4.0 (#782) 2024-02-01 14:41:25 +00:00
caarlos0 277ad52f54 docs: update cmd docs 2024-01-31 17:58:02 +00:00
69 changed files with 2772 additions and 178 deletions

View File

@ -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

View File

@ -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 }}

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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 }}

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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"} {

View File

@ -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
}

View File

@ -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",
},
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 != "" {

View File

@ -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) {

View File

@ -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": {

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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 ""

View File

@ -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

View File

@ -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,
))

View File

@ -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,

View File

@ -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, " ", " ")

View File

@ -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)

View File

@ -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) {

28
internal/sign/testdata/rsa_pkcs8.priv vendored Normal file
View File

@ -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-----

9
internal/sign/testdata/rsa_pkcs8.pub vendored Normal file
View File

@ -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-----

512
ipk/ipk.go Normal file
View File

@ -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)
}

1035
ipk/ipk_test.go Normal file
View File

@ -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)
})
}
}

108
ipk/tar.go Normal file
View File

@ -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
}

167
ipk/tar_test.go Normal file
View File

@ -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
}

15
ipk/testdata/bad_provides.golden vendored Normal file
View File

@ -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

17
ipk/testdata/control.golden vendored Normal file
View File

@ -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

10
ipk/testdata/control2.golden vendored Normal file
View File

@ -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

10
ipk/testdata/control3.golden vendored Normal file
View File

@ -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

10
ipk/testdata/control4.golden vendored Normal file
View File

@ -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

14
ipk/testdata/control_most.golden vendored Normal file
View File

@ -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

6
ipk/testdata/minimal.golden vendored Normal file
View File

@ -0,0 +1,6 @@
Architecture: arm64
Description: Minimal does nothing
Maintainer: maintainer
Package: minimal
Priority: extra
Version: 1.0.0

9
ipk/testdata/multiline.golden vendored Normal file
View File

@ -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

4
ipk/testdata/templates.golden vendored Normal file
View File

@ -0,0 +1,4 @@
Template: templates/lala
Type: string
Description: Set lala for templates.
For the test purpose this templates.golden is created.

7
ipk/testdata/withepoch.golden vendored Normal file
View File

@ -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
View File

@ -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"`

View File

@ -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")

View File

@ -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
}

View File

@ -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) {

6
scripts/nix-update-flake.sh Executable file
View File

@ -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

View File

@ -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}'" && \

View File

@ -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

View File

@ -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

BIN
testdata/acceptance/dummy.ipk vendored Normal file

Binary file not shown.

View File

@ -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

View File

@ -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

172
testdata/acceptance/ipk.dockerfile vendored Normal file
View File

@ -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"

View File

@ -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

View File

@ -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

20
testdata/acceptance/rpm.verify.yaml vendored Normal file
View File

@ -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

3
testdata/acceptance/scripts/verify.sh vendored Normal file
View File

@ -0,0 +1,3 @@
#!/bin/sh
test -e /tmp/postinstall-proof

3
testdata/scripts/verify.sh vendored Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
echo "Verify" > /dev/null

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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

View 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.

View File

@ -1 +1 @@
v2.35.2
v2.37.1

85
www/docs/static/schema.json generated vendored
View File

@ -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,