Skip to content

Commit

Permalink
Update the configureation and main fx code.
Browse files Browse the repository at this point in the history
  • Loading branch information
schmidtw committed Sep 24, 2023
1 parent e418b25 commit 20624ee
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 130 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ go.work
xmidt-agent

internal/jwtxt/cmd/example/*

*.dot
72 changes: 71 additions & 1 deletion config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,79 @@

package main

import "github.com/xmidt-org/sallust"
import (
"fmt"
"os"

"github.com/goschtalt/goschtalt"
"github.com/xmidt-org/sallust"
"gopkg.in/dealancer/validate.v2"
)

type Config struct {
SpecialValue string
Logger sallust.Config
}

// Collect and process the configuration files and env vars and
// produce a configuration object.
func provideConfig(cli *CLI) (*goschtalt.Config, error) {
gs, err := goschtalt.New(
goschtalt.StdCfgLayout(applicationName, cli.Files...),
goschtalt.ConfigIs("two_words"),
goschtalt.DefaultUnmarshalOptions(
goschtalt.WithValidator(
goschtalt.ValidatorFunc(validate.Validate),
),
),

// Seed the program with the default, built-in configuration.
// Mark this as a default so it is ordered correctly.
goschtalt.AddValue("built-in", goschtalt.Root, defaultConfig,
goschtalt.AsDefault()),
)
if err != nil {
return nil, err
}

Check warning on line 39 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L38-L39

Added lines #L38 - L39 were not covered by tests

if cli.Show {
// handleCLIShow handles the -s/--show option where the configuration is
// shown, then the program is exited.
//
// Exit with success because if the configuration is broken it will be
// very hard to debug where the problem originates. This way you can
// see the configuration and then run the service with the same
// configuration to see the error.

fmt.Fprintln(os.Stdout, gs.Explain().String())

out, err := gs.Marshal()
if err != nil {
fmt.Fprintln(os.Stderr, err)

Check warning on line 54 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L54

Added line #L54 was not covered by tests
} else {
fmt.Fprintln(os.Stdout, "## Final Configuration\n---\n"+string(out))
}

os.Exit(0)
}

var tmp Config
err = gs.Unmarshal(goschtalt.Root, &tmp)
if err != nil {
fmt.Fprintln(os.Stderr, "There is a critical error in the configuration.")
fmt.Fprintln(os.Stderr, "Run with -s/--show to see the configuration.")
fmt.Fprintf(os.Stderr, "Error: %v\n", err)

// Exit here to prevent a very difficult to debug error from occurring.
os.Exit(0)
}

return gs, nil
}

// -----------------------------------------------------------------------------
// Keep the default configuration at the bottom of the file so it is easy to
// see what the default configuration is.
// -----------------------------------------------------------------------------

var defaultConfig = Config{}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ require (
github.com/xmidt-org/wrp-go/v3 v3.2.0
go.uber.org/fx v1.20.0
go.uber.org/zap v1.26.0
gopkg.in/dealancer/validate.v2 v2.1.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/goschtalt/approx v1.0.0 // indirect
github.com/leodido/go-urn v1.1.0 // indirect
github.com/miekg/dns v1.1.25 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE
github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
Expand All @@ -30,6 +31,8 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg=
github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
Expand All @@ -40,6 +43,8 @@ github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef h1:NKxTG6GVGbfMXc2m
github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef/go.mod h1:tcaRap0jS3eifrEEllL6ZMd9dg8IlDpi2S1oARrQ+NI=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
Expand Down Expand Up @@ -86,6 +91,8 @@ gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/dealancer/validate.v2 v2.1.0 h1:XY95SZhVH1rBe8uwtnQEsOO79rv8GPwK+P3VWhQfJbA=
gopkg.in/dealancer/validate.v2 v2.1.0/go.mod h1:EipWMj8hVO2/dPXVlYRe9yKcgVd5OttpQDiM1/wZ0DE=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
5 changes: 5 additions & 0 deletions invalid.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-FileCopyrightText: 2023 Comcast Cable Communications Management, LLC
# SPDX-License-Identifier: Apache-2.0
---
invalid:
invalid: invalid
114 changes: 38 additions & 76 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,28 +36,28 @@ var (
type CLI struct {
Dev bool `optional:"" short:"d" help:"Run in development mode."`
Show bool `optional:"" short:"s" help:"Show the configuration and exit."`
Graph string `optional:"" short:"g" help:"Output the dependency graph to the specified file."`
Files []string `optional:"" short:"f" help:"Specific configuration files or directories."`
}

// xmidiAgent is the main entry point for the program. It is responsible for
// setting up the dependency injection framework and invoking the program.
func xmidtAgent(args []string) error {
// xmidtAgent is the main entry point for the program. It is responsible for
// setting up the dependency injection framework and returning the app object.
func xmidtAgent(args []string) (*fx.App, error) {
var (
gscfg *goschtalt.Config

// Capture if the program is being run in dev mode so the extra stuff
// is output as requested.
dev devMode
// Capture the dependency tree in case we need to debug something.
g fx.DotGraph

// Capture if the program should gracefully exit early & without
// reporting an error via logging.
early earlyExit
// Capture the command line arguments.
cli *CLI
)

app := fx.New(
fx.Supply(cliArgs(args)),
fx.Supply(&early),
fx.Supply(&dev),
fx.Populate(&g),
fx.Populate(&gscfg),
fx.Populate(&cli),

fx.WithLogger(func(log *zap.Logger) fxevent.Logger {
return &fxevent.ZapLogger{Logger: log}
Expand All @@ -66,92 +66,58 @@ func xmidtAgent(args []string) error {
fx.Provide(
provideCLI,
provideLogger,

// Collect and process the configuration files and env vars and
// produce a configuration object.
func(cli *CLI) (*goschtalt.Config, error) {
return goschtalt.New(
goschtalt.StdCfgLayout(applicationName, cli.Files...),
goschtalt.ConfigIs("two_words"),

// Seed the program with the default, built-in configuration
goschtalt.AddValue("built-in", goschtalt.Root,
Config{
SpecialValue: "default",
},
goschtalt.AsDefault(), // Mark this as a default so it is ordered correctly
),
)
},
provideConfig,

goschtalt.UnmarshalFunc[sallust.Config]("logger", goschtalt.Optional()),
),

fx.Invoke(
handleCLIShow,
func(gs *goschtalt.Config) {
gscfg = gs
},
),
fx.Invoke(),
)

if dev {
defer func() {
fmt.Fprintln(os.Stderr, gscfg.Explain().String())
}()
if cli != nil && cli.Graph != "" {
_ = os.WriteFile(cli.Graph, []byte(g), 0600)
}

if err := app.Err(); err != nil || early {
return err
if err := app.Err(); err != nil {
return nil, err

Check warning on line 82 in main.go

View check run for this annotation

Codecov / codecov/patch

main.go#L82

Added line #L82 was not covered by tests
}

app.Run()

return nil
return app, nil
}

func main() {
err := xmidtAgent(os.Args[1:])

app, err := xmidtAgent(os.Args[1:])

Check warning on line 89 in main.go

View check run for this annotation

Codecov / codecov/patch

main.go#L89

Added line #L89 was not covered by tests
if err == nil {
app.Run()

Check warning on line 91 in main.go

View check run for this annotation

Codecov / codecov/patch

main.go#L91

Added line #L91 was not covered by tests
return
}

fmt.Fprintln(os.Stderr, err)
os.Exit(-1)
}

// Provides a named type so it's a bit easier to flow through & use in fx.
type earlyExit bool

// Provides a named type so it's a bit easier to flow through & use in fx.
type devMode bool

// Provides a named type so it's a bit easier to flow through & use in fx.
type cliArgs []string

// handleCLIShow handles the -s/--show option where the configuration is shown,
// then the program is exited.
func handleCLIShow(cli *CLI, cfg *goschtalt.Config, early *earlyExit) {
if !cli.Show {
return
}
// Handle the CLI processing and return the processed input.
func provideCLI(args cliArgs) (*CLI, error) {
return provideCLIWithOpts(args, false)
}

fmt.Fprintln(os.Stdout, cfg.Explain().String())
func provideCLIWithOpts(args cliArgs, testOpts bool) (*CLI, error) {
var cli CLI

out, err := cfg.Marshal()
if err != nil {
fmt.Fprintln(os.Stderr, err)
} else {
fmt.Fprintln(os.Stdout, "## Final Configuration\n---\n"+string(out))
}
// Create a no-op option to satisfy the kong.New() call.
var opt kong.Option = kong.OptionFunc(
func(*kong.Kong) error {
return nil
},
)

*early = earlyExit(true)
}
if testOpts {
opt = kong.Writers(nil, nil)
}

// Handle the CLI processing and return the processed input.
func provideCLI(args cliArgs, dev *devMode, early *earlyExit) (*CLI, error) {
var cli CLI
parser, err := kong.New(&cli,
kong.Name(applicationName),
kong.Description("The cpe agent for Xmidt service.\n"+
Expand All @@ -161,25 +127,21 @@ func provideCLI(args cliArgs, dev *devMode, early *earlyExit) (*CLI, error) {
fmt.Sprintf("\tBuilt By: %s\n", builtBy),
),
kong.UsageOnError(),
opt,
)
if err != nil {
return nil, err
}

parser.Exit = func(i int) {
// Exit early on error, but we still need to return the CLI object
// otherwise fx will complain & hide the useful message we want to print.
*early = earlyExit(true)
if testOpts {
parser.Exit = func(_ int) { panic("exit") }
}

fmt.Printf("parser: %p\n", parser)
_, err = parser.Parse(args)
if err != nil {
parser.FatalIfErrorf(err)
}

// Mark the devMode state so the collector can be output
*dev = devMode(cli.Dev)
return &cli, nil
}

Expand Down
Loading

0 comments on commit 20624ee

Please sign in to comment.