Skip to content

Commit

Permalink
Merge pull request #1841 from onflow/cf/1755
Browse files Browse the repository at this point in the history
Consolidate `add` with `install` in DM and allow multiple dependency installation
  • Loading branch information
chasefleming authored Nov 25, 2024
2 parents c73ef4e + ffc5d9a commit 4bf9dc0
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 98 deletions.
79 changes: 12 additions & 67 deletions internal/dependencymanager/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,90 +20,35 @@ package dependencymanager

import (
"fmt"
"strings"

"github.com/onflow/flow-go/fvm/systemcontracts"

"github.com/onflow/flowkit/v2"
"github.com/spf13/cobra"

"github.com/onflow/flowkit/v2"
"github.com/onflow/flowkit/v2/output"
"github.com/onflow/flow-cli/internal/util"

flowGo "github.com/onflow/flow-go/model/flow"
"github.com/onflow/flowkit/v2/output"

"github.com/onflow/flow-cli/internal/command"
"github.com/onflow/flow-cli/internal/util"
)

type addFlagsCollection struct {
*Flags
name string
}

var addFlags = addFlagsCollection{
Flags: &Flags{},
}

var addCommand = &command.Command{
Cmd: &cobra.Command{
Use: "add <source string or core contract name>",
Short: "Add a single contract and its dependencies.",
Example: `flow dependencies add testnet://0afe396ebc8eee65.FlowToken
flow dependencies add FlowToken`,
Args: cobra.ExactArgs(1),
Use: "add",
Short: "This command has been deprecated.",
Long: "The 'add' command has been deprecated. Please use the 'install' command instead.",
Deprecated: "This command is deprecated. Use 'install' to manage dependencies.",
},
RunS: add,
Flags: &struct{}{},
}

func init() {
// Add common flags.
addFlags.Flags.AddToCommand(addCommand.Cmd)
// Add command-specific flags.
addCommand.Cmd.Flags().StringVar(&addFlags.name, "name", "", "Name of the dependency")
}

func add(
args []string,
_ []string,
_ command.GlobalFlags,
logger output.Logger,
flow flowkit.Services,
state *flowkit.State,
) (result command.Result, err error) {
logger.Info(fmt.Sprintf("%s Installing dependencies for %s...", util.PrintEmoji("🔄"), args[0]))

dep := args[0]

installer, err := NewDependencyInstaller(logger, state, true, "", *addFlags.Flags)
if err != nil {
logger.Error(fmt.Sprintf("Error: %v", err))
return nil, err
}

// First check if the dependency is a core contract.
coreContractName := findCoreContractCaseInsensitive(dep)
if coreContractName != "" {
if err := installer.AddByCoreContractName(coreContractName, addFlags.name); err != nil {
logger.Error(fmt.Sprintf("Error: %v", err))
return nil, err
}
return nil, nil
}

// Otherwise, add the dependency by source string.
if err := installer.AddBySourceString(dep, addFlags.name); err != nil {
logger.Error(fmt.Sprintf("Error: %v", err))
return nil, err
}

_ flowkit.Services,
_ *flowkit.State,
) (command.Result, error) {
logger.Info(fmt.Sprintf("%s The 'add' command has been deprecated. Please use 'install' instead.", util.PrintEmoji("⚠️")))
return nil, nil
}

func findCoreContractCaseInsensitive(name string) string {
for _, contract := range systemcontracts.SystemContractsForChain(flowGo.Mainnet).All() {
if strings.EqualFold(contract.Name, name) {
return contract.Name
}
}
return ""
}
26 changes: 5 additions & 21 deletions internal/dependencymanager/dependencyinstaller.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, saveStat
SkipDeployments: flags.skipDeployments,
SkipAlias: flags.skipAlias,
dependencies: make(map[string]config.Dependency),
logs: categorizedLogs{},
}, nil
}

Expand Down Expand Up @@ -176,26 +177,18 @@ func (di *DependencyInstaller) Install() error {
return fmt.Errorf("error saving state: %w", err)
}

di.logs.LogAll(di.Logger)

return nil
}

