This commit is contained in:
Arpad Ryszka 2026-01-07 20:12:19 +01:00
parent dd6be747c6
commit 0fbd63dff3
9 changed files with 194 additions and 5 deletions

View File

@ -28,17 +28,17 @@ fmt: $(sources) iniparser.gen.go docreflect.gen.go
go fmt ./...
iniparser.gen.go: ini.treerack
go run script/ini-parser/parser.go wand < ini.treerack > iniparser.gen.go || rm -f iniparser.gen.go
go run internal/script/ini-parser/parser.go wand < ini.treerack > iniparser.gen.go || rm -f iniparser.gen.go
docreflect.gen.go: $(sources)
go run script/docreflect/docs.go \
go run internal/script/docreflect/docs.go \
wand \
code.squareroundforest.org/arpio/wand/tools \
> docreflect.gen.go \
|| rm -f docreflect.gen.go
docreflect_test.go: $(sources)
go run script/docreflect/docs.go \
go run internal/script/docreflect/docs.go \
wand \
code.squareroundforest.org/arpio/wand/internal/tests/testlib \
> docreflect_test.go \
@ -54,10 +54,10 @@ docreflect_test.go: $(sources)
./cmd/wand
.build/wand.1: $(sources) iniparser.gen.go docreflect.gen.go .build
go run script/man/man.go $(date) $(version) ./cmd/wand > .build/wand.1
go run internal/script/man/man.go $(date) $(version) ./cmd/wand > .build/wand.1
cmd/wand/readme.md: $(sources) docreflect.gen.go
go run script/markdown/md.go 0 ./cmd/wand > cmd/wand/readme.md
go run internal/script/markdown/md.go 0 ./cmd/wand > cmd/wand/readme.md
$(prefix)/bin:
mkdir -p $(prefix)/bin

19
example/stdlib/go.mod Normal file
View File

@ -0,0 +1,19 @@
module example/stdlib
go 1.25.4
require code.squareroundforest.org/arpio/wand v0.0.0-20260107174558-dd6be747c6ec
require (
code.squareroundforest.org/arpio/bind v0.0.0-20251105181644-3443251be2d5 // indirect
code.squareroundforest.org/arpio/docreflect v0.0.0-20251031192707-01c5ff18fab1 // indirect
code.squareroundforest.org/arpio/html v0.0.0-20251103020946-e262eca50ac9 // indirect
code.squareroundforest.org/arpio/notation v0.0.0-20251101123932-5f5c05ee0239 // indirect
code.squareroundforest.org/arpio/textedit v0.0.0-20251207224821-c75c3965789f // indirect
code.squareroundforest.org/arpio/textfmt v0.0.0-20251207234108-fed32c8bbe18 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/term v0.37.0 // indirect
)
replace code.squareroundforest.org/arpio/wand => ../..

20
example/stdlib/go.sum Normal file
View File

@ -0,0 +1,20 @@
code.squareroundforest.org/arpio/bind v0.0.0-20251105181644-3443251be2d5 h1:SIgLIawD6Vv7rAvUobpVshLshdwFEJ0NOUrWpheS088=
code.squareroundforest.org/arpio/bind v0.0.0-20251105181644-3443251be2d5/go.mod h1:tTCmCwFABKNm3PO0Dclsp4zWhNQFTfg9+uSrgoarZFI=
code.squareroundforest.org/arpio/docreflect v0.0.0-20251031192707-01c5ff18fab1 h1:bJi41U5yGQykg6jVlD2AdWiznvx3Jg7ZpzEU85syOXw=
code.squareroundforest.org/arpio/docreflect v0.0.0-20251031192707-01c5ff18fab1/go.mod h1:/3xQI36oJG8qLBxT2fSS61P5/+i1T64fTX9GHRh8XhA=
code.squareroundforest.org/arpio/html v0.0.0-20251103020946-e262eca50ac9 h1:b7voJlwe0jKH568X+O7b/JTAUrHLTSKNSSL+hhV2Q/Q=
code.squareroundforest.org/arpio/html v0.0.0-20251103020946-e262eca50ac9/go.mod h1:hq+2CENEd4bVSZnOdq38FUFOJJnF3OTQRv78qMGkNlE=
code.squareroundforest.org/arpio/notation v0.0.0-20251101123932-5f5c05ee0239 h1:JvLVMuvF2laxXkIZbHC1/0xtKyKndAwIHbIIWkHqTzc=
code.squareroundforest.org/arpio/notation v0.0.0-20251101123932-5f5c05ee0239/go.mod h1:ait4Fvg9o0+bq5hlxi9dAcPL5a+/sr33qsZPNpToMLY=
code.squareroundforest.org/arpio/textedit v0.0.0-20251207224821-c75c3965789f h1:gomu8xTD953IkL3M528qVEuZ2z93C2I6Hr4vyIwE7kI=
code.squareroundforest.org/arpio/textedit v0.0.0-20251207224821-c75c3965789f/go.mod h1:nXdFdxdI69JrkIT97f+AEE4OgplmxbgNFZC5j7gsdqs=
code.squareroundforest.org/arpio/textfmt v0.0.0-20251207234108-fed32c8bbe18 h1:2aa62CYm9ld5SNoFxWzE2wUN0xjVWQ+xieoeFantdg4=
code.squareroundforest.org/arpio/textfmt v0.0.0-20251207234108-fed32c8bbe18/go.mod h1:+0G3gufMAP8SCEIrDT1D/DaVOSfjS8EwPTBs5vfxqQg=
code.squareroundforest.org/arpio/wand v0.0.0-20260107174558-dd6be747c6ec h1:jWW2QBcMMe1VNfTGG9gSJAE7x4ynvhEp0riJ7sLA7MM=
code.squareroundforest.org/arpio/wand v0.0.0-20260107174558-dd6be747c6ec/go.mod h1:rYqrSmdkBlKjGwEPzzWAIRQKQJCpkdzG7vDiL6Fux9Y=
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=

