Skip to content

Commit

Permalink
Add build command
Browse files Browse the repository at this point in the history
  • Loading branch information
errordeveloper committed Jul 2, 2020
1 parent 9525d17 commit 6d89cef
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 8 deletions.
151 changes: 151 additions & 0 deletions cmd/build/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package build

import (
"fmt"
"os"
"path/filepath"

"github.com/spf13/cobra"

"github.com/errordeveloper/imagine/pkg/buildx"
"github.com/errordeveloper/imagine/pkg/git"
"github.com/errordeveloper/imagine/pkg/rebuilder"
"github.com/errordeveloper/imagine/pkg/recipe"
"github.com/errordeveloper/imagine/pkg/registry"
)

type Flags struct {
Name string
Dir string
Registries []string
Root bool
Test bool
Builder string
Force bool
Cleanup bool
}

const (
baseBranch = "origin/master"
dockerfile = "Dockerfile"
)

func BuildCmd() *cobra.Command {

flags := &Flags{}

cmd := &cobra.Command{
Use: "build",
//Args: cobra.NoArgs(),
RunE: func(cmd *cobra.Command, _ []string) error {
if err := flags.InitBuildCmd(cmd); err != nil {
return err
}
return flags.RunBuildCmd()
},
}

cmd.Flags().StringVarP(&flags.Builder, "builder", "", "", "name of buildx builder")
cmd.MarkFlagRequired("builder")

cmd.Flags().StringVarP(&flags.Name, "name", "", "", "name of the image")
cmd.MarkFlagRequired("name")

cmd.Flags().StringVarP(&flags.Dir, "base", "", "", "base directory of image")
cmd.MarkFlagRequired("base")

cmd.Flags().StringArrayVarP(&flags.Registries, "registry", "", []string{}, "registry prefixes to use for tags")
cmd.MarkFlagRequired("registry")

cmd.Flags().BoolVarP(&flags.Root, "root", "", false, "where to use repo root as build context instead of base direcory")
cmd.Flags().BoolVarP(&flags.Test, "test", "", false, "whether to test image first (depends on 'test' build stage being defined)")
cmd.Flags().BoolVarP(&flags.Force, "force", "", false, "force rebuild the image")
cmd.Flags().BoolVarP(&flags.Cleanup, "cleanup", "", false, "cleanup generated manifest file")

return cmd
}

func (f *Flags) InitBuildCmd(cmd *cobra.Command) error {
return nil
}

func (f *Flags) RunBuildCmd() error {
g, err := git.NewFromCWD()
if err != nil {
return err
}

ir := &recipe.ImagineRecipe{
Name: f.Name,
HasTests: f.Test,
}

if f.Root {
ir.Scope = &recipe.ImageScopeRootDir{
Git: g,
RootDir: g.TopLevel,

RelativeDockerfilePath: filepath.Join(f.Dir, dockerfile),

WithoutSuffix: true, // TODO: add a flag
BaseBranch: baseBranch, // TODO: add a flag
}
} else {
ir.Scope = &recipe.ImageScopeSubDir{
Git: g,
RootDir: g.TopLevel,

RelativeImageDirPath: f.Dir,
Dockerfile: dockerfile,

WithoutSuffix: true, // TODO: add a flag
BaseBranch: baseBranch, // TODO: add a flag
}
}

// TODO implement usefull cheks:
// - presence of Dockerfile.dockerignore in the same direcory

m, err := ir.ToBakeManifest(f.Registries...)
if err != nil {
return err
}

rb := rebuilder.Rebuilder{
RegistryAPI: &registry.Registry{},
}

rebuild, reason, err := rb.ShouldRebuild(m)
if err != nil {
return err
}
if f.Force {
rebuild = true
reason = "forcing image rebuild"
}
if !rebuild {
fmt.Println("no need to rebuild")
return nil
}
fmt.Println(reason)

filename := fmt.Sprintf("buildx-%s.json", f.Name)
fmt.Printf("writing manifest to %q\n", filename)
if err := m.WriteFile(filename); err != nil {
return err
}

bx := buildx.Buildx{
Builder: f.Builder,
}
if err := bx.Bake(filename); err != nil {
return err
}
if f.Cleanup {
fmt.Printf("removing %q\n", filename)
if err := os.RemoveAll(filename); err != nil {
return err
}
}
return nil
}
2 changes: 2 additions & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"github.com/spf13/cobra"

"github.com/errordeveloper/imagine/cmd/build"
"github.com/errordeveloper/imagine/cmd/generate"
)

Expand All @@ -12,4 +13,5 @@ func Root(root *Command) {
root.Use = "imagine"
// root.Args = cobra.NoArgs()
root.AddCommand(generate.GenerateCmd())
root.AddCommand(build.BuildCmd())
}
27 changes: 19 additions & 8 deletions cmd/generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ type Flags struct {
Test bool
}

const (
baseBranch = "origin/master"
dockerfile = "Dockerfile"
)

func GenerateCmd() *cobra.Command {

flags := &Flags{}
Expand Down Expand Up @@ -65,18 +70,24 @@ func (f *Flags) RunGenerateCmd() error {

if f.Root {
ir.Scope = &recipe.ImageScopeRootDir{
Git: g,
RootDir: g.TopLevel,
WithoutSuffix: true, // TODO: add a flag
RelativeDockerfilePath: filepath.Join(f.Dir, "Dockerfile"),
Git: g,
RootDir: g.TopLevel,

RelativeDockerfilePath: filepath.Join(f.Dir, dockerfile),

WithoutSuffix: true, // TODO: add a flag
BaseBranch: baseBranch, // TODO: add a flag
}
} else {
ir.Scope = &recipe.ImageScopeSubDir{
Git: g,
RootDir: g.TopLevel,
Git: g,
RootDir: g.TopLevel,

RelativeImageDirPath: f.Dir,
WithoutSuffix: true, // TODO: add a flag
Dockerfile: "Dockerfile",
Dockerfile: dockerfile,

WithoutSuffix: true, // TODO: add a flag
BaseBranch: baseBranch, // TODO: add a flag
}
}

Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKv
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
Expand Down
60 changes: 60 additions & 0 deletions pkg/buildx/buildx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package buildx

import (
"fmt"
"math/rand"
"os"
"os/exec"
"time"
)

var r = rand.New(rand.NewSource(time.Now().UnixNano()))

func builderName() string {
const length = 12
const chars = "abcdef0123456789"

randomName := make([]byte, length)
for i := 0; i < length; i++ {
randomName[i] = chars[r.Intn(len(chars))]
}
return fmt.Sprintf("imagine_%s", string(randomName))
}

type Buildx struct {
Builder string
}

func (x *Buildx) mkCmd(cmd string, args ...string) *exec.Cmd {
return exec.Command("docker", append([]string{"buildx", cmd}, args...)...)
}

func New() *Buildx {
return &Buildx{
Builder: builderName(),
}
}

func (x *Buildx) Bake(filename string, args ...string) error {
cmd := x.mkCmd("bake", append([]string{"--builder", x.Builder, "--file", filename}, args...)...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
fmt.Printf("runing %q\n", cmd.String())
return cmd.Run()
}

func (x *Buildx) Create() error {
cmd := x.mkCmd("create", "--name", x.Builder)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

return cmd.Run()
}

func (x *Buildx) Delete() error {
cmd := x.mkCmd("rm", x.Builder)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

return cmd.Run()
}

0 comments on commit 6d89cef

Please sign in to comment.