Public Access
179 lines
4.3 KiB
Go
179 lines
4.3 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"gitea.fernandovideira.com/FernandoJVideira/keystone/assets"
|
|
"github.com/manifoldco/promptui"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func init() {
|
|
newCmd.AddCommand(apiCmd)
|
|
}
|
|
|
|
var apiCmd = &cobra.Command{
|
|
Use: "api",
|
|
Short: "Create a new Keystone API project",
|
|
Long: `Create a new Keystone API project with the necessary structure and files.`,
|
|
Run: genProject,
|
|
}
|
|
|
|
func genProject(cmd *cobra.Command, args []string) {
|
|
|
|
projectNamePrompt := promptui.Prompt{
|
|
Label: "Project Name",
|
|
}
|
|
|
|
rawInput, err := projectNamePrompt.Run()
|
|
if err != nil {
|
|
fmt.Printf("Prompt failed %v\n", err)
|
|
return
|
|
}
|
|
moduleName := strings.TrimSpace(rawInput)
|
|
projectDir := path.Base(strings.TrimSuffix(moduleName, "/"))
|
|
|
|
apiType := promptui.Select{
|
|
Label: "Select API Type",
|
|
Items: []string{"HTTP (REST)", "gRPC"},
|
|
}
|
|
|
|
_, result, err := apiType.Run()
|
|
|
|
if err != nil {
|
|
fmt.Printf("Prompt failed %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Logic to map the selection to a boolean
|
|
useGRPC := strings.Contains(result, "gRPC")
|
|
|
|
fmt.Printf("🚀 Scaffolding '%s' as %s...\n", moduleName, result)
|
|
if err := scaffoldProject(projectDir, moduleName, useGRPC); err != nil {
|
|
fmt.Printf("error scaffolding project: %v", err)
|
|
return
|
|
}
|
|
|
|
fmt.Println("📦 Installing tools...")
|
|
if err := installTools(useGRPC); err != nil {
|
|
fmt.Printf("error installing tools: %v", err)
|
|
return
|
|
}
|
|
|
|
fmt.Println("🧹 Tidying up Go modules...")
|
|
if err := runCommand(projectDir, "go", "mod", "tidy"); err != nil {
|
|
fmt.Printf("error running 'go mod tidy': %v", err)
|
|
return
|
|
}
|
|
|
|
fmt.Println("✅ Done!")
|
|
}
|
|
|
|
func scaffoldProject(projectDir, moduleName string, useGRPC bool) error {
|
|
|
|
err := os.MkdirAll(projectDir, 0755)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating project directory: %v", err)
|
|
}
|
|
|
|
root := "embedded"
|
|
err = fs.WalkDir(assets.EmbedFS, root, func(path string, d fs.DirEntry, err error) error {
|
|
|
|
relPath, _ := filepath.Rel(root, path)
|
|
|
|
if !useGRPC {
|
|
// If User chose HTTP: Remove gRPC stuff
|
|
if strings.HasPrefix(relPath, "pb") ||
|
|
strings.HasPrefix(relPath, "proto") ||
|
|
strings.Contains(relPath, "handlers/grpc") ||
|
|
strings.HasPrefix(relPath, "docs/statik") ||
|
|
strings.HasPrefix(relPath, "docs/swagger") {
|
|
return nil
|
|
}
|
|
} else {
|
|
// If User chose gRPC: Remove HTTP stuff
|
|
if strings.Contains(relPath, "handlers/http") {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if strings.HasSuffix(relPath, "cmd/api/main.go") {
|
|
return nil
|
|
}
|
|
|
|
if d.IsDir() {
|
|
return nil
|
|
}
|
|
|
|
contentBytes, err := assets.EmbedFS.ReadFile(path)
|
|
if err != nil {
|
|
return fmt.Errorf("error reading embedded file %s: %v", path, err)
|
|
}
|
|
content := string(contentBytes)
|
|
|
|
targetPath := filepath.Join(projectDir, relPath)
|
|
|
|
targetPath = strings.TrimSuffix(targetPath, ".tmpl")
|
|
|
|
if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil {
|
|
return fmt.Errorf("error creating directory %s: %v", filepath.Dir(targetPath), err)
|
|
}
|
|
|
|
newContent := strings.ReplaceAll(content, oldModuleName, moduleName)
|
|
newContent = strings.ReplaceAll(newContent, "{{ .ModuleName }}", moduleName)
|
|
|
|
return os.WriteFile(targetPath, []byte(newContent), 0644)
|
|
})
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error copying template files: %v\n", err)
|
|
}
|
|
|
|
// Generate main.go from template
|
|
return genFile(
|
|
"templates/main.go.tpl",
|
|
"main",
|
|
filepath.Join(projectDir, "cmd/api", "main.go"),
|
|
MainTemplateData{
|
|
ModuleName: moduleName,
|
|
UseGRPC: useGRPC,
|
|
},
|
|
)
|
|
}
|
|
|
|
func installTools(useGrpc bool) error {
|
|
tools := []string{
|
|
"github.com/air-verse/air@latest",
|
|
"github.com/golangci/golangci-lint/cmd/golangci-lint@latest",
|
|
"go.uber.org/mock/mockgen@latest",
|
|
"github.com/sqlc-dev/sqlc/cmd/sqlc@latest",
|
|
"github.com/golang-migrate/migrate/v4/cmd/migrate@latest",
|
|
}
|
|
|
|
if useGrpc {
|
|
tools = append(tools,
|
|
"google.golang.org/protobuf/cmd/protoc-gen-go@latest",
|
|
"google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest",
|
|
"github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest",
|
|
"github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest",
|
|
)
|
|
} else {
|
|
tools = append(tools,
|
|
"github.com/swaggo/swag/cmd/swag@latest",
|
|
)
|
|
}
|
|
|
|
for _, tool := range tools {
|
|
if err := runCommand("", "go", "install", tool); err != nil {
|
|
return fmt.Errorf("error installing tool %s: %v", tool, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|