Skip to content

Commit

Permalink
feat: apply auto tools migration to other commands (ignite#3524)
Browse files Browse the repository at this point in the history
* fix: add tools file check to tools migration handler

* chore: add tools migration to generate command pre run handler

* refactor: change doctor to fix dependency tools imports

* refactor: improve doctor code structure

* refactor: unify doctor messages UI message styles

* chore: define tools file path in a single package
  • Loading branch information
jeronimoalbi authored Jun 5, 2023
1 parent e19f83b commit 615c855
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 43 deletions.
8 changes: 6 additions & 2 deletions ignite/cmd/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ import (
"github.com/ignite/cli/ignite/pkg/cosmosgen"
"github.com/ignite/cli/ignite/pkg/goanalysis"
"github.com/ignite/cli/ignite/pkg/xast"
"github.com/ignite/cli/ignite/services/doctor"
)

const (
msgMigration = "Migrating blockchain config file from v%d to v%d..."
msgMigrationPrefix = "Your blockchain config version is v%d and the latest is v%d."
msgMigrationPrompt = "Would you like to upgrade your config file to v%d"
toolsFile = "tools/tools.go"
)

// NewChain returns a command that groups sub commands related to compiling, serving
Expand Down Expand Up @@ -116,7 +116,11 @@ func toolsMigrationPreRunHandler(cmd *cobra.Command, session *cliui.Session) (er
session.StartSpinner("Checking missing tools...")

appPath := flagGetPath(cmd)
toolsFilename := filepath.Join(appPath, toolsFile)
toolsFilename := filepath.Join(appPath, doctor.ToolsFile)
if _, err := os.Stat(toolsFilename); os.IsNotExist(err) {
return errors.New("the dependency tools file is missing, run `ignite doctor` and try again")
}

f, _, err := xast.ParseFile(toolsFilename)
if err != nil {
return err
Expand Down
18 changes: 15 additions & 3 deletions ignite/cmd/generate.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package ignitecmd

import "github.com/spf13/cobra"
import (
"github.com/spf13/cobra"

"github.com/ignite/cli/ignite/pkg/cliui"
)

// NewGenerate returns a command that groups code generation related sub commands.
func NewGenerate() *cobra.Command {
Expand All @@ -15,8 +19,9 @@ functionality, for example, generating an OpenAPI spec.
Produced source code can be regenerated by running a command again and is not
meant to be edited by hand.
`,
Aliases: []string{"g"},
Args: cobra.ExactArgs(1),
Aliases: []string{"g"},
Args: cobra.ExactArgs(1),
PersistentPreRunE: generatePreRunHandler,
}

flagSetPath(c)
Expand All @@ -30,3 +35,10 @@ meant to be edited by hand.

return c
}

func generatePreRunHandler(cmd *cobra.Command, _ []string) error {
session := cliui.New()
defer session.End()

return toolsMigrationPreRunHandler(cmd, session)
}
2 changes: 1 addition & 1 deletion ignite/pkg/cosmosgen/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func InstallDepTools(ctx context.Context, appPath string) error {
}
err := gocmd.Install(ctx, appPath, DepTools())
if gocmd.IsInstallError(err) {
return errors.New("unable to install dependency tools, try to run `ignite doctor` and try again")
return errors.New("unable to install dependency tools, run `ignite doctor` and try again")
}
return err
}
Expand Down
158 changes: 121 additions & 37 deletions ignite/services/doctor/doctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@ import (
"github.com/ignite/cli/ignite/pkg/cliui/icons"
"github.com/ignite/cli/ignite/pkg/cosmosgen"
"github.com/ignite/cli/ignite/pkg/events"
"github.com/ignite/cli/ignite/pkg/goanalysis"
"github.com/ignite/cli/ignite/pkg/gomodulepath"
"github.com/ignite/cli/ignite/pkg/xast"
"github.com/ignite/cli/ignite/templates/app"
)

const (
// ToolsFile defines the app relative path to the Go tools file.
ToolsFile = "tools/tools.go"
)

// DONTCOVER: Doctor read and write the filesystem intensively, so it's better
// to rely on integration tests only. See integration/doctor package.
type Doctor struct {
Expand Down Expand Up @@ -54,6 +61,7 @@ func (d *Doctor) MigrateConfig(_ context.Context) error {
if err != nil {
return errf(err)
}

f, err := os.Open(configPath)
if err != nil {
return errf(err)
Expand All @@ -64,21 +72,31 @@ func (d *Doctor) MigrateConfig(_ context.Context) error {
if err != nil {
return errf(err)
}

status := "OK"

if version != chainconfig.LatestVersion {
f.Seek(0, 0)

// migrate config file
// Convert the current config to the latest version and update the YAML file
var buf bytes.Buffer
f.Seek(0, 0)
if err := chainconfig.MigrateLatest(f, &buf); err != nil {
return errf(err)
}

if err := os.WriteFile(configPath, buf.Bytes(), 0o755); err != nil {
return errf(fmt.Errorf("config file migration failed: %w", err))
}
d.ev.Send(fmt.Sprintf("config file %s", colors.Success("migrated")),
events.Icon(icons.OK), events.ProgressFinish())

status = "migrated"
}
d.ev.Send("config file OK", events.Icon(icons.OK), events.ProgressFinish())

d.ev.Send(
fmt.Sprintf("config file %s", colors.Success(status)),
events.Icon(icons.OK),
events.ProgressFinish(),
)

return nil
}
Expand All @@ -93,53 +111,119 @@ func (d *Doctor) FixDependencyTools(ctx context.Context) error {

d.ev.Send("Checking dependency tools:", events.ProgressFinish())

const toolsGoFile = "tools/tools.go"
_, err := os.Stat(toolsGoFile)
_, err := os.Stat(ToolsFile)

switch {
case err == nil:
// tools.go exists
d.ev.Send(fmt.Sprintf("%s exists", toolsGoFile), events.Icon(icons.OK),
events.ProgressFinish())
// TODO ensure tools.go has the required dependencies
d.ev.Send(
fmt.Sprintf("%s %s", ToolsFile, colors.Success("exists")),
events.Icon(icons.OK),
events.ProgressUpdate(),
)

case os.IsNotExist(err):
// create tools.go
pathInfo, err := gomodulepath.ParseAt(".")
if err != nil {
return errf(err)
}
g, err := app.NewGenerator(&app.Options{
ModulePath: pathInfo.RawPath,
AppName: pathInfo.Package,
BinaryNamePrefix: pathInfo.Root,
IncludePrefixes: []string{toolsGoFile},
})
updated, err := d.ensureDependencyImports(ToolsFile)
if err != nil {
return errf(err)
}
// run generator
runner := genny.WetRunner(ctx)
if err := runner.With(g); err != nil {
return errf(err)
}
if err := runner.Run(); err != nil {
return errf(err)

status := "OK"
if updated {
status = "updated"
}
d.ev.Send(fmt.Sprintf("%s %s", toolsGoFile, colors.Success("created")),
events.Icon(icons.OK), events.ProgressFinish())

d.ev.Send("Installing dependency tools", events.ProgressStart())
if err := cosmosgen.InstallDepTools(ctx, "."); err != nil {
d.ev.Send(
fmt.Sprintf("tools file %s", colors.Success(status)),
events.Icon(icons.OK),
events.ProgressFinish(),
)

case os.IsNotExist(err):
if err := d.createToolsFile(ctx, ToolsFile); err != nil {
return errf(err)
}
for _, dep := range cosmosgen.DepTools() {
d.ev.Send(fmt.Sprintf("%s %s", path.Base(dep), colors.Success("installed")),
events.Icon(icons.OK), events.ProgressFinish())
}

default:
return errf(err)
}

return nil
}

func (d Doctor) createToolsFile(ctx context.Context, toolsFilename string) error {
pathInfo, err := gomodulepath.ParseAt(".")
if err != nil {
return err
}

g, err := app.NewGenerator(&app.Options{
ModulePath: pathInfo.RawPath,
AppName: pathInfo.Package,
BinaryNamePrefix: pathInfo.Root,
IncludePrefixes: []string{toolsFilename},
})
if err != nil {
return err
}

runner := genny.WetRunner(ctx)
if err := runner.With(g); err != nil {
return err
}

if err := runner.Run(); err != nil {
return err
}

d.ev.Send(
fmt.Sprintf("%s %s", toolsFilename, colors.Success("created")),
events.Icon(icons.OK),
events.ProgressFinish(),
)

d.ev.Send("Installing dependency tools", events.ProgressStart())
if err := cosmosgen.InstallDepTools(ctx, "."); err != nil {
return err
}

for _, dep := range cosmosgen.DepTools() {
d.ev.Send(
fmt.Sprintf("%s %s", path.Base(dep), colors.Success("installed")),
events.Icon(icons.OK),
events.ProgressFinish(),
)
}

return nil
}

func (d Doctor) ensureDependencyImports(toolsFilename string) (bool, error) {
d.ev.Send("Ensuring required tools imports", events.ProgressStart())

f, _, err := xast.ParseFile(toolsFilename)
if err != nil {
return false, err
}

var (
buf bytes.Buffer
missing = cosmosgen.MissingTools(f)
unused = cosmosgen.UnusedTools(f)
)

// Check if the tools file should be fixed
if len(missing) == 0 && len(unused) == 0 {
return false, nil
}

err = goanalysis.UpdateInitImports(f, &buf, missing, unused)
if err != nil {
return false, err
}

err = os.WriteFile(toolsFilename, buf.Bytes(), 0o644)
if err != nil {
return false, err
}

return true, nil
}

0 comments on commit 615c855

Please sign in to comment.