Skip to content

Commit 20978a5

Browse files
author
Florian Heinze
committed
TASK: first working comands
1 parent 7a78f18 commit 20978a5

9 files changed

Lines changed: 524 additions & 11 deletions

File tree

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
.idea
2-
test/
3-
dist/
4-
.DS_Store
2+
main
3+
*.so
4+
dist

cmd/init.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package cmd
2+
3+
import (
4+
"github.com/gookit/color"
5+
"github.com/spf13/cobra"
6+
)
7+
8+
func buildInitCommand() *cobra.Command {
9+
var execRootCmd = &cobra.Command{
10+
Use: "INIT",
11+
Short: "TODO",
12+
Long: color.Sprintf(`Usage: TODO`),
13+
Args: cobra.RangeArgs(1, 2),
14+
15+
Run: func(cmd *cobra.Command, args []string) {
16+
color.Sprintf(`RUN COMMAND`)
17+
},
18+
}
19+
return execRootCmd
20+
}

cmd/root.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"github.com/logrusorgru/aurora/v3"
6+
"github.com/spf13/cobra"
7+
"log"
8+
"math/rand"
9+
"os"
10+
"path/filepath"
11+
"regexp"
12+
"sort"
13+
"strings"
14+
"time"
15+
)
16+
17+
const DEV_SCRIPT_MARKER = "DEV_SCRIPT_MARKER"
18+
const DEV_SCRIPT_NAME = "dev.sh"
19+
const MAX_DEPTH = 100
20+
const INIT_ARGUMENT = "INIT"
21+
const LOGGING_PREFIX = "DSR - " // DevScriptRunner
22+
const LOGGING_WSPACE = " "
23+
const LOGGING_BAR = "-------------------------------------------------------"
24+
25+
var rootCmd = &cobra.Command{
26+
Long: "LONG",
27+
Use: "drydock",
28+
Short: "SHORT",
29+
Example: "",
30+
}
31+
32+
// Execute adds all child commands to the root command and sets flags appropriately.
33+
// This is called by main.main(). It only needs to happen once to the rootCmd.
34+
func Execute(version, commit string) {
35+
rootCmd.AddCommand(buildInitCommand())
36+
addDevScriptTasksAsCommands(rootCmd)
37+
rand.Seed(time.Now().UnixNano())
38+
39+
if err := rootCmd.Execute(); err != nil {
40+
fmt.Println(err)
41+
os.Exit(1)
42+
}
43+
}
44+
45+
func init() {
46+
cobra.OnInitialize()
47+
}
48+
49+
func addDevScriptTasksAsCommands(rootCmd *cobra.Command) {
50+
currentDirectory, err := os.Getwd()
51+
if err != nil {
52+
log.Fatalf("Failed to execute: '%s'", err.Error())
53+
}
54+
55+
steps := 0
56+
for {
57+
devScriptPath := filepath.Join(currentDirectory, DEV_SCRIPT_NAME)
58+
if fileExists(devScriptPath) {
59+
fmt.Println(aurora.Magenta("Found " + currentDirectory + "/" + DEV_SCRIPT_NAME))
60+
if fileContains(devScriptPath, DEV_SCRIPT_MARKER) {
61+
fmt.Println(aurora.Magenta("with '" + DEV_SCRIPT_MARKER + "'"))
62+
tasks := parseDevScriptTasks(devScriptPath)
63+
for _, task := range tasks {
64+
rootCmd.AddCommand(buildTaskCommand(task, devScriptPath))
65+
}
66+
break
67+
} else {
68+
fmt.Println(aurora.Yellow(LOGGING_WSPACE + "Marker '" + DEV_SCRIPT_MARKER + "' is missing in " + DEV_SCRIPT_NAME))
69+
fmt.Println(aurora.Yellow(LOGGING_WSPACE + "Moving up, looking for new " + DEV_SCRIPT_NAME))
70+
// Not breaking here as we want to move up
71+
}
72+
}
73+
if currentDirectory == "/" || steps >= MAX_DEPTH {
74+
fmt.Println(aurora.Yellow(aurora.Bold(LOGGING_PREFIX + "No " + DEV_SCRIPT_NAME + " with " + DEV_SCRIPT_MARKER + " found. Nothing to do here :(")))
75+
fmt.Println(aurora.Magenta(aurora.Bold(LOGGING_BAR)))
76+
break
77+
}
78+
// Moving up one directory
79+
currentDirectory = filepath.Dir(currentDirectory)
80+
steps += 1
81+
}
82+
}
83+
84+
func fileExists(path string) bool {
85+
info, err := os.Stat(path)
86+
if os.IsNotExist(err) {
87+
return false
88+
}
89+
return !info.IsDir()
90+
}
91+
92+
func fileContains(filePath string, needle string) bool {
93+
b, err := os.ReadFile(filePath)
94+
if err != nil {
95+
log.Fatalf("Failed to execute: '%s'", err.Error())
96+
}
97+
markerIsPresent, err := regexp.Match(needle, b)
98+
if err != nil {
99+
log.Fatalf("Failed to execute: '%s'", err.Error())
100+
}
101+
return markerIsPresent
102+
}
103+
104+
type DevScriptTask struct {
105+
name string
106+
comments string
107+
}
108+
109+
func parseDevScriptTasks(devScriptPath string) []DevScriptTask {
110+
// https://regex101.com/r/5LVRcP/1 -> Iteration 1 without comments before
111+
// https://regex101.com/r/XyB410/1 -> Final Iteration with comments before ;)
112+
devScriptBytes, err := os.ReadFile(devScriptPath)
113+
if err != nil {
114+
log.Fatalf("Failed to execute: '%s'", err.Error())
115+
}
116+
117+
devScriptString := string(devScriptBytes)
118+
compiledRegex := regexp.MustCompile(`(?m)(?P<comments>(?:^#.*(?:\n|\r\n|\r))*)^(?:function )?(?P<name>[a-zA-Z0-9_-]+)\s?(?:\(\))?\s?{`)
119+
captureGroupNames := compiledRegex.SubexpNames()
120+
commentsIndex := sort.StringSlice(captureGroupNames).Search("comments")
121+
taskIndex := sort.StringSlice(captureGroupNames).Search("name")
122+
matches := compiledRegex.FindAllStringSubmatch(devScriptString, -1)
123+
124+
var results = []DevScriptTask{}
125+
for _, match := range matches {
126+
task := match[taskIndex]
127+
comments := match[commentsIndex]
128+
if !strings.HasPrefix(task, "_") {
129+
results = append(results, DevScriptTask{name: task, comments: comments})
130+
}
131+
}
132+
return results
133+
}

