Open-CMSIS-Pack/cpackget

View on GitHub
cmd/commands/root.go

Summary

Maintainability
A
0 mins
Test Coverage
C
78%
/* SPDX-License-Identifier: Apache-2.0 */
/* Copyright Contributors to the cpackget project. */

package commands

import (
    "errors"
    "fmt"
    "io"
    "os"
    "path/filepath"
    "strings"

    "github.com/open-cmsis-pack/cpackget/cmd/installer"
    "github.com/open-cmsis-pack/cpackget/cmd/utils"
    log "github.com/sirupsen/logrus"
    "github.com/spf13/cobra"
    viperType "github.com/spf13/viper"
)

// AllCommands contains all available commands for cpackget
var AllCommands = []*cobra.Command{
    InitCmd,
    AddCmd,
    RmCmd,
    ListCmd,
    UpdateIndexCmd,
    UpdateCmd,
    ChecksumCreateCmd,
    ChecksumVerifyCmd,
    SignatureCreateCmd,
    SignatureVerifyCmd,
    ConnectionCmd,
}

// createPackRoot is a flag that determines if the pack root should be created or not
var createPackRoot bool

// defaultPublicIndex is the public index to use in "default mode"
const defaultPublicIndex = "https://www.keil.com/pack/index.pidx"

var viper *viperType.Viper

func configureInstallerGlobalCmd(cmd *cobra.Command, args []string) error {
    verbosiness := viper.GetBool("verbose")
    quiet := viper.GetBool("quiet")
    if quiet && verbosiness {
        return errors.New("both \"-q\" and \"-v\" were specified, please pick only one verboseness option")
    }

    log.SetLevel(log.InfoLevel)
    log.SetOutput(cmd.OutOrStdout())

    if quiet {
        log.SetLevel(log.ErrorLevel)
    }

    if verbosiness {
        log.SetLevel(log.DebugLevel)
    }

    return nil
}

// configureInstaller configures cpackget installer for adding or removing pack/pdsc
func configureInstaller(cmd *cobra.Command, args []string) error {
    err := configureInstallerGlobalCmd(cmd, args)
    if err != nil {
        return err
    }

    targetPackRoot := viper.GetString("pack-root")
    checkConnection := viper.GetBool("check-connection")

    if targetPackRoot == installer.GetDefaultCmsisPackRoot() {
        // If using the default pack root path and the public index is not found,
        // initialize it
        if !checkConnection && !utils.FileExists(filepath.Join(targetPackRoot, ".Web", "index.pidx")) {
            err := installer.SetPackRoot(targetPackRoot, true)
            if err != nil {
                return err
            }
            // Exclude index updating commands to not double update
            if cmd.Name() != "init" && cmd.Name() != "index" && cmd.Name() != "update-index" {
                installer.UnlockPackRoot()
                err = installer.UpdatePublicIndex(defaultPublicIndex, true, true, false, false, 0, 0)
                if err != nil {
                    return err
                }
                err = installer.SetPackRoot(targetPackRoot, false)
                if err != nil {
                    return err
                }
                installer.LockPackRoot()
            }
        } else {
            err := installer.SetPackRoot(targetPackRoot, createPackRoot)
            if err != nil {
                return err
            }
        }
    } else {
        err := installer.SetPackRoot(targetPackRoot, createPackRoot)
        if err != nil {
            return err
        }
    }

    return nil
}

var flags struct {
    version bool
}

var Version string
var Copyright string

func printVersionAndLicense(file io.Writer) {
    fmt.Fprintf(file, "cpackget version %v %s\n", strings.ReplaceAll(Version, "v", ""), Copyright)
}

// UsageTemplate returns usage template for the command.
var usageTemplate = `Usage:{{if .Runnable}}
  {{.UseLine}}{{end}}{{if gt (len .Aliases) 0}}

Aliases:
  {{.NameAndAliases}}{{end}}{{if .HasExample}}

Examples:
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}

Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}

Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}

Global Flags:
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}

Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
  {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}

Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`

func NewCli() *cobra.Command {
    rootCmd := &cobra.Command{
        Use:           "cpackget [command] [flags]",
        Short:         "This utility adds/removes CMSIS-Packs",
        Long:          "Please refer to the upstream repository for further information: https://github.com/Open-CMSIS-Pack/cpackget.",
        SilenceUsage:  true,
        SilenceErrors: true,
        RunE: func(cmd *cobra.Command, args []string) error {
            if flags.version {
                printVersionAndLicense(cmd.OutOrStdout())
                return nil
            }

            return cmd.Help()
        },
    }

    rootCmd.SetUsageTemplate(usageTemplate)

    defaultPackRoot := os.Getenv("CMSIS_PACK_ROOT")
    if defaultPackRoot == "" {
        defaultPackRoot = installer.GetDefaultCmsisPackRoot()
    }

    viper = viperType.New()

    rootCmd.Flags().BoolVarP(&flags.version, "version", "V", false, "Prints the version number of cpackget and exit")
    rootCmd.PersistentFlags().BoolP("quiet", "q", false, "Run cpackget silently, printing only error messages")
    rootCmd.PersistentFlags().BoolP("verbose", "v", false, "Sets verboseness level: None (Errors + Info + Warnings), -v (all + Debugging). Specify \"-q\" for no messages")
    rootCmd.PersistentFlags().StringP("pack-root", "R", defaultPackRoot, "Specifies pack root folder. Defaults to CMSIS_PACK_ROOT environment variable")
    rootCmd.PersistentFlags().UintP("concurrent-downloads", "C", 20, "Number of concurrent batch downloads. Set to 0 to disable concurrency")
    rootCmd.PersistentFlags().UintP("timeout", "T", 0, "Set maximum duration (in seconds) of a download. Disabled by default")
    _ = viper.BindPFlag("concurrent-downloads", rootCmd.PersistentFlags().Lookup("concurrent-downloads"))
    _ = viper.BindPFlag("timeout", rootCmd.PersistentFlags().Lookup("timeout"))
    _ = viper.BindPFlag("pack-root", rootCmd.PersistentFlags().Lookup("pack-root"))
    _ = viper.BindPFlag("verbose", rootCmd.PersistentFlags().Lookup("verbose"))
    _ = viper.BindPFlag("quiet", rootCmd.PersistentFlags().Lookup("quiet"))

    for _, cmd := range AllCommands {
        rootCmd.AddCommand(cmd)
    }

    return rootCmd
}