main API

main

package

API reference for the main package.

S
struct

Sysext

Configuration for system extensions

finalize-plugins/sysext.go:16-21
type Sysext struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
OSReleaseID string json:"osreleaseid"
OSReleaseVersionID string json:"osreleaseversionid"
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

finalize-plugins/sysext.go:26-33
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "sysext", Type: api.FinalizePlugin}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

PluginScope

Provide the plugin scope

Returns

int32
finalize-plugins/sysext.go:38-40
func PluginScope() int32

{ // int32 is defined as GoInt32 in cgo which is the same as a C int
	return api.IMAGENAME | api.FS | api.RECIPE
}
F
function

FinalizeBuild

Process and finalize the build by creating an extension release file and
creating a SquashFS image from the filesystem

Parameters

moduleInterface
extraData

Returns

finalize-plugins/sysext.go:46-91
func FinalizeBuild(moduleInterface *C.char, extraData *C.char) *C.char

{
	var module *Sysext
	var data *api.ScopeData

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(extraData)), &data)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	var extensionRelease strings.Builder
	fmt.Fprintf(&extensionRelease, "ID=%s\n", module.OSReleaseID)
	fmt.Fprintf(&extensionRelease, "VERSION_ID=%s\n", module.OSReleaseVersionID)

	err = os.MkdirAll(filepath.Join(data.FS, "usr/lib/extension-release.d"), 0o777)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	err = os.WriteFile(filepath.Join(data.FS, fmt.Sprintf("usr/lib/extension-release.d/extension-release.%s", data.Recipe.Id)), []byte(extensionRelease.String()), 0o777)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	mksquashfs, err := exec.LookPath("mksquashfs")
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	cmd := exec.Command(
		mksquashfs, data.FS,
		filepath.Join(data.Recipe.ParentPath, fmt.Sprintf("%s.raw", data.Recipe.Id)),
	)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Dir = data.Recipe.ParentPath

	err = cmd.Run()
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	return C.CString("")
}
F
function

main

finalize-plugins/sysext.go:93-93
func main()

{}
S
struct

SystemdRepart

Configuration for systemd repartitioning

finalize-plugins/systemd-repart.go:14-26
type SystemdRepart struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
Output string json:"output"
Json string json:"json"
SpecOutput string json:"spec_output"
Size string json:"size"
Seed string json:"seed"
Split bool json:"split"
Empty string json:"empty"
Root string json:"root"
DeferPartitions []string json:"defer_partitions"
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

finalize-plugins/systemd-repart.go:31-38
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "systemd-repart", Type: api.FinalizePlugin}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

PluginScope

Provide the plugin scope

Returns

int32
finalize-plugins/systemd-repart.go:43-45
func PluginScope() int32

{ // int32 is defined as GoInt32 in cgo which is the same as a C int
	return api.IMAGENAME | api.FS | api.RECIPE
}
F
function

parsePath

Replace placeholders in the path with actual values from ScopeData
$PROJROOT -> Recipe.ParentPath
$FSROOT -> FS

Parameters

path
string

Returns

string
finalize-plugins/systemd-repart.go:50-54
func parsePath(path string, data *api.ScopeData) string

{
	path = strings.ReplaceAll(path, "$PROJROOT", data.Recipe.ParentPath)
	path = strings.ReplaceAll(path, "$FSROOT", data.FS)
	return path
}
F
function

FinalizeBuild

Finalize the build by executing systemd-repart with the provided configuration
to generate and apply partitioning specifications and output results

Parameters

moduleInterface
extraData

Returns

finalize-plugins/systemd-repart.go:60-131
func FinalizeBuild(moduleInterface *C.char, extraData *C.char) *C.char

{
	var module *SystemdRepart
	var data *api.ScopeData

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(extraData)), &data)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	repart, err := exec.LookPath("systemd-repart")
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	if len(strings.TrimSpace(module.Json)) == 0 {
		module.Json = "off"
	}

	if len(strings.TrimSpace(module.Empty)) == 0 {
		module.Empty = "create"
	}

	if len(strings.TrimSpace(module.Root)) == 0 {
		module.Root = data.FS
	} else {
		module.Root = parsePath(module.Root, data)
	}

	args := []string{
		"--definitions=definitions",
		fmt.Sprintf("--empty=%s", module.Empty),
		fmt.Sprintf("--size=%s", module.Size),
		"--dry-run=no",
		"--discard=no",
		"--offline=true",
		"--no-pager",
		fmt.Sprintf("--split=%t", module.Split),
		fmt.Sprintf("--seed=%s", module.Seed),
		fmt.Sprintf("--root=%s", data.FS),
		module.Output,
		fmt.Sprintf("--json=%s", module.Json),
	}

	if len(module.DeferPartitions) > 0 {
		args = append(args, fmt.Sprintf("--defer-partitions=%s", strings.Join(module.DeferPartitions, ",")))
	}

	cmd := exec.Command(
		repart,
		args...,
	)
	jsonFile, err := os.Create(module.SpecOutput)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	defer jsonFile.Close()
	cmd.Stdout = jsonFile
	cmd.Stderr = os.Stderr
	cmd.Dir = data.Recipe.ParentPath

	err = cmd.Run()
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	return C.CString("")
}
F
function

main

finalize-plugins/systemd-repart.go:133-133
func main()

{}
S
struct

Genimage

Configuration for generating an image

finalize-plugins/genimage.go:14-22
type Genimage struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
GenimagePath string json:"genimagepath"
Config string json:"config"
Rootpath string json:"rootpath"
Inputpath string json:"inputpath"
Outputpath string json:"outputpath"
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

finalize-plugins/genimage.go:27-34
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "genimage", Type: api.FinalizePlugin}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

PluginScope

Provide the plugin scope

Returns

int32
finalize-plugins/genimage.go:39-41
func PluginScope() int32

{ // int32 is defined as GoInt32 in cgo which is the same as a C int
	return api.IMAGENAME | api.FS | api.RECIPE
}
F
function

ParsePath

Replace placeholders in the path with actual values from ScopeData
$PROJROOT -> Recipe.ParentPath
$FSROOT -> FS

Parameters

path
string

Returns

string
finalize-plugins/genimage.go:46-50
func ParsePath(path string, data *api.ScopeData) string

{
	path = strings.Replace(path, "$PROJROOT", data.Recipe.ParentPath, 1)
	path = strings.Replace(path, "$FSROOT", data.FS, 1)
	return path
}
F
function

FinalizeBuild

Complete the build process for a generated image module.
Find the binary if not specified, replace path placeholders
in the module paths, and run the command
with the provided configuration

Parameters

moduleInterface
extraData

Returns

finalize-plugins/genimage.go:58-101
func FinalizeBuild(moduleInterface *C.char, extraData *C.char) *C.char

{
	var module *Genimage
	var data *api.ScopeData

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(extraData)), &data)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	genimage := module.GenimagePath
	if genimage == "" {
		genimage, err = exec.LookPath("genimage")
		if err != nil {
			return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
		}
	}

	cmd := exec.Command(
		genimage,
		"--config",
		ParsePath(module.Config, data),
		"--rootpath",
		ParsePath(module.Rootpath, data),
		"--outputpath",
		ParsePath(module.Outputpath, data),
		"--inputpath",
		ParsePath(module.Inputpath, data),
	)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Dir = data.Recipe.ParentPath

	err = cmd.Run()
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	return C.CString("")
}
F
function

main

finalize-plugins/genimage.go:103-103
func main()

{}
S
struct

Shell

Configuration for a set of shell commands

finalize-plugins/shell-final.go:14-19
type Shell struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
Commands []string json:"commands"
Cwd string json:"cwd"
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

finalize-plugins/shell-final.go:24-31
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "shell-final", Type: api.FinalizePlugin}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

PluginScope

Provide the plugin scope

Returns

int32
finalize-plugins/shell-final.go:36-38
func PluginScope() int32

{ // int32 is defined as GoInt32 in cgo which is the same as a C int
	return api.IMAGENAME | api.FS | api.RECIPE
}
F
function

parsePath

Replace placeholders in the path with actual values from ScopeData
$PROJROOT -> Recipe.ParentPath
$FSROOT -> FS

Parameters

path
string

Returns

string
finalize-plugins/shell-final.go:43-47
func parsePath(path string, data *api.ScopeData) string

