99 "os"
1010 "path/filepath"
1111 "regexp"
12+ "sort"
1213 "strings"
1314 "syscall"
1415)
@@ -28,7 +29,7 @@ var Assets embed.FS
2829
2930func main () {
3031 // `os.Args[0]` will always be the path of the script
31- // `os.Args[1]` will either be INIT or a task of the dev.sh script
32+ // `os.Args[1]` will either be INIT or a name of the dev.sh script
3233 if len (os .Args ) > 1 {
3334 if os .Args [1 ] == INIT_ARGUMENT {
3435 // If we called `dev INIT`
@@ -44,7 +45,7 @@ func main() {
4445 } else {
4546 // Show usage
4647 fmt .Println (aurora .Bold ("USAGE:" ))
47- fmt .Println (" " , aurora .Bold ("dev <TASK_NAME>" ), "- to run a task of your dev.sh" )
48+ fmt .Println (" " , aurora .Bold ("dev <TASK_NAME>" ), "- to run a name of your dev.sh" )
4849 fmt .Println (" " , aurora .Bold ("dev INIT" ), "- to create a `dev.sh` in the current folder" )
4950 // Explicitly show that we exit here
5051 os .Exit (0 )
@@ -88,23 +89,19 @@ func runTask() {
8889 for {
8990 devScriptPath := filepath .Join (currentDirectory , DEV_SCRIPT_NAME )
9091 if fileExists (devScriptPath ) {
91- fmt .Println (aurora .Magenta (LOGGING_PREFIX + "Found " + DEV_SCRIPT_NAME + " in " ))
92- fmt .Println (aurora .Magenta (LOGGING_WSPACE + currentDirectory ))
92+ fmt .Println (aurora .Magenta (LOGGING_PREFIX + "Found " + currentDirectory + "/" + DEV_SCRIPT_NAME ))
9393 if fileContains (devScriptPath , DEV_SCRIPT_MARKER ) {
94- fmt .Println (aurora .Magenta (LOGGING_PREFIX + "Found marker in " ))
95- fmt .Println (aurora .Magenta (LOGGING_WSPACE + currentDirectory + "/" + DEV_SCRIPT_NAME ))
94+ fmt .Println (aurora .Magenta (LOGGING_WSPACE + "Found marker '" + DEV_SCRIPT_MARKER + "'" ))
9695 execDevScriptWithArguments (devScriptPath , os .Args [1 :])
9796 break
9897 } else {
99- fmt .Println (aurora .Yellow (LOGGING_PREFIX + "Marker '" + DEV_SCRIPT_MARKER + "' is missing in " ))
100- fmt .Println (aurora .Yellow (LOGGING_WSPACE + currentDirectory + "/" + DEV_SCRIPT_NAME ))
101- fmt .Println (aurora .Yellow (LOGGING_WSPACE + "Moving up, looking for " + DEV_SCRIPT_NAME ))
98+ fmt .Println (aurora .Yellow (LOGGING_WSPACE + "Marker '" + DEV_SCRIPT_MARKER + "' is missing in " + DEV_SCRIPT_NAME ))
99+ fmt .Println (aurora .Yellow (LOGGING_WSPACE + "Moving up, looking for new " + DEV_SCRIPT_NAME ))
102100 // Not breaking here as we want to move up
103101 }
104102 }
105103 if currentDirectory == "/" || steps >= MAX_DEPTH {
106- fmt .Println (aurora .Yellow (aurora .Bold (LOGGING_PREFIX + "No " + DEV_SCRIPT_NAME + " with " + DEV_SCRIPT_MARKER + " found" )))
107- fmt .Println (aurora .Yellow (aurora .Bold (LOGGING_WSPACE + "Nothing to do here :(" )))
104+ fmt .Println (aurora .Yellow (aurora .Bold (LOGGING_PREFIX + "No " + DEV_SCRIPT_NAME + " with " + DEV_SCRIPT_MARKER + " found. Nothing to do here :(" )))
108105 fmt .Println (aurora .Magenta (aurora .Bold (LOGGING_BAR )))
109106 break
110107 }
@@ -147,27 +144,85 @@ func copyAssetToPath(embedPath string, targetPath string) {
147144 fmt .Println (aurora .Magenta (LOGGING_PREFIX + targetPath + " was created." ))
148145}
149146
150- func execDevScriptWithArguments (devScriptPath string , arguments []string ) {
151- fmt .Println (aurora .Magenta (aurora .Bold (LOGGING_PREFIX + "Executing dev script :)" )))
152- fmt .Println (aurora .Magenta (aurora .Bold (LOGGING_BAR )))
153- err := os .Chdir (filepath .Dir (devScriptPath ))
154- if err != nil {
155- log .Fatalf ("Failed to execute: '%s'" , err .Error ())
147+ type DevScriptTask struct {
148+ name string
149+ comments string
150+ }
151+
152+ func taskExists (tasks []DevScriptTask , calledTask string ) bool {
153+ for _ , task := range tasks {
154+ if task .name == calledTask {
155+ return true
156+ }
157+ }
158+ return false
159+ }
160+
161+ func availableTasks (tasks []DevScriptTask ) string {
162+ result := ""
163+ for _ , task := range tasks {
164+ result += LOGGING_WSPACE + " " + task .name + "\n "
156165 }
157- // In case the script is not executable
158- err = os .Chmod (devScriptPath , 0755 )
166+ return result
167+ }
168+
169+ func parseDevScriptTasks (devScriptPath string ) []DevScriptTask {
170+ // https://regex101.com/r/5LVRcP/1 -> Iteration 1 without comments before
171+ // https://regex101.com/r/XyB410/1 -> Final Iteration with comments before ;)
172+ devScriptBytes , err := os .ReadFile (devScriptPath )
159173 if err != nil {
160174 log .Fatalf ("Failed to execute: '%s'" , err .Error ())
161175 }
162176
163- // We tried using exec.Command(devScriptPath, arguments...) which failed for interactive
164- // terminal calls, e.g. `docker compose exec neos /bin/bash` This is running our command
165- // as a child process. We are now replacing the process of this helper with the call of
166- // the `dev.sh` using `syscall.Exec()`
167- err = syscall .Exec (devScriptPath , append ([]string {devScriptPath }, arguments ... ), os .Environ ())
168- if err != nil {
169- log .Fatalf ("Failed to run shell script: '%s'" , err .Error ())
177+ devScriptString := string (devScriptBytes )
178+ compiledRegex := regexp .MustCompile (`(?m)(?P<comments>(?:^#.*(?:\n|\r\n|\r))*)^(?:function )?(?P<name>[a-zA-Z0-9_-]+)\s?(?:\(\))?\s?{` )
179+ captureGroupNames := compiledRegex .SubexpNames ()
180+ commentsIndex := sort .StringSlice (captureGroupNames ).Search ("comments" )
181+ taskIndex := sort .StringSlice (captureGroupNames ).Search ("name" )
182+ matches := compiledRegex .FindAllStringSubmatch (devScriptString , - 1 )
183+
184+ var results = []DevScriptTask {}
185+ for _ , match := range matches {
186+ task := match [taskIndex ]
187+ comments := match [commentsIndex ]
188+ if ! strings .HasPrefix (task , "_" ) {
189+ results = append (results , DevScriptTask {name : task , comments : comments })
190+ }
191+ }
192+ return results
193+ }
194+
195+ func execDevScriptWithArguments (devScriptPath string , arguments []string ) {
196+ tasks := parseDevScriptTasks (devScriptPath )
197+ calledTask := os .Args [1 ]
198+ if taskExists (tasks , calledTask ) {
199+ fmt .Println (aurora .Magenta (LOGGING_WSPACE + "Found task '" + calledTask + "'" ))
200+ fmt .Println (aurora .Magenta (aurora .Bold (LOGGING_PREFIX + "Executing dev script :)" )))
201+ fmt .Println (aurora .Magenta (aurora .Bold (LOGGING_BAR )))
202+ err := os .Chdir (filepath .Dir (devScriptPath ))
203+ if err != nil {
204+ log .Fatalf ("Failed to execute: '%s'" , err .Error ())
205+ }
206+ // In case the script is not executable
207+ err = os .Chmod (devScriptPath , 0755 )
208+ if err != nil {
209+ log .Fatalf ("Failed to execute: '%s'" , err .Error ())
210+ }
211+
212+ // We tried using exec.Command(devScriptPath, arguments...) which failed for interactive
213+ // terminal calls, e.g. `docker compose exec neos /bin/bash` This is running our command
214+ // as a child process. We are now replacing the process of this helper with the call of
215+ // the `dev.sh` using `syscall.Exec()`
216+ err = syscall .Exec (devScriptPath , append ([]string {devScriptPath }, arguments ... ), os .Environ ())
217+ if err != nil {
218+ log .Fatalf ("Failed to run shell script: '%s'" , err .Error ())
219+ }
220+ // IMPORTANT: As we are replacing the process of the helper nothing else will be
221+ // called, except the error handler!
222+ } else {
223+ fmt .Println (aurora .Yellow (aurora .Bold (LOGGING_WSPACE + "No task '" + calledTask + "' found. Nothing to do here :(" )))
224+ fmt .Println (aurora .Yellow (aurora .Bold (LOGGING_WSPACE + "Try one of the following:" )))
225+ fmt .Print (aurora .Yellow (availableTasks (tasks )))
226+ fmt .Println (aurora .Magenta (aurora .Bold (LOGGING_BAR )))
170227 }
171- // IMPORTANT: As we are replacing the process of the helper nothing else will be
172- // called, except the error handler!
173228}
0 commit comments