package scaffolder import ( "context" "fmt" "path/filepath" "strings" "github.com/ignite/cli/v29/ignite/pkg/cliui" "github.com/ignite/cli/v29/ignite/pkg/errors" "github.com/ignite/cli/v29/ignite/pkg/gomodulepath" "github.com/ignite/cli/v29/ignite/pkg/multiformatname" "github.com/ignite/cli/v29/ignite/pkg/xgenny" "github.com/ignite/cli/v29/ignite/templates/app" "github.com/ignite/cli/v29/ignite/templates/field" modulecreate "github.com/ignite/cli/v29/ignite/templates/module/create" ) // Init initializes a new app with name and given options. func Init( ctx context.Context, root, name, addressPrefix string, coinType uint32, defaultDenom, protoDir string, noDefaultModule, minimal bool, params, moduleConfigs []string, ) (string, string, error) { pathInfo, err := gomodulepath.Parse(name) if err != nil { return "", "", err } // Check if the module name is valid (no numbers) for _, r := range pathInfo.Package { if r >= '0' && r <= '9' { return "", "", errors.Errorf("invalid app name %s: cannot contain numbers", pathInfo.Package) } } // Create a new folder named as the blockchain when a custom path is not specified var appFolder string if root == "" { appFolder = pathInfo.Root } if root, err = filepath.Abs(root); err != nil { return "", "", err } var ( path = filepath.Join(root, appFolder) gomodule = pathInfo.RawPath ) // create the project _, err = generate( ctx, pathInfo, addressPrefix, coinType, defaultDenom, protoDir, path, noDefaultModule, minimal, params, moduleConfigs, ) return path, gomodule, err } func generate( ctx context.Context, pathInfo gomodulepath.Path, addressPrefix string, coinType uint32, defaultDenom, protoDir, absRoot string, noDefaultModule, minimal bool, params, moduleConfigs []string, ) (xgenny.SourceModification, error) { // Parse params with the associated type paramsFields, err := field.ParseFields(params, checkForbiddenTypeIndex) if err != nil { return xgenny.SourceModification{}, err } // Parse configs with the associated type configsFields, err := field.ParseFields(moduleConfigs, checkForbiddenTypeIndex) if err != nil { return xgenny.SourceModification{}, err } githubPath := gomodulepath.ExtractAppPath(pathInfo.RawPath) if !strings.Contains(githubPath, "/") { // A username must be added when the app module appPath has a single element githubPath = fmt.Sprintf("username/%s", githubPath) } appGen, err := app.NewGenerator(&app.Options{ // generate application template ModulePath: pathInfo.RawPath, AppName: pathInfo.Package, ProtoDir: protoDir, GitHubPath: githubPath, BinaryNamePrefix: pathInfo.Root, AddressPrefix: addressPrefix, CoinType: coinType, DefaultDenom: defaultDenom, IsChainMinimal: minimal, }) if err != nil { return xgenny.SourceModification{}, err } // generate module template smc, err := xgenny.NewRunner(ctx, absRoot).RunAndApply(appGen) if err != nil { return smc, err } if !noDefaultModule { moduleName, err := multiformatname.NewName(pathInfo.Package, multiformatname.NoNumber) if err != nil { return smc, err } opts := &modulecreate.CreateOptions{ ModuleName: moduleName.LowerCase, // App module ModulePath: pathInfo.RawPath, AppName: pathInfo.Package, ProtoDir: protoDir, ProtoVer: "v1", // TODO(@julienrbrt): possibly in the future add flag to specify custom proto version. Params: paramsFields, Configs: configsFields, IsIBC: false, } // Check if the module name is valid if err := checkModuleName(opts.AppPath, opts.ModuleName); err != nil { return smc, err } moduleGen, err := modulecreate.NewGenerator(opts) if err != nil { return smc, err } runner := xgenny.NewRunner(ctx, absRoot) if err := runner.Run(moduleGen, modulecreate.NewAppModify(opts)); err != nil { return smc, err } // generate module template smm, err := runner.ApplyModifications() if err != nil { return smc, err } smc.Merge(smm) } return smc, err } func AskOverwriteFiles(session *cliui.Session) func(_, _, _ []string) error { return func(_, _, duplicated []string) error { if len(duplicated) == 0 { return nil } question := fmt.Sprintf("Do you want to overwrite the existing files? \n%s", strings.Join(duplicated, "\n")) return session.AskConfirm(question) } }