{
	path = strings.ReplaceAll(path, "$PROJROOT", data.Recipe.ParentPath)
	path = strings.ReplaceAll(path, "$FSROOT", data.FS)
	return path
}
F
function

baseCommand

Check if the command is in $PATH or includes a directory path.
Return the full path if found, otherwise return the command unchanged.

Parameters

command
string

Returns

string
finalize-plugins/shell-final.go:51-62
func baseCommand(command string, data *api.ScopeData) string

{
	commandParts := strings.Split(command, " ")
	if strings.Contains(commandParts[0], "/") {
		return parsePath(commandParts[0], data)
	} else {
		command, err := exec.LookPath(commandParts[0])
		if err != nil {
			return commandParts[0]
		}
		return command
	}
}
F
function

getArgs

Extract and return arguments from a command string

Parameters

command
string

Returns

[]string
finalize-plugins/shell-final.go:65-68
func getArgs(command string, data *api.ScopeData) []string

{
	commandParts := strings.Split(parsePath(command, data), " ")
	return commandParts[1:]
}
F
function

genCommand

Generate an executable command by resolving the base command and arguments
and wrapping them with appropriate syntax for execution.

Parameters

command
string

Returns

[]string
finalize-plugins/shell-final.go:72-76
func genCommand(command string, data *api.ScopeData) []string

{
	baseCommand := baseCommand(command, data)
	args := getArgs(command, data)
	return append(append(append([]string{"-c", "'"}, strings.Join(args, " ")), baseCommand), "'")
}
F
function

FinalizeBuild

Execute shell commands from a Shell struct using the provided ScopeData.
It parses and runs each command in the context of the provided working directory,
or the recipe’s parent path if no specific directory is given.

Parameters

moduleInterface
extraData

Returns

finalize-plugins/shell-final.go:83-120
func FinalizeBuild(moduleInterface *C.char, extraData *C.char) *C.char

{
	var module *Shell
	var data *api.ScopeData

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(extraData)), &data)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	for _, command := range module.Commands {
		fmt.Println("shell-final:: bash ", "-c ", command)

		cmd := exec.Command(
			"bash", "-c", parsePath(command, data),
		)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		cmd.Env = os.Environ()
		if len(strings.TrimSpace(module.Cwd)) == 0 {
			cmd.Dir = data.Recipe.ParentPath
		} else {
			cmd.Dir = parsePath(module.Cwd, data)
		}

		err = cmd.Run()
		if err != nil {
			return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
		}
	}

	return C.CString("")
}
F
function

main

finalize-plugins/shell-final.go:122-122
func main()

{}
S
struct

DpkgBuildModule

Configuration for building a Debian package using dpkg

plugins/dpkg-buildpackage.go:12-16
type DpkgBuildModule struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
Source api.Source
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

plugins/dpkg-buildpackage.go:21-28
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "dpkg-buildpackage", Type: api.BuildPlugin, UseContainerCmds: false}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

BuildModule

Generate a command to build a Debian package using dpkg and install
the resulting .deb package. Handle downloading, moving the source,
and running dpkg-buildpackage with appropriate options.

Parameters

moduleInterface
recipeInterface
arch

Returns

plugins/dpkg-buildpackage.go:35-71
func BuildModule(moduleInterface *C.char, recipeInterface *C.char, arch *C.char) *C.char

{
	var module *DpkgBuildModule
	var recipe *api.Recipe

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(recipeInterface)), &recipe)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	if !api.TestArch(module.Source.OnlyArches, C.GoString(arch)) {
		return C.CString("")
	}

	err = api.DownloadSource(recipe, module.Source, module.Name)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	err = api.MoveSource(recipe.DownloadsPath, recipe.SourcesPath, module.Source, module.Name)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	cmd := fmt.Sprintf(
		"cd /sources/%s && dpkg-buildpackage -d -us -uc -b",
		api.GetSourcePath(module.Source, module.Name),
	)

	cmd += fmt.Sprintf(" && apt install -y --allow-downgrades ../%s*.deb", module.Source.Path)

	cmd += " && apt clean"
	return C.CString(cmd)
}
F
function

main

plugins/dpkg-buildpackage.go:73-73
func main()

{ fmt.Println("This plugin is not meant to run standalone!") }
S
struct

innerFlatpakModule

Configuration for managing Flatpak repositories and packages