cmd/task.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package cmd
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
"log"
6+
"os"
7+
"path/filepath"
8+
"syscall"
9+
)
10+
11+
func buildTaskCommand(task DevScriptTask, devScriptPath string) *cobra.Command {
12+
var cmd = &cobra.Command{
13+
Use: task.name,
14+
Short: task.comments,
15+
Long: task.comments,
16+
Args: cobra.ArbitraryArgs,
17+
Run: func(cmd *cobra.Command, args []string) {
18+
execDevScriptWithArguments(devScriptPath, append([]string{task.name}, args...))
19+
},
20+
}
21+
return cmd
22+
}
23+
24+
func execDevScriptWithArguments(devScriptPath string, arguments []string) {
25+
err := os.Chdir(filepath.Dir(devScriptPath))
26+
if err != nil {
27+
log.Fatalf("Failed to execute: '%s'", err.Error())
28+
}
29+
// In case the script is not executable
30+
err = os.Chmod(devScriptPath, 0755)
31+
if err != nil {
32+
log.Fatalf("Failed to execute: '%s'", err.Error())
33+
}
34+
35+
// We tried using exec.Command(devScriptPath, arguments...) which failed for interactive
36+
// terminal calls, e.g. `docker compose exec neos /bin/bash` This is running our command
37+
// as a child process. We are now replacing the process of this helper with the call of
38+
// the `dev.sh` using `syscall.Exec()`
39+
err = syscall.Exec(devScriptPath, append([]string{devScriptPath}, arguments...), os.Environ())
40+
if err != nil {
41+
log.Fatalf("Failed to run shell script: '%s'", err.Error())
42+
}
43+
// IMPORTANT: As we are replacing the process of the helper nothing else will be
44+
// called, except the error handler!
45+
}

dev.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set -e
1111

1212
######### TASKS #########
1313

14+
# Some Docs
1415
function foo_bar() {
1516
echo "#### TEST ####"
1617
}
@@ -33,14 +34,13 @@ function foo1() {
3334
_log_success ' $2: '"$2"
3435
}
3536

37+
# Some Docs
3638
function test() {
3739
echo "#### TEST ####"
3840
_log_success "SUCCESS"
3941
_log_warning "WARNING"
4042
_log_success "Arguments"
41-
_log_success ' $0: '"$0"
42-
_log_success ' $1: '"$1"
43-
_log_success ' $2: '"$2"
43+
echo "$@"
4444
}
4545

4646
function setup() {

go.mod

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,13 @@ module main
33
go 1.19
44

55
require (
6-
github.com/logrusorgru/aurora/v3 v3.0.0 // indirect
6+
github.com/gookit/color v1.3.5
7+
github.com/logrusorgru/aurora/v3 v3.0.0
8+
github.com/spf13/cobra v1.1.1
9+
)
10+
11+
require (
12+
github.com/inconshreveable/mousetrap v1.0.0 // indirect
13+
github.com/spf13/pflag v1.0.5 // indirect
14+
github.com/stretchr/testify v1.4.0 // indirect
715
)

0 commit comments

Comments
 (0)