package catalogue import ( "encoding/json" "fmt" "io/ioutil" "os" "path" "coopcloud.tech/abra/cli/formatter" "coopcloud.tech/abra/pkg/catalogue" "coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/git" "coopcloud.tech/abra/pkg/limit" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) // CatalogueSkipList is all the repos that are not recipes. var CatalogueSkipList = map[string]bool{ "abra": true, "abra-bash": true, "abra-apps": true, "abra-aur": true, "abra-capsul": true, "abra-gandi": true, "abra-hetzner": true, "apps": true, "aur-abra-git": true, "auto-apps-json": true, "auto-mirror": true, "backup-bot": true, "backup-bot-two": true, "coopcloud.tech": true, "coturn": true, "docker-cp-deploy": true, "docker-dind-bats-kcov": true, "docs.coopcloud.tech": true, "example": true, "gardening": true, "go-abra": true, "organising": true, "pyabra": true, "radicle-seed-node": true, "stack-ssh-deploy": true, "swarm-cronjob": true, "tagcmp": true, "tyop": true, } var catalogueGenerateCommand = &cli.Command{ Name: "generate", Aliases: []string{"g"}, Usage: "Generate a new copy of the catalogue", ArgsUsage: "[]", BashComplete: func(c *cli.Context) { catl, err := catalogue.ReadRecipeCatalogue() if err != nil { logrus.Warn(err) } if c.NArg() > 0 { return } for name := range catl { fmt.Println(name) } }, Action: func(c *cli.Context) error { recipeName := c.Args().First() repos, err := catalogue.ReadReposMetadata() if err != nil { logrus.Fatal(err) } logrus.Debugf("ensuring '%v' recipe(s) are locally present and up-to-date", len(repos)) cloneLimiter := limit.New(10) retrieveBar := formatter.CreateProgressbar(len(repos), "retrieving recipes...") ch := make(chan string, len(repos)) for _, repoMeta := range repos { go func(rm catalogue.RepoMeta) { cloneLimiter.Begin() defer cloneLimiter.End() if recipeName != "" && recipeName != rm.Name { ch <- rm.Name retrieveBar.Add(1) return } if _, exists := CatalogueSkipList[rm.Name]; exists { ch <- rm.Name retrieveBar.Add(1) return } recipeDir := path.Join(config.ABRA_DIR, "apps", rm.Name) if err := git.Clone(recipeDir, rm.SSHURL); err != nil { logrus.Fatal(err) } if err := git.EnsureUpToDate(recipeDir); err != nil { logrus.Fatal(err) } ch <- rm.Name retrieveBar.Add(1) }(repoMeta) } for range repos { <-ch // wait for everything } catl := make(catalogue.RecipeCatalogue) catlBar := formatter.CreateProgressbar(len(repos), "generating catalogue...") for _, recipeMeta := range repos { if recipeName != "" && recipeName != recipeMeta.Name { catlBar.Add(1) continue } if _, exists := CatalogueSkipList[recipeMeta.Name]; exists { catlBar.Add(1) continue } versions, err := catalogue.GetRecipeVersions(recipeMeta.Name) if err != nil { logrus.Fatal(err) } catl[recipeMeta.Name] = catalogue.RecipeMeta{ Name: recipeMeta.Name, Repository: recipeMeta.CloneURL, Icon: recipeMeta.AvatarURL, DefaultBranch: recipeMeta.DefaultBranch, Description: recipeMeta.Description, Website: recipeMeta.Website, Versions: versions, // Category: ..., // FIXME: once we sort out the machine-readable catalogue interface // Features: ..., // FIXME: once we figure out the machine-readable catalogue interface } catlBar.Add(1) } recipesJSON, err := json.MarshalIndent(catl, "", " ") if err != nil { logrus.Fatal(err) } if _, err := os.Stat(config.APPS_JSON); err != nil && os.IsNotExist(err) { if err := ioutil.WriteFile(config.APPS_JSON, recipesJSON, 0644); err != nil { logrus.Fatal(err) } } else { if recipeName != "" { catlFS, err := catalogue.ReadRecipeCatalogue() if err != nil { logrus.Fatal(err) } catlFS[recipeName] = catl[recipeName] updatedRecipesJSON, err := json.MarshalIndent(catlFS, "", " ") if err != nil { logrus.Fatal(err) } if err := ioutil.WriteFile(config.APPS_JSON, updatedRecipesJSON, 0644); err != nil { logrus.Fatal(err) } } } logrus.Infof("generated new recipe catalogue in '%s'", config.APPS_JSON) return nil }, }