Repository: goreleaser/nfpm
Pull request #325 (2021-04-23 02:09:04)

feat: overhaul cmd and release process
- use cobra so its more like goreleaser
- remove gocenter from goproxy
- using "NFPM is a simple, 0-dependencies, deb, rpm and apk packager." as description in several places
- completions for bash, fish and zsh (also in the brew tap and on the packages)
- cmd docs on website
- cmd code is pretty much ready to accept unit tests (although I haven't added any yet)
- using commit timestamp et al on ldflags so the build is reproducible
- using zip for windows archives
- install the apk package inside the docker image, so we have completions et al there as well (although they wont work as we don't create completions for ash)
- create a discussion for each release

overall, mimic a good deal of config/structure from goreleaser into nfpm.

vercel[bot]: This pull request is being automatically deployed with Vercel ([learn more](https://vercel.link/github-learn-more)).  
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: [https://vercel.com/goreleaser/nfpm/ApdeJyCePcz4P374PphZBSbE1Yze](https://vercel.com/goreleaser/nfpm/ApdeJyCePcz4P374PphZBSbE1Yze)  
✅ Preview: [https://nfpm-git-cmd-overhaul-goreleaser.vercel.app](https://nfpm-git-cmd-overhaul-goreleaser.vercel.app)


codecov[bot]: # [Codecov](https://codecov.io/gh/goreleaser/nfpm/pull/325?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) Report
> Merging [#325](https://codecov.io/gh/goreleaser/nfpm/pull/325?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) (63ff5f5) into [master](https://codecov.io/gh/goreleaser/nfpm/commit/1fb26910a00fb1e7625f2763db819521f87f1134?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) (1fb2691) will **decrease** coverage by `5.11%`.
> The diff coverage is `13.96%`.

[![Impacted file tree graph](https://codecov.io/gh/goreleaser/nfpm/pull/325/graphs/tree.svg?width=650&height=150&src=pr&token=9QKGIxn7wg&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser)](https://codecov.io/gh/goreleaser/nfpm/pull/325?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser)

```diff
@@            Coverage Diff             @@
##           master     #325      +/-   ##
==========================================
- Coverage   69.37%   64.25%   -5.12%     
==========================================
  Files           9       14       +5     
  Lines        1159     1284     +125     
==========================================
+ Hits          804      825      +21     
- Misses        223      325     +102     
- Partials      132      134       +2     
```


| [Impacted Files](https://codecov.io/gh/goreleaser/nfpm/pull/325?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) | Coverage Δ | |
|---|---|---|
| [cmd/nfpm/main.go](https://codecov.io/gh/goreleaser/nfpm/pull/325/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-Y21kL25mcG0vbWFpbi5nbw==) | `0.00% <0.00%> (ø)` | |
| [internal/cmd/completion.go](https://codecov.io/gh/goreleaser/nfpm/pull/325/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvY21kL2NvbXBsZXRpb24uZ28=) | `0.00% <0.00%> (ø)` | |
| [internal/cmd/docs.go](https://codecov.io/gh/goreleaser/nfpm/pull/325/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvY21kL2RvY3MuZ28=) | `0.00% <0.00%> (ø)` | |
| [internal/cmd/init.go](https://codecov.io/gh/goreleaser/nfpm/pull/325/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvY21kL2luaXQuZ28=) | `0.00% <0.00%> (ø)` | |
| [internal/cmd/package.go](https://codecov.io/gh/goreleaser/nfpm/pull/325/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvY21kL3BhY2thZ2UuZ28=) | `0.00% <0.00%> (ø)` | |
| [internal/cmd/root.go](https://codecov.io/gh/goreleaser/nfpm/pull/325/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvY21kL3Jvb3QuZ28=) | `0.00% <0.00%> (ø)` | |
| [rpm/rpm.go](https://codecov.io/gh/goreleaser/nfpm/pull/325/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-cnBtL3JwbS5nbw==) | `73.20% <60.00%> (-0.67%)` | :arrow_down: |
| [apk/apk.go](https://codecov.io/gh/goreleaser/nfpm/pull/325/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-YXBrL2Fway5nbw==) | `70.29% <100.00%> (+0.25%)` | :arrow_up: |
| [nfpm.go](https://codecov.io/gh/goreleaser/nfpm/pull/325/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-bmZwbS5nbw==) | `86.88% <100.00%> (+1.56%)` | :arrow_up: |
| ... and [4 more](https://codecov.io/gh/goreleaser/nfpm/pull/325/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/goreleaser/nfpm/pull/325?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/goreleaser/nfpm/pull/325?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser). Last update [fe1413c...63ff5f5](https://codecov.io/gh/goreleaser/nfpm/pull/325?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser).


Patch:
diff --git a/.gitignore b/.gitignore
index 08ba215..a3a0594 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,4 +12,5 @@ coverage.out
 /nfpm
 www/site
 .idea/
-testdata/acceptance/tmp/
\ No newline at end of file
+testdata/acceptance/tmp/
+completions/
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 85d51bd..99ae8a1 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -1,9 +1,9 @@
 env:
   - GO111MODULE=on
-  - GOPROXY=https://gocenter.io
 before:
   hooks:
-  - go mod tidy
+    - go mod tidy
+    - ./scripts/completions.sh
 gomod:
   proxy: true
 builds:
@@ -17,14 +17,17 @@ builds:
   goarch:
   - amd64
   - arm64
+  mod_timestamp: '{{ .CommitTimestamp }}'
+  flags:
+    - -trimpath
+  ldflags:
+    - -s -w -X main.version={{ .Version }} -X main.commit={{ .Commit }} -X main.date={{ .CommitDate }} -X main.builtBy=goreleaser
 dockers:
   - image_templates:
       - 'goreleaser/nfpm:{{ .Tag }}-amd64'
       - 'ghcr.io/goreleaser/nfpm:{{ .Tag }}-amd64'
     dockerfile: Dockerfile
     use_buildx: true
-    binaries:
-      - nfpm
     build_flag_templates:
       - "--pull"
       - "--label=org.opencontainers.image.created={{.Date}}"
@@ -38,8 +41,6 @@ dockers:
       - 'ghcr.io/goreleaser/nfpm:{{ .Tag }}-arm64v8'
     dockerfile: Dockerfile
     use_buildx: true
-    binaries:
-      - nfpm
     build_flag_templates:
       - "--pull"
       - "--label=org.opencontainers.image.created={{.Date}}"
@@ -77,19 +78,31 @@ archives:
     windows: Windows
     386: i386
     amd64: x86_64
+  format_overrides:
+    - goos: windows
+      format: zip
+  files:
+    - README.md
+    - LICENSE.md
+    - completions/*
 brews:
 - tap:
     owner: goreleaser
     name: homebrew-tap
   folder: Formula
   homepage:  https://github.com/goreleaser/nfpm
-  description: nFPM is not FPM
+  description: NFPM is a simple, 0-dependencies, deb, rpm and apk packager.
   test: |
     system "#{bin}/nfpm -v"
+  install: |-
+    bin.install "nfpm"
+    bash_completion.install "completions/nfpm.bash" => "nfpm"
+    zsh_completion.install "completions/nfpm.zsh" => "_nfpm"
+    fish_completion.install "completions/nfpm.fish"
 nfpms:
 - file_name_template: '{{ .ProjectName }}_{{ .Arch }}'
   homepage:  https://github.com/goreleaser/nfpm
-  description: nFPM is not FPM
+  description: NFPM is a simple, 0-dependencies, deb, rpm and apk packager.
   maintainer: Carlos Alexandro Becker <root@carlosbecker.com>
   license: MIT
   vendor: GoReleaser
@@ -97,10 +110,19 @@ nfpms:
   - apk
   - deb
   - rpm
+  contents:
+    - src: ./completions/nfpm.bash
+      dst: /etc/bash_completion.d/nfpm
+    - src: ./completions/nfpm.fish
+      dst: /usr/share/fish/completions/nfpm.fish
+    - src: ./completions/nfpm.zsh
+      dst: /usr/local/share/zsh/site-functions/_nfpm
 scoop:
   bucket:
     owner: goreleaser
     name: scoop-bucket
   homepage:  https://goreleaser.com
-  description: Deliver Go binaries as fast and easily as possible
+  description: NFPM is a simple, 0-dependencies, deb, rpm and apk packager.
   license: MIT
+release:
+  discussion_category_name: "New Releases"
diff --git a/Dockerfile b/Dockerfile
index 5aed43e..8cb2fcd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,3 +1,4 @@
 FROM alpine
-COPY nfpm /usr/local/bin/nfpm
+COPY nfpm_*.apk /tmp/
+RUN apk add --allow-untrusted /tmp/nfpm_*.apk
 ENTRYPOINT ["/usr/local/bin/nfpm"]
diff --git a/README.md b/README.md
index 65ec4f2..315cd54 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 <p align="center">
   <img alt="GoReleaser Logo" src="https://avatars2.githubusercontent.com/u/24697112?v=3&s=200" height="140" />
   <h3 align="center">NFPM</h3>
-  <p align="center">NFPM is Not FPM - a simple deb, rpm and apk packager written in Go.</p>
+  <p align="center">NFPM is a simple, 0-dependencies, deb, rpm and apk packager.</p>
   <p align="center">
     <a href="https://github.com/goreleaser/nfpm/releases/latest"><img alt="Release" src="https://img.shields.io/github/release/goreleaser/nfpm.svg?style=for-the-badge"></a>
     <a href="/LICENSE.md"><img alt="Software License" src="https://img.shields.io/badge/license-MIT-brightgreen.svg?style=for-the-badge"></a>
diff --git a/cmd/nfpm/main.go b/cmd/nfpm/main.go
index a04561d..29b2a77 100644
--- a/cmd/nfpm/main.go
+++ b/cmd/nfpm/main.go
@@ -1,21 +1,11 @@
-// Package main contains the main nfpm cli source code.
 package main
 
 import (
-	"errors"
 	"fmt"
-	"io/ioutil"
 	"os"
-	"path"
-	"path/filepath"
 	"runtime/debug"
 
-	"github.com/alecthomas/kingpin"
-
-	"github.com/goreleaser/nfpm/v2"
-	_ "github.com/goreleaser/nfpm/v2/apk"
-	_ "github.com/goreleaser/nfpm/v2/deb"
-	_ "github.com/goreleaser/nfpm/v2/rpm"
+	"github.com/goreleaser/nfpm/v2/internal/cmd"
 )
 
 // nolint: gochecknoglobals
@@ -24,40 +14,14 @@ var (
 	commit  = ""
 	date    = ""
 	builtBy = ""
-
-	app    = kingpin.New("nfpm", "not-fpm packages apps in some formats")
-	config = app.Flag("config", "config file").
-		Default("nfpm.yaml").
-		Short('f').
-		String()
-
-	pkgCmd = app.Command("pkg", "package based on the config file").Alias("package")
-	target = pkgCmd.Flag("target", "where to save the generated package (filename, folder or blank for current folder)").
-		Default("").
-		Short('t').
-		String()
-	packager = pkgCmd.Flag("packager", "which packager implementation to use").
-			Short('p').
-			Enum("deb", "rpm", "apk")
-
-	initCmd = app.Command("init", "create an empty config file")
 )
 
 func main() {
-	app.Version(buildVersion(version, commit, date, builtBy))
-	app.VersionFlag.Short('v')
-	app.HelpFlag.Short('h')
-	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
-	case initCmd.FullCommand():
-		if err := initFile(*config); err != nil {
-			kingpin.Fatalf(err.Error())
-		}
-		fmt.Printf("created config file from example: %s\n", *config)
-	case pkgCmd.FullCommand():
-		if err := doPackage(*config, *target, *packager); err != nil {
-			kingpin.Fatalf(err.Error())
-		}
-	}
+	cmd.Execute(
+		buildVersion(version, commit, date, builtBy),
+		os.Exit,
+		os.Args[1:],
+	)
 }
 
 func buildVersion(version, commit, date, builtBy string) string {
@@ -76,131 +40,3 @@ func buildVersion(version, commit, date, builtBy string) string {
 	}
 	return result
 }
-
-func initFile(config string) error {
-	return ioutil.WriteFile(config, []byte(example), 0o600)
-}
-
-var errInsufficientParams = errors.New("a packager must be specified if target is a directory or blank")
-
-// nolint:funlen
-func doPackage(configPath, target, packager string) error {
-	targetIsADirectory := false
-	stat, err := os.Stat(target)
-	if err == nil && stat.IsDir() {
-		targetIsADirectory = true
-	}
-
-	if packager == "" {
-		ext := filepath.Ext(target)
-		if targetIsADirectory || ext == "" {
-			return errInsufficientParams
-		}
-
-		packager = ext[1:]
-		fmt.Println("guessing packager from target file extension...")
-	}
-
-	config, err := nfpm.ParseFile(configPath)
-	if err != nil {
-		return err
-	}
-
-	info, err := config.Get(packager)
-	if err != nil {
-		return err
-	}
-
-	info = nfpm.WithDefaults(info)
-
-	if err = nfpm.Validate(info); err != nil {
-		return err
-	}
-
-	fmt.Printf("using %s packager...\n", packager)
-	pkg, err := nfpm.Get(packager)
-	if err != nil {
-		return err
-	}
-
-	if target == "" {
-		// if no target was specified create a package in
-		// current directory with a conventional file name
-		target = pkg.ConventionalFileName(info)
-	} else if targetIsADirectory {
-		// if a directory was specified as target, create
-		// a package with conventional file name there
-		target = path.Join(target, pkg.ConventionalFileName(info))
-	}
-
-	f, err := os.Create(target)
-	if err != nil {
-		return err
-	}
-
-	info.Target = target
-
-	err = pkg.Package(info, f)
-	_ = f.Close()
-	if err != nil {
-		os.Remove(target)
-		return err
-	}
-
-	fmt.Printf("created package: %s\n", target)
-	return nil
-}
-
-const example = `# nfpm example config file
-#
-# check https://nfpm.goreleaser.com/configuration for detailed usage
-#
-name: "foo"
-arch: "amd64"
-platform: "linux"
-version: "v1.0.0"
-section: "default"
-priority: "extra"
-replaces:
-- foobar
-provides:
-- bar
-depends:
-- foo
-- bar
-recommends:
-- whatever
-suggests:
-- something-else
-conflicts:
-- not-foo
-- not-bar
-maintainer: "John Doe <john@example.com>"
-description: |
-  FooBar is the great foo and bar software.
-    And this can be in multiple lines!
-vendor: "FooBarCorp"
-homepage: "http://example.com"
-license: "MIT"
-changelog: "changelog.yaml"
-contents:
-- src: ./foo
-  dst: /usr/local/bin/foo
-- src: ./bar
-  dst: /usr/local/bin/bar
-- src: ./foobar.conf
-  dst: /etc/foobar.conf
-  type: config
-- src: /usr/local/bin/foo
-  dst: /sbin/foo
-  type: symlink
-overrides:
-  rpm:
-    scripts:
-      preinstall: ./scripts/preinstall.sh
-      postremove: ./scripts/postremove.sh
-  deb:
-    scripts:
-      postinstall: ./scripts/postinstall.sh
-      preremove: ./scripts/preremove.sh
-`
diff --git a/go.mod b/go.mod
index abddf1e..7cbc8b9 100644
--- a/go.mod
+++ b/go.mod
@@ -8,9 +8,6 @@ require (
 	github.com/Masterminds/semver/v3 v3.1.1
 	github.com/ProtonMail/go-crypto v0.0.0-20210408094314-bf0c5240ed99
 	github.com/ProtonMail/gopenpgp/v2 v2.1.7
-	github.com/alecthomas/kingpin v2.2.6+incompatible
-	github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
-	github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
 	github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
 	github.com/go-git/go-git/v5 v5.3.0 // indirect
 	github.com/google/go-cmp v0.5.4 // indirect
@@ -24,6 +21,7 @@ require (
 	github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
 	github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b
 	github.com/sergi/go-diff v1.2.0 // indirect
+	github.com/spf13/cobra v1.1.1
 	github.com/stretchr/testify v1.7.0
 	github.com/ulikunitz/xz v0.5.9 // indirect
 	github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
diff --git a/go.sum b/go.sum
index 642a930..b9fa0c0 100644
--- a/go.sum
+++ b/go.sum
@@ -39,14 +39,8 @@ github.com/ProtonMail/gopenpgp/v2 v2.1.7 h1:6cDDCuHwC/DhRLsj0+w6e5taxtA48hpd1ZFK
 github.com/ProtonMail/gopenpgp/v2 v2.1.7/go.mod h1:mjMvRMlOlBhNuaa3z0xOmEgAkba/Mu1Z8uWwYj4/6Ws=
 github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
 github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
-github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI=
-github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
-github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -71,6 +65,7 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -126,8 +121,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/rpmpack v0.0.0-20201225075926-0a97c2c4b688 h1:jyGRCFMyDK/gKe6QRZQWci5+wEUBFElvxLHs3iwO3hY=
-github.com/google/rpmpack v0.0.0-20201225075926-0a97c2c4b688/go.mod h1:+y9lKiqDhR4zkLl+V9h4q0rdyrYVsWWm6LLCQP33DIk=
 github.com/google/rpmpack v0.0.0-20210410105602-e20c988a6f5a h1:XC048Fc/OB2rUl/BxruopEl2u/EP6cJNFveVxI1cvdk=
 github.com/google/rpmpack v0.0.0-20210410105602-e20c988a6f5a/go.mod h1:+y9lKiqDhR4zkLl+V9h4q0rdyrYVsWWm6LLCQP33DIk=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -170,6 +163,7 @@ github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
 github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
 github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
@@ -248,6 +242,7 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b h1:+gCnWOZV8Z/8jehJ2CdqB47Z3S+SREmQcuXkRFLNsiI=
@@ -256,6 +251,7 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 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/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
@@ -269,10 +265,12 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
 github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
 github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
 github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
diff --git a/internal/cmd/completion.go b/internal/cmd/completion.go
new file mode 100644
index 0000000..ae0793d
--- /dev/null
+++ b/internal/cmd/completion.go
@@ -0,0 +1,74 @@
+package cmd
+
+import "github.com/spf13/cobra"
+
+type completionCmd struct {
+	cmd *cobra.Command
+}
+
+func newCompletionCmd() *completionCmd {
+	root := &completionCmd{}
+	cmd := &cobra.Command{
+		Use:   "completion [bash|zsh|fish]",
+		Short: "Prints shell autocompletion scripts for NFPM",
+		Long: `Allows you to setup your shell to completions NFPM commands and flags.
+
+#### Bash
+
+	$ source <(nfpm completion bash)
+
+To load completions for each session, execute once:
+
+##### Linux
+
+	$ nfpm completion bash > /etc/bash_completion.d/nfpm
+
+##### MacOS
+
+	$ nfpm completion bash > /usr/local/etc/bash_completion.d/nfpm
+
+#### ZSH
+
+If shell completion is not already enabled in your environment you will need to enable it.
+You can execute the following once:
+
+	$ echo "autoload -U compinit; compinit" >> ~/.zshrc
+
+To load completions for each session, execute once:
+
+	$ nfpm completion zsh > "${fpath[1]}/_nfpm"
+
+You will need to start a new shell for this setup to take effect.
+
+#### Fish
+
+	$ nfpm completion fish | source
+
+To load completions for each session, execute once:
+
+	$ nfpm completion fish > ~/.config/fish/completions/nfpm.fish
+
+**NOTE**: If you are using an official nfpm package, it should setup completions for you out of the box.
+`,
+		SilenceUsage:          true,
+		DisableFlagsInUseLine: true,
+		ValidArgs:             []string{"bash", "zsh", "fish"},
+		Args:                  cobra.ExactValidArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			var err error
+			switch args[0] {
+			case "bash":
+				err = cmd.Root().GenBashCompletion(cmd.OutOrStdout())
+			case "zsh":
+				err = cmd.Root().GenZshCompletion(cmd.OutOrStdout())
+			case "fish":
+				err = cmd.Root().GenFishCompletion(cmd.OutOrStdout(), true)
+			}
+
+			return err
+		},
+	}
+
+	root.cmd = cmd
+	return root
+}
diff --git a/internal/cmd/doc.go b/internal/cmd/doc.go
new file mode 100644
index 0000000..45e4f2c
--- /dev/null
+++ b/internal/cmd/doc.go
@@ -0,0 +1,2 @@
+// Package cmd contains the main nfpm cli source code.
+package cmd
diff --git a/internal/cmd/docs.go b/internal/cmd/docs.go
new file mode 100644
index 0000000..75e3115
--- /dev/null
+++ b/internal/cmd/docs.go
@@ -0,0 +1,35 @@
+package cmd
+
+import (
+	"strings"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+type docsCmd struct {
+	cmd *cobra.Command
+}
+
+func newDocsCmd() *docsCmd {
+	root := &docsCmd{}
+	cmd := &cobra.Command{
+		Use:                   "docs",
+		Short:                 "Generates NFPM's command line docs",
+		SilenceUsage:          true,
+		DisableFlagsInUseLine: true,
+		Hidden:                true,
+		Args:                  cobra.NoArgs,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			root.cmd.Root().DisableAutoGenTag = true
+			return doc.GenMarkdownTreeCustom(root.cmd.Root(), "www/docs/cmd", func(_ string) string {
+				return ""
+			}, func(s string) string {
+				return "/cmd/" + strings.TrimSuffix(s, ".md")
+			})
+		},
+	}
+
+	root.cmd = cmd
+	return root
+}
diff --git a/internal/cmd/init.go b/internal/cmd/init.go
new file mode 100644
index 0000000..e6f05cf
--- /dev/null
+++ b/internal/cmd/init.go
@@ -0,0 +1,90 @@
+package cmd
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/spf13/cobra"
+)
+
+type initCmd struct {
+	cmd    *cobra.Command
+	config string
+}
+
+func newInitCmd() *initCmd {
+	root := &initCmd{}
+	cmd := &cobra.Command{
+		Use:           "init",
+		Aliases:       []string{"i"},
+		Short:         "Creates a sample nfpm.yaml config file",
+		SilenceUsage:  true,
+		SilenceErrors: true,
+		Args:          cobra.NoArgs,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			if err := os.WriteFile(root.config, []byte(example), 0o666); err != nil {
+				return fmt.Errorf("failed to create example file: %w", err)
+			}
+			return nil
+		},
+	}
+
+	cmd.Flags().StringVarP(&root.config, "config", "f", "nfpm.yaml", "Path to the to-be-created config file")
+
+	root.cmd = cmd
+	return root
+}
+
+const example = `# nfpm example config file
+#
+# check https://nfpm.goreleaser.com/configuration for detailed usage
+#
+name: "foo"
+arch: "amd64"
+platform: "linux"
+version: "v1.0.0"
+section: "default"
+priority: "extra"
+replaces:
+- foobar
+provides:
+- bar
+depends:
+- foo
+- bar
+recommends:
+- whatever
+suggests:
+- something-else
+conflicts:
+- not-foo
+- not-bar
+maintainer: "John Doe <john@example.com>"
+description: |
+  FooBar is the great foo and bar software.
+    And this can be in multiple lines!
+vendor: "FooBarCorp"
+homepage: "http://example.com"
+license: "MIT"
+changelog: "changelog.yaml"
+contents:
+- src: ./foo
+  dst: /usr/local/bin/foo
+- src: ./bar
+  dst: /usr/local/bin/bar
+- src: ./foobar.conf
+  dst: /etc/foobar.conf
+  type: config
+- src: /usr/local/bin/foo
+  dst: /sbin/foo
+  type: symlink
+overrides:
+  rpm:
+    scripts:
+      preinstall: ./scripts/preinstall.sh
+      postremove: ./scripts/postremove.sh
+  deb:
+    scripts:
+      postinstall: ./scripts/postinstall.sh
+      preremove: ./scripts/preremove.sh
+`
diff --git a/internal/cmd/package.go b/internal/cmd/package.go
new file mode 100644
index 0000000..d18d622
--- /dev/null
+++ b/internal/cmd/package.go
@@ -0,0 +1,111 @@
+package cmd
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"path"
+	"path/filepath"
+
+	"github.com/goreleaser/nfpm/v2"
+	"github.com/spf13/cobra"
+)
+
+type packageCmd struct {
+	cmd      *cobra.Command
+	config   string
+	target   string
+	packager string
+}
+
+func newPackageCmd() *packageCmd {
+	root := &packageCmd{}
+	cmd := &cobra.Command{
+		Use:           "package",
+		Aliases:       []string{"pkg", "p"},
+		Short:         "Creates a package based on the given the given config file and flags",
+		SilenceUsage:  true,
+		SilenceErrors: true,
+		Args:          cobra.NoArgs,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return doPackage(root.config, root.target, root.packager)
+		},
+	}
+
+	cmd.Flags().StringVarP(&root.config, "config", "f", "nfpm.yaml", "Config file to be used")
+	cmd.Flags().StringVarP(&root.target, "target", "t", "", "Where to save the generated package (filename, folder or empty for current folder)")
+	cmd.Flags().StringVarP(&root.packager, "packager", "p", "", "Which packager implementation to use [apk|deb|rpm]")
+
+	root.cmd = cmd
+	return root
+}
+
+var errInsufficientParams = errors.New("a packager must be specified if target is a directory or blank")
+
+// nolint:funlen
+func doPackage(configPath, target, packager string) error {
+	targetIsADirectory := false
+	stat, err := os.Stat(target)
+	if err == nil && stat.IsDir() {
+		targetIsADirectory = true
+	}
+
+	if packager == "" {
+		ext := filepath.Ext(target)
+		if targetIsADirectory || ext == "" {
+			return errInsufficientParams
+		}
+
+		packager = ext[1:]
+		fmt.Println("guessing packager from target file extension...")
+	}
+
+	config, err := nfpm.ParseFile(configPath)
+	if err != nil {
+		return err
+	}
+
+	info, err := config.Get(packager)
+	if err != nil {
+		return err
+	}
+
+	info = nfpm.WithDefaults(info)
+
+	if err = nfpm.Validate(info); err != nil {
+		return err
+	}
+
+	fmt.Printf("using %s packager...\n", packager)
+	pkg, err := nfpm.Get(packager)
+	if err != nil {
+		return err
+	}
+
+	if target == "" {
+		// if no target was specified create a package in
+		// current directory with a conventional file name
+		target = pkg.ConventionalFileName(info)
+	} else if targetIsADirectory {
+		// if a directory was specified as target, create
+		// a package with conventional file name there
+		target = path.Join(target, pkg.ConventionalFileName(info))
+	}
+
+	f, err := os.Create(target)
+	if err != nil {
+		return err
+	}
+
+	info.Target = target
+
+	err = pkg.Package(info, f)
+	_ = f.Close()
+	if err != nil {
+		os.Remove(target)
+		return err
+	}
+
+	fmt.Printf("created package: %s\n", target)
+	return nil
+}
diff --git a/internal/cmd/root.go b/internal/cmd/root.go
new file mode 100644
index 0000000..b24842c
--- /dev/null
+++ b/internal/cmd/root.go
@@ -0,0 +1,54 @@
+package cmd
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	_ "github.com/goreleaser/nfpm/v2/apk"
+	_ "github.com/goreleaser/nfpm/v2/deb"
+	_ "github.com/goreleaser/nfpm/v2/rpm"
+)
+
+func Execute(version string, exit func(int), args []string) {
+	newRootCmd(version, exit).Execute(args)
+}
+
+type rootCmd struct {
+	cmd  *cobra.Command
+	exit func(int)
+}
+
+func (cmd *rootCmd) Execute(args []string) {
+	cmd.cmd.SetArgs(args)
+
+	if err := cmd.cmd.Execute(); err != nil {
+		fmt.Println(err.Error())
+		cmd.exit(1)
+	}
+}
+
+func newRootCmd(version string, exit func(int)) *rootCmd {
+	root := &rootCmd{
+		exit: exit,
+	}
+	cmd := &cobra.Command{
+		Use:           "nfpm",
+		Short:         "Packages apps on RPM, Deb and APK formats based on a YAML configuration file",
+		Long:          `NFPM is a simple, 0-dependencies, deb, rpm and apk packager.`,
+		Version:       version,
+		SilenceUsage:  true,
+		SilenceErrors: true,
+		Args:          cobra.NoArgs,
+	}
+
+	cmd.AddCommand(
+		newInitCmd().cmd,
+		newPackageCmd().cmd,
+		newCompletionCmd().cmd,
+		newDocsCmd().cmd,
+	)
+
+	root.cmd = cmd
+	return root
+}
diff --git a/scripts/cmd_docs.sh b/scripts/cmd_docs.sh
new file mode 100755
index 0000000..02b40ec
--- /dev/null
+++ b/scripts/cmd_docs.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+set -e
+
+SED="sed"
+if which gsed >/dev/null 2>&1; then
+	SED="gsed"
+fi
+
+rm -rf www/docs/cmd/
+mkdir -p www/docs/cmd/
+go run ./cmd/nfpm docs
+"$SED" \
+	-i'' \
+	-e 's/SEE ALSO/See also/g' \
+	-e 's/^## /# /g' \
+	-e 's/^### /## /g' \
+	-e 's/^#### /### /g' \
+	-e 's/^##### /#### /g' \
+	./www/docs/cmd/*.md
diff --git a/scripts/completions.sh b/scripts/completions.sh
new file mode 100755
index 0000000..eeebab2
--- /dev/null
+++ b/scripts/completions.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+set -e
+rm -rf completions
+mkdir completions
+for sh in bash zsh fish; do
+	go run ./cmd/nfpm completion "$sh" >"completions/nfpm.$sh"
+done
diff --git a/www/docs/cmd/nfpm.md b/www/docs/cmd/nfpm.md
new file mode 100644
index 0000000..aed146f
--- /dev/null
+++ b/www/docs/cmd/nfpm.md
@@ -0,0 +1,20 @@
+# nfpm
+
+Packages apps on RPM, Deb and APK formats based on a YAML configuration file
+
+## Synopsis
+
+NFPM is a simple, 0-dependencies, deb, rpm and apk packager.
+
+## Options
+
+```
+  -h, --help   help for nfpm
+```
+
+## See also
+
+* [nfpm completion](/cmd/nfpm_completion)	 - Prints shell autocompletion scripts for NFPM
+* [nfpm init](/cmd/nfpm_init)	 - Creates a sample nfpm.yaml config file
+* [nfpm package](/cmd/nfpm_package)	 - Creates a package based on the given the given config file and flags
+
diff --git a/www/docs/cmd/nfpm_completion.md b/www/docs/cmd/nfpm_completion.md
new file mode 100644
index 0000000..dd8fdc4
--- /dev/null
+++ b/www/docs/cmd/nfpm_completion.md
@@ -0,0 +1,60 @@
+# nfpm completion
+
+Prints shell autocompletion scripts for NFPM
+
+## Synopsis
+
+Allows you to setup your shell to completions NFPM commands and flags.
+
+### Bash
+
+	$ source <(nfpm completion bash)
+
+To load completions for each session, execute once:
+
+#### Linux
+
+	$ nfpm completion bash > /etc/bash_completion.d/nfpm
+
+#### MacOS
+
+	$ nfpm completion bash > /usr/local/etc/bash_completion.d/nfpm
+
+### ZSH
+
+If shell completion is not already enabled in your environment you will need to enable it.
+You can execute the following once:
+
+	$ echo "autoload -U compinit; compinit" >> ~/.zshrc
+
+To load completions for each session, execute once:
+
+	$ nfpm completion zsh > "${fpath[1]}/_nfpm"
+
+You will need to start a new shell for this setup to take effect.
+
+### Fish
+
+	$ nfpm completion fish | source
+
+To load completions for each session, execute once:
+
+	$ nfpm completion fish > ~/.config/fish/completions/nfpm.fish
+
+**NOTE**: If you are using an official nfpm package, it should setup completions for you out of the box.
+
+
+```
+nfpm completion [bash|zsh|fish]
+```
+
+## Options
+
+```
+  -h, --help   help for completion
+```
+
+## See also
+
+* [nfpm](/cmd/nfpm)	 - Packages apps on RPM, Deb and APK formats based on a YAML configuration file
+
diff --git a/www/docs/cmd/nfpm_init.md b/www/docs/cmd/nfpm_init.md
new file mode 100644
index 0000000..cced9c3
--- /dev/null
+++ b/www/docs/cmd/nfpm_init.md
@@ -0,0 +1,19 @@
+# nfpm init
+
+Creates a sample nfpm.yaml config file
+
+```
+nfpm init [flags]
+```
+
+## Options
+
+```
+  -f, --config string   Path to the to-be-created config file (default "nfpm.yaml")
+  -h, --help            help for init
+```
+
+## See also
+
+* [nfpm](/cmd/nfpm)	 - Packages apps on RPM, Deb and APK formats based on a YAML configuration file
+
diff --git a/www/docs/cmd/nfpm_package.md b/www/docs/cmd/nfpm_package.md
new file mode 100644
index 0000000..bd5b2e0
--- /dev/null
+++ b/www/docs/cmd/nfpm_package.md
@@ -0,0 +1,21 @@
+# nfpm package
+
+Creates a package based on the given the given config file and flags
+
+```
+nfpm package [flags]
+```
+
+## Options
+
+```
+  -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]
+  -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 and APK formats based on a YAML configuration file
+
diff --git a/www/docs/index.md b/www/docs/index.md
index 2a8997e..b81a94d 100644
--- a/www/docs/index.md
+++ b/www/docs/index.md
@@ -1,4 +1,4 @@
-# Home
+# NFPM
 
 ![](/static/banner.svg)
 
diff --git a/www/docs/install.md b/www/docs/install.md
index 98b8313..6461f80 100644
--- a/www/docs/install.md
+++ b/www/docs/install.md
@@ -7,28 +7,39 @@ Here are the steps for each of them:
 
 ## Install the pre-compiled binary
 
-**homebrew tap** (only on macOS for now):
+**homebrew tap** (official):
 
-```console
-$ brew install goreleaser/tap/nfpm
+```sh
+brew install goreleaser/tap/nfpm
+```
+
+**homebrew** (may not be the latest version):
+
+```sh
+brew install nfpm
 ```
 
 **scoop**:
 
-```console
-$ scoop bucket add goreleaser https://github.com/goreleaser/scoop-bucket.git
-$ scoop install nfpm
+```sh
+scoop bucket add goreleaser https://github.com/goreleaser/scoop-bucket.git
+scoop install nfpm
 ```
 
-**deb/rpm**:
+**deb/rpm/apk**:
+
+Download the `.deb`, `.rpm` or `.apk` from the [releases page][releases] and install them with the appropriate tools.
+
+**shell script**:
 
-Download the `.deb` or `.rpm` from the [releases page][releases] and
-install with `dpkg -i` and `rpm -i` respectively.
+```sh
+curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh
+```
 
-**Shell script**:
+**go install**:
 
-```console
-$ curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh
+```sh
+go install github.com/goreleaser/nfpm
 ```
 
 **manually**:
@@ -41,14 +52,13 @@ copy to the desired location.
 You can also use it within a Docker container. To do that, you'll need to
 execute something more-or-less like the following:
 
-```console
-$ docker run --rm \
-  -v $PWD:/tmp/pkg \
-  goreleaser/nfpm pkg --config /tmp/pkg/foo.yml --target /tmp/pkg/foo.rpm
+```sh
+docker run --rm -v $PWD:/tmp/pkg goreleaser/nfpm package \
+	--config /tmp/pkg/foo.yml \
+	--target /tmp \
+	--packager deb
 ```
 
-[releases]: https://github.com/goreleaser/nfpm/releases
-
 ## Compiling from source
 
 Here you have two options:
@@ -58,27 +68,29 @@ steps on our [contributing guide](/contributing).
 
 If you just want to build from source for whatever reason, follow these steps:
 
-**Clone:**
+**clone:**
 
-```console
-$ git clone https://github.com/goreleaser/nfpm
-$ cd nfpm
+```sh
+git clone https://github.com/goreleaser/nfpm
+cd nfpm
 ```
 
-**Get the dependencies:**
+**get the dependencies:**
 
-```console
-$ go mod tidy
+```sh
+go mod tidy
 ```
 
-**Build:**
+**build:**
 
-```console
-$ go build -o nfpm cmd/nfpm/main.go
+```sh
+go build -o nfpm ./cmd/nfpm
 ```
 
-**Verify it works:**
+**verify it works:**
 
-```console
-$ ./nfpm --version
+```sh
+./nfpm --version
 ```
+
+[releases]: https://github.com/goreleaser/nfpm/releases
diff --git a/www/docs/sponsors.md b/www/docs/sponsors.md
index db7bc64..451dca9 100644
--- a/www/docs/sponsors.md
+++ b/www/docs/sponsors.md
@@ -1,8 +1,31 @@
 ---
-title: Sponsors
+title: Sponsoring the Project
 ---
 
-Does your company use goreleaser? Help keep the project bug-free and feature rich by [sponsoring the project](https://opencollective.com/goreleaser#sponsor).
+Does you or your company use NFPM?
+You can help keep the project bug-free and feature rich by sponsoring the project and the maintainers.
+
+## GitHub Sponsors
+
+GitHub Sponsors is a great way to contribute directly to the main maintainer, [caarlos0](https://github.com/caarlos0).
+
+This money usually goes to buying coffee, beer, better hardware and such.
+
+You can sponsor and see who's sponsoring Carlos [here](https://github.com/sponsors/caarlos0).
+
+<iframe src="https://github.com/sponsors/caarlos0/card" title="Sponsor caarlos0" height="225" width="600" style="border: 0;"></iframe>
+
+## OpenCollective
+
+OpenCollective is a great way to send some money towards the GoReleaser organization.
+
+This ultimately is used to buy/renew domains, keep servers up (although right now we're on free plans), print and send stickers to other contributors among other things.
+
+You can start sponsoring at the [OpenCollective website](https://opencollective.com/goreleaser).
+
+Bellow you can see a list of the current sponsors and backers on OpenCollective:
+
+### Sponsors
 
 <a href="https://opencollective.com/goreleaser/sponsors/0/website" target="_blank"><img src="https://opencollective.com/goreleaser/sponsors/0/avatar"></a>
 <a href="https://opencollective.com/goreleaser/sponsors/1/website" target="_blank"><img src="https://opencollective.com/goreleaser/sponsors/1/avatar"></a>
@@ -10,9 +33,7 @@ Does your company use goreleaser? Help keep the project bug-free and feature ric
 <a href="https://opencollective.com/goreleaser/sponsors/3/website" target="_blank"><img src="https://opencollective.com/goreleaser/sponsors/3/avatar"></a>
 <a href="https://opencollective.com/goreleaser/sponsors/4/website" target="_blank"><img src="https://opencollective.com/goreleaser/sponsors/4/avatar"></a>
 
-## Backers
-
-Love our work and community? [Become a backer](https://opencollective.com/goreleaser).
+### Backers
 
 <a href="https://opencollective.com/goreleaser/backers/0/website" target="_blank"><img src="https://opencollective.com/goreleaser/backers/0/avatar"></a>
 <a href="https://opencollective.com/goreleaser/backers/1/website" target="_blank"><img src="https://opencollective.com/goreleaser/backers/1/avatar"></a>
diff --git a/www/docs/usage.md b/www/docs/usage.md
index 03a55f2..475408a 100644
--- a/www/docs/usage.md
+++ b/www/docs/usage.md
@@ -1,27 +1,26 @@
 # Usage
 
+NFPM can be used both as command line tool or as a library.
+
 ## Command Line
 
 To create a sample config file, run:
 
-```console
-$ nfpm init
+```sh
+nfpm init
 ```
 
 You can then customize it and package to the formats you want:
 
-```console
-$ nfpm pkg --packager deb --target /tmp/
-using deb packager...
-created package: /tmp/foo_1.0.0_amd64.deb
-
-$ nfpm pkg --packager rpm --target /tmp/
-using rpm packager...
-created package: /tmp/foo-1.0.0.x86_64.rpm
+```sh
+nfpm pkg --packager deb --target /tmp/
+nfpm pkg --packager rpm --target /tmp/
 ```
 
+You can learn about it in more detail in the [command line reference section](/cmd/nfpm/).
+
 ## Go Library
 
-Check the [GoDocs](https://pkg.go.dev/github.com/goreleaser/nfpm/v2?tab=doc) page,
-as well as [NFPM command line implementation](https://github.com/goreleaser/nfpm/blob/master/cmd/nfpm/main.go)
+Check out the [GoDocs page](https://pkg.go.dev/github.com/goreleaser/nfpm/v2?tab=doc),
+the [NFPM command line implementation](https://github.com/goreleaser/nfpm/blob/master/cmd/nfpm/main.go)
 and [GoReleaser's usage](https://github.com/goreleaser/goreleaser/blob/master/internal/pipe/nfpm/nfpm.go).
diff --git a/www/mkdocs.yml b/www/mkdocs.yml
index dc9ec56..96dce7c 100644
--- a/www/mkdocs.yml
+++ b/www/mkdocs.yml
@@ -12,6 +12,19 @@ theme:
   favicon: static/favicon.ico
   include_search_page: false
   search_index_only: true
+  features:
+    - navigation.instant
+  palette:
+    - media: "(prefers-color-scheme: light)"  # Light mode
+      scheme: default
+      toggle:
+        icon: material/lightbulb-outline
+        name: Switch to light mode
+    - media: "(prefers-color-scheme: dark)"  # Dark mode
+      scheme: slate
+      toggle:
+        icon: material/lightbulb
+        name: Switch to dark mode
 
 plugins:
   # disable temporarely because its freezing the page
@@ -22,7 +35,6 @@ plugins:
   - minify:
       minify_html: true
 
-
 extra:
   social:
     - icon: fontawesome/brands/github-alt
@@ -38,6 +50,11 @@ nav:
 - index.md
 - install.md
 - usage.md
+- Command Line Reference:
+    - nfpm: cmd/nfpm.md
+    - nfpm init: cmd/nfpm_init.md
+    - nfpm package: cmd/nfpm_package.md
+    - nfpm completion: cmd/nfpm_completion.md
 - configuration.md
 - tips.md
 - contributing.md


Test patch:
diff --git a/internal/cmd/completion_test.go b/internal/cmd/completion_test.go
new file mode 100644
index 0000000..630d575
--- /dev/null
+++ b/internal/cmd/completion_test.go
@@ -0,0 +1,25 @@
+package cmd
+
+import (
+	"bytes"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestCompletionGeneration(t *testing.T) {
+	for _, shell := range []string{"bash", "zsh", "fish"} {
+		t.Run(shell, func(t *testing.T) {
+			completionCmd := newCompletionCmd().cmd
+			stdout := bytes.NewBufferString("")
+			stderr := bytes.NewBufferString("")
+			completionCmd.SetOut(stdout)
+			completionCmd.SetErr(stderr)
+			completionCmd.SetArgs([]string{shell})
+			err := completionCmd.Execute()
+			require.NoError(t, err, shell+" arg experienced error with nfpm completion:\n"+stderr.String())
+			require.Equal(t, "", stderr.String(), shell+" arg experienced error with nfpm completion:\n"+stderr.String())
+			require.NotEmpty(t, stdout.String(), shell+" arg reported nothing to stdout with nfpm completion")
+		})
+	}
+}