icns

Easily create .icns files (Mac Icons) with this Go library or the included CLI.
Log | Files | Refs | LICENSE

commit dba92d5ad3f0a327a0859aa9761b55ca6c7ec4f2
parent 3b4821d79893d224c913cde00ad30af47ed11431
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date:   Wed, 16 Sep 2026 21:44:44 -0400

cmd/icnsify: use the standard flag package

pflag is small, but once the CLI shares the library's module every dependency
appears in library consumers' module graphs. The standard package already
accepts both -input and --input, and registering a short alias per option
preserves the existing -i, -o and -r spellings.

Diffstat:
Mcmd/icnsify/doc.go | 49++++++++++++++++++++++++++++++++++++++++---------
Mcmd/icnsify/go.mod | 1-
Mcmd/icnsify/main.go | 37++++++++++++++-----------------------
3 files changed, 54 insertions(+), 33 deletions(-)

diff --git a/cmd/icnsify/doc.go b/cmd/icnsify/doc.go @@ -1,21 +1,52 @@ package main import ( + "flag" "fmt" - - "github.com/spf13/pflag" + "strconv" ) +// version is stamped by goreleaser at build time. var version = "master" -func usage() { - fmt.Printf("\n") - pflag.Usage() - fmt.Printf(` -You can also pipe to stdin and from stdout. -The pipes will be detected automatically, and both --input and --output will be ignored. +// option records a flag registered under a long and a short name so usage +// can list each one once, GNU style, instead of twice as PrintDefaults would. +type option struct { + long, short string + def, usage string +} - cat icon.png | icnsify > icon.icns +var options []option + +// stringFlag registers a string option reachable as --long or -short. +func stringFlag(p *string, long, short, def, usage string) { + flag.StringVar(p, long, def, usage) + flag.StringVar(p, short, def, usage) + options = append(options, option{long: long, short: short, def: def, usage: usage}) +} + +// intFlag registers an integer option reachable as --long or -short. +func intFlag(p *int, long, short string, def int, usage string) { + flag.IntVar(p, long, def, usage) + flag.IntVar(p, short, def, usage) + options = append(options, option{long: long, short: short, def: strconv.Itoa(def), usage: usage}) +} + +func usage() { + w := flag.CommandLine.Output() + fmt.Fprintf(w, "icnsify %s\n\nUsage: icnsify [-i input] [-o output] [-r quality]\n\nOptions:\n", version) + for _, o := range options { + fmt.Fprintf(w, " -%s, --%s\n %s", o.short, o.long, o.usage) + if o.def != "" && o.def != "0" { + fmt.Fprintf(w, " (default %s)", o.def) + } + fmt.Fprintln(w) + } + fmt.Fprint(w, ` +You can also pipe to stdin and from stdout. Pipes are detected automatically +when --input is not given, and --output is then ignored. + cat icon.png | icnsify > icon.icns + cat icon.icns | icnsify > icon.png `) } diff --git a/cmd/icnsify/go.mod b/cmd/icnsify/go.mod @@ -4,7 +4,6 @@ go 1.21.5 require ( github.com/jackmordaunt/icns/v4 v4.0.0 - github.com/spf13/pflag v1.0.5 ) require ( diff --git a/cmd/icnsify/main.go b/cmd/icnsify/main.go @@ -3,6 +3,7 @@ package main import ( "bytes" "errors" + "flag" "fmt" "image" "image/jpeg" @@ -14,8 +15,6 @@ import ( "strings" "github.com/jackmordaunt/icns/v4" - - "github.com/spf13/pflag" ) // errUsage signals that no work was requested; usage has been printed. @@ -32,26 +31,18 @@ func main() { func run() error { var ( - inputPath = pflag.StringP( - "input", - "i", - "", - "Input image for conversion to icns from jpg|png or visa versa.", - ) - outputPath = pflag.StringP( - "output", - "o", - "", - "Output path, defaults to <path/to/image>.(icns|png) depending on input.", - ) - resize = pflag.IntP( - "resize", - "r", - 5, - "Quality of resize algorithm. Values range from 0 to 5, fastest to slowest execution time. Defaults to slowest for best quality.", - ) + inputPath string + outputPath string + resize int ) - pflag.Parse() + stringFlag(&inputPath, "input", "i", "", + "Input image for conversion to icns from jpg|png or vice versa.") + stringFlag(&outputPath, "output", "o", "", + "Output path, defaults to <path/to/image>.(icns|png) depending on input.") + intFlag(&resize, "resize", "r", 5, + "Quality of resize algorithm, 0 to 5 from fastest to slowest.") + flag.Usage = usage + flag.Parse() var ( input io.Reader @@ -60,13 +51,13 @@ func run() error { // An explicit --input wins; otherwise a non-terminal stdin means we are // part of a pipeline and both paths are ignored. piping := false - if *inputPath == "" { + if inputPath == "" { var err error if piping, err = stdinIsPipe(); err != nil { return err } } - in, out, algorithm := sanitiseInputs(*inputPath, *outputPath, *resize) + in, out, algorithm := sanitiseInputs(inputPath, outputPath, resize) if piping { input, output = os.Stdin, os.Stdout } else {