-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
137 lines (117 loc) · 2.96 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package main
import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"sync"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go run main.go <parent1.sh> <parent2.sh> [--children child1.sh child2.sh ...]")
os.Exit(1)
}
// Split arguments into parents and children
var parentScripts, childScripts []string
isChildren := false
for _, arg := range os.Args[1:] {
if arg == "--children" {
isChildren = true
continue
}
if isChildren {
childScripts = append(childScripts, arg)
} else {
parentScripts = append(parentScripts, arg)
}
}
if len(parentScripts) == 0 {
fmt.Println("Error: At least one parent script is required")
os.Exit(1)
}
// Validate all scripts exist before starting execution
for _, script := range append(parentScripts, childScripts...) {
absPath, err := filepath.Abs(script)
if err != nil {
fmt.Printf("Failed to get absolute path for '%s': %v\n", script, err)
os.Exit(1)
}
// Check if file exists and is readable
if _, err := os.Stat(absPath); err != nil {
if os.IsNotExist(err) {
fmt.Printf("Script file does not exist: %s\n", absPath)
} else {
fmt.Printf("Cannot access script file '%s': %v\n", absPath, err)
}
os.Exit(1)
}
}
// Create a cancellable context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
errorChan := make(chan error, 1)
// First run all child scripts in parallel
for _, script := range childScripts {
wg.Add(1)
go func(script string) {
defer wg.Done()
absPath, err := filepath.Abs(script)
if err != nil {
fmt.Printf("Failed to get absolute path for '%s': %v\n", script, err)
cancel()
select {
case errorChan <- err:
default:
}
return
}
cmd := exec.CommandContext(ctx, "bash", absPath)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = filepath.Dir(absPath)
err = cmd.Run()
if err != nil {
fmt.Printf("Child script '%s' failed with error: %v\n", script, err)
cancel()
select {
case errorChan <- err:
default:
}
}
}(script)
}
// Wait for all child scripts to complete
childrenDone := make(chan struct{})
go func() {
wg.Wait()
close(childrenDone)
}()
// Wait for children to complete or error
select {
case <-childrenDone:
fmt.Println("All child scripts completed successfully")
case err := <-errorChan:
fmt.Printf("Exiting due to error in child scripts: %v\n", err)
os.Exit(1)
}
// Now run parent scripts sequentially
for _, script := range parentScripts {
absPath, err := filepath.Abs(script)
if err != nil {
fmt.Printf("Failed to get absolute path for '%s': %v\n", script, err)
os.Exit(1)
}
cmd := exec.Command("bash", absPath)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = filepath.Dir(absPath)
err = cmd.Run()
if err != nil {
fmt.Printf("Parent script '%s' failed with error: %v\n", script, err)
os.Exit(1)
}
}
fmt.Println("All scripts completed successfully")
}