9
9
"os"
10
10
"path/filepath"
11
11
"regexp"
12
+ "sort"
12
13
"strings"
13
14
"syscall"
14
15
)
@@ -28,7 +29,7 @@ var Assets embed.FS
28
29
29
30
func main () {
30
31
// `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
32
33
if len (os .Args ) > 1 {
33
34
if os .Args [1 ] == INIT_ARGUMENT {
34
35
// If we called `dev INIT`
@@ -44,7 +45,7 @@ func main() {
44
45
} else {
45
46
// Show usage
46
47
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" )
48
49
fmt .Println (" " , aurora .Bold ("dev INIT" ), "- to create a `dev.sh` in the current folder" )
49
50
// Explicitly show that we exit here
50
51
os .Exit (0 )
@@ -88,23 +89,19 @@ func runTask() {
88
89
for {
89
90
devScriptPath := filepath .Join (currentDirectory , DEV_SCRIPT_NAME )
90
91
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 ))
93
93
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 + "'" ))
96
95
execDevScriptWithArguments (devScriptPath , os .Args [1 :])
97
96
break
98
97
} 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 ))
102
100
// Not breaking here as we want to move up
103
101
}
104
102
}
105
103
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 :(" )))
108
105
fmt .Println (aurora .Magenta (aurora .Bold (LOGGING_BAR )))
109
106
break
110
107
}
@@ -147,27 +144,85 @@ func copyAssetToPath(embedPath string, targetPath string) {
147
144
fmt .Println (aurora .Magenta (LOGGING_PREFIX + targetPath + " was created." ))
148
145
}
149
146
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 "
156
165
}
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 )
159
173
if err != nil {
160
174
log .Fatalf ("Failed to execute: '%s'" , err .Error ())
161
175
}
162
176
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 )))
170
227
}
171
- // IMPORTANT: As we are replacing the process of the helper nothing else will be
172
- // called, except the error handler!
173
228
}
0 commit comments