10
example/stdlib/split.go Normal file
View File

@ -0,0 +1,10 @@
package main
import (
"strings"
"code.squareroundforest.org/arpio/wand"
)
func main() {
wand.Exec(strings.Split)
}

140
readme.md
View File

@ -1,3 +1,143 @@
# Wand
Wand is a library to wrap Go functions as executable binaries. It supports:
- hierarch of subcommands
- binding of command line options
- binding of environment variables
- binding of configuration entries
- positional arguments
- automatically generated help and documentation from go doc
## Example:
```
package main
import (
"strings"
"code.squareroundforest.org/arpio/wand"
)
func main() {
wand.Exec(strings.Split)
}
```
## Lib docs:
- [./lib.go](./lib.go)
- [go docs html](https://godocs.io/code.squareroundforest.org/arpio/wand)
## wand tool
The wand tool helps with following tasks:
- generating code from the go doc of the library that is converted by the wand library into an executable binary
- generating man(roff) or markdown documentation
- executing arbitrary Go functions in the command line addressed by their go path
Generating code with the docs of the wrapped library is particularly useful, because this way the automatically
generated help can be based on the go docs. This is an important part of the attempt to achieve that ideal
situation, where a solution to a problem is presented both as a library and a command line tool, and there is
only a single place ("source of truth") of documentation.
Executing arbitrary Go functions in the command line is only a lucky side effect of the way wand was built.
While it's not the primary function of the tool, it can be useful when just quickly trying out some Go functions
or expressions, without having to create a throwaway main.go file.
### wand tool installation
```
sudo make install
```
or in the current user's home:
```
prefix=~/.local make install
```
(See the recommended way below on how to use the locked version in the build tooling of a project.)
tool usage: docreflect for lib and man for cmd
### wand tool usage
Let's consider a project hierarchy such as in the root we have a library (mylib), and in the ./cmd directory we
have a main package, wrapping one or more functions of that library with wand as an executable binary:
```
./cmd/main.go
./lib.go
```
Generating the compiled docs from go doc of a library:
```
wand docreflect mylib .
```
Generating a man page for the command:
```
wand manpages --date-string $(2026-01-07) --version v1.0.0 ./cmd
```
### wand tool bonus usage
```
wand --import strings strings.Split 1:2:3 :
```
### wand tool docs
- [./cmd/readme.md](./cmd/readme.md)
When installed:
```
man wand
```
When not installed with man pages:
```
wand help
```
### wand tool usage with go.mod version
When generating the docs for a shared project, we may want to ensure that always the same version of wand is
used for both docreflect and manpages. Best is to use the version that is defined in go.mod. This can be
achieved using trivial scripts, the example below showing docreflect:
```
package main
import (
"code.squareroundforest.org/arpio/wand/tools"
"log"
"os"
)
func main() {
if len(os.Args) < 2 {
log.Fatalln("expected package name")
}
if err := tools.Docreflect(os.Stdout, os.Args[1], os.Args[2:]...); err != nil {
log.Fatalln(err)
}
}
```
and calling it, e.g. from a Makefile, with go run like:
```
go run script/gendocs.go mylib . gopath.to/me/mylib > docs.gen.go
```
---
*Made in Berlin, DE*