-
Notifications
You must be signed in to change notification settings - Fork 1
/
settings.go
158 lines (133 loc) · 4.31 KB
/
settings.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
package main
import (
"fmt"
"io"
"os"
"strconv"
"strings"
"text/tabwriter"
flag "github.com/jessevdk/go-flags"
)
const version = "0.11.0"
//Config is concrete and stored in configuration file
type Config struct {
ImageDir string `long:"dir" description:"Target Directory" default:"img" ini-name:"downdir"`
QDepth int `short:"q" long:"queue" description:"Length of the queue buffer" default:"50" ini-name:"queue_depth"`
Key string `short:"k" long:"key" description:"Derpibooru API key" ini-name:"key"`
LogFilters Bool `long:"logfilter" optional:" " optional-value:"true" description:"Enable logging of filtered images" ini-name:"logfilter"`
}
//FlagOpts are runtime boolean flags
type FlagOpts struct {
UnsafeHTTPS bool `long:"unsafe-https" description:"Disable HTTPS security verification"`
}
//FiltOpts are filtration parameters
type FiltOpts struct {
Score int `long:"score" description:"Filter option, minimal score of image for it to be downloaded"`
Faves int `long:"faves" description:"Filter option, minimal amount of people who favored image for it to be downloaded"`
ScoreF bool `no-flag:" "`
FavesF bool `no-flag:" "`
}
//TagOpts are options relevant to searching by tags
type TagOpts struct {
Tag string `short:"t" long:"tag" description:"Tag to download"`
StartPage int `short:"p" long:"startpage" description:"Starting page for search" default:"1"`
StopPage int `short:"n" long:"stoppage" description:"Stopping page for search, default - parse all search pages"`
}
//Options provide program-wide options. At maximum, we got one persistent global and one short-living copy for writing in config file
type Options struct {
*Config
*FlagOpts
*FiltOpts
*TagOpts
Args struct {
IDs []int `description:"Image IDs to download" optional:"yes"`
} `positional-args:"yes"`
}
func getOptions() (opts *Options, args []string) {
opts = new(Options)
err := flag.IniParse("config.ini", opts)
if err != nil {
switch err.(type) {
default:
lFatal(err)
case *os.PathError:
lWarn("config.ini not found, using defaults")
}
}
inisets := *opts.Config //copy value instead of reference - or we will get no results later
args, err = flag.Parse(opts)
flagsFail(err)
dirF := opts.FiltOpts.flagsPresent(os.Args)
if !dirF && inisets.ImageDir != "" {
opts.Config.ImageDir = inisets.ImageDir
}
if opts.Config.isEqual(&inisets) { //If nothing to write, no double-writing files
return
}
inifile, err := os.OpenFile("config.ini", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
if err != nil {
lFatal("Could not create configuration file")
}
defer func() {
err = inifile.Close()
if err != nil {
lFatal("Could not close configuration file")
}
}()
err = opts.Config.prettyWriteIni(inifile)
if err != nil {
lFatal("Could not write in configuration file")
}
return
}
//prettyWriteIni Uses tabwriter to make pretty ini file with
func (sets *Config) prettyWriteIni(inifile io.Writer) error {
tb := tabwriter.NewWriter(inifile, 10, 8, 0, ' ', 0) //Tabs! Elastic! Pretty!
//Ignoring errors because we write in-memory and fun could be had on return only
_, _ = fmt.Fprintf(tb, "key \t= %s\n", sets.Key)
_, _ = fmt.Fprintf(tb, "queue_depth \t= %s\n", strconv.Itoa(sets.QDepth))
_, _ = fmt.Fprintf(tb, "downdir \t= %s\n", sets.ImageDir)
_, _ = fmt.Fprintf(tb, "logfilter \t= %t\n", sets.LogFilters)
return tb.Flush() //Returns and passes error upstairs
}
//isEqual compares only options I want to preserve across launches.
func (sets *Config) isEqual(b *Config) bool {
if b == nil {
return false
}
if sets.ImageDir == b.ImageDir &&
sets.QDepth == b.QDepth &&
sets.Key == b.Key &&
sets.LogFilters == b.LogFilters {
return true
}
return false
}
func (opts *FiltOpts) flagsPresent(args []string) bool {
dirF := false
for _, arg := range args {
if strings.Contains(arg, "--score") {
opts.ScoreF = true
}
if strings.Contains(arg, "--faves") {
opts.FavesF = true
}
if strings.Contains(arg, "--dir") {
dirF = true
}
}
return dirF
}
func flagsFail(err error) {
if err != nil {
switch err.(*flag.Error).Type {
case flag.ErrHelp:
os.Exit(0) //Why fall through when asked for help? Just exit with suggestion
case flag.ErrUnknownFlag:
fmt.Println("Use --help to view all available options")
os.Exit(0)
default:
lFatal("Can't parse flags: ", err)
}
}
}