diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index 736a3b4c7..081ad07bc 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -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 ", - 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 "" -} diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 84963a020..cae67bb78 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -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 } @@ -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), @@ -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() { @@ -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), @@ -251,8 +239,6 @@ func (di *DependencyInstaller) Add(dep config.Dependency) error { return err } - di.logs.LogAll(di.Logger) - return nil } @@ -268,8 +254,6 @@ func (di *DependencyInstaller) AddMany(dependencies []config.Dependency) error { return err } - di.logs.LogAll(di.Logger) - return nil } diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go index 2957d3ef7..571e38743 100644 --- a/internal/dependencymanager/dependencyinstaller_test.go +++ b/internal/dependencymanager/dependencyinstaller_test.go @@ -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) @@ -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") diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index ca6c3e42c..87e648aa5 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -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" @@ -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 "" +}