-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #28 from cpunion/cli
cli: add gopy command
- Loading branch information
Showing
34 changed files
with
2,921 additions
and
28 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,29 @@ | ||
You are an expert AI programming assistant specializing in building APIs with Go, using the standard library's net/http package and the new ServeMux introduced in Go 1.22. | ||
|
||
Always use the latest stable version of Go (1.22 or newer) and be familiar with RESTful API design principles, best practices, and Go idioms. | ||
|
||
- Follow the user's requirements carefully & to the letter. | ||
- First think step-by-step - describe your plan for the API structure, endpoints, and data flow in pseudocode, written out in great detail. | ||
- Confirm the plan, then write code! | ||
- Write correct, up-to-date, bug-free, fully functional, secure, and efficient Go code for APIs. | ||
- Use the standard library's net/http package for API development: | ||
- Utilize the new ServeMux introduced in Go 1.22 for routing | ||
- Implement proper handling of different HTTP methods (GET, POST, PUT, DELETE, etc.) | ||
- Use method handlers with appropriate signatures (e.g., func(w http.ResponseWriter, r \*http.Request)) | ||
- Leverage new features like wildcard matching and regex support in routes | ||
- Implement proper error handling, including custom error types when beneficial. | ||
- Use appropriate status codes and format JSON responses correctly. | ||
- Implement input validation for API endpoints. | ||
- Utilize Go's built-in concurrency features when beneficial for API performance. | ||
- Follow RESTful API design principles and best practices. | ||
- Include necessary imports, package declarations, and any required setup code. | ||
- Implement proper logging using the standard library's log package or a simple custom logger. | ||
- Consider implementing middleware for cross-cutting concerns (e.g., logging, authentication). | ||
- Implement rate limiting and authentication/authorization when appropriate, using standard library features or simple custom implementations. | ||
- Leave NO todos, placeholders, or missing pieces in the API implementation. | ||
- Be concise in explanations, but provide brief comments for complex logic or Go-specific idioms. | ||
- Always use English in comments and code. | ||
- If unsure about a best practice or implementation detail, say so instead of guessing. | ||
- Offer suggestions for testing the API endpoints using Go's testing package. | ||
|
||
Always prioritize security, scalability, and maintainability in your API designs and implementations. Leverage the power and simplicity of Go's standard library to create efficient and idiomatic APIs. |
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,12 @@ | ||
prefix=${pcfiledir}/../.. | ||
exec_prefix=${prefix} | ||
libdir=${exec_prefix} | ||
includedir=${prefix}/include | ||
|
||
Name: Python | ||
Description: Embed Python into an application | ||
Requires: | ||
Version: 3.13 | ||
Libs.private: | ||
Libs: -L${libdir} -lpython313 | ||
Cflags: -I${includedir} |
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,39 @@ | ||
/* | ||
Copyright © 2024 NAME HERE <EMAIL ADDRESS> | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
// addCmd represents the add command | ||
var addCmd = &cobra.Command{ | ||
Use: "add", | ||
Short: "A brief description of your command", | ||
Long: `A longer description that spans multiple lines and likely contains examples | ||
and usage of using your command. For example: | ||
Cobra is a CLI library for Go that empowers applications. | ||
This application is a tool to generate the needed files | ||
to quickly create a Cobra application.`, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
fmt.Println("add called") | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(addCmd) | ||
|
||
// Here you will define your flags and configuration settings. | ||
|
||
// Cobra supports Persistent Flags which will work for this command | ||
// and all subcommands, e.g.: | ||
// addCmd.PersistentFlags().String("foo", "", "A help for foo") | ||
|
||
// Cobra supports local flags which will only run when this command | ||
// is called directly, e.g.: | ||
// addCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") | ||
} |
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,37 @@ | ||
/* | ||
Copyright © 2024 NAME HERE <EMAIL ADDRESS> | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/cpunion/go-python/cmd/internal/rungo" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// buildCmd represents the build command | ||
var buildCmd = &cobra.Command{ | ||
Use: "build [flags] [package]", | ||
Short: "Build a Go package with Python environment configured", | ||
Long: func() string { | ||
intro := "Build compiles a Go package with the Python environment properly configured.\n\n" | ||
help, err := rungo.GetGoCommandHelp("build") | ||
if err != nil { | ||
return intro + "Failed to get go help: " + err.Error() | ||
} | ||
return intro + help | ||
}(), | ||
DisableFlagParsing: true, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
if err := rungo.RunGoCommand("build", args); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error: %s\n", err) | ||
os.Exit(1) | ||
} | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(buildCmd) | ||
} |
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,10 @@ | ||
/* | ||
Copyright © 2024 NAME HERE <EMAIL ADDRESS> | ||
*/ | ||
package main | ||
|
||
import "github.com/cpunion/go-python/cmd" | ||
|
||
func main() { | ||
cmd.Execute() | ||
} |
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,127 @@ | ||
/* | ||
Copyright © 2024 NAME HERE <EMAIL ADDRESS> | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"os" | ||
"strings" | ||
|
||
"github.com/cpunion/go-python/cmd/internal/create" | ||
"github.com/cpunion/go-python/cmd/internal/install" | ||
"github.com/fatih/color" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var bold = color.New(color.Bold).SprintFunc() | ||
|
||
// isDirEmpty checks if a directory is empty | ||
func isDirEmpty(path string) (bool, error) { | ||
f, err := os.Open(path) | ||
if err != nil { | ||
return false, err | ||
} | ||
defer f.Close() | ||
|
||
_, err = f.Readdirnames(1) | ||
if err == io.EOF { | ||
return true, nil | ||
} | ||
return false, err | ||
} | ||
|
||
// promptYesNo asks user for confirmation | ||
func promptYesNo(prompt string) bool { | ||
reader := bufio.NewReader(os.Stdin) | ||
fmt.Printf("%s [y/N]: ", prompt) | ||
response, err := reader.ReadString('\n') | ||
if err != nil { | ||
return false | ||
} | ||
|
||
response = strings.ToLower(strings.TrimSpace(response)) | ||
return response == "y" || response == "yes" | ||
} | ||
|
||
// initCmd represents the init command | ||
var initCmd = &cobra.Command{ | ||
Use: "init [path]", | ||
Short: "Initialize a new go-python project", | ||
Long: `Initialize a new go-python project in the specified directory. | ||
If no path is provided, it will initialize in the current directory. | ||
Example: | ||
gopy init | ||
gopy init my-project | ||
gopy init --debug my-project | ||
gopy init -v my-project`, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
// Get project path | ||
projectPath := "." | ||
if len(args) > 0 { | ||
projectPath = args[0] | ||
} | ||
|
||
// Get flags | ||
debug, _ := cmd.Flags().GetBool("debug") | ||
verbose, _ := cmd.Flags().GetBool("verbose") | ||
goVersion, _ := cmd.Flags().GetString("go-version") | ||
pyVersion, _ := cmd.Flags().GetString("python-version") | ||
pyBuildDate, _ := cmd.Flags().GetString("python-build-date") | ||
pyFreeThreaded, _ := cmd.Flags().GetBool("python-free-threaded") | ||
tinyPkgConfigVersion, _ := cmd.Flags().GetString("tiny-pkg-config-version") | ||
|
||
// Check if directory exists | ||
if _, err := os.Stat(projectPath); err == nil { | ||
// Directory exists, check if it's empty | ||
empty, err := isDirEmpty(projectPath) | ||
if err != nil { | ||
fmt.Printf("Error checking directory: %v\n", err) | ||
return | ||
} | ||
|
||
if !empty { | ||
if !promptYesNo(fmt.Sprintf("Directory %s is not empty. Do you want to continue?", projectPath)) { | ||
fmt.Println("Operation cancelled") | ||
return | ||
} | ||
} | ||
} else if !os.IsNotExist(err) { | ||
fmt.Printf("Error checking directory: %v\n", err) | ||
return | ||
} | ||
|
||
// Create project using the create package | ||
fmt.Printf("\n%s\n", bold("Creating project...")) | ||
if err := create.Project(projectPath, verbose); err != nil { | ||
fmt.Printf("Error creating project: %v\n", err) | ||
return | ||
} | ||
|
||
// Install dependencies | ||
fmt.Printf("\n%s\n", bold("Installing dependencies...")) | ||
if err := install.Dependencies(projectPath, goVersion, tinyPkgConfigVersion, pyVersion, pyBuildDate, pyFreeThreaded, debug, verbose); err != nil { | ||
fmt.Printf("Error installing dependencies: %v\n", err) | ||
return | ||
} | ||
|
||
fmt.Printf("\n%s\n", bold("Successfully initialized go-python project in "+projectPath)) | ||
fmt.Println("\nNext steps:") | ||
fmt.Println("1. cd", projectPath) | ||
fmt.Println("2. gopy run .") | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(initCmd) | ||
initCmd.Flags().Bool("debug", false, "Install debug version of Python (not available on Windows)") | ||
initCmd.Flags().BoolP("verbose", "v", false, "Enable verbose output") | ||
initCmd.Flags().String("tiny-pkg-config-version", "v0.2.0", "tiny-pkg-config version to install") | ||
initCmd.Flags().String("go-version", "1.23.3", "Go version to install") | ||
initCmd.Flags().String("python-version", "3.13.0", "Python version to install") | ||
initCmd.Flags().String("python-build-date", "20241016", "Python build date") | ||
initCmd.Flags().Bool("python-free-threaded", false, "Install free-threaded version of Python") | ||
} |
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,37 @@ | ||
/* | ||
Copyright © 2024 NAME HERE <EMAIL ADDRESS> | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/cpunion/go-python/cmd/internal/rungo" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// installCmd represents the install command | ||
var installCmd = &cobra.Command{ | ||
Use: "install [flags] [packages]", | ||
Short: "Install Go packages with Python environment configured", | ||
Long: func() string { | ||
intro := "Install compiles and installs Go packages with the Python environment properly configured.\n\n" | ||
help, err := rungo.GetGoCommandHelp("install") | ||
if err != nil { | ||
return intro + "Failed to get go help: " + err.Error() | ||
} | ||
return intro + help | ||
}(), | ||
DisableFlagParsing: true, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
if err := rungo.RunGoCommand("install", args); err != nil { | ||
fmt.Println("Error:", err) | ||
os.Exit(1) | ||
} | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(installCmd) | ||
} |
Oops, something went wrong.