main
packageAPI reference for the main
package.
Imports
(11)Sysext
Configuration for system extensions
type Sysext struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | json:"name" |
| Type | string | json:"type" |
| OSReleaseID | string | json:"osreleaseid" |
| OSReleaseVersionID | string | json:"osreleaseversionid" |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
PluginScope
Provide the plugin scope
Returns
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
}
FinalizeBuild
Process and finalize the build by creating an extension release file and
creating a SquashFS image from the filesystem
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("")
}
main
func main()
{}
SystemdRepart
Configuration for systemd repartitioning
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" |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
PluginScope
Provide the plugin scope
Returns
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
}
parsePath
Replace placeholders in the path with actual values from ScopeData
$PROJROOT -> Recipe.ParentPath
$FSROOT -> FS
Parameters
Returns
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
}
FinalizeBuild
Finalize the build by executing systemd-repart with the provided configuration
to generate and apply partitioning specifications and output results
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("")
}
main
func main()
{}
Genimage
Configuration for generating an image
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" |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
PluginScope
Provide the plugin scope
Returns
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
}
ParsePath
Replace placeholders in the path with actual values from ScopeData
$PROJROOT -> Recipe.ParentPath
$FSROOT -> FS
Parameters
Returns
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
}
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
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("")
}
main
func main()
{}
Shell
Configuration for a set of shell commands
type Shell struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | json:"name" |
| Type | string | json:"type" |
| Commands | []string | json:"commands" |
| Cwd | string | json:"cwd" |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
PluginScope
Provide the plugin scope
Returns
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
}
parsePath
Replace placeholders in the path with actual values from ScopeData
$PROJROOT -> Recipe.ParentPath
$FSROOT -> FS
Parameters
Returns
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
}
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
Returns
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
}
}
getArgs
Extract and return arguments from a command string
Parameters
Returns
func getArgs(command string, data *api.ScopeData) []string
{
commandParts := strings.Split(parsePath(command, data), " ")
return commandParts[1:]
}
genCommand
Generate an executable command by resolving the base command and arguments
and wrapping them with appropriate syntax for execution.
Parameters
Returns
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), "'")
}
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.
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("")
}
main
func main()
{}
DpkgBuildModule
Configuration for building a Debian package using dpkg
type DpkgBuildModule struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | json:"name" |
| Type | string | json:"type" |
| Source | api.Source |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
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.
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)
}
main
func main()
{ fmt.Println("This plugin is not meant to run standalone!") }
innerFlatpakModule
Configuration for managing Flatpak repositories and packages
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" |
FlatpakModule
Configuration for managing Flatpak repositories and packages
for both system and user contexts
type FlatpakModule struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | json:"name" |
| Type | string | json:"type" |
| System | innerFlatpakModule | json:"system" |
| User | innerFlatpakModule | json:"user" |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
createRepo
Generate a command to add a Flatpak remote repository.
Add appropriate flags for system-wide or user-specific installation.
Parameters
Returns
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)
}
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.
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")
}
main
func main()
{ fmt.Println("This plugin is not meant to run standalone!") }
GoModule
Configuration for building a Go module
type GoModule struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | json:"name" |
| Type | string | json:"type" |
| Source | api.Source | |
| BuildVars | map[string]string | |
| BuildFlags | string |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
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.
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)
}
main
func main()
{ fmt.Println("This plugin is not meant to run standalone!") }
MakeModule
Configuration for building a project using Make
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" |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
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.
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)
}
main
func main()
{ fmt.Println("This plugin is not meant to run standalone!") }
MesonModule
Configuration for building a Meson project
type MesonModule struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | |
| Type | string | |
| BuildFlags | []string | json:"buildflags" |
| Sources | []api.Source | json"sources" |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
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.
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)
}
main
func main()
{ fmt.Println("This plugin is not meant to run standalone!") }
ShimModule
Configuration for a shim module
type ShimModule struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | json:"name" |
| Type | string | json:"type" |
| ShimType | string | json:"shimtype" |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
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.
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))
}
main
func main()
{}
AptModule
Configuration for an APT module
type AptModule struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | json:"name" |
| Type | string | json:"type" |
| Options | AptOptions | json:"options" |
| Sources | []api.Source | json:"sources" |
Uses
AptOptions
Options for APT package management
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" |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
BuildModule
Generate an apt-get install command from the provided module and recipe.
Handle package installation and apply appropriate options.
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")
}
main
func main()
{}
CMakeModule
Configuration for a CMake module
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 |
PlugInfo
Provide plugin information as a JSON string
Returns
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))
}
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.
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)
}
main
func main()
{ fmt.Println("This plugin is not meant to run standalone!") }