mukan-ignite/ignite/cmd/cmd.go
Mukan Erkin Törük c32551b6f7
Some checks failed
Docs Deploy / build_and_deploy (push) Has been cancelled
Generate Docs / cli (push) Has been cancelled
Generate Config Doc / cli (push) Has been cancelled
Go formatting / go-formatting (push) Has been cancelled
Check links / markdown-link-check (push) Has been cancelled
Integration / pre-test (push) Has been cancelled
Integration / test on (push) Has been cancelled
Integration / status (push) Has been cancelled
Lint / Lint Go code (push) Has been cancelled
Test / test (ubuntu-latest) (push) Has been cancelled
refactor: replace all github.com upstream refs with git.cw.tr/mukan-network
2026-05-11 03:36:24 +03:00

306 lines
8.1 KiB
Go

package ignitecmd
import (
"context"
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"time"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
"git.cw.tr/mukan-network/mukan-ignite/ignite/config"
chainconfig "git.cw.tr/mukan-network/mukan-ignite/ignite/config/chain"
"git.cw.tr/mukan-network/mukan-ignite/ignite/internal/announcements"
"git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/cache"
"git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/cliui"
uilog "git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/cliui/log"
"git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/dircache"
"git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/errors"
"git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/goenv"
"git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/gomodulepath"
"git.cw.tr/mukan-network/mukan-ignite/ignite/version"
)
type key int
const (
keyChainConfig key = iota
keyChainConfigPath key = iota
)
const (
flagPath = "path"
flagHome = "home"
flagYes = "yes"
flagClearCache = "clear-cache"
flagSkipProto = "skip-proto"
flagSkipBuild = "skip-build"
checkVersionTimeout = time.Millisecond * 600
cacheFileName = "ignite_cache.db"
statusGenerating = "Generating..."
statusImporting = "Importing..."
statusExporting = "Exporting..."
statusCreating = "Creating..."
statusDeleting = "Deleting..."
)
// List of CLI level one commands that should not load Ignite app instances.
var skipAppsLoadCommands = []string{"version", "help", "docs", "completion", cobra.ShellCompRequestCmd, cobra.ShellCompNoDescRequestCmd}
// New creates a new root command for `Ignite CLI` with its sub commands.
// Returns the cobra.Command, a cleanup function and an error. The cleanup
// function must be invoked by the caller to clean eventual Ignite App instances.
func New(ctx context.Context) (*cobra.Command, func(), error) {
cobra.EnableCommandSorting = false
c := &cobra.Command{
Use: "ignite",
Short: "Ignite CLI offers everything you need to scaffold, test, build, and launch your blockchain",
Long: fmt.Sprintf(`Ignite CLI is a tool for creating sovereign blockchains built with Cosmos SDK, the world's
most popular modular blockchain framework. Ignite CLI offers everything you need to scaffold,
test, build, and launch your blockchain.
To get started, create a blockchain:
$ ignite scaffold chain example
%s`, announcements.Fetch()),
SilenceUsage: true,
SilenceErrors: true,
Args: cobra.MinimumNArgs(0), // note(@julienrbrt): without this, ignite __complete(noDesc) hidden commands are not working.
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
// Check for new versions only when shell completion scripts are not being
// generated to avoid invalid output to stdout when a new version is available
if cmd.Use != "completion" || !strings.HasPrefix(cmd.Use, cobra.ShellCompRequestCmd) {
checkNewVersion(cmd)
}
return goenv.ConfigurePath()
},
}
c.AddCommand(
NewScaffold(),
NewChain(),
NewGenerate(),
NewAccount(),
NewDocs(),
NewVersion(),
NewApp(),
NewDoctor(),
NewCompletionCmd(),
NewTestnet(),
)
c.AddCommand(deprecated()...)
c.SetContext(ctx)
// Don't load Ignite apps for level one commands that doesn't allow them
if len(os.Args) >= 2 && slices.Contains(skipAppsLoadCommands, os.Args[1]) {
return c, func() {}, nil
}
// Load plugins if any
session := cliui.New(cliui.WithStdout(os.Stdout))
if err := LoadPlugins(ctx, c, session); err != nil {
return nil, nil, errors.Errorf("error while loading apps: %w", err)
}
return c, func() {
UnloadPlugins()
session.End()
}, nil
}
func flagSetVerbose() *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.BoolP(flagVerbose, "v", false, "verbose output")
return fs
}
func getVerbosity(cmd *cobra.Command) uilog.Verbosity {
if verbose, _ := cmd.Flags().GetBool(flagVerbose); verbose {
return uilog.VerbosityVerbose
}
return uilog.VerbosityDefault
}
func flagSetPath(cmd *cobra.Command) {
cmd.PersistentFlags().StringP(flagPath, "p", ".", "path of the app")
}
func flagGetPath(cmd *cobra.Command) (path string) {
path, _ = cmd.Flags().GetString(flagPath)
return
}
func goModulePath(cmd *cobra.Command) (string, error) {
path := flagGetPath(cmd)
path, err := filepath.Abs(path)
if err != nil {
return "", err
}
_, appPath, err := gomodulepath.Find(path)
if err != nil {
return "", err
}
return appPath, err
}
func flagSetHome() *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.String(flagHome, "", "directory where the blockchain node is initialized")
return fs
}
func flagSetConfig() *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.StringP(flagConfig, "c", "", "path to Ignite config file (default: ./config.yml)")
return fs
}
func getConfig(cmd *cobra.Command) (config string) {
config, _ = cmd.Flags().GetString(flagConfig)
return
}
func getChainConfig(cmd *cobra.Command) (*chainconfig.Config, string, error) {
cfg, ok := cmd.Context().Value(keyChainConfig).(*chainconfig.Config)
if ok {
configPath := cmd.Context().Value(keyChainConfigPath).(string)
return cfg, configPath, nil
}
configPath := getConfig(cmd)
path, err := goModulePath(cmd)
if err != nil {
return nil, "", err
}
if configPath == "" {
if configPath, err = chainconfig.LocateDefault(path); err != nil {
return nil, "", err
}
}
cfg, err = chainconfig.ParseFile(configPath)
if err != nil {
return nil, "", err
}
ctx := context.WithValue(cmd.Context(), keyChainConfig, cfg)
ctx = context.WithValue(ctx, keyChainConfigPath, configPath)
cmd.SetContext(ctx)
return cfg, configPath, err
}
func flagSetYes() *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.BoolP(flagYes, "y", false, "answers interactive yes/no questions with yes")
return fs
}
func getYes(cmd *cobra.Command) (ok bool) {
ok, _ = cmd.Flags().GetBool(flagYes)
return
}
func flagSetSkipProto() *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.Bool(flagSkipProto, false, "skip file generation from proto")
return fs
}
func flagGetSkipProto(cmd *cobra.Command) bool {
skip, _ := cmd.Flags().GetBool(flagSkipProto)
return skip
}
func flagSetSkipBuild() *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.Bool(flagSkipBuild, false, "skip initial build of the app (uses local binary)")
return fs
}
func flagGetSkipBuild(cmd *cobra.Command) bool {
skip, _ := cmd.Flags().GetBool(flagSkipBuild)
return skip
}
func flagSetClearCache(cmd *cobra.Command) {
cmd.PersistentFlags().Bool(flagClearCache, false, "clear the build cache (advanced)")
}
func flagGetClearCache(cmd *cobra.Command) bool {
clearCache, _ := cmd.Flags().GetBool(flagClearCache)
return clearCache
}
func deprecated() []*cobra.Command {
return []*cobra.Command{
{
Use: "build",
Hidden: true,
Deprecated: "use `ignite chain build` instead.",
},
{
Use: "serve",
Hidden: true,
Deprecated: "use `ignite chain serve` instead.",
},
{
Use: "faucet",
Hidden: true,
Deprecated: "use `ignite chain faucet` instead.",
},
{
Use: "node",
Hidden: true,
Deprecated: "use ignite connect app instead (ignite app install -g github.com/ignite/apps/connect).",
},
}
}
func checkNewVersion(cmd *cobra.Command) {
ctx, cancel := context.WithTimeout(cmd.Context(), checkVersionTimeout)
defer cancel()
isAvailable, next, err := version.CheckNext(ctx)
if err != nil || !isAvailable {
return
}
cmd.Printf("⬆️ Ignite CLI %s is available! To upgrade: https://docs.ignite.com/welcome/install#upgrade (or use snap or homebrew)\n\n", next)
}
func newCache(cmd *cobra.Command) (cache.Storage, error) {
cacheRootDir, err := config.DirPath()
if err != nil {
return cache.Storage{}, err
}
storage, err := cache.NewStorage(
filepath.Join(cacheRootDir, cacheFileName),
cache.WithVersion(version.Version),
)
if err != nil {
return cache.Storage{}, err
}
if flagGetClearCache(cmd) {
if err := storage.Clear(); err != nil {
return cache.Storage{}, err
}
if err := dircache.ClearCache(); err != nil {
return cache.Storage{}, err
}
}
return storage, nil
}