-
Notifications
You must be signed in to change notification settings - Fork 0
/
root.go
162 lines (130 loc) · 3.65 KB
/
root.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package cmd
import (
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/fsnotify/fsnotify"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const bannerMsg = `
____ ____ _ _ ___ __ ___ __ ____ __ ____
| __\| ||\/\ |\/\ | \ | \|\| \ | | |___\| \|\| __\
| \__| . || \| \| . \| \|| . \ | |__| / | \|| ]_
|___/|___/|/v\/|/v\/|/\_/|/\_/|___/ |___/|/ |/\_/|___/
`
var configFile string
func init() {
// set config defaults
viper.SetDefault("garbage-collect", false)
viper.SetConfigType("yml")
viper.SetEnvPrefix("commandline")
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viper.AutomaticEnv()
// flags
RootCmd.PersistentFlags().BoolP("quiet", "q", false, "Quiet mode. Do not display banner messages")
RootCmd.PersistentFlags().DurationP("shutdown-wait-time", "", time.Duration(500)*time.Millisecond, "Shutdown wait time")
// config
viper.BindPFlag("quiet", RootCmd.PersistentFlags().Lookup("quiet"))
viper.BindPFlag("shutdown-wait-time", RootCmd.PersistentFlags().Lookup("shutdown-wait-time"))
// local flags;
RootCmd.Flags().StringVar(&configFile, "config", "", "/path/to/config.yml")
}
// RootCmd is the main command to run the application
var RootCmd = &cobra.Command{
Use: "commandline",
Short: "Command Line Boilerplate",
Long: bannerMsg,
Run: run,
// parse the config if one is provided, or use the defaults. Set the backend
// driver to be used
PersistentPreRun: preRun,
}
func run(cmd *cobra.Command, args []string) {
if !viper.GetBool("quiet") {
fmt.Println(bannerMsg)
fmt.Println()
fmt.Printf("Started with process id: %d\n", os.Getpid())
}
// track signals
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGHUP, syscall.SIGTERM)
var waitTime time.Duration
for {
waitTime = viper.GetDuration("shutdown-wait-time")
if exit := start(sig, waitTime); exit {
return
}
}
}
func preRun(ccmd *cobra.Command, args []string) {
// if --config is passed, attempt to parse the config file
if configFile != "" {
// get the filepath
abs, err := filepath.Abs(configFile)
if err != nil {
log.Fatalf("Error reading filepath: %s", err)
os.Exit(1)
}
// get the config name
base := filepath.Base(abs)
// get the path
path := filepath.Dir(abs)
//
viper.SetConfigName(strings.Split(base, ".")[0])
viper.AddConfigPath(path)
// Find and read the config file; Handle errors reading the config file
if err := viper.ReadInConfig(); err != nil {
log.Fatalf("Failed to read config file: %s", err)
os.Exit(1)
}
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
log.Printf("Config file changed: %s\n", e.Name)
// Send a HUP signal to restart
if p, err := os.FindProcess(os.Getpid()); err == nil {
p.Signal(os.Interrupt)
}
})
}
}
func start(sig <-chan os.Signal, waittime time.Duration) bool {
log.Println("Start!")
var exitApplication bool
shutdown := make(chan interface{})
exit := make(chan interface{})
go myApplicationMain(shutdown, exit)
switch <-sig {
case syscall.SIGINT, syscall.SIGTERM:
exitApplication = true
// case syscall.SIGHUP:
default:
log.Println("Reload!!")
}
close(shutdown)
time.Sleep(waittime)
close(exit)
log.Println("Exit!")
return exitApplication
}
func myApplicationMain(shutdown, exit <-chan interface{}) {
log.Println("myApplicationMain")
for {
select {
case <-shutdown:
log.Println("myApplicationMain: shutdown started...")
// some long process....
time.Sleep(time.Second * 5)
log.Println("myApplicationMain: shutdown completed.")
return
case <-exit:
log.Println("myApplicationMain: exit now.")
return
}
}
}