From d290a4ec0ba83e6b3a36321ff555193c2474d612 Mon Sep 17 00:00:00 2001 From: decentral1se Date: Tue, 14 Sep 2021 16:00:15 +0200 Subject: [PATCH] WIP: the beginning of catalogue generation See https://git.coopcloud.tech/coop-cloud/organising/issues/159. --- cli/catalogue/catalogue.go | 17 ++++++++++ cli/catalogue/generate.go | 41 ++++++++++++++++++++++++ cli/cli.go | 2 ++ pkg/git/clone.go | 65 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 cli/catalogue/catalogue.go create mode 100644 cli/catalogue/generate.go diff --git a/cli/catalogue/catalogue.go b/cli/catalogue/catalogue.go new file mode 100644 index 000000000..21ae28d63 --- /dev/null +++ b/cli/catalogue/catalogue.go @@ -0,0 +1,17 @@ +package catalogue + +import ( + "github.com/urfave/cli/v2" +) + +// CatalogueCommand defines the `abra catalogue` command and sub-commands. +var CatalogueCommand = &cli.Command{ + Name: "catalogue", + Usage: "Manage the recipe catalogue", + Aliases: []string{"c"}, + ArgsUsage: "", + Description: "This command helps recipe packagers interact with the recipe catalogue", + Subcommands: []*cli.Command{ + catalogueGenerateCommand, + }, +} diff --git a/cli/catalogue/generate.go b/cli/catalogue/generate.go new file mode 100644 index 000000000..9a4a3f027 --- /dev/null +++ b/cli/catalogue/generate.go @@ -0,0 +1,41 @@ +package catalogue + +import ( + "path" + "strings" + + "coopcloud.tech/abra/pkg/catalogue" + "coopcloud.tech/abra/pkg/config" + "coopcloud.tech/abra/pkg/git" + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v2" +) + +var catalogueGenerateCommand = &cli.Command{ + Name: "generate", + Aliases: []string{"g"}, + Usage: "Generate a new copy of the catalogue", + BashComplete: func(c *cli.Context) {}, + Action: func(c *cli.Context) error { + catl, err := catalogue.ReadRecipeCatalogue() + if err != nil { + logrus.Fatal(err) + } + + for recipeName, recipeMeta := range catl { + recipeDir := path.Join(config.ABRA_DIR, "apps", strings.ToLower(recipeName)) + if err := git.Clone(recipeDir, recipeMeta.Repository); err != nil { + logrus.Fatal(err) + } + + if err := git.EnsureUpToDate(recipeDir); err != nil { + logrus.Fatal(err) + } + } + + // for reach app, build the recipemeta from parsing + // spit out a JSON file + + return nil + }, +} diff --git a/cli/cli.go b/cli/cli.go index 53edc88b6..336075cc3 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -6,6 +6,7 @@ import ( "os" "coopcloud.tech/abra/cli/app" + "coopcloud.tech/abra/cli/catalogue" "coopcloud.tech/abra/cli/recipe" "coopcloud.tech/abra/cli/server" "github.com/sirupsen/logrus" @@ -54,6 +55,7 @@ func RunApp(version, commit string) { app.AppCommand, server.ServerCommand, recipe.RecipeCommand, + catalogue.CatalogueCommand, VersionCommand, UpgradeCommand, }, diff --git a/pkg/git/clone.go b/pkg/git/clone.go index 6e1121d2c..1d54df024 100644 --- a/pkg/git/clone.go +++ b/pkg/git/clone.go @@ -1,9 +1,12 @@ package git import ( + "fmt" "os" + "strings" "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" "github.com/sirupsen/logrus" ) @@ -15,7 +18,6 @@ func Clone(dir, url string) error { _, err := git.PlainClone(dir, false, &git.CloneOptions{URL: url, Tags: git.AllTags}) if err != nil { logrus.Debugf("cloning from default branch failed, attempting from main branch") - // try with main branch because Git is being a Git _, err := git.PlainClone(dir, false, &git.CloneOptions{ URL: url, Tags: git.AllTags, @@ -25,9 +27,66 @@ func Clone(dir, url string) error { return err } } + logrus.Debugf("'%s' has been git cloned successfully", dir) + } else { + logrus.Debugf("'%s' already exists, doing nothing", dir) } - logrus.Debugf("'%s' has been git cloned successfully", dir) - + return nil +} + +// EnsureUpToDate ensures that a git repo on disk has the latest changes (git-fetch). +func EnsureUpToDate(dir string) error { + repo, err := git.PlainOpen(dir) + if err != nil { + return err + } + + branch := "master" + if _, err := repo.Branch("master"); err != nil { + if _, err := repo.Branch("main"); err != nil { + return err + } + branch = "main" + } + + logrus.Debugf("choosing '%s' as main git branch for in '%s'", branch, dir) + + worktree, err := repo.Worktree() + if err != nil { + return err + } + + refName := fmt.Sprintf("refs/heads/%s", branch) + checkOutOpts := &git.CheckoutOptions{ + Create: false, + Force: true, + Keep: false, + Branch: plumbing.ReferenceName(refName), + } + if err := worktree.Checkout(checkOutOpts); err != nil { + return err + } + + logrus.Debugf("successfully checked out '%s'", branch) + + remote, err := repo.Remote("origin") + if err != nil { + return err + } + + fetchOpts := &git.FetchOptions{ + RemoteName: "origin", + RefSpecs: []config.RefSpec{"refs/heads/*:refs/remotes/origin/*"}, + Force: true, + } + if err := remote.Fetch(fetchOpts); err != nil { + if !strings.Contains(err.Error(), "already up-to-date") { + return err + } + } + + logrus.Debugf("successfully fetched all changes in '%s'", dir) + return nil }