Create Recipe Templates works

This commit is contained in:
Justin Hammond 2023-05-20 02:43:28 +08:00
parent df721d773c
commit 31c8aab494
14 changed files with 651 additions and 56 deletions

View file

@ -1,10 +1,11 @@
package backends
import (
"errors"
"github.com/Fishwaldo/go-yocto/backends/kde"
"github.com/Fishwaldo/go-yocto/source"
"github.com/Fishwaldo/go-yocto/utils"
)
@ -13,7 +14,8 @@ type Backend interface {
Init() error
LoadCache() error
LoadSource() error
SearchSource(keyword string) (source []source.RecipeSource, err error)
SearchSource(keyword string) (source []source.RecipeSource, err error)
GetRecipe(identifier string) (*source.RecipeSource, error)
Ready() bool
}
@ -77,4 +79,19 @@ func SearchSource(be string, keyword string) (sources []source.RecipeSource, err
}
}
return sources, nil
}
func GetRecipe(be string, identifier string) (source *source.RecipeSource, err error) {
utils.Logger.Trace("Getting Recipe", utils.Logger.Args("backend", be, "identifier", identifier))
if be, ok := Backends[be]; ok {
if source, err := be.GetRecipe(identifier); err != nil {
utils.Logger.Error("Failed to Get Recipe", utils.Logger.Args("backend", be.GetName(), "identifier", identifier, "error", err))
return nil, errors.New("Failed to Get Recipe")
} else {
return source, nil
}
} else {
utils.Logger.Error("Backend not found", utils.Logger.Args("backend", be))
}
return nil, errors.New("Backend not found")
}

View file

@ -1,15 +1,20 @@
package kde
import (
"bufio"
"encoding/base64"
"encoding/json"
"errors"
"io/ioutil"
"net/url"
"os"
"path"
"path/filepath"
"regexp"
"strings"
// "fmt"
"github.com/Fishwaldo/go-yocto/parsers"
"github.com/Fishwaldo/go-yocto/repo"
"github.com/Fishwaldo/go-yocto/source"
@ -21,24 +26,14 @@ import (
"github.com/spf13/viper"
"github.com/xanzy/go-gitlab"
"gopkg.in/yaml.v3"
// "github.com/davecgh/go-spew/spew"
)
type Deps struct {
Dependencies []struct {
On []string
Require map[string]string
} `yaml:"Dependencies"`
Options interface{} `yaml:"Options"`
Environment interface{} `yaml:"Environment"`
}
type Project struct {
source.RecipeSource `yaml:",inline"`
ProjectPath string
Repoactive bool
Repopath string
Identifier string
Hasrepo bool
Source string
Bugzilla struct {
@ -47,12 +42,14 @@ type Project struct {
DNUlegacyproduct string `yaml:"__do_not_use-legacy-product"`
}
Topics []string
MetaData map[string]map[string]interface{}
}
type KDEBe struct {
MetaDataRepo repo.Repo
br map[string]map[string]string
pr map[string]Project
dep map[string][]string
ready bool
}
@ -103,6 +100,7 @@ func (l *KDEBe) LoadSource() (err error) {
}
maps.Clear(l.br)
maps.Clear(l.pr)
maps.Clear(l.dep)
err = l.parseMetadata()
if (err != nil) {
utils.Logger.Error("Failed to parse metadata", utils.Logger.Args("error", err))
@ -113,16 +111,18 @@ func (l *KDEBe) LoadSource() (err error) {
func (l *KDEBe) parseMetadata() (err error) {
l.pr = make(map[string]Project)
utils.Logger.Trace("Parsing metadata", utils.Logger.Args("layer", l.GetName()))
l.pr = make(map[string]Project)
l.br = make(map[string]map[string]string)
l.dep = make(map[string][]string)
brfile, err := ioutil.ReadFile(l.getDir() + "/branch-rules.yml")
if err != nil {
utils.Logger.Error("Failed to read branch-rules.yaml", utils.Logger.Args("error", err))
os.Exit(-1)
}
l.br = make(map[string]map[string]string)
err = yaml.Unmarshal(brfile, &l.br)
if err != nil {
utils.Logger.Error("Failed to unmarshal branch-rules.yaml", utils.Logger.Args("error", err))
@ -140,6 +140,22 @@ func (l *KDEBe) parseMetadata() (err error) {
os.Exit(-1)
}
/* parse dependancy file dependencies/dependency-data-kf5-qt5 */
depsfile, err := os.Open(l.getDir() + "/dependencies/dependency-data-kf5-qt5")
if err != nil {
utils.Logger.Error("Failed to open dependency file", utils.Logger.Args("error", err))
}
defer depsfile.Close()
scanner := bufio.NewScanner(depsfile)
var entry = regexp.MustCompile(`^(.*):.(.*)$`)
for scanner.Scan() {
if entry.MatchString(scanner.Text()) {
match := entry.FindStringSubmatch(scanner.Text())
l.dep[match[1]] = append(l.dep[match[1]], match[2])
}
}
/* now parse the directory */
files := findmetdata(l.getDir())
p, _ := pterm.DefaultProgressbar.WithTotal(len(files)).WithTitle("Parsing Metadata...").Start()
@ -161,7 +177,7 @@ func (l *KDEBe) parseMetadata() (err error) {
data.MetaData = make(map[string]map[string]interface{})
data.MetaData["branch-rules"] = make(map[string]interface{})
data.MetaData["branch-rules"]["branch"] = utils.Config.KDEConfig.DefaultBranch
data.RecipeSource.Backend = l.GetName()
data.RecipeSource.BackendID = l.GetName()
data.RecipeSource.Url, _ = url.JoinPath(utils.Config.KDEConfig.KDEGitLabURL, data.Repopath)
/* find out which branch this is in... */
for project, branch := range l.br[utils.Config.KDEConfig.Release] {
@ -171,36 +187,11 @@ func (l *KDEBe) parseMetadata() (err error) {
break
}
}
/* get the .kde-ci.yml for dependencies */
gf := &gitlab.GetFileOptions{
Ref: gitlab.String(data.MetaData["branch-rules"]["branch"].(string)),
}
f, res, err := gl.RepositoryFiles.GetFile(data.Repopath, ".kde-ci.yml", gf)
if err != nil {
if res.StatusCode != 404 {
utils.Logger.Error("Failed to get .kde-ci.yml", utils.Logger.Args("error", err))
}
} else {
/* now parse the .kde-ci.yml */
var deps Deps
content, err := base64.StdEncoding.DecodeString(f.Content)
if err != nil {
utils.Logger.Error("Failed to decode .kde-ci.yml", utils.Logger.Args("error", err))
} else {
ymldeps := yaml.NewDecoder(strings.NewReader(string(content)))
ymldeps.KnownFields(false);
err = ymldeps.Decode(&deps)
if err != nil {
utils.Logger.Error("Failed to unmarshal .kde-ci.yml", utils.Logger.Args("error", err, "project", data.Repopath))
} else {
data.MetaData["kde-ci"] = make(map[string]interface{})
data.MetaData["kde-ci"]["dependencies"] = deps
}
}
}
/* now get appstream if it exists */
f, res, err = gl.RepositoryFiles.GetFile(data.Repopath, "org.kde." + data.Identifier + ".appdata.xml", gf)
f, res, err := gl.RepositoryFiles.GetFile(data.Repopath, "org.kde." + data.Identifier + ".appdata.xml", gf)
if err != nil {
if res.StatusCode != 404 {
utils.Logger.Error("Failed to get appstream", utils.Logger.Args("error", err))
@ -240,6 +231,17 @@ func (l *KDEBe) parseMetadata() (err error) {
utils.Logger.Error("Failed to write metadata", utils.Logger.Args("error", err))
os.Exit(-1)
}
depcache, err := json.Marshal(l.dep)
if err != nil {
utils.Logger.Error("Failed to marshal dependancy metadata", utils.Logger.Args("error", err))
os.Exit(-1)
}
err = ioutil.WriteFile(utils.Config.BaseDir + "/" + l.GetName() + "-dep-cache.json", depcache, 0644)
if err != nil {
utils.Logger.Error("Failed to write dependancy metadata", utils.Logger.Args("error", err))
os.Exit(-1)
}
brcache, err := json.Marshal(l.br)
if err != nil {
utils.Logger.Error("Failed to marshal branch metadata", utils.Logger.Args("error", err))
@ -250,6 +252,10 @@ func (l *KDEBe) parseMetadata() (err error) {
utils.Logger.Error("Failed to write branch metadata", utils.Logger.Args("error", err))
os.Exit(-1)
}
if err := RefreshDownloadLocations(); err != nil {
utils.Logger.Error("Failed to refresh download locations", utils.Logger.Args("error", err))
os.Exit(-1)
}
utils.Logger.Trace("Parsed metadata", utils.Logger.Args("layers", len(l.pr), "branches", len(l.br)));
@ -268,6 +274,15 @@ func (l *KDEBe) LoadCache() (err error) {
utils.Logger.Error("Failed to unmarshal cache", utils.Logger.Args("error", err))
}
}
depcache, err := ioutil.ReadFile(utils.Config.BaseDir + "/" + l.GetName() + "-dep-cache.json")
if err != nil {
utils.Logger.Error("Failed to read dependancy cache", utils.Logger.Args("error", err))
} else {
err = json.Unmarshal(depcache, &l.dep)
if err != nil {
utils.Logger.Error("Failed to unmarshal dependancy cache", utils.Logger.Args("error", err))
}
}
brcache, err := ioutil.ReadFile(utils.Config.BaseDir + "/" + l.GetName() + "-branch-cache.json")
if err != nil {
utils.Logger.Error("Failed to read branch cache", utils.Logger.Args("error", err))
@ -277,7 +292,9 @@ func (l *KDEBe) LoadCache() (err error) {
utils.Logger.Error("Failed to unmarshal branch cache", utils.Logger.Args("error", err))
}
}
if err := LoadDownloadLocationsCache(); err != nil {
utils.Logger.Error("Failed to load download locations cache", utils.Logger.Args("error", err))
}
utils.Logger.Trace("KDE Cache Loaded", utils.Logger.Args("layers", len(l.pr), "branches", len(l.br)))
return nil
}
@ -312,4 +329,66 @@ func findmetdata(path string) (files []string) {
panic(err)
}
return files
}
}
func (l *KDEBe) GetRecipe(identifier string) (*source.RecipeSource, error) {
utils.Logger.Trace("Getting KDE Recipe", utils.Logger.Args("recipe", identifier))
if recipe, ok := l.pr[identifier]; ok {
/* get the summary if it exists from appstream */
if as, ok := recipe.MetaData["appstream"]; ok {
if summary, ok := as["summary"]; ok {
recipe.Summary = summary.(string)
}
} else {
result, _ := pterm.DefaultInteractiveTextInput.WithMultiLine(false).Show("Summary")
recipe.Summary = strings.TrimSpace(result)
}
/* get version from Appstream */
if as, ok := recipe.MetaData["appstream"]; ok {
if version, ok := as["version"]; ok {
recipe.Version = version.(string)
}
} else {
result, _ := pterm.DefaultInteractiveTextInput.WithMultiLine(false).Show("Version Number")
recipe.Version = strings.TrimSpace(result)
}
if dlpath, err := GetDownloadPath(recipe.Identifier, recipe.Version); err != nil {
utils.Logger.Error("Failed to get download path", utils.Logger.Args("error", err))
return nil, err
} else {
recipe.SrcURI = dlpath
}
if (len(recipe.SrcURI) > 0) {
if sha, err := GetDownloadSHA(recipe.Identifier, recipe.Version); err != nil {
utils.Logger.Error("Failed to get download SHA", utils.Logger.Args("error", err))
} else {
recipe.SrcSHA256 = sha
}
}
licenses, err := GetLicense(recipe)
if err != nil {
utils.Logger.Error("Failed to get License", utils.Logger.Args("error", err))
} else {
recipe.Licenses = licenses
}
inherits, err := GetInherits(recipe, l.dep)
if err != nil {
utils.Logger.Error("Failed to get Inherits", utils.Logger.Args("error", err))
} else {
recipe.Inherits = inherits
}
depends, err := GetDepends(recipe, l.dep)
if err != nil {
utils.Logger.Error("Failed to get Inherits", utils.Logger.Args("error", err))
} else {
recipe.Depends = depends
}
recipe.Section = path.Dir(recipe.Repopath)
return &recipe.RecipeSource, nil
}
return nil, errors.New("Recipe Not Found")
}

117
backends/kde/kdedownload.go Normal file
View file

@ -0,0 +1,117 @@
package kde
import (
"bufio"
"regexp"
"net/http"
"encoding/json"
"io/ioutil"
"errors"
"strings"
"crypto/sha256"
"io"
"fmt"
"github.com/Fishwaldo/go-yocto/utils"
"github.com/pterm/pterm"
)
type dirListing struct {
Directory string
}
var files map[string]map[string]dirListing = make(map[string]map[string]dirListing)
func LoadDownloadLocationsCache() (error) {
utils.Logger.Trace("Loading KDE Download Cache")
cache, err := ioutil.ReadFile(utils.Config.BaseDir + "/kdedownload-cache.json")
if err != nil {
utils.Logger.Error("Failed to read download cache", utils.Logger.Args("error", err))
return RefreshDownloadLocations()
} else {
err = json.Unmarshal(cache, &files)
if err != nil {
utils.Logger.Error("Failed to unmarshal cache", utils.Logger.Args("error", err))
return err
}
}
return nil
}
func RefreshDownloadLocations() (error) {
file, err := http.Get("https://download.kde.org/ls-lR")
if err != nil {
return err
}
defer file.Body.Close()
scanner := bufio.NewScanner(file.Body)
var directory = regexp.MustCompile(`^(\./)?(.+):$`)
var fn = regexp.MustCompile(`^[^dl].* ((.*)-(.*)\.tar\.(bz2|xz))$`)
var curdir string
for scanner.Scan() {
if directory.MatchString(scanner.Text()) {
curdir = strings.TrimPrefix( directory.FindStringSubmatch(scanner.Text())[2], "/srv/archives/ftp/")
}
if fn.MatchString(scanner.Text()) {
f := fn.FindStringSubmatch(scanner.Text())
if _, ok := files[f[2]]; !ok {
files[f[2]] = make(map[string]dirListing)
}
files[f[2]][f[3]] = dirListing{Directory: curdir + "/" + f[1]}
}
}
cache, err := json.Marshal(files)
if err != nil {
utils.Logger.Error("Failed to marshal metadata", utils.Logger.Args("error", err))
return err
}
err = ioutil.WriteFile(utils.Config.BaseDir + "/kdedownload-cache.json", cache, 0644)
if err != nil {
utils.Logger.Error("Failed to write metadata", utils.Logger.Args("error", err))
return err
}
return nil
}
func GetDownloadPath(source string, version string) (string, error) {
if _, ok := files[source]; !ok {
return "", errors.New("Source not found")
}
if _, ok := files[source][version]; !ok {
return "", errors.New("Version not found")
}
return "https://download.kde.org/" + files[source][version].Directory, nil
}
func GetDownloadSHA(source string, version string) (string, error) {
if _, ok := files[source]; !ok {
return "", errors.New("Source not found")
}
if _, ok := files[source][version]; !ok {
return "", errors.New("Version not found")
}
path, err := GetDownloadPath(source, version)
if err != nil {
return "", err
}
utils.Logger.Trace("Getting SHA", utils.Logger.Args("path", path))
spinnerInfo, _ := pterm.DefaultSpinner.Start("Downloading Source for SHA Calculation")
file, err := http.Get(path)
if err != nil {
utils.Logger.Warn("Failed to get SHA", utils.Logger.Args("path", path, "error", err))
spinnerInfo.Fail("Failed to Download Source for SHA Calculation")
return "", err
}
defer file.Body.Close()
hash := sha256.New()
if _, err := io.Copy(hash, file.Body); err != nil {
utils.Logger.Warn("Failed to calculate SHA", utils.Logger.Args("path", path, "error", err))
spinnerInfo.Fail("Failed to Download Source for SHA Calculation")
return "", err
}
spinnerInfo.Success("Downloaded Source for SHA Calculation")
return fmt.Sprintf("%x", hash.Sum(nil)), nil
}

View file

@ -0,0 +1,54 @@
package kde
import (
"path"
"github.com/Fishwaldo/go-yocto/utils"
)
var inheritmap map[string]string = make(map[string]string)
var dependmap map[string]string = make(map[string]string)
func init() {
inheritmap = map[string]string {
"frameworks/extra-cmake-modules": "cmake_plasma",
"frameworks/kauth": "kauth",
"frameworks/kcmutils": "kcmutils",
"frameworks/kconfig": "kconfig",
"frameworks/kcoreaddons": "kcoreaddons",
"frameworks/kdoctools": "kdoctools",
"frameworks/ki18n" : "ki18n",
}
dependmap = map[string]string {
}
}
func GetInherits(pr Project, depmap map[string][]string) (inherits []string, err error) {
utils.Logger.Trace("Getting Inherits", utils.Logger.Args("project", pr.Name))
if _, ok := depmap[pr.ProjectPath]; ok {
for _, v := range depmap[pr.ProjectPath] {
if i, ok := inheritmap[v]; ok {
inherits = append(inherits, i)
}
}
}
/* add our default inherit */
inherits = append(inherits, "reuse_license_checksums")
return inherits, nil
}
func GetDepends(pr Project, depmap map[string][]string) (depends []string, err error) {
utils.Logger.Trace("Getting Depends", utils.Logger.Args("project", pr.Name))
if _, ok := depmap[pr.ProjectPath]; ok {
for _, v := range depmap[pr.ProjectPath] {
if _, ok := inheritmap[v]; !ok {
depends = append(depends, path.Base(v))
}
}
}
return depends, nil
}

View file

@ -0,0 +1,33 @@
package kde
import (
"strings"
"github.com/Fishwaldo/go-yocto/utils"
"github.com/xanzy/go-gitlab"
)
func GetLicense(pr Project) (license []string, err error) {
utils.Logger.Trace("Getting License", utils.Logger.Args("project", pr.Name))
gl, err := gitlab.NewClient(utils.Config.KDEConfig.AccessToken, gitlab.WithBaseURL(utils.Config.KDEConfig.KDEGitLabURL+"/api/v4"))
gf := &gitlab.ListTreeOptions {
Path: gitlab.String("LICENSES"),
Ref: gitlab.String(pr.MetaData["branch-rules"]["branch"].(string)),
}
f, res, err := gl.Repositories.ListTree(pr.Repopath, gf)
if err != nil {
utils.Logger.Error("Failed to get License", utils.Logger.Args("error", err))
return nil, err
}
if res.StatusCode != 200 {
utils.Logger.Error("Failed to get License", utils.Logger.Args("error", res.Status))
return nil, err
}
for _, file := range f {
license = append(license, strings.TrimSuffix(file.Name, ".txt"))
}
return license, nil
}

39
cmd/recipe.go Normal file
View file

@ -0,0 +1,39 @@
/*
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"fmt"
"github.com/Fishwaldo/go-yocto/utils"
"github.com/spf13/cobra"
"github.com/Fishwaldo/go-yocto/cmd/recipe"
"github.com/spf13/viper"
)
// recipeCmd represents the recipe command
var recipeCmd = &cobra.Command{
Use: "recipe",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("recipe called")
},
}
func init() {
rootCmd.AddCommand(recipeCmd)
recipeCmd.AddCommand(cmdRecipe.CreateCmd)
cmdRecipe.CreateCmd.Flags().StringP("layer", "l", ".", "Layer Directory to create recipe in")
if err := viper.BindPFlag("yocto.layerdirectory", cmdRecipe.CreateCmd.Flags().Lookup("layer")); err != nil {
utils.Logger.Error("Failed to Bind Flag", utils.Logger.Args("flag", "layer", "error", err))
}
}

25
cmd/recipe/create.go Normal file
View file

@ -0,0 +1,25 @@
/*
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
*/
package cmdRecipe
import (
"github.com/Fishwaldo/go-yocto/recipe"
"github.com/Fishwaldo/go-yocto/utils"
"github.com/spf13/cobra"
)
// createCmd represents the update command
var CreateCmd = &cobra.Command{
Use: "create",
Short: "Create a new recipe",
Long: `Create a new recipe`,
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
utils.Logger.Info("Creating Recipe", utils.Logger.Args("backend", args[0], "name", args[1]))
recipe.CreateRecipe(args[0], args[1])
},
}
func init() {
}

View file

@ -29,13 +29,7 @@ to quickly create a Cobra application.`,
func init() {
rootCmd.AddCommand(sourceCmd)
sourceCmd.AddCommand(cmdSource.SearchCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// sourceCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// sourceCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

View file

@ -20,7 +20,7 @@ var SearchCmd = &cobra.Command{
if err == nil {
td := pterm.TableData{{"Name", "Description", "Backend", "Url"}}
for _, source := range sources {
td = append(td, []string{source.Name, source.Description, source.Backend, source.Url})
td = append(td, []string{source.Name, source.Description, source.BackendID, source.Url})
}
pterm.DefaultTable.WithHasHeader().WithData(
td,

1
go.mod
View file

@ -4,6 +4,7 @@ go 1.18
require (
github.com/Masterminds/semver/v3 v3.2.1
github.com/davecgh/go-spew v1.1.1
github.com/go-git/go-git/v5 v5.6.1
github.com/pterm/pterm v0.12.60
github.com/spf13/cobra v1.7.0

204
recipe/recipe.go Normal file
View file

@ -0,0 +1,204 @@
package recipe
import (
"errors"
"fmt"
"io/fs"
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"text/template"
"github.com/Fishwaldo/go-yocto/backends"
"github.com/Fishwaldo/go-yocto/source"
"github.com/Fishwaldo/go-yocto/utils"
"github.com/spf13/viper"
"github.com/pterm/pterm"
// "github.com/davecgh/go-spew/spew"
)
var (
funcs = template.FuncMap{"join": strings.Join}
parserecipename = regexp.MustCompile(`^(.*)_(.*)\.bb$`)
existingRecipes map[string]*source.RecipeSource = make(map[string]*source.RecipeSource)
)
func init() {
}
func CreateRecipe(be string, name string) (error) {
utils.Logger.Trace("Creating Recipe", utils.Logger.Args("backend", be, "name", name))
b, ok := backends.Backends[be]
if !ok {
utils.Logger.Error("Backend not found", utils.Logger.Args("backend", be))
return errors.New("backend not found")
}
if !b.Ready() {
utils.Logger.Error("Backend not ready", utils.Logger.Args("backend", be))
return errors.New("backend not ready")
}
layers := viper.GetStringSlice("yocto.layers")
for _, layer := range layers {
spinnerInfo, _ := pterm.DefaultSpinner.Start("Scanning Existing Recipe Files in " + layer)
scanRecipes(layer, 0);
spinnerInfo.Success()
}
s, err := b.GetRecipe(name)
if err != nil {
utils.Logger.Error("Failed to get Recipe", utils.Logger.Args("backend", be, "name", name, "error", err))
return err
}
/* if it already exists, bail out */
if _, ok := existingRecipes[s.Identifier]; ok {
utils.Logger.Warn("Recipe already exists", utils.Logger.Args("recipe", s.Name))
return errors.New("recipe already exists")
}
/* check out dependancies */
for _, dep := range s.Depends {
if _, ok := existingRecipes[dep]; !ok {
utils.Logger.Warn("Recipe Dependancy not found", utils.Logger.Args("recipe", s.Name, "dependancy", dep))
return errors.New("recipe dependancy not found")
}
}
if err := writeRecipeFiles(s); err != nil {
utils.Logger.Error("Failed to write Recipe Files", utils.Logger.Args("error", err))
return err
}
return nil
}
func writeRecipeFiles(s *source.RecipeSource) (error) {
dir := path.Join(viper.GetString("yocto.layerdirectory"), "recipes-" + s.Section)
if _, err := os.Stat(dir); os.IsNotExist(err) {
if err := os.Mkdir(dir, 0755); err != nil {
utils.Logger.Error("Failed to create directory", utils.Logger.Args("error", err, "dir", dir))
return err
}
}
dir = path.Join(dir, s.Identifier)
if _, err := os.Stat(dir); os.IsNotExist(err) {
if err := os.Mkdir(dir, 0755); err != nil {
utils.Logger.Error("Failed to create directory", utils.Logger.Args("error", err))
return err
}
}
utils.Logger.Info("Publishing to " + dir)
maintmpl, err := ioutil.ReadFile("templates/recipe-main.tmpl")
if err != nil {
utils.Logger.Error("Failed to read main template", utils.Logger.Args("error", err))
} else {
/* create recipe_version.bb file */
masterTmpl, err := template.New("master").Funcs(funcs).Parse(string(maintmpl))
if err != nil {
utils.Logger.Error("Failed to parse template", utils.Logger.Args("error", err))
return err
}
fname := path.Join(dir, fmt.Sprintf("%s_%s.bb", s.Identifier, s.Version))
if f, err := os.Create(fname); err != nil {
utils.Logger.Error("Failed to create file", utils.Logger.Args("error", err))
return err
} else {
if err := masterTmpl.Execute(f, s); err != nil {
utils.Logger.Error("Failed to execute template", utils.Logger.Args("error", err))
return err
} else {
utils.Logger.Info("Created " + fname)
}
f.Close();
}
/* create recipe.inc file */
maintmpl, err := ioutil.ReadFile("templates/recipe-include.tmpl")
if err != nil {
utils.Logger.Error("Failed to read main template", utils.Logger.Args("error", err))
} else {
overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(string(maintmpl))
if err != nil {
utils.Logger.Error("Failed to parse template", utils.Logger.Args("error", err))
return err
}
fname = path.Join(dir, fmt.Sprintf("%s.inc", s.Identifier))
if f, err := os.Create(fname); err != nil {
utils.Logger.Error("Failed to create file", utils.Logger.Args("error", err))
return err
} else {
if err := overlayTmpl.Execute(f, s); err != nil {
utils.Logger.Error("Failed to execute template", utils.Logger.Args("error", err))
return err
} else {
utils.Logger.Info("Created " + fname)
}
f.Close();
}
}
}
return nil
}
func scanRecipes(dir string, level int) (error) {
fsrecipessections, err := os.ReadDir(dir)
if err != nil {
utils.Logger.Error("Failed to read directory", utils.Logger.Args("error", err))
return err
}
for _, file := range fsrecipessections {
if file.IsDir() {
if (level == 0) {
ok, _ := filepath.Match("recipes-*", file.Name())
if !ok {
continue
}
}
if err := scanRecipes(path.Join(dir, file.Name()), level + 1); err != nil {
utils.Logger.Error("Failed to scan directory", utils.Logger.Args("error", err))
continue
}
} else if file.Type().IsRegular() {
if strings.EqualFold(path.Ext(file.Name()), ".bb") {
if err := parseRecipeFile(file, path.Join(dir, file.Name())); err != nil {
utils.Logger.Error("Failed to parse recipe file", utils.Logger.Args("error", err, "file", path.Join(dir, file.Name())))
continue
}
}
}
}
return nil
}
func parseRecipeFile(file fs.DirEntry, dir string) (error) {
if parserecipename.Match([]byte(file.Name())) {
match := parserecipename.FindSubmatch([]byte(file.Name()))
s := source.RecipeSource{
Identifier: string(match[1]),
Version: string(match[2]),
Section: strings.TrimPrefix(file.Name(), "-"),
BackendID: "existing",
Location: path.Join(dir, file.Name()),
}
if _, ok := existingRecipes[s.Identifier]; !ok {
existingRecipes[s.Identifier] = &s
}
}
return nil
}

View file

@ -2,10 +2,18 @@ package source
type RecipeSource struct {
Name string
Identifier string
Description string
Summary string
Version string
Url string
Backend string
Section string
BackendID string
MetaData map[string]map[string]interface{}
Inherits []string
Depends []string
SrcURI string
SrcSHA256 string
Licenses []string
Location string
}

View file

@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2023 Justin Hammond <justin@dynam.ac>
#
# SPDX-License-Identifier: MIT
DESCRIPTION = "{{.Description}}"
SUMMARY = "{{.Summary}}"
HOMEPAGE = "{{.Url}}"
LICENSE = "{{block "Licenses" .Licenses}} {{join . " & "}}{{end}}"
{{block "Inherits" .Inherits}}{{"\n"}}{{range .}}{{println "inherit" .}}{{end}}{{end}}
DEPENDS = " \
{{block "Depends" .Depends }}{{range .}}{{print " " . }} \{{println}}{{end}}{{end}}"
KF5_REUSE_LICENSECHECK_ENABLED="1"

View file

@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: none
# SPDX-License-Identifier: CC0-1.0
require ${PN}.inc
SRC_URI = "{{.SrcURI}}"
SRC_URI[sha256sum] = "{{.SrcSHA256}}"