init function

Initialize the root command with build, test, and compile commands

Show/Hide Function Body
{
	rootCmd.AddCommand(NewBuildCommand())
	rootCmd.AddCommand(NewTestCommand())
	rootCmd.AddCommand(NewCompileCommand())
}

Execute function

Execute the root command, handling root user environment setup and privilege dropping

Returns:

  • error
Show/Hide Function Body
{
	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()
}

NewTestCommand function

Create and return a new test command for the Cobra CLI

Returns:

  • *cobra.Command
Show/Hide Function Body
{
	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
}

testCommand function

Validate the provided recipe by testing it

Parameters:

  • cmd *cobra.Command
  • args []string

Returns:

  • error
Show/Hide Function Body
{
	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
}

NewBuildCommand function

Create a new build command for the Cobra CLI

Returns: new Cobra command for building a recipe

Returns:

  • *cobra.Command
Show/Hide Function Body
{
	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
}

buildCommand function

Handle the build command for the Cobra CLI

Parameters:

  • cmd *cobra.Command
  • args []string

Returns:

  • error
Show/Hide Function Body
{
	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
}

NewCompileCommand function

Create and return a new compile command for the Cobra CLI

Returns:

  • *cobra.Command
Show/Hide Function Body
{
	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
}

compileCommand function

Execute the compile command: compile the given recipe into a container image

Parameters:

  • cmd *cobra.Command
  • args []string

Returns:

  • error
Show/Hide Function Body
{
	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
}

detectRuntime function

Detect the container runtime by checking the system path

Returns: runtime name or an empty string if no runtime is found

Returns:

  • string
Show/Hide Function Body
{
	path, _ := exec.LookPath("docker")
	if path != "" {
		return "docker"
	}

	path, _ = exec.LookPath("podman")
	if path != "" {
		return "podman"
	}

	return ""
}

fmt import

Import example:

import "fmt"

os import

Import example:

import "os"

path/filepath import

Import example:

import "path/filepath"

strconv import

Import example:

import "strconv"

syscall import

Import example:

import "syscall"

github.com/spf13/cobra import

Import example:

import "github.com/spf13/cobra"

fmt import

Import example:

import "fmt"

github.com/spf13/cobra import

Import example:

import "github.com/spf13/cobra"

github.com/vanilla-os/vib/core import

Import example:

import "github.com/vanilla-os/vib/core"

errors import

Import example:

import "errors"

fmt import

Import example:

import "fmt"

os import

Import example:

import "os"

path/filepath import

Import example:

import "path/filepath"

strings import

Import example:

import "strings"

github.com/spf13/cobra import

Import example:

import "github.com/spf13/cobra"

github.com/vanilla-os/vib/core import

Import example:

import "github.com/vanilla-os/vib/core"

fmt import

Import example:

import "fmt"

os import

Import example:

import "os"

os/exec import

Import example:

import "os/exec"

github.com/spf13/cobra import

Import example:

import "github.com/spf13/cobra"

github.com/vanilla-os/vib/core import

Import example:

import "github.com/vanilla-os/vib/core"