plugins/flatpak.go:17-22
type innerFlatpakModule struct

Fields

Name Type Description
Repourl string json:"repo-url"
Reponame string json:"repo-name"
Install []string json:"install"
Remove []string json:"remove"
S
struct

FlatpakModule

Configuration for managing Flatpak repositories and packages
for both system and user contexts

plugins/flatpak.go:26-31
type FlatpakModule struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
System innerFlatpakModule json:"system"
User innerFlatpakModule json:"user"
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

plugins/flatpak.go:68-75
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "flatpak", Type: api.BuildPlugin, UseContainerCmds: false}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

createRepo

Generate a command to add a Flatpak remote repository.
Add appropriate flags for system-wide or user-specific installation.

Parameters

isSystem
bool

Returns

string
plugins/flatpak.go:79-88
func createRepo(module innerFlatpakModule, isSystem bool) string

{
	fmt.Println("Adding remote ", isSystem, " ", module)
	command := "flatpak remote-add --if-not-exists"
	if isSystem {
		command = fmt.Sprintf("%s --system", command)
	} else {
		command = fmt.Sprintf("%s --user", command)
	}
	return fmt.Sprintf("%s %s %s", command, module.Reponame, module.Repourl)
}
F
function

BuildModule

Generate setup commands for Flatpak module configuration.
Create scripts for system-wide and user-specific Flatpak setups,
including repository addition, package installation, and service configuration.

Parameters

moduleInterface
recipeInterface

Returns

plugins/flatpak.go:95-154
func BuildModule(moduleInterface *C.char, recipeInterface *C.char) *C.char

{
	var module *FlatpakModule
	var recipe *api.Recipe

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(recipeInterface)), &recipe)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	os.MkdirAll(path.Join(recipe.ParentPath, "includes.container/usr/bin/"), 0o775)
	if module.System.Reponame != "" {
		syscommands := "#!/usr/bin/env sh"
		if module.System.Repourl != "" {
			syscommands = fmt.Sprintf("%s\n%s", syscommands, createRepo(module.System, true))
			fmt.Println(syscommands)
		}
		if len(module.System.Install) != 0 {
			syscommands = fmt.Sprintf("%s\nflatpak install --system --noninteractive %s %s", syscommands, module.System.Reponame, strings.Join(module.System.Install, " "))
		}
		if len(module.System.Remove) != 0 {
			syscommands = fmt.Sprintf("%s\nflatpak uninstall --system --noninteractive %s %s", syscommands, module.User.Reponame, strings.Join(module.System.Remove, " "))
		}

		syscommands = fmt.Sprintf("%s\nsystemctl disable flatpak-system-setup.service", syscommands)
		err := os.WriteFile(path.Join(recipe.ParentPath, "includes.container/usr/bin/system-flatpak-setup"), []byte(syscommands), 0o777)
		if err != nil {
			return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
		}

	}
	if module.User.Reponame != "" {
		usercommands := "#!/usr/bin/env sh"
		if module.User.Repourl != "" {
			usercommands = fmt.Sprintf("%s\n%s", usercommands, createRepo(module.User, false))
			fmt.Println(usercommands)
		}
		if len(module.User.Install) != 0 {
			usercommands = fmt.Sprintf("%s\nflatpak install --user --noninteractive %s", usercommands, strings.Join(module.User.Install, " "))
		}
		if len(module.User.Remove) != 0 {
			usercommands = fmt.Sprintf("%s\nflatpak uninstall --user --noninteractive %s", usercommands, strings.Join(module.User.Remove, " "))
		}

		err := os.WriteFile(path.Join(recipe.ParentPath, "includes.container/usr/bin/user-flatpak-setup"), []byte(usercommands), 0o777)
		if err != nil {
			return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
		}
	}
	os.MkdirAll(path.Join(recipe.ParentPath, "includes.container/etc/systemd/user"), 0o775)
	os.MkdirAll(path.Join(recipe.ParentPath, "includes.container/etc/systemd/system"), 0o775)
	os.WriteFile(path.Join(recipe.ParentPath, "includes.container/etc/systemd/user/flatpak-user-setup.service"), []byte(UserService), 0o666)
	os.WriteFile(path.Join(recipe.ParentPath, "includes.container/etc/systemd/system/flatpak-system-setup.service"), []byte(SystemService), 0o666)

	return C.CString("systemctl enable --global flatpak-user-setup.service && systemctl enable --system flatpak-system-setup.service")
}
F
function

