/
metadata.go
100 lines (91 loc) · 2.21 KB
/
metadata.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
// Copyright (c) 2019 Dean Jackson <deanishe@deanishe.net>
// MIT Licence applies http://opensource.org/licenses/MIT
package update
import (
"encoding/json"
"errors"
"fmt"
"net/url"
"path/filepath"
aw "github.com/deanishe/awgo"
)
// Metadata is a Workflow Option. It sets a Workflow Updater based on
// a `metadata.json` file exported from Alfred 4+.
//
// URL is the location of the `metadata.json` file. Note: You *must*
// set `downloadurl` in the `metadata.json` file to the URL
// of your .alfredworkflow (or .alfred4workflow etc.) file.
func Metadata(url string) aw.Option {
return func(wf *aw.Workflow) aw.Option {
u, _ := NewUpdater(&metadataSource{url: url, fetch: getURL},
wf.Version(),
filepath.Join(wf.CacheDir(), "_aw/update"),
)
return aw.Update(u)(wf)
}
}
type metadataSource struct {
url string
dl *Download
fetch func(URL string) ([]byte, error)
}
// Downloads implements Source.
func (src *metadataSource) Downloads() ([]Download, error) {
if src.dl == nil {
var (
js []byte
dl Download
err error
)
if js, err = src.fetch(src.url); err != nil {
return nil, err
}
if dl, err = parseMetadata(js); err != nil {
return nil, err
}
src.dl = &dl
}
return []Download{*src.dl}, nil
}
// data model for metadata.json JSON.
type metadataRelease struct {
Data struct {
URL string `json:"downloadurl"`
Version string `json:"version"`
} `json:"alfredworkflow"`
}
func parseMetadata(data []byte) (Download, error) {
var (
dl Download
rel *metadataRelease
u *url.URL
v SemVer
err error
)
if err = json.Unmarshal(data, &rel); err != nil {
return dl, err
}
if rel.Data.Version == "" {
return dl, errors.New("empty version")
}
if rel.Data.URL == "" {
return dl, errors.New("empty url")
}
if v, err = NewSemVer(rel.Data.Version); err != nil {
return dl, err
}
dl.Version = v
dl.URL = rel.Data.URL
if u, err = url.Parse(rel.Data.URL); err != nil {
return dl, err
}
if u.Scheme != "http" && u.Scheme != "https" {
return dl, fmt.Errorf("invalid scheme: %s", u.Scheme)
}
dl.Filename = filepath.Base(u.Path)
m := rxWorkflowFile.FindStringSubmatch(dl.Filename)
if len(m) != 2 {
return dl, errors.New("not a workflow file")
}
return dl, nil
}