Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generate templates command #1242

Merged
merged 28 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8bf521e
Add generate setup for templates
chasefleming Oct 23, 2023
d6a51ba
Add script and tx templates
chasefleming Oct 24, 2023
86d6ea7
Generate at file path and add tests
chasefleming Oct 24, 2023
9e8d8e7
Update readme
chasefleming Oct 24, 2023
54e52d6
Update README.md
chasefleming Oct 25, 2023
8efa0c7
Update internal/super/generate.go
chasefleming Oct 25, 2023
06433cf
Update internal/super/generate.go
chasefleming Oct 25, 2023
d4aa5e5
Update internal/super/generate.go
chasefleming Oct 25, 2023
f231c5e
Update internal/super/generate.go
chasefleming Oct 25, 2023
be0ae7d
Update internal/super/generate_test.go
chasefleming Oct 25, 2023
d8df7a6
Update internal/super/generate.go
chasefleming Oct 25, 2023
a8cf73f
Add filepath import
chasefleming Oct 25, 2023
44ceeb8
Fix test for tx gen
chasefleming Oct 25, 2023
0d4e0ec
Add init to contract template
chasefleming Oct 25, 2023
106ef48
Allow user to define directory for template gen
chasefleming Oct 25, 2023
4983141
Move to subcommands
chasefleming Oct 25, 2023
3ce0087
Update internal/super/generate.go
chasefleming Oct 25, 2023
cff1357
Update internal/super/generate_test.go
chasefleming Oct 25, 2023
deb8540
Update internal/super/generate_test.go
chasefleming Oct 25, 2023
d5f20ea
fix tests
chasefleming Oct 25, 2023
3a2eec6
Run goimports
chasefleming Oct 25, 2023
4dd7808
Fix golint error for Chdir
chasefleming Oct 25, 2023
7b48f13
Add alias
chasefleming Oct 27, 2023
020da9f
Save contract to flow.json
chasefleming Oct 27, 2023
d8ecd49
Fix tests
chasefleming Oct 27, 2023
5b076c4
Use readerwriter
chasefleming Oct 30, 2023
19608ba
Merge branch 'master' into chasefleming/generate-templates
chasefleming Oct 30, 2023
2adf137
Add MkDirAll
chasefleming Oct 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,42 @@ Read about supported commands in the [CLI documentation website](https://develop
Usage:
flow [command]

Available Commands:
accounts Utilities to manage accounts
blocks Utilities to read blocks
👋 Welcome Flow developer!
If you are starting a new flow project try running 'flow setup <project_name>'.

🔥 Super Commands
chasefleming marked this conversation as resolved.
Show resolved Hide resolved
dev Build your Flow project
flix Execute FLIX template with a given id, name, or local filename
generate Generate new boilerplate files
setup Start a new Flow project

📦 Flow Entities
accounts Create and retrieve accounts and deploy contracts
blocks Retrieve blocks
collections Retrieve collections
events Retrieve events

💬 Flow Interactions
scripts Execute Cadence scripts
transactions Build, sign, send and retrieve transactions

🔨 Flow Tools
cadence Execute Cadence code
collections Utilities to read collections
chasefleming marked this conversation as resolved.
Show resolved Hide resolved
config Utilities to manage configuration
emulator Starts the Flow emulator server
dev-wallet Run a development wallet
emulator Run Flow network for development
flowser Run Flowser project explorer
test Run Cadence tests
events Utilities to read events
help Help about any command

🏄 Flow Project
deploy Deploy all project contracts
init Initialize a new configuration
keys Utilities to manage keys
project Manage your Cadence project
scripts Utilities to execute scripts
status Display the status of the Flow network
transactions Utilities to send transactions
version View version and commit information
run Start emulator and deploy all project contracts

🔒 Flow Security
keys Generate and decode Flow keys
signatures Signature verification and creation

```

The Flow CLI includes several commands to interact with Flow networks, such as querying account information, or sending transactions. It also includes the [Flow Emulator](https://developers.flow.com/tools/emulator).
Expand Down
1 change: 1 addition & 0 deletions cmd/flow/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func main() {
super.SetupCommand.AddToParent(cmd)
super.DevCommand.AddToParent(cmd)
super.FlixCommand.AddToParent(cmd)
cmd.AddCommand(super.GenerateCommand)

// structured commands
cmd.AddCommand(settings.Cmd)
Expand Down
192 changes: 192 additions & 0 deletions internal/super/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*
* Flow CLI
*
* Copyright 2019 Dapper Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package super

import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/onflow/flow-cli/flowkit"

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

"github.com/spf13/cobra"
)

type generateFlagsDef struct {
Directory string `default:"" flag:"dir" info:"Directory to generate files in"`
}

var generateFlags = generateFlagsDef{}

var GenerateCommand = &cobra.Command{
Use: "generate",
Short: "Generate new boilerplate files",
GroupID: "super",
}

var GenerateContractCommand = &command.Command{
Cmd: &cobra.Command{
Use: "contract <name>",
Short: "Generate a new contract",
Example: "flow generate contract HelloWorld",
Args: cobra.ExactArgs(1),
},
Flags: &generateFlags,
RunS: generateContract,
}

var GenerateTransactionCommand = &command.Command{
Cmd: &cobra.Command{
Use: "transaction <name>",
Short: "Generate a new transaction",
Example: "flow generate transaction SomeTransaction",
Args: cobra.ExactArgs(1),
},
Flags: &generateFlags,
RunS: generateTransaction,
}

var GenerateScriptCommand = &command.Command{
Cmd: &cobra.Command{
Use: "script <name>",
Short: "Generate a new script",
Example: "flow generate script SomeScript",
Args: cobra.ExactArgs(1),
},
Flags: &generateFlags,
RunS: generateScript,
}

func init() {
GenerateContractCommand.AddToParent(GenerateCommand)
GenerateTransactionCommand.AddToParent(GenerateCommand)
GenerateScriptCommand.AddToParent(GenerateCommand)
}

func generateContract(
args []string,
_ command.GlobalFlags,
logger output.Logger,
flow flowkit.Services,
state *flowkit.State,
) (result command.Result, err error) {
return generateNew(args, "contract", logger)
}

func generateTransaction(
args []string,
_ command.GlobalFlags,
logger output.Logger,
flow flowkit.Services,
state *flowkit.State,
) (result command.Result, err error) {
return generateNew(args, "transaction", logger)
}

func generateScript(
args []string,
_ command.GlobalFlags,
logger output.Logger,
flow flowkit.Services,
state *flowkit.State,
) (result command.Result, err error) {
return generateNew(args, "script", logger)
}

func generateNew(
args []string,
templateType string,
logger output.Logger,
) (result command.Result, err error) {
if len(args) < 1 {
return nil, fmt.Errorf("invalid number of arguments")
}

name := args[0]
var filename string

// Don't add .cdc extension if it's already there
if strings.HasSuffix(name, ".cdc") {
filename = name
} else {
filename = fmt.Sprintf("%s.cdc", name)
}

var fileToWrite string
var basePath string

if generateFlags.Directory != "" {
basePath = generateFlags.Directory
} else {
switch templateType {
case "contract":
basePath = "cadence/contracts"
case "script":
basePath = "cadence/scripts"
case "transaction":
basePath = "cadence/transactions"
default:
return nil, fmt.Errorf("invalid template type: %s", templateType)
}
}

switch templateType {
case "contract":
fileToWrite = fmt.Sprintf(`
access(all) contract %s {
init() {}
}`, name)
case "script":
fileToWrite = `access(all) fun main() {
// Script details here
}`
case "transaction":
fileToWrite = `transaction() {
prepare(account:AuthAccount) {}

execute {}
}`
default:
return nil, fmt.Errorf("invalid template type: %s", templateType)
}

filenameWithBasePath := filepath.Join(basePath, filename)

if _, err := os.Stat(filenameWithBasePath); err == nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flow-cli has the --save -s flag to save the output of a command to a file, do we need to have this logic here or can we just return the output and rely on that logic?

also state has a ReaderWriter that is used to save files and that is used elsewhere instead of os functions.

Copy link
Member Author

@chasefleming chasefleming Oct 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm yeah I guess that means that you always have to provide --save. I was hoping to just always generate them to the correct folders unless specified otherwise. But it makes sense to keep the same pattern. Just really verbose now. Writing flow generate contract woohoo --save cadence/contracts/whoohoo.cdc is so long that I'd almost rather just write the cadence instead of use this command. Makes me want to kill this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo just skip the pattern/flag here. I think think it's pretty obvious that this will be saving a file and using a flag for this is just redundant & a command like this is for ease of use so should be as shorthand as possible. I think the only purpose --save potentially has in this is as an override to the output path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fully in support for super short aliases here as well (i.e. flow g c FooBar)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to not use --save. But using ReaderWriter is recommended. I think it also creates required directories.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah ReaderWriter is no problem. Good catch. Will change that @bjartek

return nil, fmt.Errorf("file already exists: %s", filenameWithBasePath)
}

// Ensure the directory exists
if err := os.MkdirAll(basePath, 0755); err != nil {
return nil, fmt.Errorf("error creating directories: %w", err)
}

err = os.WriteFile(filenameWithBasePath, []byte(fileToWrite), 0644)
if err != nil {
return nil, fmt.Errorf("error writing file: %w", err)
}

logger.Info(fmt.Sprintf("Generated new %s: %s at %s", templateType, name, filenameWithBasePath))

return nil, err
}
Loading
Loading