package recipe import ( "fmt" "os" "path" "path/filepath" "strings" "coopcloud.tech/abra/pkg/client/stack" loader "coopcloud.tech/abra/pkg/client/stack" "coopcloud.tech/abra/pkg/compose" "coopcloud.tech/abra/pkg/config" composetypes "github.com/docker/cli/cli/compose/types" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" ) // Recipe represents a recipe. type Recipe struct { Name string Config *composetypes.Config } // UpdateLabel updates a recipe label func (r Recipe) UpdateLabel(serviceName, label string) error { pattern := fmt.Sprintf("%s/%s/compose**yml", config.APPS_DIR, r.Name) if err := compose.UpdateLabel(pattern, serviceName, label); err != nil { return err } return nil } // UpdateTag updates a recipe tag func (r Recipe) UpdateTag(image, tag string) error { pattern := fmt.Sprintf("%s/%s/compose**yml", config.APPS_DIR, r.Name) if err := compose.UpdateTag(pattern, image, tag); err != nil { return err } return nil } // Get retrieves a recipe. func Get(recipeName string) (Recipe, error) { if err := EnsureExists(recipeName); err != nil { return Recipe{}, err } pattern := fmt.Sprintf("%s/%s/compose**yml", config.APPS_DIR, recipeName) composeFiles, err := filepath.Glob(pattern) if err != nil { return Recipe{}, err } opts := stack.Deploy{Composefiles: composeFiles} emptyEnv := make(map[string]string) config, err := loader.LoadComposefile(opts, emptyEnv) if err != nil { return Recipe{}, err } return Recipe{Name: recipeName, Config: config}, nil } // EnsureExists checks whether a recipe has been cloned locally or not. func EnsureExists(recipe string) error { recipeDir := path.Join(config.ABRA_DIR, "apps", strings.ToLower(recipe)) if _, err := os.Stat(recipeDir); os.IsNotExist(err) { url := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, recipe) _, err := git.PlainClone(recipeDir, false, &git.CloneOptions{URL: url, Tags: git.AllTags}) if err != nil { // try with main branch because Git is being a Git _, err := git.PlainClone(recipeDir, false, &git.CloneOptions{ URL: url, Tags: git.AllTags, ReferenceName: plumbing.ReferenceName("refs/heads/main"), }) if err != nil { return err } } } return nil } // EnsureVersion checks whether a specific version exists for a recipe. func EnsureVersion(recipeName, version string) error { recipeDir := path.Join(config.ABRA_DIR, "apps", recipeName) repo, err := git.PlainOpen(recipeDir) if err != nil { return err } tags, err := repo.Tags() if err != nil { return nil } var tagRef plumbing.ReferenceName if err := tags.ForEach(func(ref *plumbing.Reference) (err error) { if ref.Name().Short() == version { tagRef = ref.Name() } return nil }); err != nil { return err } if tagRef.String() == "" { return fmt.Errorf("%s is not available?", version) } worktree, err := repo.Worktree() if err != nil { return err } opts := &git.CheckoutOptions{Branch: tagRef, Keep: true} if err := worktree.Checkout(opts); err != nil { return err } return nil }