// AddBySourceString processes a single dependency and installs it and any dependencies it has, as well as adding it to the state
func (di *DependencyInstaller) AddBySourceString(depSource, customName string) error {
func (di *DependencyInstaller) AddBySourceString(depSource string) error {
depNetwork, depAddress, depContractName, err := config.ParseSourceString(depSource)
if err != nil {
return fmt.Errorf("error parsing source: %w", err)
}

name := depContractName

if customName != "" {
name = customName
}

dep := config.Dependency{
Name: name,
Name: depContractName,
Source: config.Source{
NetworkName: depNetwork,
Address: flowsdk.HexToAddress(depAddress),
Expand All @@ -206,7 +199,7 @@ func (di *DependencyInstaller) AddBySourceString(depSource, customName string) e
return di.Add(dep)
}

func (di *DependencyInstaller) AddByCoreContractName(coreContractName, customName string) error {
func (di *DependencyInstaller) AddByCoreContractName(coreContractName string) error {
var depNetwork, depAddress, depContractName string
sc := systemcontracts.SystemContractsForChain(flowGo.Mainnet)
for _, coreContract := range sc.All() {
Expand All @@ -222,13 +215,8 @@ func (di *DependencyInstaller) AddByCoreContractName(coreContractName, customNam
return fmt.Errorf("contract %s not found in core contracts", coreContractName)
}

name := depContractName
if customName != "" {
name = customName
}

dep := config.Dependency{
Name: name,
Name: depContractName,
Source: config.Source{
NetworkName: depNetwork,
Address: flowsdk.HexToAddress(depAddress),
Expand All @@ -251,8 +239,6 @@ func (di *DependencyInstaller) Add(dep config.Dependency) error {
return err
}

di.logs.LogAll(di.Logger)

return nil
}

Expand All @@ -268,8 +254,6 @@ func (di *DependencyInstaller) AddMany(dependencies []config.Dependency) error {
return err
}

di.logs.LogAll(di.Logger)

return nil
}

Expand Down
4 changes: 2 additions & 2 deletions internal/dependencymanager/dependencyinstaller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func TestDependencyInstallerAdd(t *testing.T) {
}

sourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name)
err := di.AddBySourceString(sourceStr, "")
err := di.AddBySourceString(sourceStr)
assert.NoError(t, err, "Failed to install dependencies")

filePath := fmt.Sprintf("imports/%s/%s.cdc", serviceAddress.String(), tests.ContractHelloString.Name)
Expand Down Expand Up @@ -215,7 +215,7 @@ func TestDependencyInstallerAdd(t *testing.T) {
dependencies: make(map[string]config.Dependency),
}

err := di.AddByCoreContractName("FlowToken", "")
err := di.AddByCoreContractName("FlowToken")
assert.NoError(t, err, "Failed to install dependencies")

filePath := fmt.Sprintf("imports/%s/%s.cdc", "1654653399040a61", "FlowToken")
Expand Down
71 changes: 63 additions & 8 deletions internal/dependencymanager/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ package dependencymanager

import (
"fmt"
"strings"

"github.com/onflow/flow-go/fvm/systemcontracts"
flowGo "github.com/onflow/flow-go/model/flow"

"github.com/onflow/flow-cli/internal/util"

Expand All @@ -35,33 +39,84 @@ var installFlags = Flags{}

var installCommand = &command.Command{
Cmd: &cobra.Command{
Use: "install",
Short: "Install contract and dependencies.",
Example: "flow dependencies install",
Use: "install",
Short: "Install contract and dependencies.",
Example: `flow dependencies install
flow dependencies install testnet://0afe396ebc8eee65.FlowToken
flow dependencies install FlowToken
flow dependencies install FlowToken NonFungibleToken`,
Args: cobra.ArbitraryArgs,
},
Flags: &installFlags,
RunS: install,
}

func install(
_ []string,
args []string,
_ command.GlobalFlags,
logger output.Logger,
flow flowkit.Services,
state *flowkit.State,
) (result command.Result, err error) {
logger.Info(util.MessageWithEmojiPrefix("🔄", "Installing dependencies from flow.json..."))

installer, err := NewDependencyInstaller(logger, state, true, "", installFlags)
if err != nil {
logger.Error(fmt.Sprintf("Error: %v", err))
logger.Error(fmt.Sprintf("Error initializing dependency installer: %v", err))
return nil, err
}

if len(args) > 0 {
for _, dep := range args {
logger.Info(fmt.Sprintf("%s Processing dependency %s...", util.PrintEmoji("🔄"), dep))

// Check if the dependency is a core contract
coreContractName := findCoreContractCaseInsensitive(dep)
if coreContractName != "" {
if err := installer.AddByCoreContractName(coreContractName); err != nil {
logger.Error(fmt.Sprintf("Error adding core contract %s: %v", coreContractName, err))
return nil, err
}
continue
}

if err := installer.AddBySourceString(dep); err != nil {
if strings.Contains(err.Error(), "invalid dependency source format") {
logger.Error(fmt.Sprintf("Error: '%s' is neither a core contract nor a valid dependency source format.\nPlease provide a valid dependency source in the format 'network://address.ContractName', e.g., 'testnet://0x1234567890abcdef.MyContract', or use a valid core contract name such as 'FlowToken'.", dep))
} else {
logger.Error(fmt.Sprintf("Error adding dependency %s: %v", dep, err))
}
return nil, err
}
}

logger.Info(util.MessageWithEmojiPrefix("🔄", "Installing added dependencies..."))

if err := installer.Install(); err != nil {
logger.Error(fmt.Sprintf("Error installing dependencies: %v", err))
return nil, err
}

installer.logs.LogAll(logger)

return nil, nil
}

logger.Info(util.MessageWithEmojiPrefix("🔄", "Installing dependencies from flow.json..."))

if err := installer.Install(); err != nil {
logger.Error(fmt.Sprintf("Error: %v", err))
logger.Error(fmt.Sprintf("Error installing dependencies: %v", err))
return nil, err
}

installer.logs.LogAll(logger)

return nil, nil
}

func findCoreContractCaseInsensitive(name string) string {
for _, contract := range systemcontracts.SystemContractsForChain(flowGo.Mainnet).All() {
if strings.EqualFold(contract.Name, name) {
return contract.Name
}
}
return ""
}

0 comments on commit 4bf9dc0

Please sign in to comment.