refactor(recipe): better naming, sorting and types

In order to arrange various types of sorting for the app catalogue, it
seems like the recommended approach is to maintain a separate data
structure alongside the JSON map we get from apps.coopcloud.tech.

Therefore, I attempt to provide a ToList() method and accompanying
sort.Sort interface sorting implementations. For now, this is just
sorting by app name.

I am testing this type of implementation here before moving on to
arrange different types of sorting for the `app list` command.
This commit is contained in:
decentral1se 2021-07-26 17:25:08 +02:00
parent 1f62ace524
commit 60a70d2d83
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC

View File

@ -8,6 +8,7 @@ import (
"os" "os"
"path" "path"
"sort" "sort"
"strings"
"text/template" "text/template"
"time" "time"
@ -34,38 +35,48 @@ type Feature struct {
Tests string `json:"tests"` Tests string `json:"tests"`
} }
type Version struct { type Tag = string
type Service = string
type ServiceMeta struct {
Digest string `json:"digest"` Digest string `json:"digest"`
Image string `json:"image"` Image string `json:"image"`
Tag string `json:"tag"` Tag string `json:"tag"`
} }
type App struct { type App struct {
Category string `json:"category"` Category string `json:"category"`
DefaultBranch string `json:"default_branch"` DefaultBranch string `json:"default_branch"`
Description string `json:"description"` Description string `json:"description"`
Features Feature `json:"features"` Features Feature `json:"features"`
Icon string `json:"icon"` Icon string `json:"icon"`
Name string `json:"name"` Name string `json:"name"`
Repository string `json:"repository"` Repository string `json:"repository"`
Versions map[string]map[string]Version `json:"versions"` Versions map[Tag]map[Service]ServiceMeta `json:"versions"`
Website string `json:"website"` Website string `json:"website"`
} }
type Apps map[string]App type Name = string
type AppsCatalogue map[Name]App
func (a Apps) SortByName() []string { func (a AppsCatalogue) ToList() []App {
var names []string apps := make([]App, 0, len(a))
for name := range a { for name := range a {
names = append(names, name) apps = append(apps, a[name])
} }
sort.Strings(names) return apps
return names }
type ByAppName []App
func (a ByAppName) Len() int { return len(a) }
func (a ByAppName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAppName) Less(i, j int) bool {
return strings.ToLower(a[i].Name) < strings.ToLower(a[j].Name)
} }
var httpClient = &http.Client{Timeout: 5 * time.Second} var httpClient = &http.Client{Timeout: 5 * time.Second}
var AppsUrl = "https://apps.coopcloud.tech" var AppsCatalogueURL = "https://apps.coopcloud.tech"
func readJson(url string, target interface{}) error { func readJson(url string, target interface{}) error {
res, err := httpClient.Get(url) res, err := httpClient.Get(url)
@ -76,8 +87,8 @@ func readJson(url string, target interface{}) error {
return json.NewDecoder(res.Body).Decode(target) return json.NewDecoder(res.Body).Decode(target)
} }
func AppsFSIsLatest() (bool, error) { func AppsCatalogueFSIsLatest() (bool, error) {
res, err := httpClient.Head(AppsUrl) res, err := httpClient.Head(AppsCatalogueURL)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -106,29 +117,29 @@ func AppsFSIsLatest() (bool, error) {
return true, nil return true, nil
} }
func ReadApps() (Apps, error) { func ReadAppsCatalogue() (AppsCatalogue, error) {
apps := make(Apps) apps := make(AppsCatalogue)
appsFSIsLatest, err := AppsFSIsLatest() appsFSIsLatest, err := AppsCatalogueFSIsLatest()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !appsFSIsLatest { if !appsFSIsLatest {
if err := ReadAppsWeb(&apps); err != nil { if err := ReadAppsCatalogueWeb(&apps); err != nil {
return nil, err return nil, err
} }
return apps, nil return apps, nil
} }
if err := ReadAppsFS(&apps); err != nil { if err := ReadAppsCatalogueFS(&apps); err != nil {
return nil, err return nil, err
} }
return apps, nil return apps, nil
} }
func ReadAppsFS(target interface{}) error { func ReadAppsCatalogueFS(target interface{}) error {
appsJsonFS, err := ioutil.ReadFile(config.APPS_JSON) appsJsonFS, err := ioutil.ReadFile(config.APPS_JSON)
if err != nil { if err != nil {
return err return err
@ -139,8 +150,8 @@ func ReadAppsFS(target interface{}) error {
return nil return nil
} }
func ReadAppsWeb(target interface{}) error { func ReadAppsCatalogueWeb(target interface{}) error {
if err := readJson(AppsUrl, &target); err != nil { if err := readJson(AppsCatalogueURL, &target); err != nil {
return err return err
} }
@ -160,14 +171,15 @@ var recipeListCommand = &cli.Command{
Name: "list", Name: "list",
Aliases: []string{"ls"}, Aliases: []string{"ls"},
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
apps, err := ReadApps() catalogue, err := ReadAppsCatalogue()
if err != nil { if err != nil {
logrus.Fatal(err.Error()) logrus.Fatal(err.Error())
} }
apps := catalogue.ToList()
sort.Sort(ByAppName(apps))
tableCol := []string{"Name", "Category", "Status"} tableCol := []string{"Name", "Category", "Status"}
table := createTable(tableCol) table := createTable(tableCol)
for _, name := range apps.SortByName() { for _, app := range apps {
app := apps[name]
status := fmt.Sprintf("%v", app.Features.Status) status := fmt.Sprintf("%v", app.Features.Status)
tableRow := []string{app.Name, app.Category, status} tableRow := []string{app.Name, app.Category, status}
table.Append(tableRow) table.Append(tableRow)
@ -188,7 +200,7 @@ var recipeVersionCommand = &cli.Command{
return nil return nil
} }
apps, err := ReadApps() apps, err := ReadAppsCatalogue()
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
return nil return nil