Няма описание
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package util
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "regexp"
  8. "strings"
  9. )
  10. // ValidateProjectDirName 验证项目ID是否为合法的目录名
  11. func ValidateProjectDirName(projectID string) error {
  12. if len(projectID) == 0 {
  13. return errors.New("项目ID不能为空")
  14. }
  15. if len(projectID) > 64 {
  16. return errors.New("项目ID长度不能超过64字符")
  17. }
  18. // 合法字符:字母、数字、下划线、连字符
  19. validPattern := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
  20. if !validPattern.MatchString(projectID) {
  21. return errors.New("项目ID只能包含字母、数字、下划线和连字符")
  22. }
  23. // 保留名称检查
  24. reservedNames := []string{".", "..", "con", "nul", "prn", "aux", "com1", "com2", "com3", "com4", "lpt1", "lpt2", "lpt3"}
  25. for _, name := range reservedNames {
  26. if strings.EqualFold(projectID, name) {
  27. return fmt.Errorf("项目ID不能使用系统保留名称: %s", name)
  28. }
  29. }
  30. // 不能以点或空格开头结尾
  31. if strings.HasPrefix(projectID, ".") || strings.HasSuffix(projectID, ".") {
  32. return errors.New("项目ID不能以点开头或结尾")
  33. }
  34. if strings.HasPrefix(projectID, " ") || strings.HasSuffix(projectID, " ") {
  35. return errors.New("项目ID不能以空格开头或结尾")
  36. }
  37. return nil
  38. }
  39. // CreateProjectDirectory 创建项目目录结构
  40. func CreateProjectDirectory(basePath, projectID string) error {
  41. // 验证项目ID
  42. if err := ValidateProjectDirName(projectID); err != nil {
  43. return fmt.Errorf("项目ID验证失败: %w", err)
  44. }
  45. // 构建完整项目路径
  46. projectPath := filepath.Join(basePath, projectID)
  47. // 创建项目根目录
  48. if err := os.MkdirAll(projectPath, 0755); err != nil {
  49. return fmt.Errorf("创建项目目录失败: %w", err)
  50. }
  51. // 创建子目录
  52. subdirs := []string{
  53. ".opencode",
  54. "logs",
  55. "data",
  56. }
  57. for _, subdir := range subdirs {
  58. dirPath := filepath.Join(projectPath, subdir)
  59. if err := os.MkdirAll(dirPath, 0755); err != nil {
  60. return fmt.Errorf("创建子目录 %s 失败: %w", subdir, err)
  61. }
  62. }
  63. return nil
  64. }
  65. // EnsureDirectoryExists 确保目录存在,如果不存在则创建
  66. func EnsureDirectoryExists(path string) error {
  67. if _, err := os.Stat(path); os.IsNotExist(err) {
  68. if err := os.MkdirAll(path, 0755); err != nil {
  69. return fmt.Errorf("创建目录失败: %w", err)
  70. }
  71. }
  72. return nil
  73. }
  74. // GetProjectPath 获取项目完整路径
  75. func GetProjectPath(basePath, projectID string) string {
  76. return filepath.Join(basePath, projectID)
  77. }
  78. // GetOpenCodeConfigPath 获取项目OpenCode配置文件路径
  79. func GetOpenCodeConfigPath(basePath, projectID string) string {
  80. return filepath.Join(basePath, projectID, ".opencode", "opencode.json")
  81. }
  82. // GetProjectLogsPath 获取项目日志目录路径
  83. func GetProjectLogsPath(basePath, projectID string) string {
  84. return filepath.Join(basePath, projectID, "logs")
  85. }