gig-gitignore工具实战开发(三):gig add基础实现
gig-gitignore工具实战开发(三):gig add基础实现
✨ 前言: 在上一篇我们已经设计了多源模板系统,本篇我们来进行实战。先实现gig add命令基础代码。
一、项目初始化
暂略,主要包含如下工作
- go mod init 项目初始化
- 添加cobra、viper等相关库
- 配置初始化等等
参考依赖
require (github.com/manifoldco/promptui v0.9.0github.com/nicksnyder/go-i18n/v2 v2.6.0github.com/rivo/tview v0.0.0-20240307173318-e804876934a1github.com/sergi/go-diff v1.4.0github.com/spf13/afero v1.12.0github.com/spf13/cobra v1.9.1github.com/spf13/viper v1.20.1golang.org/x/text v0.23.0gopkg.in/yaml.v3 v3.0.1)
二、add命令实现
添加add.go
命令行中调用
cobra-cli add add
添加参数
func init() {rootCmd.AddCommand(addCmd)addCmd.Flags().BoolVar(&yesFlag, \"yes\", false, \"自动确认所有交互,无需人工输入\")addCmd.Flags().BoolVarP(&updateFlag, \"update\", \"u\", false, \"强制更新github模板\")}
- yes参数可以忽略交互,适合自动化流程
- update主要针对github模板,默认不进行更新
业务逻辑处理
根据传入参数不同,分别进行处理
func(cmd *cobra.Command, args []string) {var languages []stringif len(args) == 0 {detected := utils.DetectionUtil.DetectProjectTypes(models.AppConfig.Detection.FileMap)if len(detected) > 0 {languages = promptUserForTypes(detected)}if len(languages) == 0 {fmt.Println(\"未检测到项目类型,请手动输入语言参数。例如:gig add python\")os.Exit(1)}} else {languages = args}switch genType {case \"ai\":result, err := utils.AI.StreamChat(\"add\", strings.Join(languages, \", \"))if err != nil {fmt.Println(\"AI 生成失败:\", err)os.Exit(1)}cleanedContent := cleanupAIOutput(result)updateGitignoreWithContent(cleanedContent)case \"github\":handleAdd(languages, \"github\", updateFlag)case \"local\":handleAdd(languages, \"local\", false)case \"api\":result, err := getGitignoreFromAPI(languages)if err != nil {fmt.Println(\"API 获取失败:\", err)os.Exit(1)}updateGitignoreWithContent(result)default:fmt.Printf(\"Error: Invalid type \'%s\'. Please use \'local\', \'github\', \'ai\' 或 \'api\'.\\n\", genType)}},}
其中代码需要进行识别项目语言,我们进行如下工具封装,根据核心特征进行判断。由于项目繁多,不可能包括所有,用户可以自行进行核心特征拓展。
// 自动识别项目类型(递归遍历,仅根据配置文件匹配,特殊目录优化)func (d Detection) DetectProjectTypes(fileMap map[string]string) []string {fmt.Println(\"typeMap:\", fileMap)if len(fileMap) == 0 {// 配置为空时兜底return nil}langSet := make(map[string]struct{})// 特殊目录与类型的映射(可扩展)specialDirs := map[string]string{\"node_modules\": \"node\",// 可按需添加:// \".venv\": \"python\",// \"vendor\": \"go\",// \"target\": \"rust\",}filepath.Walk(\".\", func(path string, info os.FileInfo, err error) error {if err != nil {return nil // 忽略错误}if info.IsDir() {base := filepath.Base(path)// 跳过隐藏目录(如.git、.idea等)if strings.HasPrefix(base, \".\") && path != \".\" {return filepath.SkipDir}// 特殊目录:遇到直接判定类型并跳过递归if lang, ok := specialDirs[base]; ok {langSet[lang] = struct{}{}return filepath.SkipDir}return nil}name := info.Name()if lang, ok := fileMap[name]; ok {langSet[lang] = struct{}{}}return nil})var langs []stringfor lang := range langSet {langs = append(langs, lang)}return langs}
识别出的语言有可能有误,这时候用户可以进行修正
func promptUserForTypes(detected []string) []string {if yesFlag {fmt.Printf(\"检测到以下项目类型:%s\\n\", strings.Join(detected, \", \"))fmt.Println(\"已自动确认项目类型 (--yes)\")return detected}fmt.Printf(\"检测到以下项目类型:%s\\n\", strings.Join(detected, \", \"))fmt.Print(\"是否确认?(直接回车确认,或输入新的类型列表,如:go,python):\")input, _ := bufio.NewReader(os.Stdin).ReadString(\'\\n\')input = strings.TrimSpace(input)if input == \"\" {return detected}var result []stringfor _, t := range strings.Split(input, \",\") {t = strings.TrimSpace(t)if t != \"\" {result = append(result, t)}}return result}