github.com/mloves0824/enron/cmd/enron@v0.0.0-20230830012320-113bbf6be3c8/internal/project/project.go (about) 1 package project 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "os" 8 "path/filepath" 9 "strings" 10 "time" 11 12 "github.com/AlecAivazis/survey/v2" 13 "github.com/spf13/cobra" 14 15 "github.com/mloves0824/enron/cmd/enron/internal/base" 16 ) 17 18 // CmdNew represents the new command. 19 var CmdNew = &cobra.Command{ 20 Use: "new", 21 Short: "Create a service template", 22 Long: "Create a service project using the repository template. Example: enron new helloworld", 23 Run: run, 24 } 25 26 var ( 27 repoURL string 28 branch string 29 timeout string 30 nomod bool 31 ) 32 33 func init() { 34 if repoURL = os.Getenv("ENRON_LAYOUT_REPO"); repoURL == "" { 35 repoURL = "https://github.com/mloves0824/enron-layout.git" 36 } 37 timeout = "60s" 38 CmdNew.Flags().StringVarP(&repoURL, "repo-url", "r", repoURL, "layout repo") 39 CmdNew.Flags().StringVarP(&branch, "branch", "b", branch, "repo branch") 40 CmdNew.Flags().StringVarP(&timeout, "timeout", "t", timeout, "time out") 41 CmdNew.Flags().BoolVarP(&nomod, "nomod", "", nomod, "retain go mod") 42 } 43 44 func run(_ *cobra.Command, args []string) { 45 wd, err := os.Getwd() 46 if err != nil { 47 panic(err) 48 } 49 t, err := time.ParseDuration(timeout) 50 if err != nil { 51 panic(err) 52 } 53 ctx, cancel := context.WithTimeout(context.Background(), t) 54 defer cancel() 55 name := "" 56 if len(args) == 0 { 57 prompt := &survey.Input{ 58 Message: "What is project name ?", 59 Help: "Created project name.", 60 } 61 err = survey.AskOne(prompt, &name) 62 if err != nil || name == "" { 63 return 64 } 65 } else { 66 name = args[0] 67 } 68 projectName, workingDir := processProjectParams(name, wd) 69 p := &Project{Name: projectName} 70 done := make(chan error, 1) 71 go func() { 72 if !nomod { 73 done <- p.New(ctx, workingDir, repoURL, branch) 74 return 75 } 76 projectRoot := getgomodProjectRoot(workingDir) 77 if gomodIsNotExistIn(projectRoot) { 78 done <- fmt.Errorf("🚫 go.mod don't exists in %s", projectRoot) 79 return 80 } 81 82 packagePath, e := filepath.Rel(projectRoot, filepath.Join(workingDir, projectName)) 83 if e != nil { 84 done <- fmt.Errorf("🚫 failed to get relative path: %v", err) 85 return 86 } 87 packagePath = strings.ReplaceAll(packagePath, "\\", "/") 88 89 mod, e := base.ModulePath(filepath.Join(projectRoot, "go.mod")) 90 if e != nil { 91 done <- fmt.Errorf("🚫 failed to parse `go.mod`: %v", e) 92 return 93 } 94 // Get the relative path for adding a project based on Go modules 95 p.Path = filepath.Join(strings.TrimPrefix(workingDir, projectRoot+"/"), p.Name) 96 done <- p.Add(ctx, workingDir, repoURL, branch, mod, packagePath) 97 }() 98 select { 99 case <-ctx.Done(): 100 if errors.Is(ctx.Err(), context.DeadlineExceeded) { 101 fmt.Fprint(os.Stderr, "\033[31mERROR: project creation timed out\033[m\n") 102 return 103 } 104 fmt.Fprintf(os.Stderr, "\033[31mERROR: failed to create project(%s)\033[m\n", ctx.Err().Error()) 105 case err = <-done: 106 if err != nil { 107 fmt.Fprintf(os.Stderr, "\033[31mERROR: Failed to create project(%s)\033[m\n", err.Error()) 108 } 109 } 110 } 111 112 func processProjectParams(projectName string, workingDir string) (projectNameResult, workingDirResult string) { 113 _projectDir := projectName 114 _workingDir := workingDir 115 // Process ProjectName with system variable 116 if strings.HasPrefix(projectName, "~") { 117 homeDir, err := os.UserHomeDir() 118 if err != nil { 119 // cannot get user home return fallback place dir 120 return _projectDir, _workingDir 121 } 122 _projectDir = filepath.Join(homeDir, projectName[2:]) 123 } 124 125 // check path is relative 126 if !filepath.IsAbs(projectName) { 127 absPath, err := filepath.Abs(projectName) 128 if err != nil { 129 return _projectDir, _workingDir 130 } 131 _projectDir = absPath 132 } 133 134 return filepath.Base(_projectDir), filepath.Dir(_projectDir) 135 } 136 137 func getgomodProjectRoot(dir string) string { 138 if dir == filepath.Dir(dir) { 139 return dir 140 } 141 if gomodIsNotExistIn(dir) { 142 return getgomodProjectRoot(filepath.Dir(dir)) 143 } 144 return dir 145 } 146 147 func gomodIsNotExistIn(dir string) bool { 148 _, e := os.Stat(filepath.Join(dir, "go.mod")) 149 return os.IsNotExist(e) 150 }