diff --git a/cmd/build.go b/cmd/build.go index cafbdf5..a61e71c 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -24,7 +24,7 @@ func buildCommand(cmd *cobra.Command, args []string) error { } recipePath := args[0] - err := core.BuildRecipe(recipePath) + _, err := core.BuildRecipe(recipePath) if err != nil { return err } diff --git a/cmd/compile.go b/cmd/compile.go new file mode 100644 index 0000000..588e43a --- /dev/null +++ b/cmd/compile.go @@ -0,0 +1,34 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" + "github.com/vanilla-os/vib/core" +) + +func NewCompileCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "compile", + Short: "Compile a recipe", + RunE: compileCommand, + } + cmd.Flags().SetInterspersed(false) + + return cmd +} + +func compileCommand(cmd *cobra.Command, args []string) error { + if len(args) < 2 { + return fmt.Errorf("no recipe path or runtime specified") + } + + recipePath := args[0] + runtime := args[1] + err := core.CompileRecipe(recipePath, runtime) + if err != nil { + return err + } + + return nil +} diff --git a/cmd/root.go b/cmd/root.go index d3fb3b1..ceddb33 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -12,6 +12,7 @@ var rootCmd = &cobra.Command{ func init() { rootCmd.AddCommand(NewBuildCommand()) rootCmd.AddCommand(NewValidateCommand()) + rootCmd.AddCommand(NewCompileCommand()) } func Execute() error { diff --git a/core/build.go b/core/build.go index a365a00..85c7e8e 100644 --- a/core/build.go +++ b/core/build.go @@ -6,11 +6,11 @@ import ( ) // BuildRecipe builds a Containerfile from a recipe path -func BuildRecipe(recipePath string) error { +func BuildRecipe(recipePath string) (Recipe, error) { // load the recipe recipe, err := LoadRecipe(recipePath) if err != nil { - return err + return Recipe{}, err } fmt.Printf("Building recipe %s\n", recipe.Name) @@ -18,14 +18,14 @@ func BuildRecipe(recipePath string) error { // resolve (and download) the sources modules, sources, err := ResolveSources(recipe) if err != nil { - return err + 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 err + return Recipe{}, err } // build the modules* @@ -33,16 +33,16 @@ func BuildRecipe(recipePath string) error { // in the Containerfile to build the modules cmds, err := BuildModules(recipe, modules) if err != nil { - return err + return Recipe{}, err } // build the Containerfile err = BuildContainerfile(recipe, cmds) if err != nil { - return err + return Recipe{}, err } - return nil + return *recipe, nil } // BuildContainerfile builds a Containerfile from a recipe diff --git a/core/compile.go b/core/compile.go new file mode 100644 index 0000000..ec17965 --- /dev/null +++ b/core/compile.go @@ -0,0 +1,85 @@ +package core + +import ( + "fmt" + "os" + "os/exec" +) + +// CompileRecipe compiles a recipe into a runnable image. +func CompileRecipe(recipePath string, runtime string) error { + recipe, err := BuildRecipe(recipePath) + if err != nil { + return err + } + + storePath := fmt.Sprintf("%s/%s", os.Getenv("HOME"), ".vib/store") + if _, err := os.Stat(storePath); os.IsNotExist(err) { + err = os.MkdirAll(storePath, 0755) + if err != nil { + return err + } + } + + switch runtime { + case "docker": + err = compileDocker(recipe, storePath) + if err != nil { + return err + } + case "podman": + err = compilePodman(recipe, storePath) + if err != nil { + return err + } + case "buildah": + return fmt.Errorf("buildah not implemented yet") + default: + return fmt.Errorf("no runtime specified and the prometheus library is not implemented yet") + } + + fmt.Printf("Image %s built successfully\n", recipe.Id) + fmt.Printf("Remember to point %s to %s\n", runtime, storePath) + + return nil +} + +func compileDocker(recipe Recipe, storePath string) error { + docker, err := exec.LookPath("docker") + if err != nil { + return err + } + + cmd := exec.Command( + docker, "build", + "-t", recipe.Id, + "-f", recipe.Containerfile, + "--root", storePath, + ".", + ) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Dir = recipe.ParentPath + + return cmd.Run() +} + +func compilePodman(recipe Recipe, storePath string) error { + podman, err := exec.LookPath("podman") + if err != nil { + return err + } + + cmd := exec.Command( + podman, "build", + "-t", recipe.Id, + "-f", recipe.Containerfile, + "--root", storePath, + ".", + ) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Dir = recipe.ParentPath + + return cmd.Run() +} diff --git a/core/structs.go b/core/structs.go index 0c1bef7..e338120 100644 --- a/core/structs.go +++ b/core/structs.go @@ -3,6 +3,7 @@ package core type Recipe struct { Base string `json:"base"` Name string + Id string Labels map[string]string `json:"labels"` Args map[string]string `json:"args"` Runs []string `json:"runs"` diff --git a/example/example.yml b/example/example.yml index 7854d2b..9f5a428 100644 --- a/example/example.yml +++ b/example/example.yml @@ -1,5 +1,6 @@ base: debian:sid-slim -name: Vanilla Core +name: Vib Example +id: vib-example labels: maintainer: Vanilla OS Contributors args: