Create a new build command for the Cobra CLI
Returns: new Cobra command for building a recipe
{
cmd := &cobra.Command{
Use: "build",
Short: "Build the given recipe",
Long: "Build the given Vib recipe into a Containerfile",
Example: ` Using the recipe.yml/yaml or vib.yml/yaml file in the current directory:
vib build
To specify a recipe file, use:
vib build /path/to/recipe.yml`,
RunE: buildCommand,
}
cmd.Flags().SetInterspersed(false)
return cmd
}
Handle the build command for the Cobra CLI
{
commonNames := []string{
"recipe.yml",
"recipe.yaml",
"vib.yml",
"vib.yaml",
}
var recipePath string
if len(args) == 0 {
for _, name := range commonNames {
if _, err := os.Stat(name); err == nil {
recipePath = name
break
}
}
} else {
recipePath = args[0]
/*
Check whether the provided file has either yml or yaml extension,
if not, then return an error
Operations on recipePath:
1. Get the recipePath extension, then
2. Trim the left dot(.) and
3. Convert the extension to lower case.
Covers the following:
1. filename.txt - Invalid extension
2. filename. - No extension
3. filename - No extension
4. filename.YAML or filename.YML - uppercase extension
*/
extension := strings.ToLower(strings.TrimLeft(filepath.Ext(recipePath), "."))
if len(extension) == 0 || (extension != "yml" && extension != "yaml") {
return fmt.Errorf("%s is an invalid recipe file", recipePath)
}
// Check whether the provided file exists, if not, then return an error
if _, err := os.Stat(recipePath); errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("%s does not exist", recipePath)
}
}
if recipePath == "" {
return fmt.Errorf("missing recipe path")
}
_, err := core.BuildRecipe(recipePath)
if err != nil {
return err
}
return nil
}
Create and return a new compile command for the Cobra CLI
{
cmd := &cobra.Command{
Use: "compile",
Short: "Compile the given recipe",
Long: "Compile the given Vib recipe into a working container image, using the specified runtime (docker/podman)",
Example: ` vib compile // using the recipe in the current directory and the system's default runtime
vib compile --runtime podman // using the recipe in the current directory and Podman as the runtime
vib compile /path/to/recipe.yml --runtime podman // using the recipe at the specified path and Podman as the runtime
Both docker and podman are supported as runtimes. If none is specified, the detected runtime will be used, giving priority to Docker.`,
RunE: compileCommand,
}
cmd.Flags().StringP("runtime", "r", "", "The runtime to use (docker/podman)")
cmd.Flags().SetInterspersed(false)
return cmd
}
Execute the compile command: compile the given recipe into a container image
{
commonNames := []string{
"recipe.yml",
"recipe.yaml",
"vib.yml",
"vib.yaml",
}
var recipePath string
var runtime string
runtime, _ = cmd.Flags().GetString("runtime")
if len(args) == 0 {
for _, name := range commonNames {
if _, err := os.Stat(name); err == nil {
recipePath = name
break
}
}
} else {
recipePath = args[0]
}
if recipePath == "" {
return fmt.Errorf("missing recipe path")
}
detectedRuntime := detectRuntime()
if runtime == "" && detectedRuntime == "" {
return fmt.Errorf("missing runtime, and no one was detected")
} else if runtime == "" {
runtime = detectedRuntime
}
err := core.CompileRecipe(recipePath, runtime, IsRoot, OrigGID, OrigUID)
if err != nil {
return err
}
return nil
}
Detect the container runtime by checking the system path
Returns: runtime name or an empty string if no runtime is found
{
path, _ := exec.LookPath("docker")
if path != "" {
return "docker"
}
path, _ = exec.LookPath("podman")
if path != "" {
return "podman"
}
return ""
}
Initialize the root command with build, test, and compile commands
{
rootCmd.AddCommand(NewBuildCommand())
rootCmd.AddCommand(NewTestCommand())
rootCmd.AddCommand(NewCompileCommand())
}
Execute the root command, handling root user environment setup and privilege dropping
{
if os.Getuid() == 0 {
IsRoot = true
gid, err := strconv.Atoi(os.Getenv("SUDO_GID"))
if err != nil {
return fmt.Errorf("failed to get user uid through SUDO_UID: %s", err.Error())
}
OrigGID = gid // go moment??
uid, err := strconv.Atoi(os.Getenv("SUDO_UID"))
if err != nil {
return fmt.Errorf("failed to get user uid through SUDO_GID: %s", err.Error())
}
OrigUID = uid
user := os.Getenv("SUDO_USER")
os.Setenv("HOME", filepath.Join("/home", user))
err = syscall.Seteuid(OrigUID)
if err != nil {
fmt.Println("WARN: Failed to drop root privileges")
}
err = syscall.Setgid(OrigGID)
if err != nil {
fmt.Println("WARN: Failed to drop root privileges")
}
}
return rootCmd.Execute()
}
Create and return a new test command for the Cobra CLI
{
cmd := &cobra.Command{
Use: "test",
Short: "Test the given recipe",
Long: "Test the given Vib recipe to check if it's valid",
RunE: testCommand,
}
cmd.Flags().SetInterspersed(false)
return cmd
}
Validate the provided recipe by testing it
{
if len(args) == 0 {
return fmt.Errorf("no recipe path specified")
}
recipePath := args[0]
_, err := core.TestRecipe(recipePath)
if err != nil {
return err
}
return nil
}
import "errors"
import "fmt"
import "os"
import "path/filepath"
import "strings"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/vib/core"
import "fmt"
import "os"
import "os/exec"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/vib/core"
import "fmt"
import "os"
import "path/filepath"
import "strconv"
import "syscall"
import "github.com/spf13/cobra"
import "fmt"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/vib/core"