166 lines
4.0 KiB
Go
166 lines
4.0 KiB
Go
package recipe
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"sort"
|
|
"text/template"
|
|
|
|
"coopcloud.tech/abra/catalogue"
|
|
"coopcloud.tech/abra/cli/formatter"
|
|
"coopcloud.tech/abra/config"
|
|
|
|
"github.com/go-git/go-git/v5"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
var recipeListCommand = &cli.Command{
|
|
Name: "list",
|
|
Usage: "List all available recipes",
|
|
Aliases: []string{"ls"},
|
|
Action: func(c *cli.Context) error {
|
|
catl, err := catalogue.ReadAppsCatalogue()
|
|
if err != nil {
|
|
logrus.Fatal(err.Error())
|
|
}
|
|
apps := catl.Flatten()
|
|
sort.Sort(catalogue.ByAppName(apps))
|
|
tableCol := []string{"Name", "Category", "Status"}
|
|
table := formatter.CreateTable(tableCol)
|
|
for _, app := range apps {
|
|
status := fmt.Sprintf("%v", app.Features.Status)
|
|
tableRow := []string{app.Name, app.Category, status}
|
|
table.Append(tableRow)
|
|
}
|
|
table.Render()
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var recipeVersionCommand = &cli.Command{
|
|
Name: "versions",
|
|
Usage: "List available versions for <recipe>",
|
|
ArgsUsage: "<recipe>",
|
|
Action: func(c *cli.Context) error {
|
|
recipe := c.Args().First()
|
|
if recipe == "" {
|
|
cli.ShowSubcommandHelp(c)
|
|
return nil
|
|
}
|
|
|
|
catalogue, err := catalogue.ReadAppsCatalogue()
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
return nil
|
|
}
|
|
|
|
if app, ok := catalogue[recipe]; ok {
|
|
tableCol := []string{"Version", "Service", "Image", "Digest"}
|
|
table := formatter.CreateTable(tableCol)
|
|
for version := range app.Versions {
|
|
for service := range app.Versions[version] {
|
|
meta := app.Versions[version][service]
|
|
table.Append([]string{version, service, meta.Image, meta.Digest})
|
|
}
|
|
}
|
|
table.SetAutoMergeCells(true)
|
|
table.Render()
|
|
return nil
|
|
}
|
|
|
|
logrus.Fatalf("'%s' recipe doesn't exist?", recipe)
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var recipeCreateCommand = &cli.Command{
|
|
Name: "create",
|
|
Usage: "Create a new recipe",
|
|
ArgsUsage: "<recipe>",
|
|
Action: func(c *cli.Context) error {
|
|
recipe := c.Args().First()
|
|
if recipe == "" {
|
|
cli.ShowSubcommandHelp(c)
|
|
return nil
|
|
}
|
|
|
|
directory := path.Join(config.APPS_DIR, recipe)
|
|
if _, err := os.Stat(directory); !os.IsNotExist(err) {
|
|
logrus.Fatalf("'%s' recipe directory already exists?", directory)
|
|
return nil
|
|
}
|
|
|
|
url := fmt.Sprintf("%s/example.git", config.REPOS_BASE_URL)
|
|
_, err := git.PlainClone(directory, false, &git.CloneOptions{URL: url, Tags: git.AllTags})
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
return nil
|
|
}
|
|
|
|
gitRepo := path.Join(config.APPS_DIR, recipe, ".git")
|
|
if err := os.RemoveAll(gitRepo); err != nil {
|
|
logrus.Fatal(err)
|
|
return nil
|
|
}
|
|
|
|
toParse := []string{
|
|
path.Join(config.APPS_DIR, recipe, "README.md"),
|
|
path.Join(config.APPS_DIR, recipe, ".env.sample"),
|
|
path.Join(config.APPS_DIR, recipe, ".drone.yml"),
|
|
}
|
|
for _, path := range toParse {
|
|
file, err := os.OpenFile(path, os.O_RDWR, 0755)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
return nil
|
|
}
|
|
|
|
tpl, err := template.ParseFiles(path)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
return nil
|
|
}
|
|
|
|
// TODO: ask for description and probably other things so that the
|
|
// template repository is more "ready" to go than the current best-guess
|
|
// mode of templating
|
|
if err := tpl.Execute(file, struct {
|
|
Name string
|
|
Description string
|
|
}{recipe, "TODO"}); err != nil {
|
|
logrus.Fatal(err)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
fmt.Printf(
|
|
"New recipe '%s' created in %s, happy hacking!",
|
|
recipe, path.Join(config.APPS_DIR, recipe),
|
|
)
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var RecipeCommand = &cli.Command{
|
|
Name: "recipe",
|
|
Usage: "Manage app recipes",
|
|
Description: `
|
|
A recipe is a blueprint for an app. It is made up of two things:
|
|
|
|
- A libre software app (e.g. Nextcloud, Wordpress, Mastodon)
|
|
- A package configuration which describes how to deploy and maintain it
|
|
|
|
Recipes are developed, maintained and extended by the Co-op Cloud volunteer-run
|
|
community. Each recipe has a "level" which is intended as a way to quickly show
|
|
how reliable this app is to deploy and maintain in its current state.
|
|
`,
|
|
Subcommands: []*cli.Command{
|
|
recipeListCommand,
|
|
recipeVersionCommand,
|
|
recipeCreateCommand,
|
|
},
|
|
}
|