main

plugins/flatpak.go:156-156
func main()

{ fmt.Println("This plugin is not meant to run standalone!") }
S
struct

GoModule

Configuration for building a Go module

plugins/go.go:12-18
type GoModule struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
Source api.Source
BuildVars map[string]string
BuildFlags string
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

plugins/go.go:23-30
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "go", Type: api.BuildPlugin, UseContainerCmds: false}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

BuildModule

Generate a command to build a Go project. Add options for
setting the output binary name and location based on the provided buildVars
and BuildFlags, and handle downloading and moving the source.

Parameters

moduleInterface
recipeInterface
arch

Returns

plugins/go.go:37-87
func BuildModule(moduleInterface *C.char, recipeInterface *C.char, arch *C.char) *C.char

{
	var module *GoModule
	var recipe *api.Recipe

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(recipeInterface)), &recipe)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	if !api.TestArch(module.Source.OnlyArches, C.GoString(arch)) {
		return C.CString("")
	}

	err = api.DownloadSource(recipe, module.Source, module.Name)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	err = api.MoveSource(recipe.DownloadsPath, recipe.SourcesPath, module.Source, module.Name)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	buildVars := map[string]string{}
	for k, v := range module.BuildVars {
		buildVars[k] = v
	}

	buildFlags := ""
	if module.BuildFlags != "" {
		buildFlags = " " + module.BuildFlags
	}

	buildVars["GO_OUTPUT_BIN"] = module.Name
	if module.BuildVars["GO_OUTPUT_BIN"] != "" {
		buildVars["GO_OUTPUT_BIN"] = module.BuildVars["GO_OUTPUT_BIN"]
	}

	cmd := fmt.Sprintf(
		"cd /sources/%s && go build%s -o %s",
		api.GetSourcePath(module.Source, module.Name),
		buildFlags,
		buildVars["GO_OUTPUT_BIN"],
	)

	return C.CString(cmd)
}
F
function

main

plugins/go.go:89-89
func main()

{ fmt.Println("This plugin is not meant to run standalone!") }
S
struct

MakeModule

Configuration for building a project using Make

plugins/make.go:13-20
type MakeModule struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
BuildCommand string json:"buildcommand"
InstallCommand string json:"installcommand"
IntermediateSteps []string json:"intermediatesteps"
Sources []api.Source json:"sources"
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

plugins/make.go:25-32
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "make", Type: api.BuildPlugin, UseContainerCmds: false}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

BuildModule

Generate a command to build a Make project. Change directory
to the source path, run ‘make’ to build the project, and ‘make install’
to install the built project. Handle downloading and moving the source.

Parameters

moduleInterface
recipeInterface
arch

Returns

plugins/make.go:39-84
func BuildModule(moduleInterface *C.char, recipeInterface *C.char, arch *C.char) *C.char

{
	var module *MakeModule
	var recipe *api.Recipe

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(recipeInterface)), &recipe)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	for _, source := range module.Sources {
		if api.TestArch(source.OnlyArches, C.GoString(arch)) {
			err = api.DownloadSource(recipe, source, module.Name)
			if err != nil {
				return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
			}
			err = api.MoveSource(recipe.DownloadsPath, recipe.SourcesPath, source, module.Name)
			if err != nil {
				return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
			}
		}
	}

	buildCommand := "make"
	installCommand := "make install"
	intermediateSteps := " && "

	if len(strings.TrimSpace(module.BuildCommand)) != 0 {
		buildCommand = module.BuildCommand
	}

	if len(strings.TrimSpace(module.InstallCommand)) != 0 {
		installCommand = module.InstallCommand
	}

	if len(module.IntermediateSteps) != 0 {
		intermediateSteps = " && " + strings.Join(module.IntermediateSteps, " && ") + " && "
	}

	cmd := "cd /sources/" + api.GetSourcePath(module.Sources[0], module.Name) + " && " + buildCommand + intermediateSteps + installCommand
	return C.CString(cmd)
}
F
function

main

plugins/make.go:86-86
func main()

{ fmt.Println("This plugin is not meant to run standalone!") }
S
struct

