/
config.go
160 lines (139 loc) · 3.66 KB
/
config.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
package main
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/reddit/baseplate.go/log"
yaml "gopkg.in/yaml.v2"
"go.yhsif.com/godrive-fuse/gfs"
)
// ConfigFilename is the filename used under root config directory.
const ConfigFilename = "config.yaml"
// Default top level config values.
const (
DefaultLogLevel = log.InfoLevel
)
// Config defines the structure of the main config file used.
type Config struct {
// log level used, default to info level.
LogLevel log.Level `yaml:"log_level"`
OAuthClient OAuthClientConfig `yaml:"oauth_client"`
HTTPClient HTTPClientConfig `yaml:"http_client"`
Daemon DaemonConfig `yaml:"daemon"`
Mountpoints gfs.Mountpoints `yaml:"mountpoints"`
}
// ParseConfig parses content read from config file.
func ParseConfig(f io.Reader) (cfg Config, err error) {
err = yaml.NewDecoder(f).Decode(&cfg)
if err != nil {
return
}
// Default fallback handlings
if cfg.LogLevel == "" {
cfg.LogLevel = DefaultLogLevel
}
return
}
// ParseConfigFromDir parses the config file from root config directory.
func ParseConfigFromDir(dir string) (cfg Config, err error) {
path := filepath.Join(dir, ConfigFilename)
defer func() {
if err != nil {
if os.IsNotExist(err) {
fmt.Fprintf(
os.Stderr,
"Config file %s does not exist. Please rerun %s init to create it.\n",
path,
os.Args[0],
)
os.Exit(-1)
}
logAndExit(err)
}
}()
var f *os.File
f, err = os.Open(path)
if err != nil {
return
}
defer f.Close()
return ParseConfig(f)
}
// DefaultConfigFile is the config file created for user to modify.
const DefaultConfigFile = `# godrive-fuse config file
# The miminal log level to keep, should be one of:
# - debug
# - info
# - warn
# - error
# - panic
# - fatal
# Default is info.
log_level:
# OAuth client related configs
oauth_client:
# TODO
client_id:
client_secret:
# HTTP client related configs, controls both OAuth flow and Google Drive API
http_client:
# A go time.Duration format string, e.g. "5s" means "5 seconds".
# See https://pkg.go.dev/time?tab=doc#ParseDuration for more info.
# Default is 5s
timeout:
# Daemon related configs, controls how to run daemon when mounting
daemon:
# The directory to put log and pid files for the daemon.
# Default is $XDG_DATA_HOME/godrive-fuse,
# and default of $XDG_DATA_HOME is $HOME/.local/share.
dir:
# When starting new daemon,
# also cleanup old pid and log files that's created N days ago.
# Default is 0 (don't cleanup anything).
cleanup_days:
# A string -> string map of mountpoints.
# Keys are local directories, and values are google drive directories.
mountpoints:
# Uncomment the next line to mount your whole google drive to /tmp/drive:
#/tmp/drive: /
`
// In this file we cannot use baseplate log yet, so use this function to panic
func logAndExit(args ...interface{}) {
fmt.Fprintln(os.Stderr, args...)
os.Exit(-1)
// panic(args[0])
}
// InitConfigFile creates the DefaultConfigFile if it does not already exist.
func InitConfigFile(dir string) {
path := filepath.Join(dir, ConfigFilename)
_, err := os.Lstat(path)
if err == nil {
fmt.Fprintf(
os.Stderr,
"Config file %s already exists, leaving it alone.\n",
path,
)
os.Exit(-1)
}
if !os.IsNotExist(err) {
logAndExit(err)
}
if err := os.MkdirAll(dir, 0755); err != nil {
logAndExit(err)
}
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
logAndExit(err)
}
defer func() {
if err := f.Close(); err != nil {
logAndExit(err)
}
}()
if _, err := io.Copy(f, strings.NewReader(DefaultConfigFile)); err != nil {
logAndExit(err)
}
fmt.Printf("Config file %s created, please edit it before first use.\n", path)
}