2013-09-28 23:08:21 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2016-11-18 16:48:03 +00:00
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/hex"
|
2014-09-05 21:48:02 +00:00
|
|
|
"encoding/json"
|
2013-09-28 23:08:21 +00:00
|
|
|
"flag"
|
|
|
|
"fmt"
|
2016-11-18 16:48:03 +00:00
|
|
|
"io"
|
2015-10-28 16:59:36 +00:00
|
|
|
"io/ioutil"
|
2015-05-11 14:40:15 +00:00
|
|
|
"log"
|
2013-09-28 23:08:21 +00:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
2015-09-10 17:06:48 +00:00
|
|
|
"runtime"
|
2013-09-28 23:08:21 +00:00
|
|
|
"strings"
|
2015-05-13 19:43:41 +00:00
|
|
|
|
2016-11-15 17:01:18 +00:00
|
|
|
"github.com/git-lfs/git-lfs/config"
|
2013-09-28 23:08:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2017-10-07 16:17:03 +00:00
|
|
|
BuildOS = flag.String("os", "", "OS to target: darwin,freebsd,linux,windows")
|
|
|
|
BuildArch = flag.String("arch", "", "Arch to target: 386,amd64")
|
2017-07-31 20:14:41 +00:00
|
|
|
BuildAll = flag.Bool("all", false, "Builds all architectures")
|
|
|
|
BuildDwarf = flag.Bool("dwarf", false, "Includes DWARF tables in build artifacts")
|
|
|
|
BuildLdFlags = flag.String("ldflags", "", "-ldflags to pass to the compiler")
|
2017-07-31 20:14:51 +00:00
|
|
|
BuildGcFlags = flag.String("gcflags", "", "-gcflags to pass to the compiler")
|
2017-07-31 20:14:41 +00:00
|
|
|
ShowHelp = flag.Bool("help", false, "Shows help")
|
|
|
|
matrixKeys = map[string]string{
|
2014-09-05 21:48:02 +00:00
|
|
|
"darwin": "Mac",
|
|
|
|
"freebsd": "FreeBSD",
|
|
|
|
"linux": "Linux",
|
|
|
|
"windows": "Windows",
|
|
|
|
"amd64": "AMD64",
|
|
|
|
}
|
2017-02-14 00:22:33 +00:00
|
|
|
LdFlags []string
|
2013-09-28 23:08:21 +00:00
|
|
|
)
|
|
|
|
|
2014-09-05 23:28:14 +00:00
|
|
|
func mainBuild() {
|
2013-09-28 23:08:21 +00:00
|
|
|
if *ShowHelp {
|
2014-05-22 23:08:14 +00:00
|
|
|
fmt.Println("usage: script/bootstrap [-os] [-arch] [-all]")
|
2013-09-28 23:08:21 +00:00
|
|
|
flag.PrintDefaults()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-09-10 17:06:48 +00:00
|
|
|
fmt.Printf("Using %s\n", runtime.Version())
|
|
|
|
|
2015-09-14 11:33:59 +00:00
|
|
|
genOut, err := exec.Command("go", "generate", "./commands").CombinedOutput()
|
|
|
|
if err != nil {
|
2015-09-15 09:08:21 +00:00
|
|
|
fmt.Fprintf(os.Stderr, "go generate failed:\n%v", string(genOut))
|
2015-09-14 11:33:59 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
2015-07-31 14:49:30 +00:00
|
|
|
cmd, _ := exec.Command("git", "rev-parse", "--short", "HEAD").Output()
|
2015-07-28 22:05:15 +00:00
|
|
|
|
|
|
|
if len(cmd) > 0 {
|
2017-02-14 00:22:33 +00:00
|
|
|
LdFlags = append(LdFlags, "-X", strings.TrimSpace(
|
|
|
|
"github.com/git-lfs/git-lfs/config.GitCommit="+string(cmd),
|
|
|
|
))
|
2015-07-28 22:05:15 +00:00
|
|
|
}
|
2017-02-14 16:24:07 +00:00
|
|
|
if !*BuildDwarf {
|
2017-02-14 00:23:49 +00:00
|
|
|
LdFlags = append(LdFlags, "-s", "-w")
|
|
|
|
}
|
2014-09-05 21:48:02 +00:00
|
|
|
|
2015-07-28 22:05:15 +00:00
|
|
|
buildMatrix := make(map[string]Release)
|
2014-09-05 21:48:02 +00:00
|
|
|
errored := false
|
|
|
|
|
2017-10-07 16:17:03 +00:00
|
|
|
var platforms, arches []string
|
|
|
|
if len(*BuildOS) > 0 {
|
|
|
|
platforms = strings.Split(*BuildOS, ",")
|
|
|
|
}
|
|
|
|
if len(*BuildArch) > 0 {
|
|
|
|
arches = strings.Split(*BuildArch, ",")
|
|
|
|
}
|
2013-09-28 23:08:21 +00:00
|
|
|
if *BuildAll {
|
2017-10-07 16:17:03 +00:00
|
|
|
platforms = []string{"linux", "darwin", "freebsd", "windows"}
|
|
|
|
arches = []string{"amd64", "386"}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(platforms) < 1 || len(arches) < 1 {
|
|
|
|
if err := build("", "", buildMatrix); err != nil {
|
2015-06-07 15:40:35 +00:00
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
|
|
|
return // skip build matrix stuff
|
2014-09-05 21:48:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-07 16:17:03 +00:00
|
|
|
for _, buildos := range platforms {
|
|
|
|
for _, buildarch := range arches {
|
|
|
|
err := build(strings.TrimSpace(buildos), strings.TrimSpace(buildarch), buildMatrix)
|
|
|
|
if err != nil {
|
|
|
|
errored = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-07 15:40:35 +00:00
|
|
|
if errored {
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
2014-09-05 21:48:02 +00:00
|
|
|
|
2015-06-07 15:40:35 +00:00
|
|
|
by, err := json.Marshal(buildMatrix)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Error encoding build matrix to json:", err)
|
|
|
|
}
|
2014-09-05 21:48:02 +00:00
|
|
|
|
2015-06-07 15:40:35 +00:00
|
|
|
file, err := os.Create("bin/releases/build_matrix.json")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Error creating build_matrix.json:", err)
|
|
|
|
}
|
2014-09-05 21:48:02 +00:00
|
|
|
|
2015-06-07 15:40:35 +00:00
|
|
|
written, err := file.Write(by)
|
|
|
|
file.Close()
|
2014-09-05 21:48:02 +00:00
|
|
|
|
2015-06-07 15:40:35 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Error writing build_matrix.json", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if jsonSize := len(by); written != jsonSize {
|
|
|
|
log.Fatalf("Expected to write %d bytes, actually wrote %d.\n", jsonSize, written)
|
2013-09-28 23:08:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-05 21:48:02 +00:00
|
|
|
func build(buildos, buildarch string, buildMatrix map[string]Release) error {
|
2013-11-05 23:15:21 +00:00
|
|
|
addenv := len(buildos) > 0 && len(buildarch) > 0
|
2016-05-13 16:43:04 +00:00
|
|
|
name := "git-lfs-" + config.Version
|
2013-11-05 23:15:21 +00:00
|
|
|
dir := "bin"
|
|
|
|
|
|
|
|
if addenv {
|
2013-09-28 23:08:21 +00:00
|
|
|
fmt.Printf("Building for %s/%s\n", buildos, buildarch)
|
2013-11-06 00:41:31 +00:00
|
|
|
dir = filepath.Join(dir, "releases", buildos+"-"+buildarch, name)
|
2013-09-28 23:08:21 +00:00
|
|
|
}
|
|
|
|
|
2015-06-07 15:40:35 +00:00
|
|
|
if err := buildCommand(dir, buildos, buildarch); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2013-09-28 23:08:21 +00:00
|
|
|
|
|
|
|
if addenv {
|
2014-05-22 23:29:55 +00:00
|
|
|
err := os.MkdirAll(dir, 0755)
|
|
|
|
if err != nil {
|
2015-05-11 14:40:15 +00:00
|
|
|
log.Println("Error setting up installer:\n", err.Error())
|
2014-09-05 21:48:02 +00:00
|
|
|
return err
|
2014-05-22 23:29:55 +00:00
|
|
|
}
|
|
|
|
|
2014-09-05 21:48:02 +00:00
|
|
|
err = setupInstaller(buildos, buildarch, dir, buildMatrix)
|
2013-11-05 23:50:21 +00:00
|
|
|
if err != nil {
|
2015-05-11 14:40:15 +00:00
|
|
|
log.Println("Error setting up installer:\n", err.Error())
|
2014-09-05 21:48:02 +00:00
|
|
|
return err
|
2013-11-05 23:50:21 +00:00
|
|
|
}
|
2013-09-28 23:08:21 +00:00
|
|
|
}
|
2014-09-05 21:48:02 +00:00
|
|
|
|
|
|
|
return nil
|
2013-11-05 23:15:21 +00:00
|
|
|
}
|
2013-09-28 23:08:21 +00:00
|
|
|
|
2015-05-25 18:30:14 +00:00
|
|
|
func buildCommand(dir, buildos, buildarch string) error {
|
2013-11-05 23:15:21 +00:00
|
|
|
addenv := len(buildos) > 0 && len(buildarch) > 0
|
|
|
|
|
2015-05-25 18:30:14 +00:00
|
|
|
bin := filepath.Join(dir, "git-lfs")
|
2013-11-05 21:42:53 +00:00
|
|
|
|
2013-11-05 23:35:05 +00:00
|
|
|
if buildos == "windows" {
|
|
|
|
bin = bin + ".exe"
|
|
|
|
}
|
|
|
|
|
2015-07-28 22:23:28 +00:00
|
|
|
args := make([]string, 1, 6)
|
2015-07-28 22:05:15 +00:00
|
|
|
args[0] = "build"
|
2017-07-31 20:14:41 +00:00
|
|
|
if len(*BuildLdFlags) > 0 {
|
|
|
|
args = append(args, "-ldflags", *BuildLdFlags)
|
|
|
|
} else if len(LdFlags) > 0 {
|
2017-02-14 00:22:33 +00:00
|
|
|
args = append(args, "-ldflags", strings.Join(LdFlags, " "))
|
2015-07-28 22:05:15 +00:00
|
|
|
}
|
2017-07-31 20:14:51 +00:00
|
|
|
|
|
|
|
if len(*BuildGcFlags) > 0 {
|
|
|
|
args = append(args, "-gcflags", *BuildGcFlags)
|
|
|
|
}
|
|
|
|
|
2015-07-28 22:05:15 +00:00
|
|
|
args = append(args, "-o", bin, ".")
|
|
|
|
|
|
|
|
cmd := exec.Command("go", args...)
|
2013-09-28 23:08:21 +00:00
|
|
|
if addenv {
|
2016-02-02 22:45:52 +00:00
|
|
|
cmd.Env = buildGoEnv(buildos, buildarch)
|
2013-09-28 23:08:21 +00:00
|
|
|
}
|
|
|
|
|
2013-11-06 00:20:30 +00:00
|
|
|
output, err := cmd.CombinedOutput()
|
|
|
|
if len(output) > 0 {
|
|
|
|
fmt.Println(string(output))
|
2013-09-28 23:08:21 +00:00
|
|
|
}
|
2013-11-06 00:20:30 +00:00
|
|
|
return err
|
2013-09-28 23:08:21 +00:00
|
|
|
}
|
2013-11-05 23:15:21 +00:00
|
|
|
|
2016-02-02 22:46:57 +00:00
|
|
|
func buildGoEnv(buildos, buildarch string) []string {
|
2016-02-23 16:51:12 +00:00
|
|
|
env := make([]string, 6, 9)
|
2016-02-02 22:46:57 +00:00
|
|
|
env[0] = "GOOS=" + buildos
|
|
|
|
env[1] = "GOARCH=" + buildarch
|
2016-02-02 22:45:52 +00:00
|
|
|
env[2] = "GOPATH=" + os.Getenv("GOPATH")
|
|
|
|
env[3] = "GOROOT=" + os.Getenv("GOROOT")
|
2016-02-22 18:29:05 +00:00
|
|
|
env[4] = "PATH=" + os.Getenv("PATH")
|
2016-02-23 16:51:12 +00:00
|
|
|
env[5] = "GO15VENDOREXPERIMENT=" + os.Getenv("GO15VENDOREXPERIMENT")
|
2016-02-02 22:45:52 +00:00
|
|
|
for _, key := range []string{"TMP", "TEMP", "TEMPDIR"} {
|
|
|
|
v := os.Getenv(key)
|
|
|
|
if len(v) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
env = append(env, key+"="+v)
|
|
|
|
}
|
|
|
|
return env
|
|
|
|
}
|
|
|
|
|
2014-09-05 21:48:02 +00:00
|
|
|
func setupInstaller(buildos, buildarch, dir string, buildMatrix map[string]Release) error {
|
2015-10-28 16:59:36 +00:00
|
|
|
textfiles := []string{
|
2015-09-10 17:06:48 +00:00
|
|
|
"README.md", "CHANGELOG.md",
|
|
|
|
}
|
|
|
|
|
2015-10-28 16:59:36 +00:00
|
|
|
if buildos == "windows" {
|
|
|
|
return winInstaller(textfiles, buildos, buildarch, dir, buildMatrix)
|
|
|
|
} else {
|
|
|
|
return unixInstaller(textfiles, buildos, buildarch, dir, buildMatrix)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func unixInstaller(textfiles []string, buildos, buildarch, dir string, buildMatrix map[string]Release) error {
|
|
|
|
for _, filename := range textfiles {
|
2015-09-10 17:06:48 +00:00
|
|
|
cmd := exec.Command("cp", filename, filepath.Join(dir, filename))
|
|
|
|
if err := logAndRun(cmd); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-06 17:49:34 +00:00
|
|
|
fullInstallPath := filepath.Join(dir, "install.sh")
|
|
|
|
cmd := exec.Command("cp", "script/install.sh.example", fullInstallPath)
|
2013-11-05 23:50:21 +00:00
|
|
|
if err := logAndRun(cmd); err != nil {
|
2013-11-05 23:15:21 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2013-12-06 17:49:34 +00:00
|
|
|
if err := os.Chmod(fullInstallPath, 0755); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2013-11-05 23:50:21 +00:00
|
|
|
name := zipName(buildos, buildarch) + ".tar.gz"
|
2013-11-06 00:40:49 +00:00
|
|
|
cmd = exec.Command("tar", "czf", "../"+name, filepath.Base(dir))
|
2013-11-05 23:15:21 +00:00
|
|
|
cmd.Dir = filepath.Dir(dir)
|
2016-11-18 16:48:03 +00:00
|
|
|
if err := logAndRun(cmd); err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
addToMatrix(buildMatrix, buildos, buildarch, name)
|
|
|
|
return nil
|
2013-11-05 23:50:21 +00:00
|
|
|
}
|
|
|
|
|
2015-10-28 16:59:36 +00:00
|
|
|
func winInstaller(textfiles []string, buildos, buildarch, dir string, buildMatrix map[string]Release) error {
|
|
|
|
for _, filename := range textfiles {
|
|
|
|
by, err := ioutil.ReadFile(filename)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
winEndings := strings.Replace(string(by), "\n", "\r\n", -1)
|
|
|
|
err = ioutil.WriteFile(filepath.Join(dir, filename), []byte(winEndings), 0644)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
installerPath := filepath.Dir(filepath.Dir(dir))
|
|
|
|
name := zipName(buildos, buildarch) + ".zip"
|
|
|
|
full := filepath.Join(installerPath, name)
|
|
|
|
matches, err := filepath.Glob(dir + "/*")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
args := make([]string, len(matches)+2)
|
|
|
|
args[0] = "-j" // junk the zip paths
|
|
|
|
args[1] = full
|
|
|
|
copy(args[2:], matches)
|
|
|
|
|
|
|
|
cmd := exec.Command("zip", args...)
|
2016-11-18 16:48:03 +00:00
|
|
|
if err := logAndRun(cmd); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
addToMatrix(buildMatrix, buildos, buildarch, name)
|
|
|
|
return nil
|
2015-10-28 16:59:36 +00:00
|
|
|
}
|
|
|
|
|
2014-09-05 21:48:02 +00:00
|
|
|
func addToMatrix(buildMatrix map[string]Release, buildos, buildarch, name string) {
|
|
|
|
buildMatrix[fmt.Sprintf("%s-%s", buildos, buildarch)] = Release{
|
|
|
|
Label: releaseLabel(buildos, buildarch),
|
|
|
|
Filename: name,
|
2016-11-18 16:48:03 +00:00
|
|
|
SHA256: hashRelease(name),
|
2014-09-05 21:48:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-18 16:48:03 +00:00
|
|
|
func hashRelease(name string) string {
|
|
|
|
full := filepath.Join("bin/releases", name)
|
|
|
|
file, err := os.Open(full)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("unable to open release %q: %+v\n", full, err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
h := sha256.New()
|
|
|
|
if _, err = io.Copy(h, file); err != nil {
|
|
|
|
fmt.Printf("error reading release %q: %+v\n", full, err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
|
|
}
|
|
|
|
|
2013-11-05 23:50:21 +00:00
|
|
|
func logAndRun(cmd *exec.Cmd) error {
|
|
|
|
fmt.Printf(" - %s\n", strings.Join(cmd.Args, " "))
|
|
|
|
if len(cmd.Dir) > 0 {
|
|
|
|
fmt.Printf(" - in %s\n", cmd.Dir)
|
|
|
|
}
|
|
|
|
|
2013-11-06 00:20:30 +00:00
|
|
|
output, err := cmd.CombinedOutput()
|
|
|
|
fmt.Println(string(output))
|
|
|
|
return err
|
2013-11-05 23:15:21 +00:00
|
|
|
}
|
2013-11-05 23:50:21 +00:00
|
|
|
|
|
|
|
func zipName(os, arch string) string {
|
2016-05-13 16:43:04 +00:00
|
|
|
return fmt.Sprintf("git-lfs-%s-%s-%s", os, arch, config.Version)
|
2013-11-05 23:50:21 +00:00
|
|
|
}
|
2014-09-05 21:48:02 +00:00
|
|
|
|
|
|
|
func releaseLabel(buildos, buildarch string) string {
|
|
|
|
return fmt.Sprintf("%s %s", key(buildos), key(buildarch))
|
|
|
|
}
|
|
|
|
|
|
|
|
func key(k string) string {
|
|
|
|
if s, ok := matrixKeys[k]; ok {
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
return k
|
|
|
|
}
|