## X-Flags

## What does this library?

This library provides a simple way to use flags in your application. It extends the standard library
to be able to define and use a structure with flags.

It supports:

* [X]  Define flags in a structure
* [X]  Define callbacks for flags
* [X]  Define default values for flags
* [X]  Define aliases for flags
* [X]  Define required flags

## Installation

```shell
go get gitlab.schukai.com/oss/libraries/go/network/xflags
```

**Note:** This library uses [Go Modules](https://github.com/golang/go/wiki/Modules) to manage dependencies.

## Usage

### Initialize

A new flag set is created using the `xflags.New()` function. 
The structure passed is used as the type for the flags.

```go
package main

import (
	"fmt"
	"os"
	"gitlab.schukai.com/oss/libraries/go/network/xflags"
)

```

### Definition

The flags are defined in the structure. The structure can be nested.
The name of the field is used as the name of the flag. The type of the
field is used as the type of the flag.

```go
type Definition struct {
  Verbose bool `short:"v" long:"verbose" description:"Show verbose debug information"`
  Serve   struct {
    Host string `short:"h" long:"host" description:"Host to bind to" default:"localhost"`
    Port int    `short:"p" long:"port" description:"Port to bind to" default:"8080"`
  } `command:"serve" description:"Run the HTTP server" call:"DoServe"`
}
```

The following tags are supported:

| Tag           | Context | Description                                |
|---------------|---------|--------------------------------------------|
| `short`       | Value   | Short name of the flag.                    |
| `long`        | Value   | Long name of the flag.                     |
| `description` | Value   | Description of the flag.                   |
| `required`    | Value   | Flag is required.                          |
| `shadow`      | Value | Copy the value to the shadow structure.    |
| `command`     | Command | Flag is a command.                         |
| `call`        | Command | Function to call when the command is used. |
| `ignore`      | -/-     | Property is ignored.                       |

### Callbacks

The functions are called up with a receiver. The receiver is the
configuration. The function must have the following signature: 
`func (d *Definition) DoServe(s *setting[Definition])`

Let's assume we have the above definition. The Property `Serve` contains
the command `serve`. Furthermore, the command has the tag `call` with
the value `DoServe`. The function `DoServe` is called when the command
`serve` is used.

Important: The function must be exported, that means it 
must start with a capital letter.

The function is called with the receiver `*Definition`

An example for the function `DoServe`:

```go
func (d *Definition) DoServe(_ *setting[Definition]) {
   fmt.Printf("Serving on %s:%d", d.Serve.Host, d.Serve.Port)
}
```

In this example, the function is called with the receiver `*Definition`.
The function is called with the setting `*setting[Definition]`. The
setting is used to get the values of the flags. But in this example, we
don't need the setting. So we use the underscore `_` to ignore the
setting.

### New Setting

The function `New` creates a new setting for the given
definition. The function returns a pointer to the setting.
The first argument is a name for the setting. The second argument is the
definition.

A good choice for the name is the argument `os.Args[0]`.

```go
setting := New(os.Args[0], Definition{})
```

### Parse

The flags are parsed using the `Parse()` function. The function returns
the command and the setting. The command is the name of the command
which was used. The setting is the setting of the flags.

```go
setting.Parse(os.Args[1:])
```

For testing, you can use the following arguments:

```go
setting.Parse([]string{"--verbose", "serve", "--host", "localhost", "--port", "8080"})
```

### Get Values

The values of the flags are available in the setting. The values are
available in the structure. The structure is the same as the definition.

```go
fmt.Printf("Host: %s", setting.GetValues().Serve.Host)
fmt.Printf("Port: %d", setting.GetValues().Serve.Port)
```

### Execute

The function `Execute()` executes the command. See the section
[Callbacks](#callbacks) for more information.

```go
setting.Execute()
```

### Shadow

The shadow structure is used to copy the values of the flags to the
shadow structure. The shadow structure is set using the `SetShadow()`
and configured using the tag `shadow`.

```go
type Shadow struct {
  Verbose bool
  Serve   struct {
    Host string
    Port int
  }
}

func main() {
  setting := New(os.Args[0], Definition{})
  setting.SetShadow(Shadow{})
  setting.Parse(os.Args[1:])
  setting.Execute()
  fmt.Printf("Shadow: %+v", setting.GetShadow())
}
```

### Arguments

the free arguments can be fetched with the method `Args()`.

### Check Status

The execution result can be queried with the functions:

- `HelpRequested() bool`
- `WasExecuted() bool`
- `Error() error`
- `MissingCommand() bool`

## Contributing

Merge requests are welcome. For major changes, please open an issue first to discuss what
you would like to change. **Please make sure to update tests as appropriate.**

Versioning is done with [SemVer](https://semver.org/).
Changelog is generated with [git-chglog](https://github.com/git-chglog/git-chglog#git-chglog)

Commit messages should follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification.
Messages are started with a type, which is one of the following:

- **feat**: A new feature
- **fix**: A bug fix
- **doc**: Documentation only changes
- **refactor**: A code change that neither fixes a bug nor adds a feature
- **perf**: A code change that improves performance
- **test**: Adding missing or correcting existing tests
- **chore**: Other changes that don't modify src or test files

The footer would be used for a reference to an issue or a breaking change.

A commit that has a footer `BREAKING CHANGE:`, or appends a ! after the type/scope,
introduces a breaking API change (correlating with MAJOR in semantic versioning).
A BREAKING CHANGE can be part of commits of any type.

the following is an example of a commit message:

```text
feat: add 'extras' field
```

## License

[AGPL-3.0](https://choosealicense.com/licenses/agpl-3.0/)