Fixed issue with generate and added some documentation to funcs
This commit is contained in:
parent
7494468bed
commit
cd840b2bf0
9 changed files with 219 additions and 158 deletions
|
|
@ -55,7 +55,7 @@ func init() {
|
||||||
fetchCmd.Flags().IntVar(&remotePort, "port", 3334, "set the remote configurator port")
|
fetchCmd.Flags().IntVar(&remotePort, "port", 3334, "set the remote configurator port")
|
||||||
fetchCmd.Flags().StringSliceVar(&targets, "target", nil, "set the target configs to make")
|
fetchCmd.Flags().StringSliceVar(&targets, "target", nil, "set the target configs to make")
|
||||||
fetchCmd.Flags().StringVarP(&outputPath, "output", "o", "", "set the output path for config targets")
|
fetchCmd.Flags().StringVarP(&outputPath, "output", "o", "", "set the output path for config targets")
|
||||||
fetchCmd.Flags().StringVar(&accessToken, "access-token", "o", "", "set the output path for config targets")
|
fetchCmd.Flags().StringVar(&accessToken, "access-token", "o", "set the output path for config targets")
|
||||||
|
|
||||||
rootCmd.AddCommand(fetchCmd)
|
rootCmd.AddCommand(fetchCmd)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,12 +61,12 @@ var generateCmd = &cobra.Command{
|
||||||
fmt.Printf("%v\n", string(b))
|
fmt.Printf("%v\n", string(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
RunTargets(targets...)
|
RunTargets(&config, args, targets...)
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunTargets(config *configurator.Config, targets ...string) {
|
func RunTargets(config *configurator.Config, args []string, targets ...string) {
|
||||||
// generate config with each supplied target
|
// generate config with each supplied target
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
params := generator.Params{
|
params := generator.Params{
|
||||||
|
|
@ -75,13 +75,13 @@ func RunTargets(config *configurator.Config, targets ...string) {
|
||||||
Target: target,
|
Target: target,
|
||||||
Verbose: verbose,
|
Verbose: verbose,
|
||||||
}
|
}
|
||||||
outputBytes, err := generator.Generate(&config, params)
|
outputBytes, err := generator.Generate(config, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to generate config: %v\n", err)
|
fmt.Printf("failed to generate config: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
outputMap := util.ConvertMapOutput(outputBytes)
|
outputMap := generator.ConvertContentsToString(outputBytes)
|
||||||
|
|
||||||
// if we have more than one target and output is set, create configs in directory
|
// if we have more than one target and output is set, create configs in directory
|
||||||
var (
|
var (
|
||||||
|
|
@ -129,10 +129,10 @@ func RunTargets(config *configurator.Config, targets ...string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove any targets that are the same as current to prevent infinite loop
|
// remove any targets that are the same as current to prevent infinite loop
|
||||||
nextTargets := util.CopyIf(config.Targets[targets].Targets, func(t T) bool { return t != target })
|
nextTargets := util.CopyIf(config.Targets[target].RunTargets, func(t string) bool { return t != target })
|
||||||
|
|
||||||
// ...then, run any other targets that the current target has
|
// ...then, run any other targets that the current target has
|
||||||
RunTargets(config, nextTargets...)
|
RunTargets(config, args, nextTargets...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
byTarget bool
|
||||||
pluginDirs []string
|
pluginDirs []string
|
||||||
generators map[string]generator.Generator
|
generators map[string]generator.Generator
|
||||||
)
|
)
|
||||||
|
|
@ -17,6 +18,7 @@ var (
|
||||||
var inspectCmd = &cobra.Command{
|
var inspectCmd = &cobra.Command{
|
||||||
Use: "inspect",
|
Use: "inspect",
|
||||||
Short: "Inspect generator plugin information",
|
Short: "Inspect generator plugin information",
|
||||||
|
Long: "The 'inspect' sub-command takes a list of directories and prints all found plugin information.",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
// load specific plugins from positional args
|
// load specific plugins from positional args
|
||||||
generators = make(map[string]generator.Generator)
|
generators = make(map[string]generator.Generator)
|
||||||
|
|
@ -26,6 +28,10 @@ var inspectCmd = &cobra.Command{
|
||||||
fmt.Printf("failed to load plugin at path '%s': %v\n", path, err)
|
fmt.Printf("failed to load plugin at path '%s': %v\n", path, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// path is directory, so no plugin is loaded, but no error was returned
|
||||||
|
if gen == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
generators[path] = gen
|
generators[path] = gen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,5 +65,6 @@ var inspectCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
inspectCmd.Flags().BoolVar(&byTarget, "by-target", false, "set whether to ")
|
||||||
rootCmd.AddCommand(inspectCmd)
|
rootCmd.AddCommand(inspectCmd)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/OpenCHAMI/configurator/internal/util"
|
"github.com/OpenCHAMI/configurator/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ClientOption func(*SmdClient)
|
||||||
type SmdClient struct {
|
type SmdClient struct {
|
||||||
http.Client `json:"-"`
|
http.Client `json:"-"`
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
|
|
@ -22,10 +23,6 @@ type SmdClient struct {
|
||||||
AccessToken string `yaml:"access-token"`
|
AccessToken string `yaml:"access-token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Params = map[string]any
|
|
||||||
type Option func(Params)
|
|
||||||
type ClientOption func(*SmdClient)
|
|
||||||
|
|
||||||
func NewSmdClient(opts ...ClientOption) SmdClient {
|
func NewSmdClient(opts ...ClientOption) SmdClient {
|
||||||
client := SmdClient{}
|
client := SmdClient{}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
|
|
@ -80,14 +77,14 @@ func WithSecureTLS(certPath string) ClientOption {
|
||||||
return WithCertPool(certPool)
|
return WithCertPool(certPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithVerbosity() Option {
|
func WithVerbosity() util.Option {
|
||||||
return func(p util.Params) {
|
return func(p util.Params) {
|
||||||
p["verbose"] = true
|
p["verbose"] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewParams() Params {
|
func NewParams() util.Params {
|
||||||
return Params{
|
return util.Params{
|
||||||
"verbose": false,
|
"verbose": false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ type Config struct {
|
||||||
Options Options `yaml:"options"`
|
Options Options `yaml:"options"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a new config with default parameters.
|
||||||
func NewConfig() Config {
|
func NewConfig() Config {
|
||||||
return Config{
|
return Config{
|
||||||
Version: "",
|
Version: "",
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,11 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Mappings = map[string]any
|
type Mappings map[string]any
|
||||||
type Files = map[string][]byte
|
type Files map[string][]byte
|
||||||
|
|
||||||
|
// Generator interface used to define how files are created. Plugins can
|
||||||
|
// be created entirely independent of the main driver program.
|
||||||
type Generator interface {
|
type Generator interface {
|
||||||
GetName() string
|
GetName() string
|
||||||
GetVersion() string
|
GetVersion() string
|
||||||
|
|
@ -24,6 +27,7 @@ type Generator interface {
|
||||||
Generate(config *configurator.Config, opts ...util.Option) (Files, error)
|
Generate(config *configurator.Config, opts ...util.Option) (Files, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Params defined and used by the "generate" subcommand.
|
||||||
type Params struct {
|
type Params struct {
|
||||||
Args []string
|
Args []string
|
||||||
PluginPaths []string
|
PluginPaths []string
|
||||||
|
|
@ -31,139 +35,15 @@ type Params struct {
|
||||||
Verbose bool
|
Verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadPlugin(path string) (Generator, error) {
|
func ConvertContentsToString(f Files) map[string]string {
|
||||||
p, err := plugin.Open(path)
|
n := make(map[string]string, len(f))
|
||||||
if err != nil {
|
for k, v := range f {
|
||||||
return nil, fmt.Errorf("failed to load plugin: %v", err)
|
n[k] = string(v)
|
||||||
}
|
}
|
||||||
|
return n
|
||||||
// load the "Generator" symbol from plugin
|
|
||||||
symbol, err := p.Lookup("Generator")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to look up symbol at path '%s': %v", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// assert that the plugin loaded has a valid generator
|
|
||||||
gen, ok := symbol.(Generator)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("failed to load the correct symbol type at path '%s'", path)
|
|
||||||
}
|
|
||||||
return gen, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadPlugins(dirpath string, opts ...util.Option) (map[string]Generator, error) {
|
|
||||||
// check if verbose option is supplied
|
|
||||||
var (
|
|
||||||
gens = make(map[string]Generator)
|
|
||||||
params = util.GetParams(opts...)
|
|
||||||
)
|
|
||||||
|
|
||||||
items, _ := os.ReadDir(dirpath)
|
|
||||||
for _, item := range items {
|
|
||||||
if item.IsDir() {
|
|
||||||
subitems, _ := os.ReadDir(item.Name())
|
|
||||||
for _, subitem := range subitems {
|
|
||||||
if !subitem.IsDir() {
|
|
||||||
gen, err := LoadPlugin(subitem.Name())
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("failed to load generator in directory '%s': %v\n", item.Name(), err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if verbose, ok := params["verbose"].(bool); ok {
|
|
||||||
if verbose {
|
|
||||||
fmt.Printf("-- found plugin '%s'\n", item.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gens[gen.GetName()] = gen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
gen, err := LoadPlugin(dirpath + item.Name())
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("failed to load generator: %v\n", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if verbose, ok := params["verbose"].(bool); ok {
|
|
||||||
if verbose {
|
|
||||||
fmt.Printf("-- found plugin '%s'\n", dirpath+item.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gens[gen.GetName()] = gen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return gens, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithTarget(target string) util.Option {
|
|
||||||
return func(p util.Params) {
|
|
||||||
if p != nil {
|
|
||||||
p["target"] = target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithType(_type string) util.Option {
|
|
||||||
return func(p util.Params) {
|
|
||||||
if p != nil {
|
|
||||||
p["type"] = _type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithClient(client configurator.SmdClient) util.Option {
|
|
||||||
return func(p util.Params) {
|
|
||||||
p["client"] = client
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithOption(key string, value any) util.Option {
|
|
||||||
return func(p util.Params) {
|
|
||||||
p[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to get client in generator plugins.
|
|
||||||
func GetClient(params util.Params) *configurator.SmdClient {
|
|
||||||
return util.Get[configurator.SmdClient](params, "client")
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetTarget(config *configurator.Config, key string) configurator.Target {
|
|
||||||
return config.Targets[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetParams(opts ...util.Option) util.Params {
|
|
||||||
params := util.Params{}
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(params)
|
|
||||||
}
|
|
||||||
return params
|
|
||||||
}
|
|
||||||
|
|
||||||
func ApplyTemplates(mappings map[string]any, paths ...string) (Files, error) {
|
|
||||||
var (
|
|
||||||
data = exec.NewContext(mappings)
|
|
||||||
outputs = Files{}
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, path := range paths {
|
|
||||||
// load jinja template from file
|
|
||||||
t, err := gonja.FromFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read template from file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute/render jinja template
|
|
||||||
b := bytes.Buffer{}
|
|
||||||
if err = t.Execute(&b, data); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to execute: %v", err)
|
|
||||||
}
|
|
||||||
outputs[path] = b.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
return outputs, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loads files without applying any Jinja 2 templating.
|
||||||
func LoadFiles(paths ...string) (Files, error) {
|
func LoadFiles(paths ...string) (Files, error) {
|
||||||
var outputs = Files{}
|
var outputs = Files{}
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
|
|
@ -193,6 +73,167 @@ func LoadFiles(paths ...string) (Files, error) {
|
||||||
return outputs, nil
|
return outputs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loads a single generator plugin given a single file path.
|
||||||
|
func LoadPlugin(path string) (Generator, error) {
|
||||||
|
// skip loading plugin if path is a directory with no error
|
||||||
|
if isDir, err := util.IsDirectory(path); err == nil && isDir {
|
||||||
|
return nil, nil
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to test if path is directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try and open the plugin
|
||||||
|
p, err := plugin.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to open plugin: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the "Generator" symbol from plugin
|
||||||
|
symbol, err := p.Lookup("Generator")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to look up symbol at path '%s': %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert that the plugin loaded has a valid generator
|
||||||
|
gen, ok := symbol.(Generator)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to load the correct symbol type at path '%s'", path)
|
||||||
|
}
|
||||||
|
return gen, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loads all generator plugins in a given directory.
|
||||||
|
//
|
||||||
|
// Returns a map of generators. Each generator can be accessed by the name
|
||||||
|
// returned by the generator.GetName() implemented.
|
||||||
|
func LoadPlugins(dirpath string, opts ...util.Option) (map[string]Generator, error) {
|
||||||
|
// check if verbose option is supplied
|
||||||
|
var (
|
||||||
|
gens = make(map[string]Generator)
|
||||||
|
params = util.GetParams(opts...)
|
||||||
|
)
|
||||||
|
|
||||||
|
items, _ := os.ReadDir(dirpath)
|
||||||
|
for _, item := range items {
|
||||||
|
if item.IsDir() {
|
||||||
|
subitems, _ := os.ReadDir(item.Name())
|
||||||
|
for _, subitem := range subitems {
|
||||||
|
if !subitem.IsDir() {
|
||||||
|
gen, err := LoadPlugin(subitem.Name())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to load generator in directory '%s': %v\n", item.Name(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if verbose, ok := params["verbose"].(bool); ok {
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("-- found plugin '%s'\n", item.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gens[gen.GetName()] = gen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gen, err := LoadPlugin(dirpath + item.Name())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to load plugin: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if verbose, ok := params["verbose"].(bool); ok {
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("-- found plugin '%s'\n", dirpath+item.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gens[gen.GetName()] = gen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gens, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option to specify "target" in parameter map. This is used to set which generator
|
||||||
|
// to use to generate a config file.
|
||||||
|
func WithTarget(target string) util.Option {
|
||||||
|
return func(p util.Params) {
|
||||||
|
if p != nil {
|
||||||
|
p["target"] = target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option to specify "type" in parameter map. This is not currently used.
|
||||||
|
func WithType(_type string) util.Option {
|
||||||
|
return func(p util.Params) {
|
||||||
|
if p != nil {
|
||||||
|
p["type"] = _type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option to a specific client to include in implementing plugin generator.Generate().
|
||||||
|
//
|
||||||
|
// NOTE: This may be changed to pass some kind of client interface as an argument in
|
||||||
|
// the future instead.
|
||||||
|
func WithClient(client configurator.SmdClient) util.Option {
|
||||||
|
return func(p util.Params) {
|
||||||
|
p["client"] = client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get client in generator.Generate() plugin implementations.
|
||||||
|
func GetClient(params util.Params) *configurator.SmdClient {
|
||||||
|
return util.Get[configurator.SmdClient](params, "client")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get the target in generator.Generate() plugin implementations.
|
||||||
|
func GetTarget(config *configurator.Config, key string) configurator.Target {
|
||||||
|
return config.Targets[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to load all options set with With*() into parameter map.
|
||||||
|
func GetParams(opts ...util.Option) util.Params {
|
||||||
|
params := util.Params{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(params)
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper function to slightly abstract away some of the nuances with using gonja
|
||||||
|
// into a single function call. This function is *mostly* for convenience and
|
||||||
|
// simplication.
|
||||||
|
func ApplyTemplates(mappings map[string]any, paths ...string) (Files, error) {
|
||||||
|
var (
|
||||||
|
data = exec.NewContext(mappings)
|
||||||
|
outputs = Files{}
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
// load jinja template from file
|
||||||
|
t, err := gonja.FromFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read template from file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute/render jinja template
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
if err = t.Execute(&b, data); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute: %v", err)
|
||||||
|
}
|
||||||
|
outputs[path] = b.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function to generate a collection of files as a map with the path as the key and
|
||||||
|
// the contents of the file as the value. This function currently expects a list of plugin
|
||||||
|
// paths to load all plugins within a directory. Then, each plugin's generator.Generate()
|
||||||
|
// function is called for each target specified.
|
||||||
|
//
|
||||||
|
// This function is the corresponding implementation for the "generate" CLI subcommand.
|
||||||
|
// It is also call when running the configurator as a service with the "/generate" route.
|
||||||
|
//
|
||||||
|
// TODO: Separate loading plugins so we can load them once when running as a service.
|
||||||
func Generate(config *configurator.Config, params Params) (Files, error) {
|
func Generate(config *configurator.Config, params Params) (Files, error) {
|
||||||
// load generator plugins to generate configs or to print
|
// load generator plugins to generate configs or to print
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,9 @@ type Server struct {
|
||||||
TokenAuth *jwtauth.JWTAuth
|
TokenAuth *jwtauth.JWTAuth
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *Server {
|
func New(config *configurator.Config) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
|
Config: config,
|
||||||
Server: &http.Server{
|
Server: &http.Server{
|
||||||
Addr: "localhost:3334",
|
Addr: "localhost:3334",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,11 @@ import (
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Params = map[string]any
|
// Params are accessible in generator.Generate().
|
||||||
|
type Params map[string]any
|
||||||
type Option func(Params)
|
type Option func(Params)
|
||||||
|
|
||||||
|
// Extract all parameters from the options passed as map[string]any.
|
||||||
func GetParams(opts ...Option) Params {
|
func GetParams(opts ...Option) Params {
|
||||||
params := Params{}
|
params := Params{}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
|
|
@ -17,7 +19,8 @@ func GetParams(opts ...Option) Params {
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
func OptionExists(params Params, opt string) bool {
|
// Test if an option is present in params
|
||||||
|
func (p *Params) OptionExists(params Params, opt string) bool {
|
||||||
var k []string = maps.Keys(params)
|
var k []string = maps.Keys(params)
|
||||||
return slices.Contains(k, opt)
|
return slices.Contains(k, opt)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Wrapper function to simplify checking if a path exists.
|
||||||
func PathExists(path string) (bool, error) {
|
func PathExists(path string) (bool, error) {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
@ -22,6 +23,19 @@ func PathExists(path string) (bool, error) {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsDirectory(path string) (bool, error) {
|
||||||
|
// This returns an *os.FileInfo type
|
||||||
|
fileInfo, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to stat path: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDir is short for fileInfo.Mode().IsDir()
|
||||||
|
return fileInfo.IsDir(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper function to confine making a HTTP request into a single function
|
||||||
|
// instead of multiple.
|
||||||
func MakeRequest(url string, httpMethod string, body []byte, headers map[string]string) (*http.Response, []byte, error) {
|
func MakeRequest(url string, httpMethod string, body []byte, headers map[string]string) (*http.Response, []byte, error) {
|
||||||
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
req, err := http.NewRequest(httpMethod, url, bytes.NewBuffer(body))
|
req, err := http.NewRequest(httpMethod, url, bytes.NewBuffer(body))
|
||||||
|
|
@ -44,14 +58,9 @@ func MakeRequest(url string, httpMethod string, body []byte, headers map[string]
|
||||||
return res, b, err
|
return res, b, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertMapOutput(m map[string][]byte) map[string]string {
|
// Returns the git commit string by executing command.
|
||||||
n := make(map[string]string, len(m))
|
// NOTE: This currently requires git to be installed.
|
||||||
for k, v := range m {
|
// TODO: Change how this is done to not require executing a command.
|
||||||
n[k] = string(v)
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func GitCommit() string {
|
func GitCommit() string {
|
||||||
c := exec.Command("git", "rev-parse", "HEAD")
|
c := exec.Command("git", "rev-parse", "HEAD")
|
||||||
stdout, err := c.Output()
|
stdout, err := c.Output()
|
||||||
|
|
@ -62,13 +71,15 @@ func GitCommit() string {
|
||||||
return strings.TrimRight(string(stdout), "\n")
|
return strings.TrimRight(string(stdout), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: would it be better to use slices.DeleteFunc instead
|
// General function to remove element by a given index.
|
||||||
|
// NOTE: would it be better to use slices.DeleteFunc instead?
|
||||||
func RemoveIndex[T comparable](s []T, index int) []T {
|
func RemoveIndex[T comparable](s []T, index int) []T {
|
||||||
ret := make([]T, 0)
|
ret := make([]T, 0)
|
||||||
ret = append(ret, s[:index]...)
|
ret = append(ret, s[:index]...)
|
||||||
return append(ret, s[index+1:]...)
|
return append(ret, s[index+1:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// General function to copy elements from slice if condition is true.
|
||||||
func CopyIf[T comparable](s []T, condition func(t T) bool) []T {
|
func CopyIf[T comparable](s []T, condition func(t T) bool) []T {
|
||||||
var f = make([]T, 0)
|
var f = make([]T, 0)
|
||||||
for _, e := range s {
|
for _, e := range s {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue