Skip to content

Add support for specifying the priority with addrepo subcommand #116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion googet.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ type repoEntry struct {
Name string
URL string
UseOAuth bool
Priority priority.Value
Priority priority.Value `yaml:",omitempty"`
}

// UnmarshalYAML provides custom unmarshalling for repoEntry objects.
Expand Down
44 changes: 31 additions & 13 deletions googet_addrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,64 +21,82 @@ import (
"path/filepath"
"strings"

"github.com/go-yaml/yaml"
"github.com/google/googet/v2/oswrap"
"github.com/google/googet/v2/priority"
"github.com/google/logger"
"github.com/google/subcommands"
)

type addRepoCmd struct {
file string
file string
priority string
}

func (*addRepoCmd) Name() string { return "addrepo" }
func (*addRepoCmd) Synopsis() string { return "add repository" }
func (*addRepoCmd) Usage() string {
return fmt.Sprintf(`%s addrepo [-file] <name> <url>:
return fmt.Sprintf(`%s addrepo [-file <repofile>] [-priority <value>] <name> <url>:
Add repository to GooGet's repository list.
If -file is not set 'name.repo' will be used for the file name
overwriting any existing file with than name.
If -file is set the specified repo will be appended to that repo file,
creating it if it does not exist.
If -priority is specified, the repo will be configured with this priority level.
`, filepath.Base(os.Args[0]))
}

func (cmd *addRepoCmd) SetFlags(f *flag.FlagSet) {
f.StringVar(&cmd.file, "file", "", "repo file to add this repository to")
f.StringVar(&cmd.priority, "priority", "", "priority level assigned to repository")
}

func (cmd *addRepoCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
var name, url string
var newEntry repoEntry
switch f.NArg() {
case 0, 1:
fmt.Fprintln(os.Stderr, "Not enough arguments")
f.Usage()
return subcommands.ExitUsageError
case 2:
name = f.Arg(0)
url = f.Arg(1)
newEntry.Name = f.Arg(0)
newEntry.URL = f.Arg(1)
default:
fmt.Fprintln(os.Stderr, "Excessive arguments")
f.Usage()
return subcommands.ExitUsageError
}

if cmd.file == "" {
cmd.file = name + ".repo"
cmd.file = newEntry.Name + ".repo"
} else {
if !strings.HasSuffix(cmd.file, ".repo") {
fmt.Fprintln(os.Stderr, "Repo file name must end in '.repo'")
return subcommands.ExitUsageError
}
}

if cmd.priority != "" {
var err error
newEntry.Priority, err = priority.FromString(cmd.priority)
if err != nil {
fmt.Fprintf(os.Stderr, "Unrecognized priority value: %q\n", cmd.priority)
return subcommands.ExitUsageError
}
}

content, err := yaml.Marshal([]repoEntry{newEntry})
if err != nil {
logger.Fatal(err)
}

repoPath := filepath.Join(rootDir, repoDir, cmd.file)

if _, err := oswrap.Stat(repoPath); err != nil && os.IsNotExist(err) {
re := repoEntry{Name: name, URL: url}
if err := writeRepoFile(repoFile{repoPath, []repoEntry{re}}); err != nil {
if err := writeRepoFile(repoFile{repoPath, []repoEntry{newEntry}}); err != nil {
logger.Fatal(err)
}
fmt.Printf("Wrote repo file %s with content:\n Name: %s\n URL: %s\n", repoPath, re.Name, re.URL)
fmt.Printf("Wrote repo file %s with content:\n%s\n", repoPath, content)
return subcommands.ExitSuccess
}

Expand All @@ -89,19 +107,19 @@ func (cmd *addRepoCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfac

var res []repoEntry
for _, re := range rf.repoEntries {
if re.Name != name && re.URL != url {
if re.Name != newEntry.Name && re.URL != newEntry.URL {
res = append(res, re)
}
}

re := repoEntry{Name: name, URL: url}
res = append(res, re)
res = append(res, newEntry)
rf = repoFile{rf.fileName, res}

if err := writeRepoFile(rf); err != nil {
logger.Fatal(err)
}
fmt.Printf("Appended to repo file %s with the following content:\n Name: %s\n URL: %s\n", repoPath, re.Name, re.URL)

fmt.Printf("Appended to repo file %s with the following content:\n%s\n", repoPath, content)

return subcommands.ExitSuccess
}
74 changes: 74 additions & 0 deletions googet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ package main

import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -475,3 +477,75 @@ func TestUpdates(t *testing.T) {
})
}
}

func TestWriteRepoFile(t *testing.T) {
for _, tc := range []struct {
name string
entries []repoEntry
want string
}{
{
name: "with-no-priority-specified",
entries: []repoEntry{{Name: "bar", URL: "https://foo.com/googet/bar"}},
want: `- name: bar
url: https://foo.com/googet/bar
useoauth: false
`,
},
{
name: "with-default-priority",
entries: []repoEntry{{Name: "bar", URL: "https://foo.com/googet/bar", Priority: priority.Default}},
want: `- name: bar
url: https://foo.com/googet/bar
useoauth: false
priority: default
`,
},
{
name: "with-rollback-priority",
entries: []repoEntry{{Name: "bar", URL: "https://foo.com/googet/bar", Priority: priority.Rollback}},
want: `- name: bar
url: https://foo.com/googet/bar
useoauth: false
priority: rollback
`,
},
{
name: "with-non-standard-priority",
entries: []repoEntry{{Name: "bar", URL: "https://foo.com/googet/bar", Priority: 42}},
want: `- name: bar
url: https://foo.com/googet/bar
useoauth: false
priority: 42
`,
},
} {
t.Run(tc.name, func(t *testing.T) {
f, err := os.CreateTemp("", "test.repo")
if err != nil {
t.Fatalf("os.CreateTemp: %v", err)
}
defer func() {
os.Remove(f.Name())
}()
if err := f.Close(); err != nil {
t.Fatalf("f.Close: %v", err)
}
rf := repoFile{fileName: f.Name(), repoEntries: tc.entries}
if err := writeRepoFile(rf); err != nil {
t.Fatalf("writeRepoFile(%v): %v", rf, err)
}
b, err := os.ReadFile(f.Name())
if err != nil {
t.Fatalf("os.ReadFile(%v): %v", f.Name(), err)
}
t.Logf("wrote repo file contents:\n%v", string(b))
// Make the diff easier to read by splitting into lines first.
got := strings.Split(string(b), "\n")
want := strings.Split(tc.want, "\n")
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("writeRepoFile got unexpected diff (-want +got):\n%v", diff)
}
})
}
}
17 changes: 17 additions & 0 deletions priority/priority.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ var priorityNameToValue = map[string]Value{
"rollback": Rollback,
}

// priorityValueToName maps integer priorities to their semantic names.
var priorityValueToName = map[Value]string{
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) {
Expand All @@ -36,3 +44,12 @@ func FromString(s string) (Value, error) {
i, err := strconv.Atoi(s)
return Value(i), err
}

// MarshalYAML marshals a priority value as a semantic name if possible
// otherwise as an integer.
func (v Value) MarshalYAML() (any, error) {
if name, ok := priorityValueToName[v]; ok {
return name, nil
}
return int(v), nil
}
Loading