Skip to content

Commit 1f1baf4

Browse files
authored
Merge pull request #2 from clemthi/version-bump
Go version bump
2 parents 9c8215b + 0aabf00 commit 1f1baf4

File tree

6 files changed

+102
-35
lines changed

6 files changed

+102
-35
lines changed

.gitignore

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# GO
2+
3+
# If you prefer the allow list template instead of the deny list, see community template:
4+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
5+
#
16
# Binaries for programs and plugins
27
*.exe
38
*.exe~
@@ -13,3 +18,23 @@
1318

1419
# Dependency directories (remove the comment below to include it)
1520
# vendor/
21+
22+
# Go workspace file
23+
go.work
24+
25+
## VSCODE
26+
27+
.vscode/*
28+
# !.vscode/settings.json
29+
# !.vscode/tasks.json
30+
# !.vscode/launch.json
31+
# !.vscode/extensions.json
32+
# !.vscode/*.code-snippets
33+
34+
# Local History for Visual Studio Code
35+
.history/
36+
37+
# Built Visual Studio Code Extensions
38+
*.vsix
39+
40+

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ This small application allows to start multiple applications at once and if one
55
## Usage
66

77
```shell
8-
runsyncedapp.exe --config=myconfig.json
8+
runsyncedapp.exe --config=myconfig.json --verbose
99
```
1010

1111
- `config` : path of the config file
12-
12+
- `verbose` : show all logs
1313

1414
## JSON configuration
1515

16-
The JSON configuration file looks like:
16+
The configuration file looks like this:
1717

1818
```json
1919
{
@@ -44,6 +44,6 @@ The parameters are the following:
4444
- `waitCheck`: time in second to wait after the applications starts and the verifications
4545
- `waitExit`: time in second to wait before the applications closures
4646
- `applications`: array of application to execute:
47-
- `path`: full path of the application
48-
- `useExistingInstance`: don't start a new instance if it's already running
49-
- `killOnExit`: kill the application if it's running after another app has been killed
47+
- `path`: full path of the application
48+
- `useExistingInstance`: don't start a new instance if it's already running
49+
- `killOnExit`: kill the application if it's running after another app has been killed

config.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
{
2-
"waitCheck": 10,
3-
"waitExit": 10,
2+
"waitCheck": 1,
3+
"waitExit": 1,
44
"applications": [
55
{
6-
"path": "C:\\Windows\\notepad.exe",
7-
"useExistingInstance": true,
6+
"path": "C:\\Windows\\System32\\dxdiag.exe",
7+
"useExistingInstance": false,
88
"killOnExit": true
99
},
1010
{
11-
"path": "C:\\Windows\\System32\\calc.exe",
11+
"path": "C:\\Windows\\System32\\ftp.exe",
1212
"useExistingInstance": false,
1313
"killOnExit": true
1414
},
1515
{
16-
"path": "C:\\Windows\\write.exe",
16+
"path": "C:\\Windows\\System32\\msinfo32.exe",
1717
"useExistingInstance": false,
1818
"killOnExit": false
1919
}

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module github.com/clemthi/runsyncapps
22

3-
go 1.18
3+
go 1.22
44

55
require github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19
6+
7+
require github.com/stretchr/testify v1.9.0 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,10 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
13
github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19 h1:WjT3fLi9n8YWh/Ih8Q1LHAPsTqGddPcHqscN+PJ3i68=
24
github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
5+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
6+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
8+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
9+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
10+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

main.go

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package main
33
import (
44
"encoding/json"
55
"flag"
6-
"io/ioutil"
7-
"log"
6+
"fmt"
7+
"log/slog"
88
"os"
99
"os/exec"
1010
"time"
@@ -31,79 +31,95 @@ type ProcessDetails struct {
3131
}
3232

3333
func main() {
34-
configFile := flag.String("config", "config.json", "path to a configuration file")
35-
flag.Parse()
34+
slog.SetLogLoggerLevel(slog.LevelInfo)
3635

37-
config, err := loadConfigFile(*configFile)
36+
slog.Debug("Loading flags")
37+
configFile := *flag.String("config", "config.json", "path to a configuration file")
38+
verbose := *flag.Bool("verbose", false, "show all logs")
39+
40+
if verbose {
41+
slog.SetLogLoggerLevel(slog.LevelDebug)
42+
}
43+
44+
config, err := loadConfigFile(configFile)
3845
if err != nil {
39-
log.Fatalf("Cannot load config file %s : %s", *configFile, err)
46+
exitWithMsg(fmt.Sprintf("Cannot load config file %s : %s", configFile, err))
4047
}
4148

42-
runningProcs, err := startProcesses(config.Applications, true)
49+
runningProcs, err := startProcesses(config.Applications)
4350
if err != nil {
44-
log.Fatalf("Error launching apps : %s", err)
51+
exitWithMsg(fmt.Sprintf("Error launching apps : %s", err))
4552
}
4653

4754
time.Sleep(time.Duration(config.WaitCheck) * time.Second)
4855
checkRunningProcesses(runningProcs)
4956

5057
time.Sleep(time.Duration(config.WaitExit) * time.Second)
5158
killProcesses(runningProcs)
52-
log.Printf("Done")
59+
slog.Debug("Exiting")
5360
}
5461

55-
func loadConfigFile(configFile string) (ConfigFile, error) {
56-
file, err := ioutil.ReadFile(configFile)
62+
func loadConfigFile(configFile string) (*ConfigFile, error) {
63+
slog.Debug(fmt.Sprintf("Loading config file %s", configFile))
64+
file, err := os.ReadFile(configFile)
5765
if err != nil {
58-
log.Fatalf("Error opening config %s : %s", configFile, err)
66+
return nil, err
5967
}
6068

6169
var jsonData ConfigFile
6270
err = json.Unmarshal([]byte(file), &jsonData)
6371

64-
return jsonData, err
72+
return &jsonData, err
6573
}
6674

67-
func startProcesses(apps []AppConfig, checkCurrentProcesses bool) (map[int]ProcessDetails, error) {
75+
func startProcesses(apps []AppConfig) (map[int]ProcessDetails, error) {
6876
procs := make(map[int]ProcessDetails)
6977

7078
runningProcs, err := ps.Processes()
7179
if err != nil {
72-
log.Fatalf("Error listing processed (%s)", err)
80+
exitWithMsg(fmt.Sprintf("Error listing processed (%s)", err))
7381
}
7482

7583
for _, app := range apps {
7684
newProc := ProcessDetails{path: app.Path, pid: -1, killOnExit: app.KillOnExit}
7785

7886
if app.UseExistingInstance {
87+
// check existing processes
7988
currentPid, err := findPidFromPath(app.Path, runningProcs)
8089
if err != nil {
81-
log.Fatalf("Error checking running processes : %s", err)
90+
slog.Warn(fmt.Sprintf("Error checking running processes : %s", err))
8291
}
8392
if currentPid != -1 {
8493
newProc.pid = currentPid
85-
log.Printf("Found running app %s [PID : %d]\n", newProc.path, newProc.pid)
94+
slog.Info(fmt.Sprintf("Found running app %s [PID : %d]\n", newProc.path, newProc.pid))
8695
}
8796
}
8897

98+
// start app if not found in existing processes
8999
if newProc.pid == -1 {
90100
cmd := exec.Command(app.Path)
91101
err := cmd.Start()
92102
if err != nil {
93103
return nil, err
94104
}
95105
newProc.pid = cmd.Process.Pid
96-
log.Printf("Starting apps %s [PID : %d]\n", newProc.path, newProc.pid)
106+
slog.Info(fmt.Sprintf("Starting apps %s [PID : %d]", newProc.path, newProc.pid))
97107
}
98108
procs[newProc.pid] = newProc
99109
}
100110

101111
return procs, nil
102112
}
103113

114+
func exitWithMsg(msg string) {
115+
slog.Error(msg)
116+
os.Exit(1)
117+
}
118+
104119
func findPidFromPath(path string, procs []ps.Process) (int, error) {
105120
for _, proc := range procs {
106121
if procPath, _ := proc.Path(); procPath == path {
122+
slog.Debug(fmt.Sprintf("Found running app %s with PID %d", path, proc.Pid()))
107123
return proc.Pid(), nil
108124
}
109125
}
@@ -124,33 +140,49 @@ func checkRunningProcesses(procs map[int]ProcessDetails) {
124140
go checkRunningProcess(pid, chanProcesses)
125141
}
126142
closedProcess := <-chanProcesses
127-
log.Printf("Process closed %s [PID: %d]", procs[closedProcess].path, closedProcess)
143+
slog.Info(fmt.Sprintf("Process closed %s [PID: %d]", procs[closedProcess].path, closedProcess))
128144
}
129145

130146
func checkRunningProcess(pid int, processes chan int) {
131147
process, err := os.FindProcess(pid)
132148
if err != nil {
133149
processes <- pid
134150
}
151+
152+
// Wait the process to exit
153+
slog.Debug(fmt.Sprintf("Waiting process [PID: %d] to exit", pid))
135154
processState, err := process.Wait()
136155
if err != nil {
156+
slog.Warn(fmt.Sprintf("Error while waiting process [PID: %d]", pid))
137157
processes <- pid
158+
return
138159
}
160+
139161
if processState.Exited() {
162+
slog.Info(fmt.Sprintf("Process [PID: %d] exited with code %d", pid, processState.ExitCode()))
140163
processes <- pid
164+
return
141165
}
166+
167+
// something went wrong (?), let's assume process is over
168+
slog.Warn(fmt.Sprintf("Process [PID: %d] exited but : %s ", pid, processState))
169+
processes <- pid
142170
}
143171

144172
func killProcesses(procs map[int]ProcessDetails) {
173+
slog.Info("Killing other apps")
145174
for _, proc := range procs {
146175
if proc.killOnExit {
176+
slog.Debug(fmt.Sprintf("Killing process %s [PID: %d]", proc.path, proc.pid))
147177
procKilled, err := killProcess(proc.pid)
148178
if err != nil {
149-
log.Printf("Error when killing process%s [PID: %d] : %s", proc.path, proc.pid, err)
179+
slog.Warn(fmt.Sprintf("Error when killing process %s [PID: %d] : %s", proc.path, proc.pid, err))
150180
}
151181
if procKilled {
152-
log.Printf("Killed process %s [PID: %d]", proc.path, proc.pid)
182+
slog.Info(fmt.Sprintf("Killed process %s [PID: %d]", proc.path, proc.pid))
153183
}
184+
} else {
185+
slog.Debug(fmt.Sprintf("Skipping process %s [PID: %d]", proc.path, proc.pid))
154186
}
155187
}
156188
}
@@ -163,7 +195,7 @@ func killProcess(pid int) (bool, error) {
163195
process, _ := os.FindProcess(pid)
164196
err := process.Kill()
165197
if err != nil {
166-
log.Printf("Cannot kill process %d", pid)
198+
slog.Warn(fmt.Sprintf("Cannot kill process %d", pid))
167199
return false, err
168200
}
169201
return true, nil

0 commit comments

Comments
 (0)