Skip to content

Commit

Permalink
Allow using semantic names for priority levels. (#115)
Browse files Browse the repository at this point in the history
This maps certain strings like "rollback" or "canary"
to a standard integer priority so that priorities in
repo configs may be specified with these strings.
  • Loading branch information
nguyen-phillip authored Jul 10, 2024
1 parent 32a9293 commit 3a61116
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 50 deletions.
7 changes: 4 additions & 3 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"cloud.google.com/go/storage"
"github.com/google/googet/v2/goolib"
"github.com/google/googet/v2/oswrap"
"github.com/google/googet/v2/priority"
"github.com/google/logger"
"golang.org/x/oauth2/google"
"google.golang.org/api/googleapi"
Expand Down Expand Up @@ -94,15 +95,15 @@ func (ps *PackageState) Match(pi goolib.PackageInfo) bool {

// Repo represents a single downloaded repo.
type Repo struct {
Priority int
Priority priority.Value
Packages []goolib.RepoSpec
}

// RepoMap describes each repo's packages as seen from a client.
type RepoMap map[string]Repo

// AvailableVersions builds a RepoMap from a list of sources.
func AvailableVersions(ctx context.Context, srcs map[string]int, cacheDir string, cacheLife time.Duration, proxyServer string) RepoMap {
func AvailableVersions(ctx context.Context, srcs map[string]priority.Value, cacheDir string, cacheLife time.Duration, proxyServer string) RepoMap {
rm := make(RepoMap)
for r, pri := range srcs {
rf, err := unmarshalRepoPackages(ctx, r, cacheDir, cacheLife, proxyServer)
Expand Down Expand Up @@ -329,7 +330,7 @@ func FindRepoSpec(pi goolib.PackageInfo, repo Repo) (goolib.RepoSpec, error) {
// package specs in psm.
func latest(psm map[string][]*goolib.PkgSpec, rm RepoMap) (string, string) {
var ver, repo string
var pri int
var pri priority.Value
for r, pl := range psm {
for _, pkg := range pl {
q := rm[r].Priority
Expand Down
35 changes: 17 additions & 18 deletions googet.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,27 @@ import (
"os"
"path"
"path/filepath"
"strconv"
"strings"
"time"

"github.com/go-yaml/yaml"
"github.com/google/googet/v2/client"
"github.com/google/googet/v2/goolib"
"github.com/google/googet/v2/priority"
"github.com/google/googet/v2/system"
"github.com/google/logger"
"github.com/google/subcommands"
"github.com/olekukonko/tablewriter"
)

const (
stateFile = "googet.state"
confFile = "googet.conf"
logFile = "googet.log"
cacheDir = "cache"
repoDir = "repos"
envVar = "GooGetRoot"
logSize = 10 * 1024 * 1024
defaultPriority = 500
stateFile = "googet.state"
confFile = "googet.conf"
logFile = "googet.log"
cacheDir = "cache"
repoDir = "repos"
envVar = "GooGetRoot"
logSize = 10 * 1024 * 1024
)

var (
Expand Down Expand Up @@ -84,11 +83,11 @@ type repoEntry struct {
Name string
URL string
UseOAuth bool
Priority int
Priority priority.Value
}

// UnmarshalYAML provides custom unmarshalling for repoEntry objects.
func (r *repoEntry) UnmarshalYAML(unmarshal func(interface{}) error) error {
func (r *repoEntry) UnmarshalYAML(unmarshal func(any) error) error {
var u map[string]string
if err := unmarshal(&u); err != nil {
return err
Expand All @@ -103,7 +102,7 @@ func (r *repoEntry) UnmarshalYAML(unmarshal func(interface{}) error) error {
r.UseOAuth = strings.ToLower(v) == "true"
case "priority":
var err error
r.Priority, err = strconv.Atoi(v)
r.Priority, err = priority.FromString(v)
if err != nil {
return fmt.Errorf("invalid priority: %v", v)
}
Expand Down Expand Up @@ -195,12 +194,12 @@ func validateRepoURL(u string) bool {
// The repos are mapped to priority values. If a repo config does not specify a priority, the repo
// is assigned the default priority value. If the same repo appears multiple times with different
// priority values, it is mapped to the highest seen priority value.
func repoList(dir string) (map[string]int, error) {
func repoList(dir string) (map[string]priority.Value, error) {
rfs, err := repos(dir)
if err != nil {
return nil, err
}
result := make(map[string]int)
result := make(map[string]priority.Value)
for _, rf := range rfs {
for _, re := range rf.repoEntries {
u := re.URL
Expand All @@ -212,7 +211,7 @@ func repoList(dir string) (map[string]int, error) {
}
p := re.Priority
if p <= 0 {
p = defaultPriority
p = priority.Default
}
if q, ok := result[u]; !ok || p > q {
result[u] = p
Expand Down Expand Up @@ -292,13 +291,13 @@ func readStateFromPath(sf string) (*client.GooGetState, error) {
return client.UnmarshalState(b)
}

func buildSources(s string) (map[string]int, error) {
func buildSources(s string) (map[string]priority.Value, error) {
if s == "" {
return repoList(filepath.Join(rootDir, repoDir))
}
m := make(map[string]int)
m := make(map[string]priority.Value)
for _, src := range strings.Split(s, ",") {
m[src] = defaultPriority
m[src] = priority.Default
}
return m, nil
}
Expand Down
31 changes: 18 additions & 13 deletions googet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/google/googet/v2/client"
"github.com/google/googet/v2/goolib"
"github.com/google/googet/v2/oswrap"
"github.com/google/googet/v2/priority"
)

func TestRepoList(t *testing.T) {
Expand All @@ -41,30 +42,34 @@ func TestRepoList(t *testing.T) {

repoTests := []struct {
content []byte
want map[string]int
want map[string]priority.Value
allowUnsafeURL bool
}{
{[]byte("\n"), nil, false},
{[]byte("# This is just a comment"), nil, false},
{[]byte("url: " + testRepo), map[string]int{testRepo: 500}, false},
{[]byte("\n # Comment\nurl: " + testRepo), map[string]int{testRepo: 500}, false},
{[]byte("- url: " + testRepo), map[string]int{testRepo: 500}, false},
{[]byte("url: " + testRepo), map[string]priority.Value{testRepo: priority.Default}, false},
{[]byte("\n # Comment\nurl: " + testRepo), map[string]priority.Value{testRepo: priority.Default}, false},
{[]byte("- url: " + testRepo), map[string]priority.Value{testRepo: priority.Default}, false},
// The HTTP repo should be dropped.
{[]byte("- url: " + testHTTPRepo), nil, false},
// The HTTP repo should not be dropped.
{[]byte("- url: " + testHTTPRepo), map[string]int{testHTTPRepo: 500}, true},
{[]byte("- URL: " + testRepo), map[string]int{testRepo: 500}, false},
{[]byte("- url: " + testHTTPRepo), map[string]priority.Value{testHTTPRepo: priority.Default}, true},
{[]byte("- URL: " + testRepo), map[string]priority.Value{testRepo: priority.Default}, false},
// The HTTP repo should be dropped.
{[]byte("- url: " + testRepo + "\n\n- URL: " + testHTTPRepo), map[string]int{testRepo: 500}, false},
{[]byte("- url: " + testRepo + "\n\n- URL: " + testHTTPRepo), map[string]priority.Value{testRepo: priority.Default}, false},
// The HTTP repo should not be dropped.
{[]byte("- url: " + testRepo + "\n\n- URL: " + testHTTPRepo), map[string]int{testRepo: 500, testHTTPRepo: 500}, true},
{[]byte("- url: " + testRepo + "\n\n- URL: " + testRepo), map[string]int{testRepo: 500}, false},
{[]byte("- url: " + testRepo + "\n\n- url: " + testRepo), map[string]int{testRepo: 500}, false},
{[]byte("- url: " + testRepo + "\n\n- URL: " + testHTTPRepo), map[string]priority.Value{testRepo: priority.Default, testHTTPRepo: 500}, true},
{[]byte("- url: " + testRepo + "\n\n- URL: " + testRepo), map[string]priority.Value{testRepo: priority.Default}, false},
{[]byte("- url: " + testRepo + "\n\n- url: " + testRepo), map[string]priority.Value{testRepo: priority.Default}, false},
// Should contain oauth- prefix
{[]byte("- url: " + testRepo + "\n useoauth: true"), map[string]int{"oauth-" + testRepo: 500}, false},
{[]byte("- url: " + testRepo + "\n useoauth: true"), map[string]priority.Value{"oauth-" + testRepo: priority.Default}, false},
// Should not contain oauth- prefix
{[]byte("- url: " + testRepo + "\n useoauth: false"), map[string]int{testRepo: 500}, false},
{[]byte("- url: " + testRepo + "\n priority: 1200"), map[string]int{testRepo: 1200}, false},
{[]byte("- url: " + testRepo + "\n useoauth: false"), map[string]priority.Value{testRepo: priority.Default}, false},
{[]byte("- url: " + testRepo + "\n priority: 1200"), map[string]priority.Value{testRepo: priority.Value(1200)}, false},
{[]byte("- url: " + testRepo + "\n priority: default"), map[string]priority.Value{testRepo: priority.Default}, false},
{[]byte("- url: " + testRepo + "\n priority: canary"), map[string]priority.Value{testRepo: priority.Canary}, false},
{[]byte("- url: " + testRepo + "\n priority: pin"), map[string]priority.Value{testRepo: priority.Pin}, false},
{[]byte("- url: " + testRepo + "\n priority: rollback"), map[string]priority.Value{testRepo: priority.Rollback}, false},
}

for i, tt := range repoTests {
Expand Down
3 changes: 2 additions & 1 deletion googet_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/google/googet/v2/client"
"github.com/google/googet/v2/goolib"
"github.com/google/googet/v2/install"
"github.com/google/googet/v2/priority"
"github.com/google/logger"
"github.com/google/subcommands"
)
Expand Down Expand Up @@ -112,7 +113,7 @@ func updates(pm packageMap, rm client.RepoMap) []goolib.PackageInfo {
logger.Info(err)
continue
}
c, err := goolib.ComparePriorityVersion(rm[r].Priority, v, defaultPriority, ver)
c, err := goolib.ComparePriorityVersion(rm[r].Priority, v, priority.Default, ver)
if err != nil {
logger.Error(err)
continue
Expand Down
3 changes: 2 additions & 1 deletion goolib/goospec.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"time"

"github.com/blang/semver"
"github.com/google/googet/v2/priority"
)

type build struct {
Expand Down Expand Up @@ -170,7 +171,7 @@ func fixVer(ver string) string {
}

// ComparePriorityVersion compares (p1, v1) to (p2, v2) as priority-version tuples.
func ComparePriorityVersion(p1 int, v1 string, p2 int, v2 string) (int, error) {
func ComparePriorityVersion(p1 priority.Value, v1 string, p2 priority.Value, v2 string) (int, error) {
if p1 < p2 {
return -1, nil
}
Expand Down
29 changes: 15 additions & 14 deletions goolib/goospec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"testing"

"github.com/blang/semver"
"github.com/google/googet/v2/priority"
)

func mkVer(sem string, rel int64) Version {
Expand Down Expand Up @@ -208,24 +209,24 @@ func TestBadCompare(t *testing.T) {
func TestComparePriorityVersion(t *testing.T) {
for _, tc := range []struct {
desc string
p1 int
p1 priority.Value
v1 string
p2 int
p2 priority.Value
v2 string
want int
}{
{"same priority, same version, lesser release", 500, "1.2.3@1", 500, "1.2.3@2", -1},
{"same priority lesser version", 500, "1.2.3@1", 500, "1.2.4@2", -1},
{"same priority, greater version", 500, "1.2.4@1", 500, "1.2.3@2", 1},
{"same priority, same version", 500, "1.2.3", 500, "1.2.3", 0},
{"lesser priority, same version, lesser release", 500, "1.2.3@1", 1000, "1.2.3@2", -1},
{"lesser priority, lesser version", 500, "1.2.3@1", 1000, "1.2.4@2", -1},
{"lesser priority, greater version", 500, "1.2.4@1", 1000, "1.2.3@2", -1},
{"lesser priority, same version", 500, "1.2.3", 1000, "1.2.3", -1},
{"greater priority, same version, lesser release", 1000, "1.2.3@1", 500, "1.2.3@2", 1},
{"greater priority, lesser version", 1000, "1.2.3@1", 500, "1.2.4@2", 1},
{"greater priority, greater version", 1000, "1.2.4@1", 500, "1.2.3@2", 1},
{"greater priority, same version", 1000, "1.2.3", 500, "1.2.3", 1},
{"same priority, same version, lesser release", priority.Value(500), "1.2.3@1", priority.Value(500), "1.2.3@2", -1},
{"same priority lesser version", priority.Value(500), "1.2.3@1", priority.Value(500), "1.2.4@2", -1},
{"same priority, greater version", priority.Value(500), "1.2.4@1", priority.Value(500), "1.2.3@2", 1},
{"same priority, same version", priority.Value(500), "1.2.3", priority.Value(500), "1.2.3", 0},
{"lesser priority, same version, lesser release", priority.Value(500), "1.2.3@1", priority.Value(1000), "1.2.3@2", -1},
{"lesser priority, lesser version", priority.Value(500), "1.2.3@1", priority.Value(1000), "1.2.4@2", -1},
{"lesser priority, greater version", priority.Value(500), "1.2.4@1", priority.Value(1000), "1.2.3@2", -1},
{"lesser priority, same version", priority.Value(500), "1.2.3", priority.Value(1000), "1.2.3", -1},
{"greater priority, same version, lesser release", priority.Value(1000), "1.2.3@1", priority.Value(500), "1.2.3@2", 1},
{"greater priority, lesser version", priority.Value(1000), "1.2.3@1", priority.Value(500), "1.2.4@2", 1},
{"greater priority, greater version", priority.Value(1000), "1.2.4@1", priority.Value(500), "1.2.3@2", 1},
{"greater priority, same version", priority.Value(1000), "1.2.3", priority.Value(500), "1.2.3", 1},
} {
t.Run(tc.desc, func(t *testing.T) {
if got, err := ComparePriorityVersion(tc.p1, tc.v1, tc.p2, tc.v2); err != nil {
Expand Down
38 changes: 38 additions & 0 deletions priority/priority.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Package priority provides standard priority levels.
package priority

import "strconv"

// Value is an integer priority associated with a repo.
type Value int

const (
// None is an unspecified priority level.
None Value = 0
// Default is the default priority level for everything.
Default Value = 500
// Canary is the priority level for canary repos.
Canary Value = 1300
// Pin is the priority level for user-pinned repos.
Pin Value = 1400
// Rollback is the priority level for rollback repos.
Rollback Value = 1500
)

// priorityNameToValue maps semantic priority names to their integer values.
var priorityNameToValue = map[string]Value{
"default": Default,
"canary": Canary,
"pin": Pin,
"rollback": Rollback,
}

// FromString converts the string s into a priority Value, where s represents
// either a semantic priority name or an integer.
func FromString(s string) (Value, error) {
if v, ok := priorityNameToValue[s]; ok {
return v, nil
}
i, err := strconv.Atoi(s)
return Value(i), err
}
31 changes: 31 additions & 0 deletions priority/priority_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package priority

import (
"testing"
)

func TestFromString(t *testing.T) {
for _, tc := range []struct {
s string
want Value
wantErr bool
}{
{s: "default", want: Default},
{s: "canary", want: Canary},
{s: "pin", want: Pin},
{s: "rollback", want: Rollback},
{s: "100", want: Value(100)},
{s: "bad", wantErr: true},
} {
t.Run(tc.s, func(t *testing.T) {
got, err := FromString(tc.s)
if err != nil && !tc.wantErr {
t.Errorf("FromString(%s) failed: %v", tc.s, err)
} else if err == nil && tc.wantErr {
t.Errorf("FromString(%s) got nil error, wanted non-nil", tc.s)
} else if got != tc.want {
t.Errorf("FromString(%s) got: %v, want: %v", tc.s, got, tc.want)
}
})
}
}

0 comments on commit 3a61116

Please sign in to comment.