Created
August 20, 2014 20:32
-
-
Save spheromak/f7b3212bf5f188bfb35c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"os" | |
"os/exec" | |
"path/filepath" | |
"text/template" | |
"code.google.com/p/go-uuid/uuid" | |
"github.com/jessevdk/go-flags" | |
) | |
type Options struct { | |
Package string `short:"p" long:"package" description:"package to build" env:"PACKAGE" required:"true"` | |
Template string `short:"t" long:"template" description:"Input template to parse will Dockerfile.in in the container dir" env:"TEMPLATE"` | |
Version string `short:"v" long:"version" description:"Major Version" env:"VERSION" required:"true"` | |
Rev string `short:"r" long:"rev" description:"Revsion" env:"REV" default:"0"` | |
Docker string `short:"d" long:"docker-path" description:"Path to the docker binary. We look in $PATH by default" env:"DOCKER_BIN"` | |
OS string | |
BuildOS []string `short:"b" long:"build-os" description:"specify the os's too buld" env:"BUILDOS" env-delim:"," default:"el5" default:"el6" default:"el7"` | |
Cached bool `short:"c" long:"cached" description:"disable/enable layer caching for builds Enabled by default" default:"true" env:"CACHED"` | |
} | |
var opts Options | |
// findbin returns the path to the current runnign binary | |
func FindBin() (dir string) { | |
dir, err := filepath.Abs(filepath.Dir(os.Args[0])) | |
if err != nil { | |
log.Fatal(err) | |
} | |
return | |
} | |
// findDocker looks for docker and bails if it can't find it | |
func findDocker() (path string) { | |
path, err := exec.LookPath("docker") | |
if err != nil { | |
log.Fatal("Couldn't find docker in $PATH use -d to specify the path to docker binary.") | |
} | |
path, _ = filepath.Abs(path) | |
return | |
} | |
// cliDefaults sets the options to default vaules if env or switches haven't specified them | |
// TODO: use go-flags callbacks for these | |
func cliDefaults() { | |
if opts.Template == "" { | |
opts.Template = fmt.Sprintf("%s/%s/Dockerfile.in", FindBin(), opts.Package) | |
} | |
if opts.Version == "" { | |
fmt.Println("Please Specify a version to build") | |
os.Exit(1) | |
} | |
if opts.Docker == "" { | |
opts.Docker = findDocker() | |
} | |
} | |
func main() { | |
// process flags | |
if _, err := flags.Parse(&opts); err != nil { | |
if err.(*flags.Error).Type == flags.ErrHelp { | |
os.Exit(0) | |
} else { | |
log.Println(err.Error()) | |
os.Exit(1) | |
} | |
} | |
cliDefaults() | |
// open template file for processing | |
inputTemplate, err := ioutil.ReadFile(opts.Template) | |
if err != nil { | |
fmt.Println("Template File: ", opts.Template) | |
log.Fatalf("Error reading templatefile: %s \n %s", opts.Template, err.Error()) | |
} | |
// assemble template | |
t := template.Must(template.New("letter").Parse(string(inputTemplate))) | |
// loop over platforms and build | |
for _, platform := range opts.BuildOS { | |
opts.OS = platform | |
buff := new(bytes.Buffer) | |
err := t.Execute(buff, opts) | |
if err != nil { | |
log.Fatalf("Error compiling template: %s\n %s", opts.Template, err.Error()) | |
} | |
// Set CWD to project dir | |
pkgDir := fmt.Sprintf("%s/%s", FindBin(), opts.Package) | |
err = os.Chdir(pkgDir) | |
if err != nil { | |
fmt.Printf("Error chaning directory to %s\n%s", pkgDir, err.Error()) | |
} | |
// TODO: might be able to call this from docker golib direct | |
// This builds the docker container from the compiled template \m/ | |
container := fmt.Sprintf("%s:build_%s", opts.Package, opts.OS) | |
// store and use the generated dockerfile | |
cmd := exec.Command(opts.Docker, "build", "-t", container, "-") | |
cmd.Stdin = buff | |
if opts.Cached == true { | |
// i | |
err = ioutil.WriteFile(fmt.Sprintf("%s/Dockerfile", pkgDir), buff.Bytes(), 0640) | |
if err != nil { | |
log.Fatalf("Error writing generated dockerfile for %s.\n%s", pkgDir, err.Error()) | |
} | |
cmd = exec.Command(opts.Docker, "build", "-t", container, ".") | |
cmd.Stdin = nil | |
} | |
cmd.Stdout = os.Stdout | |
cmd.Stderr = os.Stderr | |
err = cmd.Run() | |
if err != nil { | |
log.Fatalf("Error while building %s-%s-%s\n %s", opts.Package, opts.Version, opts.Rev, err.Error()) | |
} | |
instance := fmt.Sprintf("%s%s", opts.Package, uuid.New()) | |
// start the container so we can get the rpm | |
out, err := exec.Command(opts.Docker, "run", "--name", instance, container).Output() | |
if err != nil { | |
fmt.Println("Issue running instance: ", instance, out) | |
log.Fatal(err) | |
} | |
// pull the package | |
// example instance:/collectd-5.4.1/collectd-5.4.1-1.milt-el6.x86_64.rpm | |
pkgFile := fmt.Sprintf("%s:%s-%s/%s-%s-%s-%s.x86_64.rpm", instance, opts.Package, opts.Version, opts.Package, opts.Version, opts.Rev, opts.OS) | |
out, err = exec.Command(opts.Docker, "cp", pkgFile, FindBin()).Output() | |
if err != nil { | |
fmt.Printf("Issue running %s\n%s\n%s", cmd, out, err.Error()) | |
os.Exit(1) | |
} | |
// stop the container | |
out, err = exec.Command(opts.Docker, "stop", instance).Output() | |
if err != nil { | |
fmt.Printf("Issue tryin to shutdown instance %s\n%s", instance, err.Error()) | |
os.Exit(1) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment