With Store
tiny2 Example
By integrated with hedzr/store1, your app can manage its configuration dataset seamlessly and fluently.
In tiny1 example app, A DummyStore will be created by cmdr internally, which receives any accessing requests to app configuration dataset, and discard them.
As above, we adds the integration to Store
(hedzr/store), which provides a powerful in-memory hierarchical configuration store.
The multilevel subcommands jump
> to
was been also added.
hedzr/cmdr-loaders
provides a cmdr.Create()
-like API (lite.Create()
) with further support to TOML and JSON file formats. It will load those configuration files from standard locations compliant with GNU File strandard and Unix File specification, ....
hedzr/cmdr-loaders
is similar with it but has more codecs, such as for YAML, for HCL, and so on. This helper module would import more third-party packages into your project.
On the above, lite.PrepareApp()
or loaders.PrepareApp()
provides more wrapper codes.
All purposes of these helpers are:
- integrated with
store.Store
, - integrated with default loaders so the OS env and disk files can be loaded automatically,
- flatten the basis of an app such as app name, author and others.
In total, lite.Create()
is first of our recommended list, else are cmdr.Create()
or loaders.Create()
.
When a step by step initializing style is what you desire, please use cmdr.New()
.
Howto integrate Store
and loaders
manually
This is a sample code to show how to integrate Store
and loaders
manually, which is similar with lite.Create()
or loaders.Create()
.
Associate your logics with OnAction
handler
The OnAction
handler is a callback function that will be executed when the command is invoked. It is a good place to put your business logic.
The normally usage is to attach it to the end of a command building sequence, like this:
We do not recommend to use OnAction
on the jump
command, because it is a multi-level subcommand. The end users won't realize that jump
can be executed directly, as it is not the final command they are interested in.
Instead, it is better to use OnAction
on the to
command, which is the final command that will be executed.
cmd.Store()
vs cmd.Set()
cmd.Store()
vs cmd.Set()
Programmatically, you can code with app.Store()/app.Set()
.
The cmd.Store()
returns a subset of app's whole Store, which have a root key pointed to key path app.cmd.jump.to
. That means, cmd.Store().MustBool("full")
can read and write the state of a command line flag --full
.
The cmd.Set()
returns the app's whole Store, which equals to app.Set()
,So you need a cmd.Set().MustBool("app.cmd.jump.to.full")
to access the state of --full
. Another way is,
The similar call to app.Store()
will get a subtree pointed to app.cmd
, which stores the values of all of command-line flags. So app.Store().MustBool("jump.to.full")
can query the same key above.
For a short and concise calling statement, it's useful by using GetXXX
/MustXXX
on the object of cmd.Store()
/app.Store()
.
The prefix app.cmd
is used for serializing the Option Store
, such as YAML, TOML, etc.. The notable point is app
will be stripped when you're really serializing it. So a key app.some.path.debug
will be stored as some.path.debug
in a YAML file:
As a sample, here is a Store's YAML file content:
Build()
and `With(cb)
As a Builder Pattern, Build()
will end a building sequence in app/b.Cmd("long","short",...)...Build()
.
But you can always end the building sequence by With(cb)
call, the form is app/b.Cmd("long","short",...)...With(cb)
.
In With(cb)
code block of jump
, to
subcommand was been created and attached to.
Similar with it, inside With(cb)
block of to
, full
option was been attached to.
So a end-user can type tiny2 jump to --full
in shell to enable it.
In OnAction(cb)
code block, --full
enables dumping the internal Store
data structure to console. Just like this following,
Operate to Store
In this above tree structure,
app.cmd
subtree includes the mapping to the cmdline options
and its final value of tiny2
app.
Also, you can read/write the configuration key and value by
app.Store()/app.Set()
.
As a shortcut, you can use cmd.Store()
and cmd.Set()
in
the OnAction
handler func.
cmd.Store()
will return a reference to its associating subtree
in the whole Store. So cmd.Store().MustBool("full")
would
access the final value of full
option.
cmd.Set()
returns the whole Store, just like app.Set().
Use it you can pass key path as cmd.Set().MustBool("app.cmd.jump.to.full")
to get the value of full
option.
app.Set()
is like above, a uncut complete store will be given to you.
app.Store()
returns the subtree to app.cmd
, so you can
inspect the values of cmdline options in a better way.
For example, app.Store().MustBool("jump.to.full")
is
whether a end-user input --full
at least once at command
line or not.
Accessing an integer value by cmd.MustInt("option-long-name")
, or
a time duration value by `cmd.MustDuration("option-long-name"),
and so on.
Load external sources
you may load configuration dataset from external sources, such as a .toml file, a .yaml file, or a remote config center like consul or etcd.
We will discuss it at next section.
App ret-code
The subcommand to
shows you how to terminate the app and
exit to OS with a ret code.
To mark a ret code, invoking app.SetSuggestRetCode(retCode)
.
It will be retrieved at main()
function later.
main()
will use the code to exit to OS, by invoking os.Exit(app.SuggestRetCode())
.
Why so complex?
A incorrect way is exiting at anywhere
.
For a service app or anyelse, you should end a program normally with graceful cleanup,
which means, the executing step will end at end of main()
. Thus the running go routines,
opened resources, connections will be shut down gracefully.
As a best practise, marking ret code with app.SetSuggestRetCode(retCode)
,
and returning to main()
by return err
deeply,
so any cleanup codes has chances to be called,
now you can end the program with os.Exit(app.SuggestRetCode())
finally,
which will notify the ret code to OS.
Footnotes
-
hedzr/store
is a high-performance configure management library. ↩
How is this guide?
Last updated on