A target is any exported function that has an optional first argument of context.Context, has either
no return or just an error return, and where the arguments are all of type string, int, float64, bool, or
time.Duration. Pointer types of these (*string, *int, *float64, *bool, *time.Duration) are
also accepted and treated as optional arguments (see Optional Arguments below). A target
may end with one ...string argument, which receives the remaining command-line tokens. Pointer-style optional
arguments may precede that variadic argument.
e.g. these are all acceptable targets
func Build()
func Install(ctx context.Context) error
func Run(what string) error
func Exec(ctx context.Context, name string, count int, debug bool, timeout time.Duration) error
func Greet(name string, greeting *string)
func RunAll(ctx context.Context, prefix string, args ...string) error
func RunWithOptions(ctx context.Context, prefix *string, args ...string) error
A target is effectively a subcommand of mage while running mage in
this directory. i.e. you can run a target by running mage <target>
Arguments aside from context are taken from the CLI arguments after the target name.
string is passed as-is, int are converted with strconv.Atoi, bool are converted with
strconv.ParseBool, and time.Duration are converted with time.ParseDuration.
Thus you could call Exec above by running
mage exec somename 5 true 100ms
All arguments are mandatory and must be specified in the order they appear in the function.
You can intersperse multiple targets with arguments as you’d expect:
mage run foo.exe exec somename 5 true 100ms
A target may declare one terminal ...string argument. After Mage consumes the
target’s fixed arguments and any pointer-style optional flags, it passes the
variadic tail unchanged and in order. The variadic argument may be empty.
func Run(prefix string, args ...string) {
fmt.Printf("prefix=%s args=%q\n", prefix, args)
}
$ mage run go test ./... -race
prefix=go args=["test" "./..." "-race"]
A variadic target is terminal for that Mage invocation. Fixed-arity targets may
run before it, but tokens after its name and fixed arguments are never parsed as
later targets—even when a token matches another target name. Tokens beginning
with -, including --, are ordinary values for a variadic target without
pointer-style optional arguments.
When a variadic target has pointer-style optional arguments, Mage parses its
optional flags before starting the variadic tail. The first non-option token
starts the tail implicitly. If the first tail token begins with -, use -- to
end option parsing explicitly; that separator is omitted, and every later token
is passed through unchanged. See Flags for examples and the
exact scope of this separator.
The function signature is the argument-ownership boundary. Mage does not guess
the boundary from known target names, require a global -- separator, or expose
the remaining values through a global or shared extra-arguments accessor. This
keeps a command’s meaning stable when other targets are added or renamed.
This support makes existing exported functions ending in ...string, including
functions that combine pointer-style optional arguments with ...string,
visible as targets. Such functions can now appear in mage -l and mage -h,
and can expose an existing case-insensitive target or alias name conflict.
Rename an exported helper or make it unexported if it is not intended to be a
Mage target.
Variadic arguments of other types are not targets.
You can define flags (optional arguments) by using pointer types for any of the
supported argument types (*string, *int, *float64, *bool,
*time.Duration). Optional arguments are passed on the command line using
-name=value syntax, where name is the Go parameter name (case-insensitive).
If an optional argument is not provided, the pointer will be nil.
For *bool parameters, you can use the shorthand -name without a value,
which is equivalent to -name=true.
func Greet(name string, greeting *string) {
if greeting != nil {
fmt.Printf("%s, %s!\n", *greeting, name)
} else {
fmt.Printf("Hello, %s!\n", name)
}
}
You can call this target with or without the optional argument:
$ mage greet World
Hello, World!
$ mage greet World -greeting=Hi
Hi, World!
Optional arguments can be mixed freely with required arguments in the function
signature. Required arguments are always positional, while optional arguments use
the -name=value flag syntax and can appear in any order after the required
arguments.
An optional target may also end with a terminal ...string argument:
func Run(ctx context.Context, name string, verbose *bool, args ...string) error {
verboseValue := "<nil>"
if verbose != nil {
verboseValue = fmt.Sprint(*verbose)
}
fmt.Printf("name=%s verbose=%s args=%q\n", name, verboseValue, args)
return nil
}
The first non-option token starts the variadic tail, so flags must come first. Once the tail starts, Mage preserves every remaining token without trying to parse more flags or targets:
$ mage run worker -verbose input.txt -literal build
name=worker verbose=true args=["input.txt" "-literal" "build"]
If the tail itself must start with a token beginning in -, place a literal
-- before it. The first -- ends option parsing and is not passed to the
target; everything after it, including unknown flags, repeated -- tokens, and
target names, is passed unchanged:
$ mage run worker -- -literal -- build
name=worker verbose=<nil> args=["-literal" "--" "build"]
Before that boundary, unknown or malformed options retain the usual target
option errors. This target-level -- is recognized only while a target that
combines pointer-style optional arguments and ...string is parsing options.
For a variadic target without optional arguments, -- remains an ordinary
variadic value. Non-variadic targets retain their existing option-error or
subsequent-target dispatch behavior.
If the function has an error return, errors returned from the function will print to stdout and cause the magefile to exit with an exit code of 1. Any functions that do not fit this pattern are not considered targets by mage.
A target may be designated the default target, which is run when the user runs
mage with no target specified. To denote the default, create a var Default = <targetname> If no default target is specified, running mage with no target
will print the list of targets, like mage -l.
Multiple targets can be specified as args to Mage, for example mage foo bar baz. Targets will be run serially, from left to right (so in this case, foo,
then once foo is done, bar, then once bar is done, baz). Dependencies run using
mg.Deps will still only run once per mage execution, so if each of the targets
depend on the same function, that function will only be run once for all
targets. If any target panics or returns an error, no later targets will be run.
Because a variadic target consumes every remaining token, it must be the final
target in a multiple-target invocation.
A default context is passed into any target with a context argument. This context will have a timeout if mage was run with -t, and thus will cancel the running targets and dependencies at that time. To pass this context to dependencies, use mg.CtxDeps(ctx, …) to pass the context from the target to its dependencies (and pass the context to sub-dependencies). Dependencies run with mg.Deps will not get the starting context, and thus will not be cancelled when the timeout set with -t expires.
mg.CtxDeps will pass along whatever context you give it, so if you want to modify the original context, or pass in your own, that will work like you expect it to.
Target aliases can be specified using the following notation:
var Aliases = map[string]interface{} {
"i": Install,
"build": Install,
"ls": List,
}
The key is an alias and the value is a function identifier. An alias can be used interchangeably with it’s target.
Namespaces are a way to group related commands, much like subcommands in a
normal application. To define a namespace in your magefile, simply define an
exported named type of type mg.Namespace. Then, every method on that type which
matches the normal target signature becomes a target under that namespace.
import "github.com/magefile/mage/mg"
type Build mg.Namespace
// Builds the site using hugo.
func (Build) Site() error {
return nil
}
// Builds the pdf docs.
func (Build) Docs() {}
To call a namespaced target, type it as namespace:target. For example, the
above would be called by typing
$ mage build:site
Similarly, the help for the target will show how it may be called:
$ mage -l
build:docs Builds the pdf docs.
build:site Builds the site using hugo.