internal/cmd/root.go (106 lines of code) (raw):
/*
* Copyright 2021-2024 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cmd
import (
"fmt"
"os"
"github.com/JetBrains/qodana-cli/internal/core"
"github.com/JetBrains/qodana-cli/internal/platform/msg"
"github.com/JetBrains/qodana-cli/internal/platform/qdenv"
"github.com/JetBrains/qodana-cli/internal/platform/version"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// isHelpOrVersion checks if only help was requested.
func isHelpOrVersion(args []string) bool {
return len(args) == 2 && (args[1] == "--help" || args[1] == "-h" || args[1] == "help" || args[1] == "--version" || args[1] == "-v")
}
func isCompletionRequested(args []string) bool {
return len(args) >= 2 && args[1] == "completion"
}
// isCommandRequested checks if any command is requested.
func isCommandRequested(commands []*cobra.Command, args []string) string {
for _, c := range commands {
for _, a := range args {
if c.Name() == a {
return c.Name()
}
}
}
return ""
}
// setDefaultCommandIfNeeded sets default scan command if no other command is requested.
func setDefaultCommandIfNeeded(rootCmd *cobra.Command, args []string) {
if !isHelpOrVersion(args) && isCommandRequested(
rootCmd.Commands(),
args[1:],
) == "" && !isCompletionRequested(args) {
newArgs := append([]string{"scan"}, args[1:]...)
rootCmd.SetArgs(newArgs)
}
}
// Execute is a main CLI entrypoint: handles user interrupt, CLI start and everything else.
func Execute() {
if !qdenv.IsContainer() && os.Geteuid() == 0 {
msg.WarningMessage("Running the tool as root is dangerous: please run it as a regular user")
}
go core.CheckForUpdates(version.Version)
if !msg.IsInteractive() || os.Getenv("NO_COLOR") != "" { // http://no-color.org
msg.DisableColor()
}
setDefaultCommandIfNeeded(rootCommand, os.Args)
if err := rootCommand.Execute(); err != nil {
core.CheckForUpdates(version.Version)
_, err = fmt.Fprintf(os.Stderr, "error running command: %s\n", err)
if err != nil {
return
}
os.Exit(1)
}
core.CheckForUpdates(version.Version)
}
// newRootCommand constructs root command.
func newRootCommand() *cobra.Command {
rootCmd := &cobra.Command{
Use: "qodana",
Short: "Run Qodana CLI",
Long: msg.InfoString(version.Version),
Version: version.Version,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
logLevel, err := log.ParseLevel(viper.GetString("log-level"))
if err != nil {
log.Fatal(err)
}
log.SetLevel(logLevel)
},
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
err := cmd.Help()
if err != nil {
return
}
}
},
}
rootCmd.PersistentFlags().String("log-level", "error", "Set log-level for output")
rootCmd.PersistentFlags().BoolVar(
&core.DisableCheckUpdates,
"disable-update-checks",
false,
"Disable check for updates",
)
if err := viper.BindPFlag("log-level", rootCmd.PersistentFlags().Lookup("log-level")); err != nil {
log.Fatal(err)
}
return rootCmd
}
var rootCommand = newRootCommand()
// InitCli adds all child commands to the root command.
func InitCli() {
rootCommand.AddCommand(
newInitCommand(),
newScanCommand(),
newShowCommand(),
newSendCommand(),
newPullCommand(),
newViewCommand(),
newContributorsCommand(),
newClocCommand(),
)
}
// InitWithCustomCommands adds custom commands to the root command.
func InitWithCustomCommands(commands []*cobra.Command) {
rootCommand.AddCommand(commands...)
}