Skip to content

Commit

Permalink
Add custom output directory support
Browse files Browse the repository at this point in the history
  • Loading branch information
Billy He committed Jun 24, 2019
1 parent 60aa510 commit 68ea220
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 26 deletions.
57 changes: 32 additions & 25 deletions builder/builder.go
Expand Up @@ -14,10 +14,10 @@ import (
)

type dockerBuilder struct {
options *builderOptions
srcPath string
buildPath string
libPaths []string
options *builderOptions
srcPath string
outPath string
libPaths []string
}

func newDockerBuilder(options *builderOptions) *dockerBuilder {
Expand All @@ -30,22 +30,22 @@ func (b *dockerBuilder) build() error {
return err
}

err = b.ensureBuildDirectory()
err = b.ensureOutputDirectory()
if err != nil {
return err
}

err = b.prepareBuildDirectory()
err = b.prepareOutputDirectory()
if err != nil {
return err
}

buildTemplate, err := b.validateBuildDirectory()
shouldBuildTemplate, err := b.validateOutputDirectory()
if err != nil {
return err
}

if buildTemplate {
if shouldBuildTemplate {
err = b.buildTemplate()
if err != nil {
return err
Expand All @@ -65,9 +65,16 @@ func (b *dockerBuilder) ensurePaths() error {
if err != nil {
return fmt.Errorf("unable to determine absolute path for: %+v", b.options.srcPath)
}

b.srcPath = absSrcPath
b.buildPath = filepath.Join(b.srcPath, "_docker-build")

b.outPath = filepath.Join(b.srcPath, "_docker-build")
if len(b.options.outPath) > 0 {
absOutPath, err := filepath.Abs(b.options.outPath)
if err != nil {
return fmt.Errorf("unable to determine absolute path for: %+v", b.options.srcPath)
}
b.outPath = absOutPath
}

b.libPaths = make([]string, 0)
for _, libPath := range b.options.libPaths {
Expand All @@ -81,46 +88,46 @@ func (b *dockerBuilder) ensurePaths() error {
return nil
}

func (b *dockerBuilder) ensureBuildDirectory() error {
err := os.RemoveAll(b.buildPath)
func (b *dockerBuilder) ensureOutputDirectory() error {
err := os.RemoveAll(b.outPath)
if err != nil {
return err
}

err = os.MkdirAll(b.buildPath, 0755)
err = os.MkdirAll(b.outPath, 0755)
if err != nil {
return err
}

return nil
}

func (b *dockerBuilder) prepareBuildDirectory() error {
func (b *dockerBuilder) prepareOutputDirectory() error {
if _, err := os.Stat(filepath.Join(b.srcPath, "Dockerfile.template")); err == nil {
// If Dockerfile.template exists, then copy it over.
if err = copy.Copy(filepath.Join(b.srcPath, "Dockerfile.template"), filepath.Join(b.buildPath, "Dockerfile.template")); err != nil {
if err = copy.Copy(filepath.Join(b.srcPath, "Dockerfile.template"), filepath.Join(b.outPath, "Dockerfile.template")); err != nil {
return err
}
} else {
// If Dockerfile.template doesn't exist ...
if _, err := os.Stat(filepath.Join(b.srcPath, "Dockerfile")); err == nil {
// ... but Dockerfile exists, then copy Dockerfile over ...
if err = copy.Copy(filepath.Join(b.srcPath, "Dockerfile"), filepath.Join(b.buildPath, "Dockerfile")); err != nil {
if err = copy.Copy(filepath.Join(b.srcPath, "Dockerfile"), filepath.Join(b.outPath, "Dockerfile")); err != nil {
return err
}
}
}

if _, err := os.Stat(filepath.Join(b.srcPath, "src")); err == nil {
if err = copy.Copy(filepath.Join(b.srcPath, "src"), filepath.Join(b.buildPath, "src")); err != nil {
if err = copy.Copy(filepath.Join(b.srcPath, "src"), filepath.Join(b.outPath, "src")); err != nil {
return err
}
}

return nil
}

func (b *dockerBuilder) validateBuildDirectory() (bool, error) {
func (b *dockerBuilder) validateOutputDirectory() (bool, error) {
hasDockerfileTemplate := false
hasDockerfile := false

Expand All @@ -142,7 +149,7 @@ func (b *dockerBuilder) validateBuildDirectory() (bool, error) {
}

func (b *dockerBuilder) buildTemplate() error {
dockerfileTemplate, err := readFileToString(filepath.Join(b.buildPath, "Dockerfile.template"))
dockerfileTemplate, err := readFileToString(filepath.Join(b.outPath, "Dockerfile.template"))
if err != nil {
return err
}
Expand All @@ -156,7 +163,7 @@ func (b *dockerBuilder) buildTemplate() error {
for _, libPath := range b.libPaths {
libFilePath := filepath.Join(libPath, pathString)
if _, err := os.Stat(libFilePath); err == nil {
err = copy.Copy(libFilePath, filepath.Join(b.buildPath, pathString))
err = copy.Copy(libFilePath, filepath.Join(b.outPath, pathString))
if err != nil {
return err
}
Expand Down Expand Up @@ -190,7 +197,7 @@ func (b *dockerBuilder) buildTemplate() error {
dockerfileTemplate = strings.ReplaceAll(dockerfileTemplate, templateString, valueString)
}

return writeStringToFile(filepath.Join(b.buildPath, "Dockerfile"), dockerfileTemplate)
return writeStringToFile(filepath.Join(b.outPath, "Dockerfile"), dockerfileTemplate)
}

func (b *dockerBuilder) readAllVariables() (map[string]string, error) {
Expand Down Expand Up @@ -286,15 +293,15 @@ func (b *dockerBuilder) readFragmentVariables() (map[string]string, error) {
}

func (b *dockerBuilder) buildImage() error {
err := os.RemoveAll(filepath.Join(b.buildPath, "Dockerfile.template"))
err := os.RemoveAll(filepath.Join(b.outPath, "Dockerfile.template"))
if err != nil {
return err
}

if b.options.dryRun {
buildCommand := fmt.Sprintf("docker build %+v %+v", strings.Join(b.options.buildOpts, " "), b.buildPath)
buildCommand := fmt.Sprintf("docker build %+v %+v", strings.Join(b.options.buildOpts, " "), b.outPath)

dockerFile, err := readFileToString(filepath.Join(b.buildPath, "Dockerfile"))
dockerFile, err := readFileToString(filepath.Join(b.outPath, "Dockerfile"))
if err != nil {
return err
}
Expand All @@ -305,7 +312,7 @@ func (b *dockerBuilder) buildImage() error {
} else {
dockerOptions := []string{"build"}
dockerOptions = append(dockerOptions, b.options.buildOpts...)
dockerOptions = append(dockerOptions, b.buildPath)
dockerOptions = append(dockerOptions, b.outPath)

cmd := exec.Command("docker", dockerOptions...)
cmd.Stdout = os.Stdout
Expand Down
7 changes: 6 additions & 1 deletion builder/options.go
Expand Up @@ -12,6 +12,7 @@ type builderOptions struct {
srcPath string
libPaths []string
buildOpts []string
outPath string
}

type stringsFlag []string
Expand All @@ -31,10 +32,11 @@ func (v *stringsFlag) Set(value string) error {
func helpMessage() string {
return strings.Join([]string{
"Usage:",
" $ docker-builder -src [SOURCE PATH] (-lib [LIB PATH])* (-dry)? -- [BUILD OPTIONS]",
" $ docker-builder -src [SOURCE PATH] (-lib [LIB PATH])* (-out [OUT PATH])? (-dry)? -- [BUILD OPTIONS]",
"Example:",
" $ docker-builder \\",
" -src path/to/image/dir \\",
" -out path/to/output/dir \\",
" -lib path/to/lib \\",
" -lib path/to/another/lib \\",
" -- -t my/image:tag",
Expand All @@ -44,11 +46,13 @@ func helpMessage() string {
func parseOptions(args []string) (*builderOptions, error) {
var dryRunFlag bool
var srcPathFlag string
var outPathFlag string
var libPathFlags stringsFlag

flags := flag.NewFlagSet(args[0], flag.ExitOnError)
flags.BoolVar(&dryRunFlag, "dry", false, "dry run")
flags.StringVar(&srcPathFlag, "src", "", "source directory")
flags.StringVar(&outPathFlag, "out", "", "output directory")
flags.Var(&libPathFlags, "lib", "lib directory")

err := flags.Parse(args[1:])
Expand All @@ -73,6 +77,7 @@ func parseOptions(args []string) (*builderOptions, error) {
return &builderOptions{
dryRun: dryRunFlag,
srcPath: trimString(srcPathFlag),
outPath: trimString(outPathFlag),
libPaths: libPaths,
buildOpts: buildOpts,
}, nil
Expand Down
11 changes: 11 additions & 0 deletions builder/options_test.go
Expand Up @@ -15,6 +15,17 @@ func TestOptions(t *testing.T) {
}
})

t.Run("parse output directory option", func(t *testing.T) {
opts, err := parseOptions([]string{"", "-out", "path/to/out"})
if err != nil {
t.Fatalf("failed to parse options: %+v", err)
}

if opts.outPath != "path/to/out" {
t.Fatalf("unexpected output directory option: %+v", opts.outPath)
}
})

t.Run("parse lib directory option", func(t *testing.T) {
opts, err := parseOptions([]string{"", "-lib", "path/to/lib"})
if err != nil {
Expand Down

0 comments on commit 68ea220

Please sign in to comment.