MesonModule

Configuration for building a Meson project

plugins/meson.go:14-19
type MesonModule struct

Fields

Name Type Description
Name string
Type string
BuildFlags []string json:"buildflags"
Sources []api.Source json"sources"
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

plugins/meson.go:24-31
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "meson", Type: api.BuildPlugin, UseContainerCmds: false}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

BuildModule

Generate a command to build a Meson project. Handle source downloading, moving,
and use Meson and Ninja build tools with a temporary build directory based on the checksum.

Parameters

moduleInterface
recipeInterface
arch

Returns

plugins/meson.go:37-82
func BuildModule(moduleInterface *C.char, recipeInterface *C.char, arch *C.char) *C.char

{
	var module *MesonModule
	var recipe *api.Recipe

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(recipeInterface)), &recipe)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	for _, source := range module.Sources {
		if api.TestArch(source.OnlyArches, C.GoString(arch)) {
			err = api.DownloadSource(recipe, source, module.Name)
			if err != nil {
				return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
			}
			err = api.MoveSource(recipe.DownloadsPath, recipe.SourcesPath, source, module.Name)
			if err != nil {
				return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
			}
		}
	}

	var tmpDir string
	if strings.EqualFold(module.Sources[0].Type, "git") == true {
		tmpDir = fmt.Sprintf("/tmp/%s-%s", module.Sources[0].Commit, module.Name)
	} else if module.Sources[0].Type == "tar" || module.Sources[0].Type == "local" {
		tmpDir = fmt.Sprintf("/tmp/%s-%s", module.Sources[0].Checksum, module.Name)
	} else {
		tmpDir = fmt.Sprintf("/tmp/%s-%s", sha1.Sum([]byte(module.Sources[0].URL)), module.Name)
	}
	cmd := fmt.Sprintf(
		"cd /sources/%s && meson %s %s && ninja -C %s && ninja -C %s install",
		api.GetSourcePath(module.Sources[0], module.Name),
		strings.Join(module.BuildFlags, " "),
		tmpDir,
		tmpDir,
		tmpDir,
	)

	return C.CString(cmd)
}
F
function

main

plugins/meson.go:84-84
func main()

{ fmt.Println("This plugin is not meant to run standalone!") }
S
struct

ShimModule

Configuration for a shim module

plugins/shim.go:18-22
type ShimModule struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
ShimType string json:"shimtype"
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

plugins/shim.go:27-34
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "shim", Type: api.BuildPlugin, UseContainerCmds: false}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

BuildModule

Generate a command to build a shim module. Create temporary directories,
write module and recipe data to files, and execute the plugin command with
the paths to these files.

Parameters

moduleInterface
recipeInterface

Returns

plugins/shim.go:41-81
func BuildModule(moduleInterface *C.char, recipeInterface *C.char) *C.char

{
	var module *ShimModule
	var recipe *api.Recipe

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(recipeInterface)), &recipe)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	fmt.Printf("[SHIM] Starting plugin: %s\n", module.ShimType)

	dataDir, err := os.MkdirTemp("", fmt.Sprintf("*-vibshim-%s", module.ShimType))
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	defer os.RemoveAll(dataDir)

	pluginCommand := fmt.Sprintf("%s/%s", recipe.PluginPath, module.ShimType)
	modulePath := filepath.Join(dataDir, "moduleInterface")
	recipePath := filepath.Join(dataDir, "recipeInterface")

	err = os.WriteFile(modulePath, []byte(C.GoString(moduleInterface)), 0o777)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	err = os.WriteFile(recipePath, []byte(C.GoString(recipeInterface)), 0o777)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	out, err := exec.Command(pluginCommand, modulePath, recipePath).Output()
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(out))
}
F
function

main

plugins/shim.go:83-83
func main()

{}
S
struct

AptModule

Configuration for an APT module

plugins/apt.go:18-23
type AptModule struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
Options AptOptions json:"options"
Sources []api.Source json:"sources"
S
struct

AptOptions

Options for APT package management

plugins/apt.go:26-31
type AptOptions struct

Fields

Name Type Description
NoRecommends bool json:"no_recommends"
InstallSuggests bool json:"install_suggests"
FixMissing bool json:"fix_missing"
FixBroken bool json:"fix_broken"
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

