Skip to content

Commit

Permalink
Handle admxgen configuration in separate package
Browse files Browse the repository at this point in the history
Similarly to how we handle adsysd and adwatchd, handle the Cobra
configuration in a separate package that we call from the main package,
thus leaving the main package unaware of implementation details.
  • Loading branch information
GabrielNagy committed May 29, 2024
1 parent bb73f60 commit 01bfe9d
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 82 deletions.
117 changes: 117 additions & 0 deletions cmd/admxgen/commands/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Package commands is the admxgen command handling.
package commands

import (
"github.com/leonelquinteros/gotext"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/ubuntu/adsys/internal/ad/admxgen"
"github.com/ubuntu/adsys/internal/cmdhandler"
"github.com/ubuntu/adsys/internal/config"
"github.com/ubuntu/decorate"
)

// App encapsulates the commands and configuration of the admxgen application.
type App struct {
rootCmd cobra.Command
viper *viper.Viper
}

// New registers commands and return a new App.
func New() *App {
a := App{}

a.viper = viper.New()
a.rootCmd = cobra.Command{
Use: "admxgen COMMAND",
Short: gotext.Get("Generate Active Directory admx and adml files"),
Long: gotext.Get(`Generate ADMX and intermediary working files from a list of policy definition files.`),
Args: cmdhandler.SubcommandsRequiredWithSuggestions,
RunE: cmdhandler.NoCmd,
PersistentPreRunE: func(_ *cobra.Command, _ []string) error {
// Command parsing has been successful. Returns runtime (or
// configuration) error now and so, don't print usage.
a.rootCmd.SilenceUsage = true

config.SetVerboseMode(a.viper.GetInt("verbose"))
return nil
},

// We display usage error ourselves
SilenceErrors: true,
}

a.rootCmd.PersistentFlags().CountP("verbose", "v", gotext.Get("issue INFO (-v), DEBUG (-vv) or DEBUG with caller (-vvv) output"))
decorate.LogOnError(a.viper.BindPFlag("verbose", a.rootCmd.PersistentFlags().Lookup("verbose")))

// Install subcommands
a.installExpand()
a.installAdmx()
a.installDoc()

return &a
}

// Run executes the app.
func (a *App) Run() error {
return a.rootCmd.Execute()
}

// UsageError returns if the error is a command parsing or runtime one.
func (a App) UsageError() bool {
return !a.rootCmd.SilenceUsage
}

func (a *App) installExpand() {
cmd := &cobra.Command{
Use: "expand SOURCE DEST",
Short: gotext.Get("Generates intermediary policy definition files"),
Long: gotext.Get(`Generates an intermediary policy definition file into DEST directory from all the policy definition files in SOURCE directory, using the correct decoder.
The generated definition file will be of the form expanded_policies.RELEASE.yaml`),
Args: cobra.ExactArgs(2),
RunE: func(_ *cobra.Command, args []string) error {
return admxgen.Expand(args[0], args[1], viper.GetString("root"), viper.GetString("current-session"))
},
}
cmd.Flags().StringP("root", "r", "/", gotext.Get("root filesystem path to use. Default to /."))
decorate.LogOnError(viper.BindPFlag("root", cmd.Flags().Lookup("root")))

cmd.Flags().StringP("current-session", "s", "", gotext.Get(`current session to consider for dconf per-session overrides. Default to "".`))
decorate.LogOnError(viper.BindPFlag("current-session", cmd.Flags().Lookup("current-session")))

a.rootCmd.AddCommand(cmd)
}

func (a *App) installAdmx() {
var autoDetectReleases, allowMissingKeys *bool
cmd := &cobra.Command{
Use: "admx CATEGORIES_DEF.YAML SOURCE DEST",
Short: gotext.Get("Create finale admx and adml files"),
Long: gotext.Get("Collects all intermediary policy definition files in SOURCE directory to create admx and adml templates in DEST, based on CATEGORIES_DEF.yaml."),
Args: cobra.ExactArgs(3),
RunE: func(_ *cobra.Command, args []string) error {
return admxgen.GenerateAD(args[0], args[1], args[2], *autoDetectReleases, *allowMissingKeys)
},
}
autoDetectReleases = cmd.Flags().BoolP("auto-detect-releases", "a", false, gotext.Get("override supported releases in categories definition file and will takes all yaml files in SOURCE directory and use the basename as their versions."))
decorate.LogOnError(a.viper.BindPFlag("auto-detect-releases", cmd.Flags().Lookup("auto-detect-releases")))

allowMissingKeys = cmd.Flags().BoolP("allow-missing-keys", "k", false, gotext.Get(`avoid fail but display a warning if some keys are not available in a release. This is the case when news keys are added to non-lts releases.`))
decorate.LogOnError(a.viper.BindPFlag("allow-missing-keys", cmd.Flags().Lookup("allow-missing-keys")))

a.rootCmd.AddCommand(cmd)
}

