Created
August 21, 2014 04:07
-
-
Save spheromak/fe95fb8c663e9490c84b 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 fatalExec(cmd *exec.Cmd) { | |
cmd.Stdout = os.Stdout | |
cmd.Stderr = os.Stdout | |
fmt.Println("EXEC:", cmd.Args) | |
err := cmd.Run() | |
if err != nil { | |
log.Fatalf("Issue running %s \n%s", cmd.Args, err.Error()) | |
} | |
} | |
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))) | |
binPath := FindBin() | |
// Set CWD to project dir | |
pkgDir := fmt.Sprintf("%s/%s", binPath, opts.Package) | |
err = os.Chdir(pkgDir) | |
if err != nil { | |
fmt.Printf("Error chaning directory to %s\n%s", pkgDir, err.Error()) | |
} | |
// 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()) | |
} | |
// TODO: might be able to call this from docker golib direct | |
// This builds the docker container from the compiled template \m/ | |
// store and use the generated dockerfile | |
container := fmt.Sprintf("%s:build_%s", opts.Package, opts.OS) | |
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 | |
} | |
fatalExec(cmd) | |
// start the container so we can get the rpm | |
instance := fmt.Sprintf("%s%s", opts.Package, uuid.New()) | |
fatalExec(exec.Command(opts.Docker, "run", "--name", instance, container)) | |
// 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.x86_64.rpm", instance, opts.Package, opts.Version, opts.Package, opts.Version, opts.Rev) | |
localFile := fmt.Sprintf("%s/%s-%s-%s.%s.x86_64.rpm", binPath, opts.Package, opts.Version, opts.Rev, opts.OS) | |
fatalExec(exec.Command(opts.Docker, "cp", pkgFile, localFile)) | |
// stop the container | |
fatalExec(exec.Command(opts.Docker, "stop", instance)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment