/
main.go
101 lines (80 loc) · 2.01 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
package main
import (
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"github.com/marema31/jocasta/config"
"github.com/marema31/jocasta/logwriter"
)
// Theses variables will be provided by goreleaser via ldflags.
var (
version = "dev"
commit = "none"
date = "unknown"
)
func main() {
i := 1
configPath := "."
configFile := ".jocasta"
if len(os.Args) > 2 && os.Args[1] == "-c" {
i = 3
configPath = filepath.Dir(os.Args[2])
configFile = filepath.Base(os.Args[2])
}
if (len(os.Args)-i) < 1 || os.Args[i] == "-h" {
fmt.Printf("jocasta %v, commit %v, built at %v\n\n", version, commit, date)
fmt.Println("usage: jocasta [-c configFileWithoutExtension] command to run with args")
fmt.Println()
fmt.Println("The config file name must be provided without the file extension, jocasta will try json, toml and yaml")
os.Exit(0)
}
config, err := config.New(configPath, configFile, os.Args[i])
if err != nil {
log.Fatal(err)
}
fmt.Printf("Will run %s\n", strings.Join(os.Args[i:], " "))
cmd := exec.Command(os.Args[i], os.Args[i+1:]...) //nolint: gosec
stderr, err := cmd.StderrPipe()
if err != nil {
log.Fatal(err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
logerr, err := logwriter.New("err", config)
if err != nil {
log.Fatal(err)
}
logout, err := logwriter.New("out", config)
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
// cmd.Wait() should be called only after we finish reading
// from stdout and stderr
// wg ensures that we finish
var wg sync.WaitGroup
wg.Add(2) //nolint: gomnd
go transfer(stdout, logout, &wg)
go transfer(stderr, logerr, &wg)
wg.Wait()
err = cmd.Wait()
if err != nil {
log.Fatalf("Unable to exec %s: %s\n", os.Args[i], err)
}
}
// will be called as goroutine to allow the stdout and stderr to be captured in parallel.
func transfer(in io.Reader, out io.Writer, wg *sync.WaitGroup) {
if _, err := io.Copy(out, in); err != nil {
log.Fatal(err)
}
wg.Done()
}