func (a *App) installDoc() {
cmd := &cobra.Command{
Use: "doc CATEGORIES_DEF.YAML SOURCE DEST",
Short: gotext.Get("Create markdown documentation"),
Long: gotext.Get("Collects all intermediary policy definition files in SOURCE directory to create markdown documentation in DEST, based on CATEGORIES_DEF.yaml."),
Args: cobra.ExactArgs(3),
RunE: func(_ *cobra.Command, args []string) error {
return admxgen.GenerateDoc(args[0], args[1], args[2])
},
}

a.rootCmd.AddCommand(cmd)
}
97 changes: 15 additions & 82 deletions cmd/admxgen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,100 +6,33 @@ package main
import (
"os"

"github.com/leonelquinteros/gotext"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/ubuntu/adsys/internal/ad/admxgen"
"github.com/ubuntu/adsys/internal/cmdhandler"
"github.com/ubuntu/adsys/internal/config"
"github.com/ubuntu/decorate"
"github.com/ubuntu/adsys/cmd/admxgen/commands"
)

func main() {
type app interface {
Run() error
UsageError() bool
}

func run(a app) int {
log.SetFormatter(&log.TextFormatter{
DisableLevelTruncation: true,
DisableTimestamp: true,
})

viper := viper.New()

rootCmd := cobra.Command{
Use: "admxgen COMMAND",
Short: gotext.Get("Generate Active Directory admx and adml files"),
Long: gotext.Get(`Generate ADMX and intermediary working files from a list of policy definition files.`),
Args: cmdhandler.SubcommandsRequiredWithSuggestions,
RunE: cmdhandler.NoCmd,
PersistentPreRunE: func(_ *cobra.Command, _ []string) error {
config.SetVerboseMode(viper.GetInt("verbose"))
return nil
},
}

rootCmd.PersistentFlags().CountP("verbose", "v", gotext.Get("issue INFO (-v), DEBUG (-vv) or DEBUG with caller (-vvv) output"))
decorate.LogOnError(viper.BindPFlag("verbose", rootCmd.PersistentFlags().Lookup("verbose")))

// Install subcommands
installExpand(&rootCmd, viper)
installAdmx(&rootCmd, viper)
installDoc(&rootCmd, viper)

if err := rootCmd.Execute(); err != nil {
if err := a.Run(); err != nil {
log.Error(err)
os.Exit(1)
}
}

func installExpand(rootCmd *cobra.Command, viper *viper.Viper) {
cmd := &cobra.Command{
Use: "expand SOURCE DEST",
Short: gotext.Get("Generates intermediary policy definition files"),
Long: gotext.Get(`Generates an intermediary policy definition file into DEST directory from all the policy definition files in SOURCE directory, using the correct decoder.
The generated definition file will be of the form expanded_policies.RELEASE.yaml`),
Args: cobra.ExactArgs(2),
RunE: func(_ *cobra.Command, args []string) error {
return admxgen.Expand(args[0], args[1], viper.GetString("root"), viper.GetString("current-session"))
},
if a.UsageError() {
return 2
}
return 1
}
cmd.Flags().StringP("root", "r", "/", gotext.Get("root filesystem path to use. Default to /."))
decorate.LogOnError(viper.BindPFlag("root", cmd.Flags().Lookup("root")))

cmd.Flags().StringP("current-session", "s", "", gotext.Get(`current session to consider for dconf per-session overrides. Default to "".`))
decorate.LogOnError(viper.BindPFlag("current-session", cmd.Flags().Lookup("current-session")))

rootCmd.AddCommand(cmd)
return 0
}

func installAdmx(rootCmd *cobra.Command, viper *viper.Viper) {
var autoDetectReleases, allowMissingKeys *bool
cmd := &cobra.Command{
Use: "admx CATEGORIES_DEF.YAML SOURCE DEST",
Short: gotext.Get("Create finale admx and adml files"),
Long: gotext.Get("Collects all intermediary policy definition files in SOURCE directory to create admx and adml templates in DEST, based on CATEGORIES_DEF.yaml."),
Args: cobra.ExactArgs(3),
RunE: func(_ *cobra.Command, args []string) error {
return admxgen.GenerateAD(args[0], args[1], args[2], *autoDetectReleases, *allowMissingKeys)
},
}
autoDetectReleases = cmd.Flags().BoolP("auto-detect-releases", "a", false, gotext.Get("override supported releases in categories definition file and will takes all yaml files in SOURCE directory and use the basename as their versions."))
decorate.LogOnError(viper.BindPFlag("auto-detect-releases", cmd.Flags().Lookup("auto-detect-releases")))

allowMissingKeys = cmd.Flags().BoolP("allow-missing-keys", "k", false, gotext.Get(`avoid fail but display a warning if some keys are not available in a release. This is the case when news keys are added to non-lts releases.`))
decorate.LogOnError(viper.BindPFlag("allow-missing-keys", cmd.Flags().Lookup("allow-missing-keys")))

rootCmd.AddCommand(cmd)
}

func installDoc(rootCmd *cobra.Command, _ *viper.Viper) {
cmd := &cobra.Command{
Use: "doc CATEGORIES_DEF.YAML SOURCE DEST",
Short: gotext.Get("Create markdown documentation"),
Long: gotext.Get("Collects all intermediary policy definition files in SOURCE directory to create markdown documentation in DEST, based on CATEGORIES_DEF.yaml."),
Args: cobra.ExactArgs(3),
RunE: func(_ *cobra.Command, args []string) error {
return admxgen.GenerateDoc(args[0], args[1], args[2])
},
}

rootCmd.AddCommand(cmd)
func main() {
os.Exit(run(commands.New()))
}

0 comments on commit 01bfe9d

Please sign in to comment.