conf: add pretty printing,raw conf, conf tests
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
* also, set debug logger directly in config if devel mode is set * add new flag to indicate whether the passed config is path or raw config
This commit is contained in:
parent
2a56ba3456
commit
dfdcc77737
@ -1,6 +1,12 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.dotya.ml/mirre-mt/pcmt/slogging"
|
"git.dotya.ml/mirre-mt/pcmt/slogging"
|
||||||
"github.com/philandstuff/dhall-golang/v6"
|
"github.com/philandstuff/dhall-golang/v6"
|
||||||
)
|
)
|
||||||
@ -15,15 +21,72 @@ type Config struct {
|
|||||||
SessionCookieSecret string
|
SessionCookieSecret string
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadConfig(path string) (*Config, error) {
|
func LoadConfig(conf string, isPath bool) (*Config, error) {
|
||||||
var config Config
|
var config Config
|
||||||
|
|
||||||
err := dhall.UnmarshalFile(path, &config)
|
var err error
|
||||||
|
|
||||||
|
if isPath {
|
||||||
|
slogging.GetLogger().Debug("config from file")
|
||||||
|
|
||||||
|
err = dhall.UnmarshalFile(conf, &config)
|
||||||
|
} else {
|
||||||
|
slogging.GetLogger().Debug("config raw from cmdline")
|
||||||
|
|
||||||
|
err = dhall.Unmarshal([]byte(conf), &config)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
slogging.GetLogger().Debugf("parsed config: %+v", config)
|
if config.DevelMode {
|
||||||
|
_ = slogging.SetLevel(slogging.LevelDebug)
|
||||||
|
|
||||||
|
slogging.GetLogger().Debugf("parsed config: %+v", config)
|
||||||
|
|
||||||
|
if dhallCmdExists() {
|
||||||
|
_ = prettyPrintConfig(conf, isPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &config, nil
|
return &config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prettyPrintConfig(conf string, isPath bool) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if isPath {
|
||||||
|
cmd = exec.CommandContext(ctx, "/bin/sh", "-c", "dhall --file "+conf) //nolint:gosec
|
||||||
|
} else {
|
||||||
|
cmd = exec.CommandContext(ctx, "/bin/sh", "-c", "dhall <<< \""+conf+"\"") //nolint:gosec
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
slogging.GetLogger().Debug("could not pretty-print config", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if isPath {
|
||||||
|
fmt.Fprintln(os.Stderr, "\n"+conf+":\n"+string(output))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintln(os.Stderr, "\nconfig:\n"+string(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dhallCmdExists() bool {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := exec.CommandContext(ctx, "/bin/sh", "-c", "command -v dhall").Run(); err != nil {
|
||||||
|
slogging.GetLogger().Debug("no command dhall")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
114
config/config_test.go
Normal file
114
config/config_test.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.dotya.ml/mirre-mt/pcmt/slogging"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfig(t *testing.T) {
|
||||||
|
if os.Getenv("CI") == "true" {
|
||||||
|
t.Skip("we're running in CI apparently, skipping these tests")
|
||||||
|
}
|
||||||
|
|
||||||
|
confPath := "./testconfigs/"
|
||||||
|
ts := []struct {
|
||||||
|
name string
|
||||||
|
fails bool
|
||||||
|
isPath bool
|
||||||
|
conf string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// incorrect type of the `Host` field.
|
||||||
|
name: "1.dhall",
|
||||||
|
fails: true,
|
||||||
|
isPath: true,
|
||||||
|
conf: "1.dhall",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2.dhall",
|
||||||
|
fails: false,
|
||||||
|
isPath: true,
|
||||||
|
conf: "2.dhall",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3.dhall",
|
||||||
|
fails: false,
|
||||||
|
isPath: false,
|
||||||
|
conf: `
|
||||||
|
let ConfigSchema =
|
||||||
|
https://git.dotya.ml/mirre-mt/pcmt/raw/branch/development/config/schema/package.dhall
|
||||||
|
sha256:ad7ba86d5d388a99b7543faa0e4c81ba1d9b78fa6c32fdaf4ac4477089d177be
|
||||||
|
? https://git.dotya.ml/mirre-mt/pcmt/raw/branch/development/config/schema/package.dhall
|
||||||
|
|
||||||
|
let Config = ConfigSchema.Schema
|
||||||
|
|
||||||
|
let c = Config::{ DevelMode = True }
|
||||||
|
|
||||||
|
in c
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// misses final `in`.
|
||||||
|
name: "4.dhall",
|
||||||
|
fails: true,
|
||||||
|
isPath: false,
|
||||||
|
conf: `
|
||||||
|
let ConfigSchema =
|
||||||
|
https://git.dotya.ml/mirre-mt/pcmt/raw/branch/development/config/schema/package.dhall
|
||||||
|
sha256:ad7ba86d5d388a99b7543faa0e4c81ba1d9b78fa6c32fdaf4ac4477089d177be
|
||||||
|
? https://git.dotya.ml/mirre-mt/pcmt/raw/branch/development/config/schema/package.dhall
|
||||||
|
|
||||||
|
let Config = ConfigSchema.Schema
|
||||||
|
|
||||||
|
let c = Config::{ DevelMode = True }
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "5.dhall",
|
||||||
|
fails: false,
|
||||||
|
isPath: false,
|
||||||
|
conf: `
|
||||||
|
let ConfigSchema =
|
||||||
|
https://git.dotya.ml/mirre-mt/pcmt/raw/branch/development/config/schema/package.dhall
|
||||||
|
in ConfigSchema.Schema::{ DevelMode = True, Port = 5555 }
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "6.dhall",
|
||||||
|
fails: false,
|
||||||
|
isPath: false,
|
||||||
|
conf: `
|
||||||
|
let ConfigSchema =
|
||||||
|
https://git.dotya.ml/mirre-mt/pcmt/raw/branch/development/config/schema/package.dhall
|
||||||
|
in ConfigSchema.Schema.default // { DevelMode = True }
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = slogging.Init(false)
|
||||||
|
|
||||||
|
for _, tc := range ts {
|
||||||
|
t.Logf("running test case %s", tc.name)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
shouldFail := tc.fails
|
||||||
|
|
||||||
|
if tc.isPath {
|
||||||
|
_, err = LoadConfig(confPath+tc.conf, tc.isPath)
|
||||||
|
} else {
|
||||||
|
_, err = LoadConfig(tc.conf, tc.isPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case err == nil && shouldFail:
|
||||||
|
t.Errorf("test case '%s' should have failed", tc.name)
|
||||||
|
|
||||||
|
case err != nil && !shouldFail:
|
||||||
|
t.Log(err)
|
||||||
|
t.Errorf("test case '%s' should not have failed", tc.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
config/testconfigs/1.dhall
Normal file
9
config/testconfigs/1.dhall
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
let ConfigSchema =
|
||||||
|
https://git.dotya.ml/mirre-mt/pcmt/raw/branch/development/config/schema/package.dhall
|
||||||
|
sha256:ad7ba86d5d388a99b7543faa0e4c81ba1d9b78fa6c32fdaf4ac4477089d177be
|
||||||
|
|
||||||
|
let Config = ConfigSchema.Schema
|
||||||
|
|
||||||
|
let c = Config::{ Host = False }
|
||||||
|
|
||||||
|
in c
|
9
config/testconfigs/2.dhall
Normal file
9
config/testconfigs/2.dhall
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
let ConfigSchema =
|
||||||
|
https://git.dotya.ml/mirre-mt/pcmt/raw/branch/development/config/schema/package.dhall
|
||||||
|
sha256:ad7ba86d5d388a99b7543faa0e4c81ba1d9b78fa6c32fdaf4ac4477089d177be
|
||||||
|
|
||||||
|
let Config = ConfigSchema.Schema
|
||||||
|
|
||||||
|
let c = Config::{ Host = "localhost" }
|
||||||
|
|
||||||
|
in c
|
19
run.go
19
run.go
@ -51,13 +51,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.`
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
host = flag.String("host", "unset", "host address to listen on")
|
host = flag.String("host", "unset", "host address to listen on")
|
||||||
port = flag.Int("port", -1, "TCP port to listen on")
|
port = flag.Int("port", -1, "TCP port to listen on")
|
||||||
configFlag = flag.String("config", "config.dhall", "Default path of the config file")
|
configFlag = flag.String("config", "config.dhall", "Default path of the config file")
|
||||||
devel = flag.Bool("devel", false, "Run the application in dev mode, connect to a local browser-sync instance for hot-reloading")
|
configIsPathFlag = flag.Bool("configIsPath", true, "Whether the provided config is path or raw config")
|
||||||
license = flag.Bool("license", false, "Print licensing information and exit")
|
devel = flag.Bool("devel", false, "Run the application in dev mode, connect to a local browser-sync instance for hot-reloading")
|
||||||
version = "dev"
|
license = flag.Bool("license", false, "Print licensing information and exit")
|
||||||
log *slogging.Logger
|
version = "dev"
|
||||||
|
log *slogging.Logger
|
||||||
)
|
)
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
@ -81,9 +82,9 @@ func run() error {
|
|||||||
// TODO: SBOM: https://actuated.dev/blog/sbom-in-github-actions
|
// TODO: SBOM: https://actuated.dev/blog/sbom-in-github-actions
|
||||||
// TODO: SBOM: https://www.docker.com/blog/generate-sboms-with-buildkit/
|
// TODO: SBOM: https://www.docker.com/blog/generate-sboms-with-buildkit/
|
||||||
|
|
||||||
conf, err := config.LoadConfig(*configFlag)
|
conf, err := config.LoadConfig(*configFlag, *configIsPathFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error loading config file at '%s', bailing", *configFlag)
|
log.Errorf("error loading config file '%s', bailing", *configFlag)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user