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

GoReleaser Logo

NFPM

-

NFPM is Not FPM - a simple deb, rpm and apk packager written in Go.

+

NFPM is a simple, 0-dependencies, deb, rpm and apk packager.

Release Software License 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 " -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/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") + }) + } +} 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 " +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` or `.rpm` from the [releases page][releases] and -install with `dpkg -i` and `rpm -i` respectively. +Download the `.deb`, `.rpm` or `.apk` from the [releases page][releases] and install them with the appropriate tools. -**Shell script**: +**shell script**: -```console -$ curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh +```sh +curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh +``` + +**go install**: + +```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). + + + +## 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 @@ -10,9 +33,7 @@ Does your company use goreleaser? Help keep the project bug-free and feature ric -## Backers - -Love our work and community? [Become a backer](https://opencollective.com/goreleaser). +### Backers 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