plugins/apt.go:36-43
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "apt", Type: api.BuildPlugin, UseContainerCmds: false}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

BuildModule

Generate an apt-get install command from the provided module and recipe.
Handle package installation and apply appropriate options.

Parameters

moduleInterface
recipeInterface
arch

Returns

plugins/apt.go:49-119
func BuildModule(moduleInterface *C.char, recipeInterface *C.char, arch *C.char) *C.char

{
	var module *AptModule
	var recipe *api.Recipe

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(recipeInterface)), &recipe)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	args := ""
	if module.Options.NoRecommends {
		args += "--no-install-recommends "
	}
	if module.Options.InstallSuggests {
		args += "--install-suggests "
	}
	if module.Options.FixMissing {
		args += "--fix-missing "
	}
	if module.Options.FixBroken {
		args += "--fix-broken "
	}

	packages := ""
	for _, source := range module.Sources {
		if api.TestArch(source.OnlyArches, C.GoString(arch)) {
			if len(source.Packages) > 0 {
				for _, pkg := range source.Packages {
					packages += pkg + " "
				}
			}

			if len(strings.TrimSpace(source.Path)) > 0 {
				fileInfo, err := os.Stat(source.Path)
				if err != nil {
					return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
				}
				if !fileInfo.Mode().IsRegular() {
					continue
				}
				file, err := os.Open(source.Path)
				if err != nil {
					return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
				}
				defer file.Close()

				scanner := bufio.NewScanner(file)
				for scanner.Scan() {
					packages += scanner.Text() + " "
				}

				if err := scanner.Err(); err != nil {
					return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
				}
			}
		}
	}

	if len(packages) >= 1 {
		cmd := fmt.Sprintf("apt-get install -y %s %s && apt-get clean", args, packages)

		return C.CString(cmd)
	}

	return C.CString("ERROR: no packages or paths specified")
}
F
function

main

plugins/apt.go:121-121
func main()

{}
S
struct

CMakeModule

Configuration for a CMake module

plugins/cmake.go:13-19
type CMakeModule struct

Fields

Name Type Description
Name string json:"name"
Type string json:"type"
BuildVars map[string]string json:"buildvars"
BuildFlags string json:"buildflags"
Source api.Source
F
function

PlugInfo

Provide plugin information as a JSON string

Returns

plugins/cmake.go:24-31
func PlugInfo() *C.char

{
	plugininfo := &api.PluginInfo{Name: "cmake", Type: api.BuildPlugin, UseContainerCmds: false}
	pluginjson, err := json.Marshal(plugininfo)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	return C.CString(string(pluginjson))
}
F
function

BuildModule

Generate a shell command to build a CMake project based on the provided module and recipe.
Download and move the source, set up build variables and flags, and construct the CMake build command.

Parameters

moduleInterface
recipeInterface
arch

Returns

plugins/cmake.go:37-80
func BuildModule(moduleInterface *C.char, recipeInterface *C.char, arch *C.char) *C.char

{
	var module *CMakeModule
	var recipe *api.Recipe

	err := json.Unmarshal([]byte(C.GoString(moduleInterface)), &module)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	err = json.Unmarshal([]byte(C.GoString(recipeInterface)), &recipe)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}

	if !api.TestArch(module.Source.OnlyArches, C.GoString(arch)) {
		return C.CString("")
	}

	err = api.DownloadSource(recipe, module.Source, module.Name)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	err = api.MoveSource(recipe.DownloadsPath, recipe.SourcesPath, module.Source, module.Name)
	if err != nil {
		return C.CString(fmt.Sprintf("ERROR: %s", err.Error()))
	}
	buildVars := map[string]string{}
	for k, v := range module.BuildVars {
		buildVars[k] = v
	}

	buildFlags := ""
	if module.BuildFlags != "" {
		buildFlags = " " + module.BuildFlags
	}

	cmd := fmt.Sprintf(
		"cd /sources/%s && mkdir -p build && cd build && cmake ../%s && make",
		filepath.Join(recipe.SourcesPath, api.GetSourcePath(module.Source, module.Name)),
		buildFlags,
	)

	return C.CString(cmd)
}
F
function

main

plugins/cmake.go:82-82
func main()

{ fmt.Println("This plugin is not meant to run standalone!") }