203 lines
6.1 KiB
Go
203 lines
6.1 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
scaffoldpkg "gitea.lclr.dev/AI/mcp-framework/scaffold"
|
|
)
|
|
|
|
const toolName = "mcp-framework"
|
|
|
|
func main() {
|
|
if err := run(os.Args[1:], os.Stdout, os.Stderr); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func run(args []string, stdout, stderr io.Writer) error {
|
|
if stdout == nil {
|
|
stdout = io.Discard
|
|
}
|
|
if stderr == nil {
|
|
stderr = io.Discard
|
|
}
|
|
|
|
if len(args) == 0 || isHelpArg(args[0]) {
|
|
printGlobalHelp(stdout)
|
|
return nil
|
|
}
|
|
|
|
switch args[0] {
|
|
case "scaffold":
|
|
return runScaffold(args[1:], stdout, stderr)
|
|
default:
|
|
return fmt.Errorf("unknown command %q", args[0])
|
|
}
|
|
}
|
|
|
|
func runScaffold(args []string, stdout, stderr io.Writer) error {
|
|
if len(args) == 0 || isHelpArg(args[0]) {
|
|
printScaffoldHelp(stdout)
|
|
return nil
|
|
}
|
|
|
|
switch args[0] {
|
|
case "init":
|
|
return runScaffoldInit(args[1:], stdout, stderr)
|
|
default:
|
|
return fmt.Errorf("unknown scaffold subcommand %q", args[0])
|
|
}
|
|
}
|
|
|
|
func runScaffoldInit(args []string, stdout, stderr io.Writer) error {
|
|
if shouldShowHelp(args) {
|
|
printScaffoldInitHelp(stdout)
|
|
return nil
|
|
}
|
|
|
|
fs := flag.NewFlagSet("scaffold init", flag.ContinueOnError)
|
|
fs.SetOutput(io.Discard)
|
|
|
|
var target string
|
|
var modulePath string
|
|
var binaryName string
|
|
var description string
|
|
var docsURL string
|
|
var defaultProfile string
|
|
var profiles string
|
|
var knownEnv string
|
|
var secretStorePolicy string
|
|
var releaseDriver string
|
|
var releaseBaseURL string
|
|
var releaseRepository string
|
|
var releaseTokenEnv string
|
|
var releasePublicKeyEnv string
|
|
var overwrite bool
|
|
|
|
fs.StringVar(&target, "target", "", "Répertoire cible du nouveau projet (requis)")
|
|
fs.StringVar(&modulePath, "module", "", "Chemin de module Go du projet généré")
|
|
fs.StringVar(&binaryName, "binary", "", "Nom du binaire généré")
|
|
fs.StringVar(&description, "description", "", "Description bootstrap du binaire")
|
|
fs.StringVar(&docsURL, "docs-url", "", "URL de documentation du projet")
|
|
fs.StringVar(&defaultProfile, "default-profile", "", "Profil par défaut")
|
|
fs.StringVar(&profiles, "profiles", "", "Liste CSV de profils connus")
|
|
fs.StringVar(&knownEnv, "known-env", "", "Liste CSV de variables d'environnement connues")
|
|
fs.StringVar(&secretStorePolicy, "secret-store-policy", "", "Politique secret store (auto, keyring-any, kwallet-only, env-only)")
|
|
fs.StringVar(&releaseDriver, "release-driver", "", "Driver de release (gitea, gitlab, github)")
|
|
fs.StringVar(&releaseBaseURL, "release-base-url", "", "Base URL de la forge release")
|
|
fs.StringVar(&releaseRepository, "release-repository", "", "Repository release (org/repo)")
|
|
fs.StringVar(&releaseTokenEnv, "release-token-env", "", "Nom de variable d'environnement pour le token release")
|
|
fs.StringVar(&releasePublicKeyEnv, "release-pubkey-env", "", "Nom de variable d'environnement pour la cle publique Ed25519 de signature")
|
|
fs.BoolVar(&overwrite, "overwrite", false, "Autorise l'écrasement des fichiers existants")
|
|
|
|
if err := fs.Parse(args); err != nil {
|
|
_ = stderr
|
|
return fmt.Errorf("parse scaffold init flags: %w", err)
|
|
}
|
|
|
|
if fs.NArg() > 0 {
|
|
return fmt.Errorf("unexpected argument(s): %s", strings.Join(fs.Args(), ", "))
|
|
}
|
|
|
|
if strings.TrimSpace(target) == "" {
|
|
return errors.New("--target is required")
|
|
}
|
|
|
|
result, err := scaffoldpkg.Generate(scaffoldpkg.Options{
|
|
TargetDir: target,
|
|
ModulePath: modulePath,
|
|
BinaryName: binaryName,
|
|
Description: description,
|
|
DocsURL: docsURL,
|
|
DefaultProfile: defaultProfile,
|
|
Profiles: parseCSV(profiles),
|
|
KnownEnvironmentVariables: parseCSV(knownEnv),
|
|
SecretStorePolicy: secretStorePolicy,
|
|
ReleaseDriver: releaseDriver,
|
|
ReleaseBaseURL: releaseBaseURL,
|
|
ReleaseRepository: releaseRepository,
|
|
ReleaseTokenEnv: releaseTokenEnv,
|
|
ReleasePublicKeyEnv: releasePublicKeyEnv,
|
|
Overwrite: overwrite,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := fmt.Fprintf(stdout, "Scaffold generated in %s\n", result.Root); err != nil {
|
|
return err
|
|
}
|
|
for _, file := range result.Files {
|
|
if _, err := fmt.Fprintf(stdout, "- %s\n", file); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func printGlobalHelp(w io.Writer) {
|
|
fmt.Fprintf(
|
|
w,
|
|
"Usage:\n %s <command> [options]\n\nCommands:\n scaffold init Génère un nouveau projet MCP\n\nUse `%s help` for this message.\n",
|
|
toolName,
|
|
toolName,
|
|
)
|
|
}
|
|
|
|
func printScaffoldHelp(w io.Writer) {
|
|
fmt.Fprintf(
|
|
w,
|
|
"Usage:\n %s scaffold init [flags]\n\nSubcommands:\n init Génère un nouveau squelette MCP\n",
|
|
toolName,
|
|
)
|
|
}
|
|
|
|
func printScaffoldInitHelp(w io.Writer) {
|
|
fmt.Fprintf(
|
|
w,
|
|
"Usage:\n %s scaffold init --target <dir> [flags]\n\nFlags:\n --target Répertoire cible (requis)\n --module Module Go (ex: example.com/my-mcp)\n --binary Nom du binaire\n --description Description bootstrap\n --docs-url URL de documentation\n --default-profile Profil par défaut\n --profiles CSV des profils connus\n --known-env CSV des variables d'environnement connues\n --secret-store-policy auto|keyring-any|kwallet-only|env-only\n --release-driver gitea|gitlab|github\n --release-base-url URL de base de la forge\n --release-repository Dépôt release (org/repo)\n --release-token-env Variable token release\n --release-pubkey-env Variable cle publique Ed25519 release\n --overwrite Écraser les fichiers existants\n",
|
|
toolName,
|
|
)
|
|
}
|
|
|
|
func shouldShowHelp(args []string) bool {
|
|
for _, arg := range args {
|
|
if isHelpArg(arg) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isHelpArg(arg string) bool {
|
|
switch strings.TrimSpace(arg) {
|
|
case "-h", "--help", "help":
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func parseCSV(value string) []string {
|
|
if strings.TrimSpace(value) == "" {
|
|
return nil
|
|
}
|
|
|
|
parts := strings.Split(value, ",")
|
|
result := make([]string, 0, len(parts))
|
|
for _, part := range parts {
|
|
trimmed := strings.TrimSpace(part)
|
|
if trimmed == "" {
|
|
continue
|
|
}
|
|
result = append(result, trimmed)
|
|
}
|
|
return result
|
|
}
|