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
|
package main
import (
"fmt"
"strings"
"github.com/charmbracelet/log"
)
type Source struct {
URL string `json:"url"`
SHA256 string `json:"sha256"`
Unpack bool `json:"unpack"`
Type string `json:"type"`
Version string `json:"version,omitempty"`
URLTemplate string `json:"url_template,omitempty"`
TagPredicate string `json:"tag_predicate,omitempty"`
TrimTagPrefix string `json:"trim_tag_prefix,omitempty"`
Pinned bool `json:"pinned,omitempty"`
Force bool `json:"force,omitempty"`
}
func (source *Source) Update(sources *Sources, name string, force bool, forcePinned bool) (bool, error) {
log.Infof("checking %s", name)
updated := false
if !sources.Exists(name) {
log.Warnf("skipped %s: source does not exist", name)
return updated, nil
}
if source.Pinned && !forcePinned {
log.Infof("skipped %s: source is pinned", name)
return updated, nil
}
if source.Type == "git" {
log.Debugf("checking %s: remote git tag", name)
tag, err := source.fetchLatestGitTag()
if err != nil {
return updated, err
}
if tag != source.Version || force || source.Force {
if tag != source.Version {
log.Infof("bumped %s: %s -> %s", name, source.Version, tag)
}
if tag != source.Version {
updated = true
}
source.Version = tag
if strings.Contains(source.URLTemplate, "{version}") {
source.URL = strings.ReplaceAll(source.URLTemplate, "{version}", source.Version)
log.Debugf("patched %s: substituted url template", name)
}
} else {
log.Infof("skipped %s: version remains unchanged", name)
return updated, nil
}
}
log.Debugf("checking %s: sha256", name)
sha256, err := fetchSHA256(source.URL, source.Unpack)
if err != nil {
return updated, err
}
if sha256 != source.SHA256 {
log.Infof("rehashed %s: %s -> %s", name, source.SHA256, sha256)
source.SHA256 = sha256
updated = true
}
(*sources)[name] = *source
return updated, nil
}
func (source *Source) fetchLatestGitTag() (string, error) {
if source.Type == "git" {
repository := "https://github.com/" + strings.Split(source.URL, "/")[3] + "/" + strings.Split(source.URL, "/")[4]
remotes, err := command("bash", false, "-c", fmt.Sprintf("git ls-remote %s | awk -F'/' '{print $NF}' | sort -V", repository))
if err != nil {
return "", err
}
refs := strings.Split(remotes, "\n")
var latest string
if source.TagPredicate == "" {
latest = refs[len(refs)-2]
} else {
for i := len(refs) - 2; i >= 0; i-- {
if strings.Contains(refs[i], source.TagPredicate) {
latest = refs[i]
break
}
}
}
if source.TrimTagPrefix != "" {
latest = strings.TrimPrefix(latest, source.TrimTagPrefix)
}
return latest, nil
}
return "", fmt.Errorf("source is not a git repository")
}
|