Skip to content

Commit

Permalink
feat: add module support
Browse files Browse the repository at this point in the history
  • Loading branch information
mirkobrombin authored Dec 3, 2023
2 parents 46df2be + c843eac commit 9f691cd
Show file tree
Hide file tree
Showing 18 changed files with 434 additions and 175 deletions.
76 changes: 18 additions & 58 deletions core/resolver.go → api/download.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package core
package api

import (
"crypto/sha256"
Expand All @@ -11,70 +11,30 @@ import (
"strings"
)

// ResolveSources resolves the sources of a recipe and downloads them
// to the downloads directory. Note that modules in this function are
// returned in the order they should be built.
func ResolveSources(recipe *Recipe) ([]Module, []Source, error) {
fmt.Println("Resolving sources")

modules := GetAllModules(recipe.Modules)
var sources []Source

for _, module := range modules {
fmt.Printf("Resolving source for: %s\n", module.Name)

if module.Source.URL == "" {
continue
}

module.Source.Module = module.Name
err := DownloadSource(recipe, module.Source)
if err != nil {
return nil, nil, err
}

sources = append(sources, module.Source)
}

return modules, sources, nil
}

// GetAllModules returns a list of all modules in a ordered list
func GetAllModules(modules []Module) []Module {
var orderedList []Module

for _, module := range modules {
orderedList = append(orderedList, GetAllModules(module.Modules)...)
orderedList = append(orderedList, module)
}

return orderedList
}

// DownloadSource downloads a source to the downloads directory
// according to its type (git, tar, ...)
func DownloadSource(recipe *Recipe, source Source) error {
func DownloadSource(downloadPath string, source Source, moduleName string) error {
fmt.Printf("Downloading source: %s\n", source.URL)

if source.Type == "git" {
return DownloadGitSource(recipe, source)
return DownloadGitSource(downloadPath, source, moduleName)
} else if source.Type == "tar" {
err := DownloadTarSource(recipe, source)
err := DownloadTarSource(downloadPath, source, moduleName)
if err != nil {
return err
}
return checksumValidation(source, filepath.Join(recipe.DownloadsPath, source.Module))
return checksumValidation(source, filepath.Join(downloadPath, moduleName))
} else {
return fmt.Errorf("unsupported source type %s", source.Type)
}
}

// DownloadGitSource downloads a git source to the downloads directory
// and checks out the commit or tag
func DownloadGitSource(recipe *Recipe, source Source) error {
func DownloadGitSource(downloadPath string, source Source, moduleName string) error {
fmt.Printf("Source is git: %s\n", source.URL)

dest := filepath.Join(recipe.DownloadsPath, source.Module)
dest := filepath.Join(downloadPath, moduleName)

if source.Commit == "" && source.Tag == "" && source.Branch == "" {
return fmt.Errorf("missing source commit, tag or branch")
Expand Down Expand Up @@ -156,10 +116,10 @@ func DownloadGitSource(recipe *Recipe, source Source) error {
}

// DownloadTarSource downloads a tar archive to the downloads directory
func DownloadTarSource(recipe *Recipe, source Source) error {
func DownloadTarSource(downloadPath string, source Source, moduleName string) error {
fmt.Printf("Source is tar: %s\n", source.URL)
//Create the destination path
dest := filepath.Join(recipe.DownloadsPath, source.Module)
dest := filepath.Join(downloadPath, moduleName)
//Download the resource
res, err := http.Get(source.URL)
if err != nil {
Expand All @@ -185,11 +145,11 @@ func DownloadTarSource(recipe *Recipe, source Source) error {

// MoveSources moves all sources from the downloads directory to the
// sources directory
func MoveSources(recipe *Recipe, sources []Source) error {
func MoveSources(downloadPath string, sourcesPath string, sources []Source, moduleName string) error {
fmt.Println("Moving sources")

for _, source := range sources {
err := MoveSource(recipe, source)
err := MoveSource(downloadPath, sourcesPath, source, moduleName)
if err != nil {
return err
}
Expand All @@ -201,26 +161,26 @@ func MoveSources(recipe *Recipe, sources []Source) error {
// MoveSource moves a source from the downloads directory to the
// sources directory, by extracting if a tar archive or moving if a
// git repository
func MoveSource(recipe *Recipe, source Source) error {
fmt.Printf("Moving source: %s\n", source.Module)
func MoveSource(downloadPath string, sourcesPath string, source Source, moduleName string) error {
fmt.Printf("Moving source: %s\n", moduleName)

if source.Type == "git" {
return os.Rename(
filepath.Join(recipe.DownloadsPath, source.Module),
filepath.Join(recipe.SourcesPath, source.Module),
filepath.Join(downloadPath, moduleName),
filepath.Join(sourcesPath, moduleName),
)
} else if source.Type == "tar" {
cmd := exec.Command(
"tar",
"-xf", filepath.Join(recipe.DownloadsPath, source.Module),
"-C", recipe.SourcesPath,
"-xf", filepath.Join(downloadPath, moduleName),
"-C", sourcesPath,
)
err := cmd.Run()
if err != nil {
return err
}

return os.Remove(filepath.Join(recipe.DownloadsPath, source.Module))
return os.Remove(filepath.Join(downloadPath, moduleName))
} else {
return fmt.Errorf("unsupported source type %s", source.Type)
}
Expand Down
3 changes: 3 additions & 0 deletions api/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/vanilla-os/vib/api

go 1.21
31 changes: 31 additions & 0 deletions api/structs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package api

type Source struct {
URL string `json:"url"`
Checksum string `json:"checksum"`
Type string `json:"type"`
Commit string `json:"commit"`
Tag string `json:"tag"`
Branch string `json:"branch"`
Packages []string `json:"packages"`
Paths []string `json:"paths"`
}

type Recipe struct {
Base string `json:"base"`
Name string
Id string
SingleLayer bool `json:"singlelayer"`
Labels map[string]string `json:"labels"`
Adds map[string]string `json:"adds"`
Args map[string]string `json:"args"`
Runs []string `json:"runs"`
Cmd string `json:"cmd"`
Modules []interface{} `json:"modules"`
Path string
ParentPath string
DownloadsPath string
SourcesPath string
PluginPath string
Containerfile string
}
15 changes: 14 additions & 1 deletion core/apt.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,26 @@ import (
"bufio"
"errors"
"fmt"
"github.com/mitchellh/mapstructure"
"github.com/vanilla-os/vib/api"
"os"
"path/filepath"
)

type AptModule struct {
Name string `json:"name"`
Type string `json:"type"`
Source api.Source `json:"source"`
}

// BuildAptModule builds a module that installs packages
// using the apt package manager
func BuildAptModule(recipe *Recipe, module Module) (string, error) {
func BuildAptModule(moduleInterface interface{}, recipe *api.Recipe) (string, error) {
var module AptModule
err := mapstructure.Decode(moduleInterface, &module)
if err != nil {
return "", err
}
if len(module.Source.Packages) > 0 {
packages := ""
for _, pkg := range module.Source.Packages {
Expand Down
117 changes: 83 additions & 34 deletions core/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,42 @@ package core

import (
"fmt"
"github.com/mitchellh/mapstructure"
"github.com/vanilla-os/vib/api"
"os"
"strings"
)

// BuildRecipe builds a Containerfile from a recipe path
func BuildRecipe(recipePath string) (Recipe, error) {
func BuildRecipe(recipePath string) (api.Recipe, error) {
// load the recipe
recipe, err := LoadRecipe(recipePath)
if err != nil {
return Recipe{}, err
return api.Recipe{}, err
}

fmt.Printf("Building recipe %s\n", recipe.Name)

// resolve (and download) the sources
modules, sources, err := ResolveSources(recipe)
if err != nil {
return Recipe{}, err
}

// move them to the sources directory so they can be
// used by the modules during the build
err = MoveSources(recipe, sources)
if err != nil {
return Recipe{}, err
}

// build the modules*
// * actually just build the commands that will be used
// in the Containerfile to build the modules
cmds, err := BuildModules(recipe, modules)
cmds, err := BuildModules(recipe, recipe.Modules)
if err != nil {
return Recipe{}, err
return api.Recipe{}, err
}

// build the Containerfile
err = BuildContainerfile(recipe, cmds)
if err != nil {
return Recipe{}, err
return api.Recipe{}, err
}

return *recipe, nil
}

// BuildContainerfile builds a Containerfile from a recipe
// and a list of modules commands
func BuildContainerfile(recipe *Recipe, cmds []ModuleCommand) error {
func BuildContainerfile(recipe *api.Recipe, cmds []ModuleCommand) error {
containerfile, err := os.Create(recipe.Containerfile)
if err != nil {
return err
Expand Down Expand Up @@ -172,13 +162,16 @@ func BuildContainerfile(recipe *Recipe, cmds []ModuleCommand) error {
}

// BuildModules builds a list of modules commands from a list of modules
func BuildModules(recipe *Recipe, modules []Module) ([]ModuleCommand, error) {
func BuildModules(recipe *api.Recipe, modules []interface{}) ([]ModuleCommand, error) {
cmds := []ModuleCommand{}
for _, moduleInterface := range modules {
var module Module
err := mapstructure.Decode(moduleInterface, &module)
if err != nil {
return nil, err
}

for _, module := range modules {
fmt.Printf("Creating build command for %s\n", module.Name)

cmd, err := BuildModule(recipe, module)
cmd, err := BuildModule(recipe, moduleInterface)
if err != nil {
return nil, err
}
Expand All @@ -195,25 +188,81 @@ func BuildModules(recipe *Recipe, modules []Module) ([]ModuleCommand, error) {
// BuildModule builds a module command from a module
// this is done by calling the appropriate module builder
// function based on the module type
func BuildModule(recipe *Recipe, module Module) (string, error) {
func BuildModule(recipe *api.Recipe, moduleInterface interface{}) (string, error) {
var module Module
err := mapstructure.Decode(moduleInterface, &module)
if err != nil {
return "", err
}
var commands string
if len(module.Modules) > 0 {
for _, nestedModule := range module.Modules {
buildModule, err := BuildModule(recipe, nestedModule)
if err != nil {
return "", err
}
commands = commands + " && " + buildModule
}
}

switch module.Type {
case "apt":
return BuildAptModule(recipe, module)
command, err := BuildAptModule(moduleInterface, recipe)
if err != nil {
return "", err
}
commands = commands + " && " + command
case "cmake":
return BuildCMakeModule(module)
command, err := BuildCMakeModule(moduleInterface, recipe)
if err != nil {
return "", err
}
commands = commands + " && " + command
case "dpkg":
return BuildDpkgModule(module)
command, err := BuildDpkgModule(moduleInterface, recipe)
if err != nil {
return "", err
}
commands = commands + " && " + command
case "dpkg-buildpackage":
return BuildDpkgBuildPkgModule(module)
command, err := BuildDpkgBuildPkgModule(moduleInterface, recipe)
if err != nil {
return "", err
}
commands = commands + " && " + command
case "go":
return BuildGoModule(module)
command, err := BuildGoModule(moduleInterface, recipe)
if err != nil {
return "", err
}
commands = commands + " && " + command
case "make":
return BuildMakeModule(module)
command, err := BuildMakeModule(moduleInterface, recipe)
if err != nil {
return "", err
}
commands = commands + " && " + command
case "meson":
return BuildMesonModule(module)
command, err := BuildMesonModule(moduleInterface, recipe)
if err != nil {
return "", err
}
commands = commands + " && " + command
case "shell":
return BuildShellModule(module)
command, err := BuildShellModule(moduleInterface, recipe)
if err != nil {
return "", err
}
commands = commands + " && " + command
case "includes":
return "", nil
default:
return "", fmt.Errorf("unknown module type %s", module.Type)
command, err := LoadPlugin(module.Type, moduleInterface, recipe)
if err != nil {
return "", err
}
commands = commands + " && " + command
}

return strings.TrimPrefix(commands, " && "), err
}
Loading

0 comments on commit 9f691cd

Please sign in to comment.