mirror of
https://github.com/restic/rest-server.git
synced 2025-10-19 07:33:21 +00:00
Update build.go
This commit is contained in:
parent
f02ee7386a
commit
cd62c2bceb
1 changed files with 148 additions and 41 deletions
189
build.go
189
build.go
|
@ -6,12 +6,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,15 +23,17 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
var config = struct {
|
var config = struct {
|
||||||
Name string
|
Name string
|
||||||
Namespace string
|
Namespace string
|
||||||
Main string
|
Main string
|
||||||
Tests []string
|
Tests []string
|
||||||
|
MinVersion GoVersion
|
||||||
}{
|
}{
|
||||||
Name: "rest-server", // name of the program executable and directory
|
Name: "rest-server", // name of the program executable and directory
|
||||||
Namespace: "github.com/restic/rest-server", // subdir of GOPATH, e.g. "github.com/foo/bar"
|
Namespace: "github.com/restic/rest-server", // subdir of GOPATH, e.g. "github.com/foo/bar"
|
||||||
Main: "github.com/restic/rest-server/cmd/rest-server", // package name for the main package
|
Main: "github.com/restic/rest-server/cmd/rest-server", // package name for the main package
|
||||||
Tests: []string{"github.com/restic/rest-server"}, // tests to run
|
Tests: []string{"github.com/restic/rest-server"}, // tests to run
|
||||||
|
MinVersion: GoVersion{Major: 1, Minor: 7, Patch: 0}, // minimum Go version supported
|
||||||
}
|
}
|
||||||
|
|
||||||
// specialDir returns true if the file begins with a special character ('.' or '_').
|
// specialDir returns true if the file begins with a special character ('.' or '_').
|
||||||
|
@ -41,7 +43,7 @@ func specialDir(name string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
base := filepath.Base(name)
|
base := filepath.Base(name)
|
||||||
if base[0] == '_' || base[0] == '.' {
|
if base == "vendor" || base[0] == '_' || base[0] == '.' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,20 +65,27 @@ func excludePath(name string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateGopath builds a valid GOPATH at dst, with all Go files in src/ copied to dst/prefix/, so calling
|
// updateGopath builds a valid GOPATH at dst, with all Go files in src/ copied
|
||||||
|
// to dst/prefix/, so calling
|
||||||
//
|
//
|
||||||
// updateGopath("/tmp/gopath", "/home/u/rest-server", "github.com/restic/rest-server")
|
// updateGopath("/tmp/gopath", "/home/u/restic", "github.com/restic/restic")
|
||||||
//
|
//
|
||||||
// with "/home/u/restic" containing the file "foo.go" yields the following tree at "/tmp/gopath":
|
// with "/home/u/restic" containing the file "foo.go" yields the following tree
|
||||||
|
// at "/tmp/gopath":
|
||||||
//
|
//
|
||||||
// /tmp/gopath
|
// /tmp/gopath
|
||||||
// └── src
|
// └── src
|
||||||
// └── github.com
|
// └── github.com
|
||||||
// └── restic
|
// └── restic
|
||||||
// └── rest-server
|
// └── restic
|
||||||
// └── foo.go
|
// └── foo.go
|
||||||
func updateGopath(dst, src, prefix string) error {
|
func updateGopath(dst, src, prefix string) error {
|
||||||
|
verbosePrintf("copy contents of %v to %v\n", src, filepath.Join(dst, prefix))
|
||||||
return filepath.Walk(src, func(name string, fi os.FileInfo, err error) error {
|
return filepath.Walk(src, func(name string, fi os.FileInfo, err error) error {
|
||||||
|
if name == src {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if specialDir(name) {
|
if specialDir(name) {
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
return filepath.SkipDir
|
return filepath.SkipDir
|
||||||
|
@ -85,6 +94,10 @@ func updateGopath(dst, src, prefix string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -125,7 +138,6 @@ func copyFile(dst, src string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fsrc.Close()
|
|
||||||
|
|
||||||
if err = os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
if err = os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||||
fmt.Printf("MkdirAll(%v)\n", filepath.Dir(dst))
|
fmt.Printf("MkdirAll(%v)\n", filepath.Dir(dst))
|
||||||
|
@ -136,17 +148,35 @@ func copyFile(dst, src string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fdst.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(fdst, fsrc)
|
if _, err = io.Copy(fdst, fsrc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
err = fsrc.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
err = fdst.Close()
|
||||||
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = os.Chmod(dst, fi.Mode())
|
err = os.Chmod(dst, fi.Mode())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = os.Chtimes(dst, fi.ModTime(), fi.ModTime())
|
err = os.Chtimes(dst, fi.ModTime(), fi.ModTime())
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// die prints the message with fmt.Fprintf() to stderr and exits with an error
|
||||||
|
// code.
|
||||||
|
func die(message string, args ...interface{}) {
|
||||||
|
fmt.Fprintf(os.Stderr, message, args...)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func showUsage(output io.Writer) {
|
func showUsage(output io.Writer) {
|
||||||
|
@ -171,7 +201,8 @@ func verbosePrintf(message string, args ...interface{}) {
|
||||||
fmt.Printf("build: "+message, args...)
|
fmt.Printf("build: "+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanEnv returns a clean environment with GOPATH and GOBIN removed (if present).
|
// cleanEnv returns a clean environment with GOPATH and GOBIN removed (if
|
||||||
|
// present).
|
||||||
func cleanEnv() (env []string) {
|
func cleanEnv() (env []string) {
|
||||||
for _, v := range os.Environ() {
|
for _, v := range os.Environ() {
|
||||||
if strings.HasPrefix(v, "GOPATH=") || strings.HasPrefix(v, "GOBIN=") {
|
if strings.HasPrefix(v, "GOPATH=") || strings.HasPrefix(v, "GOBIN=") {
|
||||||
|
@ -217,7 +248,8 @@ func test(cwd, gopath string, args ...string) error {
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// getVersion returns the version string from the file VERSION in the current directory.
|
// getVersion returns the version string from the file VERSION in the current
|
||||||
|
// directory.
|
||||||
func getVersionFromFile() string {
|
func getVersionFromFile() string {
|
||||||
buf, err := ioutil.ReadFile("VERSION")
|
buf, err := ioutil.ReadFile("VERSION")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -228,8 +260,9 @@ func getVersionFromFile() string {
|
||||||
return strings.TrimSpace(string(buf))
|
return strings.TrimSpace(string(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
// getVersion returns a version string which is a combination of the contents of the file VERSION in the current
|
// getVersion returns a version string which is a combination of the contents
|
||||||
// directory and the version from git (if available).
|
// of the file VERSION in the current directory and the version from git (if
|
||||||
|
// available).
|
||||||
func getVersion() string {
|
func getVersion() string {
|
||||||
versionFile := getVersionFromFile()
|
versionFile := getVersionFromFile()
|
||||||
versionGit := getVersionFromGit()
|
versionGit := getVersionFromGit()
|
||||||
|
@ -247,7 +280,8 @@ func getVersion() string {
|
||||||
return fmt.Sprintf("%s (%s)", versionFile, versionGit)
|
return fmt.Sprintf("%s (%s)", versionFile, versionGit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getVersionFromGit returns a version string that identifies the currently checked out git commit.
|
// getVersionFromGit returns a version string that identifies the currently
|
||||||
|
// checked out git commit.
|
||||||
func getVersionFromGit() string {
|
func getVersionFromGit() string {
|
||||||
cmd := exec.Command("git", "describe",
|
cmd := exec.Command("git", "describe",
|
||||||
"--long", "--tags", "--dirty", "--always")
|
"--long", "--tags", "--dirty", "--always")
|
||||||
|
@ -262,7 +296,8 @@ func getVersionFromGit() string {
|
||||||
return version
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constants represents a set of constants that are set in the final binary to the given value via compiler flags.
|
// Constants represents a set of constants that are set in the final binary to
|
||||||
|
// the given value via compiler flags.
|
||||||
type Constants map[string]string
|
type Constants map[string]string
|
||||||
|
|
||||||
// LDFlags returns the string that can be passed to go build's `-ldflags`.
|
// LDFlags returns the string that can be passed to go build's `-ldflags`.
|
||||||
|
@ -276,12 +311,81 @@ func (cs Constants) LDFlags() string {
|
||||||
return strings.Join(l, " ")
|
return strings.Join(l, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
// GoVersion is the version of Go used to compile the project.
|
||||||
log.SetFlags(0)
|
type GoVersion struct {
|
||||||
|
Major int
|
||||||
|
Minor int
|
||||||
|
Patch int
|
||||||
|
}
|
||||||
|
|
||||||
ver := runtime.Version()
|
// ParseGoVersion parses the Go version s. If s cannot be parsed, the returned GoVersion is null.
|
||||||
if strings.HasPrefix(ver, "go1") && ver < "go1.7" {
|
func ParseGoVersion(s string) (v GoVersion) {
|
||||||
log.Fatalf("Go version %s detected, rest-server requires at least Go 1.7\n", ver)
|
if !strings.HasPrefix(s, "go") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s = s[2:]
|
||||||
|
data := strings.Split(s, ".")
|
||||||
|
if len(data) != 3 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
major, err := strconv.Atoi(data[0])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
minor, err := strconv.Atoi(data[1])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
patch, err := strconv.Atoi(data[2])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v = GoVersion{
|
||||||
|
Major: major,
|
||||||
|
Minor: minor,
|
||||||
|
Patch: patch,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// AtLeast returns true if v is at least as new as other. If v is empty, true is returned.
|
||||||
|
func (v GoVersion) AtLeast(other GoVersion) bool {
|
||||||
|
var empty GoVersion
|
||||||
|
|
||||||
|
// the empty version satisfies all versions
|
||||||
|
if v == empty {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major < other.Major {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Minor < other.Minor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Patch < other.Patch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v GoVersion) String() string {
|
||||||
|
return fmt.Sprintf("Go %d.%d.%d", v.Major, v.Minor, v.Patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ver := ParseGoVersion(runtime.Version())
|
||||||
|
if !ver.AtLeast(config.MinVersion) {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s detected, this program requires at least %s\n", ver, config.MinVersion)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTags := []string{}
|
buildTags := []string{}
|
||||||
|
@ -307,7 +411,7 @@ func main() {
|
||||||
keepGopath = true
|
keepGopath = true
|
||||||
case "-t", "-tags", "--tags":
|
case "-t", "-tags", "--tags":
|
||||||
if i+1 >= len(params) {
|
if i+1 >= len(params) {
|
||||||
log.Fatal("-t given but no tag specified")
|
die("-t given but no tag specified")
|
||||||
}
|
}
|
||||||
skipNext = true
|
skipNext = true
|
||||||
buildTags = strings.Split(params[i+1], " ")
|
buildTags = strings.Split(params[i+1], " ")
|
||||||
|
@ -328,7 +432,7 @@ func main() {
|
||||||
showUsage(os.Stdout)
|
showUsage(os.Stdout)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
log.Printf("Error: unknown option %q\n\n", arg)
|
fmt.Fprintf(os.Stderr, "Error: unknown option %q\n\n", arg)
|
||||||
showUsage(os.Stderr)
|
showUsage(os.Stderr)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
@ -347,23 +451,23 @@ func main() {
|
||||||
|
|
||||||
root, err := os.Getwd()
|
root, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Getwd(): %v\n", err)
|
die("Getwd(): %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gopath, err := ioutil.TempDir("", fmt.Sprintf("%v-build-", config.Name))
|
gopath, err := ioutil.TempDir("", fmt.Sprintf("%v-build-", config.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("TempDir(): %v\n", err)
|
die("TempDir(): %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
verbosePrintf("create GOPATH at %v\n", gopath)
|
verbosePrintf("create GOPATH at %v\n", gopath)
|
||||||
if err = updateGopath(gopath, root, config.Namespace); err != nil {
|
if err = updateGopath(gopath, root, config.Namespace); err != nil {
|
||||||
log.Fatalf("copying files from %v/src to %v/src failed: %v\n", root, gopath, err)
|
die("copying files from %v/src to %v/src failed: %v\n", root, gopath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
vendor := filepath.Join(root, "vendor")
|
vendor := filepath.Join(root, "vendor")
|
||||||
if directoryExists(vendor) {
|
if directoryExists(vendor) {
|
||||||
if err = updateGopath(gopath, vendor, ""); err != nil {
|
if err = updateGopath(gopath, vendor, filepath.Join(config.Namespace, "vendor")); err != nil {
|
||||||
log.Fatalf("copying files from %v to %v failed: %v\n", root, gopath, err)
|
die("copying files from %v to %v failed: %v\n", root, gopath, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,7 +475,7 @@ func main() {
|
||||||
if !keepGopath {
|
if !keepGopath {
|
||||||
verbosePrintf("remove %v\n", gopath)
|
verbosePrintf("remove %v\n", gopath)
|
||||||
if err = os.RemoveAll(gopath); err != nil {
|
if err = os.RemoveAll(gopath); err != nil {
|
||||||
log.Fatalf("remove GOPATH at %s failed: %v\n", gopath, err)
|
die("remove GOPATH at %s failed: %v\n", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
verbosePrintf("leaving temporary GOPATH at %v\n", gopath)
|
verbosePrintf("leaving temporary GOPATH at %v\n", gopath)
|
||||||
|
@ -387,9 +491,12 @@ func main() {
|
||||||
|
|
||||||
cwd, err := os.Getwd()
|
cwd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Getwd() returned %v\n", err)
|
die("Getwd() returned %v\n", err)
|
||||||
|
}
|
||||||
|
output := outputFilename
|
||||||
|
if !filepath.IsAbs(output) {
|
||||||
|
output = filepath.Join(cwd, output)
|
||||||
}
|
}
|
||||||
output := filepath.Join(cwd, outputFilename)
|
|
||||||
|
|
||||||
version := getVersion()
|
version := getVersion()
|
||||||
constants := Constants{}
|
constants := Constants{}
|
||||||
|
@ -407,7 +514,7 @@ func main() {
|
||||||
|
|
||||||
err = build(filepath.Join(gopath, "src"), targetGOOS, targetGOARCH, gopath, args...)
|
err = build(filepath.Join(gopath, "src"), targetGOOS, targetGOARCH, gopath, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("build failed: %v\n", err)
|
die("build failed: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if runTests {
|
if runTests {
|
||||||
|
@ -415,7 +522,7 @@ func main() {
|
||||||
|
|
||||||
err = test(cwd, gopath, config.Tests...)
|
err = test(cwd, gopath, config.Tests...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("running tests failed: %v\n", err)
|
die("running tests failed: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue