Skip to content

Commit 1771119

Browse files
committed
Rearrange logs, add version command
1 parent 9d1796c commit 1771119

File tree

4 files changed

+211
-153
lines changed

4 files changed

+211
-153
lines changed

.goreleaser.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ builds:
1616
goarch:
1717
- amd64
1818
# - i386 # does anyone care about i386?
19+
ldflags:
20+
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser
1921
archives:
2022
- replacements:
2123
darwin: Darwin
@@ -24,15 +26,15 @@ archives:
2426
386: i386
2527
amd64: x86_64
2628
checksum:
27-
name_template: 'checksums.txt'
29+
name_template: "checksums.txt"
2830
snapshot:
2931
name_template: "{{ .Tag }}-next"
3032
changelog:
3133
sort: asc
3234
filters:
3335
exclude:
34-
- '^docs:'
35-
- '^test:'
36+
- "^docs:"
37+
- "^test:"
3638
# https://goreleaser.com/customization/homebrew/
3739
brews:
3840
- tap:

dev_notes.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,4 @@ git push origin v0.1
1717
- https://github.com/koekeishiya/homebrew-formulae/blob/master/yabai.rb
1818
- user agent change (reddit API best practices)
1919
- better image parsing (go/colly - see nagracks)
20-
- `write-schedule --path [defaults to ...] --format [cron|systemctl|mac thingie]`
21-
- Lingon (in Downloads)
2220
- rate limiting ( fetchbot? )
23-
- better logging

grabbit.go

Lines changed: 98 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,22 @@ import (
2020
"github.com/natefinch/lumberjack"
2121
"github.com/vartanbeno/go-reddit/reddit"
2222
"go.uber.org/zap"
23-
"go.uber.org/zap/zapcore"
2423
kingpin "gopkg.in/alecthomas/kingpin.v2"
2524
"gopkg.in/yaml.v2"
2625
)
2726

27+
// Version will be overwritten at build time
28+
var Version = "devVersion"
29+
30+
// Commit will be overwritten at build time
31+
var Commit = "devCommit"
32+
33+
// Date will be overwritten at build time
34+
var Date = "devDate"
35+
36+
// BuiltBy will be overwritten at build time
37+
var BuiltBy = "devBuiltBy"
38+
2839
type subreddit struct {
2940
Name string
3041
Destination string
@@ -91,16 +102,10 @@ func genFilePath(destinationDir string, title string, fullURL string) (string, e
91102
return fileName, nil
92103
}
93104

94-
func readConfig(configPath string) (*lumberjack.Logger, []subreddit, error) {
95-
96-
configBytes, err := ioutil.ReadFile(configPath)
97-
if err != nil {
98-
// It's ok to not have a config (first run, for example)
99-
return nil, nil, errors.WithStack(err)
100-
}
105+
func readConfig(configBytes []byte) (*lumberjack.Logger, []subreddit) {
101106

102107
cfg := config{}
103-
err = yaml.UnmarshalStrict(configBytes, &cfg)
108+
err := yaml.UnmarshalStrict(configBytes, &cfg)
104109
if err != nil {
105110
// not ok to get invalid YAML
106111
log.Panicf("readConfig: yaml decode: %+v\n", errors.WithStack(err))
@@ -128,7 +133,14 @@ func readConfig(configPath string) (*lumberjack.Logger, []subreddit, error) {
128133
subreddits = append(subreddits, sr)
129134
}
130135

131-
return lumberjackLogger, subreddits, nil
136+
return lumberjackLogger, subreddits
137+
}
138+
139+
func isImage(URL string) error {
140+
if strings.HasSuffix(URL, ".jpg") {
141+
return nil
142+
}
143+
return errors.New("string doesn't end in .jpg")
132144
}
133145

134146
func grab(sugar *zap.SugaredLogger, subreddits []subreddit) error {
@@ -149,6 +161,7 @@ func grab(sugar *zap.SugaredLogger, subreddits []subreddit) error {
149161
for _, subreddit := range subreddits {
150162

151163
info, err := os.Stat(subreddit.Destination)
164+
// NOTE: should I move these checks to config parsing time?
152165
if err != nil {
153166
logAndPrint(sugar, os.Stderr,
154167
"destination error - skipping all posts",
@@ -187,56 +200,59 @@ func grab(sugar *zap.SugaredLogger, subreddits []subreddit) error {
187200
}
188201

189202
for _, post := range posts {
190-
if strings.HasSuffix(post.URL, ".jpg") {
191-
192-
filePath, err := genFilePath(subreddit.Destination, post.Title, post.URL)
193-
if err != nil {
194-
logAndPrint(sugar, os.Stderr,
195-
"genFilePath err",
196-
"subreddit", subreddit.Name,
197-
"url", post.URL,
198-
"err", errors.WithStack(err),
199-
)
200-
continue
201-
}
202-
if fileExists(filePath) {
203-
logAndPrint(sugar, os.Stdout,
204-
"file already exists!",
205-
"filePath", filePath,
206-
)
207-
continue
208-
}
209-
err = downloadFile(post.URL, filePath)
210-
if err != nil {
211-
logAndPrint(sugar, os.Stderr,
212-
"downloadFile error",
213-
"subreddit", subreddit.Name,
214-
"url", post.URL,
215-
"err", errors.WithStack(err),
216-
)
217-
218-
} else {
219-
logAndPrint(sugar, os.Stdout,
220-
"downloaded file",
221-
"subreddit", subreddit.Name,
222-
"filePath", filePath,
223-
"url", post.URL,
224-
)
225-
}
226-
} else {
203+
err = isImage(post.URL)
204+
if err != nil {
205+
logAndPrint(sugar, os.Stderr,
206+
"can't download image",
207+
"subreddit", subreddit.Name,
208+
"url", post.URL,
209+
"err", err,
210+
)
211+
continue
212+
}
213+
214+
filePath, err := genFilePath(subreddit.Destination, post.Title, post.URL)
215+
if err != nil {
227216
logAndPrint(sugar, os.Stderr,
228-
"Could not download",
217+
"genFilePath err",
229218
"subreddit", subreddit.Name,
230219
"url", post.URL,
220+
"err", errors.WithStack(err),
231221
)
222+
continue
232223
}
224+
if fileExists(filePath) {
225+
logAndPrint(sugar, os.Stdout,
226+
"file already exists!",
227+
"filePath", filePath,
228+
)
229+
continue
230+
}
231+
err = downloadFile(post.URL, filePath)
232+
if err != nil {
233+
logAndPrint(sugar, os.Stderr,
234+
"downloadFile error",
235+
"subreddit", subreddit.Name,
236+
"url", post.URL,
237+
"err", errors.WithStack(err),
238+
)
239+
continue
240+
241+
}
242+
logAndPrint(sugar, os.Stdout,
243+
"downloaded file",
244+
"subreddit", subreddit.Name,
245+
"filePath", filePath,
246+
"url", post.URL,
247+
)
233248
}
234249
}
235-
236250
return nil
237251
}
238252

239253
func editConfig(sugar *zap.SugaredLogger, configPath string, editor string) error {
254+
// TODO: make this a serialized config struct
255+
// so I get a compile warning if there's problems
240256
emptyConfigContent := []byte(`version: 2.0.0
241257
# make lumberjacklogger nil to not log to file
242258
lumberjacklogger:
@@ -258,6 +274,11 @@ subreddits:
258274
_, err := os.Stat(configPath)
259275
if os.IsNotExist(err) {
260276
err = ioutil.WriteFile(configPath, emptyConfigContent, 0644)
277+
logAndPrint(
278+
sugar, os.Stdout,
279+
"wrote default config",
280+
"configPath", configPath,
281+
)
261282
if err != nil {
262283
logAndPrint(
263284
sugar, os.Stderr,
@@ -299,8 +320,9 @@ subreddits:
299320
return err
300321
}
301322

302-
fmt.Printf("Executing: %s %s\n", executable, configPath)
303-
sugar.Infow("Executing",
323+
logAndPrint(
324+
sugar, os.Stdout,
325+
"Opening editor",
304326
"editor", executable,
305327
"configPath", configPath,
306328
)
@@ -322,62 +344,8 @@ subreddits:
322344
return nil
323345
}
324346

325-
// newLogger builds a logger. if lumberjackLogger or fp are nil, then that respective sink won't be made
326-
func newLogger(lumberjackLogger *lumberjack.Logger, fp *os.File, lvl zapcore.LevelEnabler) *zap.Logger {
327-
encoderConfig := zapcore.EncoderConfig{
328-
// Keys can be anything except the empty string.
329-
TimeKey: "timestamp",
330-
LevelKey: "level",
331-
NameKey: "name", // TODO: what is this?
332-
CallerKey: "caller",
333-
FunctionKey: "function", // zapcore.OmitKey,
334-
MessageKey: "msg",
335-
StacktraceKey: "stacktrace",
336-
LineEnding: zapcore.DefaultLineEnding,
337-
EncodeLevel: zapcore.CapitalLevelEncoder,
338-
EncodeTime: zapcore.ISO8601TimeEncoder,
339-
EncodeDuration: zapcore.StringDurationEncoder,
340-
EncodeCaller: zapcore.ShortCallerEncoder,
341-
}
342-
343-
coreSlice := make([]zapcore.Core, 0, 2)
344-
345-
if lumberjackLogger != nil {
346-
jsonCore := zapcore.NewCore(
347-
zapcore.NewJSONEncoder(encoderConfig),
348-
zapcore.AddSync(lumberjackLogger),
349-
lvl,
350-
)
351-
coreSlice = append(coreSlice, jsonCore)
352-
}
353-
354-
if fp != nil {
355-
encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
356-
fpCore := zapcore.NewCore(
357-
zapcore.NewConsoleEncoder(encoderConfig),
358-
zapcore.Lock(fp),
359-
lvl,
360-
)
361-
coreSlice = append(coreSlice, fpCore)
362-
}
363-
364-
combinedCore := zapcore.NewTee(
365-
coreSlice...,
366-
)
367-
368-
logger := zap.New(
369-
combinedCore,
370-
zap.AddCaller(),
371-
// Using errors package to get better stack traces
372-
// zap.AddStacktrace(stackTraceLvl),
373-
// TODO: replace with version (goreleaser embeds it)
374-
zap.Fields(zap.Int("pid", os.Getpid())),
375-
)
376-
377-
return logger
378-
}
379-
380347
func run() error {
348+
381349
// cli and go!
382350
app := kingpin.New("grabbit", "Get top images from subreddits").UsageTemplate(kingpin.DefaultUsageTemplate)
383351
app.HelpFlag.Short('h')
@@ -389,6 +357,8 @@ func run() error {
389357

390358
grabCmd := app.Command("grab", "Grab images. Use `edit-config` first to create a config")
391359

360+
versionCmd := app.Command("version", "print grabbit build and version information")
361+
392362
cmd := kingpin.MustParse(app.Parse(os.Args[1:]))
393363

394364
configPath, err := homedir.Expand(*appConfigPathFlag)
@@ -398,11 +368,15 @@ func run() error {
398368
panic(err)
399369
}
400370

401-
lumberjackLogger, subreddits, cfgErr := readConfig(configPath)
371+
configBytes, cfgErr := ioutil.ReadFile(configPath)
372+
373+
// if configBytes == []byte{}, then this will be
374+
// defaulted to nothing and the logging won't work
375+
// Stuff will still be printed out with logAndPrint though
376+
lumberjackLogger, subreddits := readConfig(configBytes)
402377

403378
logger := newLogger(
404379
lumberjackLogger,
405-
// os.Stdout, // TODO: get an os.File from readConfig to put in here - os.Stderr
406380
nil,
407381
zap.DebugLevel,
408382
)
@@ -415,55 +389,32 @@ func run() error {
415389
return editConfig(sugar, configPath, *editConfigCmdEditorFlag)
416390
case grabCmd.FullCommand():
417391
if cfgErr != nil {
418-
fmt.Fprintf(os.Stderr, "Config error: maybe try `edit-config`: %v\n", cfgErr)
392+
logAndPrint(
393+
sugar, os.Stderr,
394+
"Config error - try `edit-config`",
395+
"cfgErr", cfgErr,
396+
"cfgErrMsg", cfgErr.Error(),
397+
)
419398
return cfgErr
420399
}
421400
return grab(sugar, subreddits)
401+
case versionCmd.FullCommand():
402+
logAndPrint(
403+
sugar, os.Stdout,
404+
"Version and build information",
405+
"BuiltBy", BuiltBy,
406+
"Commit", Commit,
407+
"Date", Date,
408+
"Version", Version,
409+
)
422410
}
423411

424412
return nil
425413
}
426414

427-
// logAndPrint produces a more human readable error message for the console.
428-
// It's really only designed for simple keys/value messages It prints Info if
429-
// fp == os.Stdout, Error if fp == os.Stderr, and panics otherwise.
430-
func logAndPrint(sugar *zap.SugaredLogger, fp *os.File, msg string, keysAndValues ...interface{}) {
431-
432-
switch fp {
433-
case os.Stdout:
434-
sugar.Infow(msg, keysAndValues...)
435-
msg = "INFO: " + msg
436-
case os.Stderr:
437-
sugar.Errorw(msg, keysAndValues...)
438-
msg = "ERROR: " + msg
439-
default:
440-
log.Panicf("logAndPrint: fp not os.Stderr or os.Stdout: %#v\n", fp)
441-
}
442-
443-
length := len(keysAndValues)
444-
if length%2 != 0 {
445-
log.Panicf("printMsgKeysAndValues: len() not even: %#v\n", keysAndValues...)
446-
}
447-
448-
keys := make([]string, length/2)
449-
values := make([]interface{}, length/2)
450-
for i := 0; i < length/2; i++ {
451-
keys[i] = keysAndValues[i*2].(string)
452-
values[i] = keysAndValues[i*2+1]
453-
}
454-
455-
fmtStr := msg + "\n"
456-
for i := 0; i < length/2; i++ {
457-
fmtStr += (" " + keys[i] + ": %#v\n")
458-
}
459-
460-
fmtStr += "\n"
461-
fmt.Fprintf(fp, fmtStr, values...)
462-
}
463-
464415
func main() {
465416
err := run()
466417
if err != nil {
467-
panic(err)
418+
os.Exit(1)
468419
}
469420
}

0 commit comments

Comments
 (0)