forked from rollkit/rollkit
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: rollkit start running application logic of the rollup (rollkit#…
…1680) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added functionality to intercept and run an entry point specified in a TOML configuration file. - Introduced a new command for initializing TOML files with specific configurations. - **Bug Fixes** - Ensured proper handling of configuration read errors and empty entry points during interception. - **Documentation** - Updated documentation to include new TOML command operations and initialization steps. - **Tests** - Added tests for the intercept command, covering successful interception, configuration read errors, and empty entry points. - **Chores** - Added a new dependency on `github.com/BurntSushi/toml` version `v1.3.2`. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Matthew Sevey <15232757+MSevey@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Loading branch information
1 parent
3368b73
commit c2bcb6c
Showing
12 changed files
with
715 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package commands | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
|
||
cometos "github.com/cometbft/cometbft/libs/os" | ||
"github.com/spf13/cobra" | ||
|
||
rollconf "github.com/rollkit/rollkit/config" | ||
) | ||
|
||
const rollupBinEntrypoint = "entrypoint" | ||
|
||
var rollkitConfig rollconf.TomlConfig | ||
|
||
// InterceptCommand intercepts the command and runs it against the `entrypoint` | ||
// specified in the rollkit.toml configuration file. | ||
func InterceptCommand( | ||
rollkitCommand *cobra.Command, | ||
readToml func() (rollconf.TomlConfig, error), | ||
runEntrypoint func(*rollconf.TomlConfig, []string) error, | ||
) (bool, error) { | ||
// Grab flags and verify command | ||
flags := []string{} | ||
if len(os.Args) >= 2 { | ||
flags = os.Args[1:] | ||
|
||
// Handle specific cases first for help, version, and start | ||
switch os.Args[1] { | ||
case "help", "--help", "h", "-h", | ||
"version", "--version", "v", "-v": | ||
return false, nil | ||
case "start": | ||
goto readTOML | ||
} | ||
|
||
// Check if user attempted to run a rollkit command | ||
for _, cmd := range rollkitCommand.Commands() { | ||
if os.Args[1] == cmd.Use { | ||
return false, nil | ||
} | ||
} | ||
} | ||
|
||
readTOML: | ||
var err error | ||
rollkitConfig, err = readToml() | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
// To avoid recursive calls, we check if the root directory is the rollkit repository itself | ||
if filepath.Base(rollkitConfig.RootDir) == "rollkit" { | ||
return false, nil | ||
} | ||
|
||
// After successfully reading the TOML file, we expect to be able to use the entrypoint | ||
if rollkitConfig.Entrypoint == "" { | ||
return true, fmt.Errorf("no entrypoint specified in %s", rollconf.RollkitToml) | ||
} | ||
|
||
return true, runEntrypoint(&rollkitConfig, flags) | ||
} | ||
|
||
// RunRollupEntrypoint runs the entrypoint specified in the rollkit.toml configuration file. | ||
// If the entrypoint is not built, it will build it first. The entrypoint is built | ||
// in the same directory as the rollkit.toml file. The entrypoint is run with the | ||
// same flags as the original command, but with the `--home` flag set to the config | ||
// directory of the chain specified in the rollkit.toml file. This is so the entrypoint, | ||
// which is a separate binary of the rollup, can read the correct chain configuration files. | ||
func RunRollupEntrypoint(rollkitConfig *rollconf.TomlConfig, args []string) error { | ||
var entrypointSourceFile string | ||
if !filepath.IsAbs(rollkitConfig.RootDir) { | ||
entrypointSourceFile = filepath.Join(rollkitConfig.RootDir, rollkitConfig.Entrypoint) | ||
} else { | ||
entrypointSourceFile = rollkitConfig.Entrypoint | ||
} | ||
|
||
// The entrypoint binary file is always in the same directory as the rollkit.toml file. | ||
entrypointBinaryFile := filepath.Join(rollkitConfig.RootDir, rollupBinEntrypoint) | ||
|
||
if !cometos.FileExists(entrypointBinaryFile) { | ||
if !cometos.FileExists(entrypointSourceFile) { | ||
return fmt.Errorf("no entrypoint file: %s", entrypointSourceFile) | ||
} | ||
|
||
// try to build the entrypoint as a go binary | ||
buildArgs := []string{"build", "-o", entrypointBinaryFile, entrypointSourceFile} | ||
buildCmd := exec.Command("go", buildArgs...) //nolint:gosec | ||
buildCmd.Stdout = os.Stdout | ||
buildCmd.Stderr = os.Stderr | ||
if err := buildCmd.Run(); err != nil { | ||
return fmt.Errorf("failed to build entrypoint: %w", err) | ||
} | ||
} | ||
|
||
var runArgs []string | ||
runArgs = append(runArgs, args...) | ||
if rollkitConfig.Chain.ConfigDir != "" { | ||
// The entrypoint is a separate binary based on https://github.com/rollkit/cosmos-sdk, so | ||
// we have to pass --home flag to the entrypoint to read the correct chain configuration files if specified. | ||
runArgs = append(runArgs, "--home", rollkitConfig.Chain.ConfigDir) | ||
} | ||
|
||
entrypointCmd := exec.Command(entrypointBinaryFile, runArgs...) //nolint:gosec | ||
entrypointCmd.Stdout = os.Stdout | ||
entrypointCmd.Stderr = os.Stderr | ||
|
||
if err := entrypointCmd.Run(); err != nil { | ||
return fmt.Errorf("failed to run entrypoint: %w", err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package commands | ||
|
||
import ( | ||
"errors" | ||
"os" | ||
"testing" | ||
|
||
rollconf "github.com/rollkit/rollkit/config" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
func TestInterceptCommand(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
rollkitCommands []string | ||
mockReadToml func() (rollconf.TomlConfig, error) | ||
mockRunEntrypoint func(rollkitConfig *rollconf.TomlConfig, args []string) error | ||
args []string | ||
wantErr bool | ||
wantExecuted bool | ||
}{ | ||
{ | ||
name: "Successful intercept with entrypoint", | ||
rollkitCommands: []string{"docs-gen", "toml"}, | ||
mockReadToml: func() (rollconf.TomlConfig, error) { | ||
return rollconf.TomlConfig{ | ||
Entrypoint: "test-entrypoint", | ||
Chain: rollconf.ChainTomlConfig{ConfigDir: "/test/config"}, | ||
|
||
RootDir: "/test/root", | ||
}, nil | ||
}, | ||
mockRunEntrypoint: func(config *rollconf.TomlConfig, flags []string) error { | ||
return nil | ||
}, | ||
args: []string{"rollkit", "start"}, | ||
wantErr: false, | ||
wantExecuted: true, | ||
}, | ||
{ | ||
name: "Configuration read error", | ||
rollkitCommands: []string{"docs-gen", "toml"}, | ||
mockReadToml: func() (rollconf.TomlConfig, error) { | ||
return rollconf.TomlConfig{}, errors.New("read error") | ||
}, | ||
args: []string{"rollkit", "start"}, | ||
wantErr: true, | ||
wantExecuted: false, | ||
}, | ||
{ | ||
name: "Empty entrypoint", | ||
rollkitCommands: []string{"docs-gen", "toml"}, | ||
mockReadToml: func() (rollconf.TomlConfig, error) { | ||
return rollconf.TomlConfig{Entrypoint: ""}, nil | ||
}, | ||
args: []string{"rollkit", "start"}, | ||
wantErr: true, | ||
wantExecuted: true, | ||
}, | ||
{ | ||
name: "Skip intercept, rollkit command", | ||
rollkitCommands: []string{"docs-gen", "toml"}, | ||
mockReadToml: func() (rollconf.TomlConfig, error) { | ||
return rollconf.TomlConfig{ | ||
Entrypoint: "test-entrypoint", | ||
Chain: rollconf.ChainTomlConfig{ConfigDir: "/test/config"}, | ||
|
||
RootDir: "/test/root", | ||
}, nil | ||
}, | ||
mockRunEntrypoint: func(config *rollconf.TomlConfig, flags []string) error { | ||
return nil | ||
}, | ||
args: []string{"rollkit", "docs-gen"}, | ||
wantErr: false, | ||
wantExecuted: false, | ||
}, | ||
{ | ||
name: "Skip intercept, help command", | ||
rollkitCommands: []string{"docs-gen", "toml"}, | ||
mockReadToml: func() (rollconf.TomlConfig, error) { | ||
return rollconf.TomlConfig{ | ||
Entrypoint: "test-entrypoint", | ||
Chain: rollconf.ChainTomlConfig{ConfigDir: "/test/config"}, | ||
|
||
RootDir: "/test/root", | ||
}, nil | ||
}, | ||
mockRunEntrypoint: func(config *rollconf.TomlConfig, flags []string) error { | ||
return nil | ||
}, | ||
args: []string{"rollkit", "-h"}, | ||
wantErr: false, | ||
wantExecuted: false, | ||
}, | ||
{ | ||
name: "Skip intercept, rollkit repository itself", | ||
rollkitCommands: []string{"docs-gen", "toml"}, | ||
mockReadToml: func() (rollconf.TomlConfig, error) { | ||
return rollconf.TomlConfig{ | ||
Entrypoint: "test-entrypoint", | ||
Chain: rollconf.ChainTomlConfig{ConfigDir: "/test/config"}, | ||
|
||
RootDir: "/test/rollkit", | ||
}, nil | ||
}, | ||
mockRunEntrypoint: func(config *rollconf.TomlConfig, flags []string) error { | ||
return nil | ||
}, | ||
args: []string{"rollkit", "start"}, | ||
wantErr: false, | ||
wantExecuted: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
os.Args = tt.args | ||
|
||
cmd := &cobra.Command{Use: "test"} | ||
for _, c := range tt.rollkitCommands { | ||
cmd.AddCommand(&cobra.Command{Use: c}) | ||
} | ||
|
||
ok, err := InterceptCommand( | ||
cmd, | ||
tt.mockReadToml, | ||
tt.mockRunEntrypoint, | ||
) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("InterceptCommand() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if ok != tt.wantExecuted { | ||
t.Errorf("InterceptCommand() executed = %v, wantExecuted %v", ok, tt.wantExecuted) | ||
return | ||
} | ||
}) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package commands | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
rollconf "github.com/rollkit/rollkit/config" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
// NewTomlCmd creates a new cobra command group for TOML file operations. | ||
func NewTomlCmd() *cobra.Command { | ||
TomlCmd := &cobra.Command{ | ||
Use: "toml", | ||
Short: "TOML file operations", | ||
Long: `This command group is used to interact with TOML files.`, | ||
Example: ` rollkit toml init`, | ||
} | ||
|
||
TomlCmd.AddCommand(initCmd) | ||
|
||
return TomlCmd | ||
} | ||
|
||
var initCmd = &cobra.Command{ | ||
Use: "init", | ||
Short: fmt.Sprintf("Initialize a new %s file", rollconf.RollkitToml), | ||
Long: fmt.Sprintf("This command initializes a new %s file in the current directory.", rollconf.RollkitToml), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
if _, err := os.Stat(rollconf.RollkitToml); err == nil { | ||
fmt.Printf("%s file already exists in the current directory.\n", rollconf.RollkitToml) | ||
os.Exit(1) | ||
} | ||
|
||
// try find main.go file under the current directory | ||
dirName, entrypoint := rollconf.FindEntrypoint() | ||
if entrypoint == "" { | ||
fmt.Println("Could not find a rollup main.go entrypoint under the current directory. Please put an entrypoint in the rollkit.toml file manually.") | ||
} else { | ||
fmt.Printf("Found rollup entrypoint: %s, adding to rollkit.toml\n", entrypoint) | ||
} | ||
|
||
// checking for default cosmos chain config directory | ||
chainConfigDir, ok := rollconf.FindConfigDir(dirName) | ||
if !ok { | ||
fmt.Printf("Could not find rollup config under %s. Please put the chain.config_dir in the rollkit.toml file manually.\n", chainConfigDir) | ||
} else { | ||
fmt.Printf("Found rollup configuration under %s, adding to rollkit.toml\n", chainConfigDir) | ||
} | ||
|
||
config := rollconf.TomlConfig{ | ||
Entrypoint: entrypoint, | ||
Chain: rollconf.ChainTomlConfig{ | ||
ConfigDir: chainConfigDir, | ||
}, | ||
} | ||
|
||
// marshal the config to a toml file in the current directory | ||
if err := rollconf.WriteTomlConfig(config); err != nil { | ||
fmt.Println("Error writing rollkit.toml file:", err) | ||
os.Exit(1) | ||
} | ||
|
||
fmt.Printf("Initialized %s file in the current directory.\n", rollconf.RollkitToml) | ||
}, | ||
} |
Oops, something went wrong.