forked from TrueCloudLab/restic
Add build.go
This commit is contained in:
parent
c6db8eb19c
commit
9e9177ab73
6 changed files with 262 additions and 36 deletions
|
@ -43,11 +43,10 @@ Restic is a program that does backups right. The design goals are:
|
|||
Building
|
||||
========
|
||||
|
||||
Install Go/Golang (at least version 1.3), then run `make`, afterwards you'll
|
||||
find the binary in the current directory:
|
||||
Install Go/Golang (at least version 1.3), then run `go run build.go`,
|
||||
afterwards you'll find the binary in the current directory:
|
||||
|
||||
$ make
|
||||
[...]
|
||||
$ go run build.go
|
||||
|
||||
$ ./restic --help
|
||||
Usage:
|
||||
|
|
256
build.go
Normal file
256
build.go
Normal file
|
@ -0,0 +1,256 @@
|
|||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
verbose bool
|
||||
keepGopath bool
|
||||
)
|
||||
|
||||
const timeFormat = "2006-01-02 15:04:05"
|
||||
|
||||
// specialDir returns true if the file begins with a special character ('.' or '_').
|
||||
func specialDir(name string) bool {
|
||||
if name == "." {
|
||||
return false
|
||||
}
|
||||
|
||||
base := filepath.Base(name)
|
||||
return base[0] == '_' || base[0] == '.'
|
||||
}
|
||||
|
||||
// updateGopath builds a valid GOPATH at dst, with all Go files in src/ copied
|
||||
// to dst/prefix/, so calling
|
||||
//
|
||||
// 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":
|
||||
//
|
||||
// /tmp/gopath
|
||||
// └── src
|
||||
// └── github.com
|
||||
// └── restic
|
||||
// └── restic
|
||||
// └── foo.go
|
||||
func updateGopath(dst, src, prefix string) error {
|
||||
return filepath.Walk(src, func(name string, fi os.FileInfo, err error) error {
|
||||
if specialDir(name) {
|
||||
if fi.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ext := path.Ext(name)
|
||||
if ext != ".go" && ext != ".s" {
|
||||
return nil
|
||||
}
|
||||
|
||||
intermediatePath, err := filepath.Rel(src, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fileSrc := filepath.Join(src, intermediatePath)
|
||||
fileDst := filepath.Join(dst, "src", prefix, intermediatePath)
|
||||
|
||||
return copyFile(fileDst, fileSrc)
|
||||
})
|
||||
}
|
||||
|
||||
// copyFile creates dst from src, preserving file attributes and timestamps.
|
||||
func copyFile(dst, src string) error {
|
||||
fi, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fsrc, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
fmt.Printf("MkdirAll(%v)\n", filepath.Dir(dst))
|
||||
return err
|
||||
}
|
||||
|
||||
fdst, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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 {
|
||||
err = os.Chmod(dst, fi.Mode())
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
err = os.Chtimes(dst, fi.ModTime(), fi.ModTime())
|
||||
}
|
||||
|
||||
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) {
|
||||
fmt.Fprintf(output, "USAGE: go run build.go OPTIONS\n")
|
||||
fmt.Fprintf(output, "\n")
|
||||
fmt.Fprintf(output, "OPTIONS:\n")
|
||||
fmt.Fprintf(output, " -v --verbose output more messages\n")
|
||||
}
|
||||
|
||||
func verbosePrintf(message string, args ...interface{}) {
|
||||
if !verbose {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf(message, args...)
|
||||
}
|
||||
|
||||
// cleanEnv returns a clean environment with GOPATH and GOBIN removed (if
|
||||
// present).
|
||||
func cleanEnv() (env []string) {
|
||||
for _, v := range os.Environ() {
|
||||
if strings.HasPrefix(v, "GOPATH=") || strings.HasPrefix(v, "GOBIN=") {
|
||||
continue
|
||||
}
|
||||
|
||||
env = append(env, v)
|
||||
}
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
// build runs "go build args..." with GOPATH set to gopath.
|
||||
func build(gopath string, args ...string) error {
|
||||
args = append([]string{"build"}, args...)
|
||||
cmd := exec.Command("go", args...)
|
||||
cmd.Env = append(cleanEnv(), "GOPATH="+gopath)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
verbosePrintf("go %s\n", args)
|
||||
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// getVersion returns a version string, either from the file VERSION in the
|
||||
// current directory or from git.
|
||||
func getVersion() string {
|
||||
v, err := ioutil.ReadFile("VERSION")
|
||||
version := strings.TrimSpace(string(v))
|
||||
if err == nil {
|
||||
verbosePrintf("version from file 'VERSION' is %s\n", version)
|
||||
return version
|
||||
}
|
||||
|
||||
return gitVersion()
|
||||
}
|
||||
|
||||
// gitVersion returns a version string that identifies the currently checked
|
||||
// out git commit.
|
||||
func gitVersion() string {
|
||||
cmd := exec.Command("git", "describe",
|
||||
"--long", "--tags", "--dirty", "--always")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
die("git describe returned error: %v\n", err)
|
||||
}
|
||||
|
||||
version := strings.TrimSpace(string(out))
|
||||
verbosePrintf("git version is %s\n", version)
|
||||
return version
|
||||
}
|
||||
|
||||
func main() {
|
||||
for _, arg := range os.Args[1:] {
|
||||
switch arg {
|
||||
case "-v", "--verbose":
|
||||
verbose = true
|
||||
case "-k", "--keep-gopath":
|
||||
keepGopath = true
|
||||
case "-h":
|
||||
showUsage(os.Stdout)
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Error: unknown option %q\n\n", arg)
|
||||
showUsage(os.Stderr)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
root, err := os.Getwd()
|
||||
if err != nil {
|
||||
die("Getwd(): %v\n", err)
|
||||
}
|
||||
|
||||
gopath, err := ioutil.TempDir("", "restic-build-")
|
||||
if err != nil {
|
||||
die("TempDir(): %v\n", err)
|
||||
}
|
||||
|
||||
verbosePrintf("create GOPATH at %v\n", gopath)
|
||||
if err = updateGopath(gopath, root, "github.com/restic/restic"); err != nil {
|
||||
die("copying files from %v to %v failed: %v\n", root, gopath, err)
|
||||
}
|
||||
|
||||
vendor := filepath.Join(root, "Godeps", "_workspace", "src")
|
||||
if err = updateGopath(gopath, vendor, ""); err != nil {
|
||||
die("copying files from %v to %v failed: %v\n", root, gopath, err)
|
||||
}
|
||||
|
||||
version := getVersion()
|
||||
compileTime := time.Now().Format(timeFormat)
|
||||
args := []string{
|
||||
"-tags", "release",
|
||||
"-ldflags", fmt.Sprintf(`-s -X main.version %q -X main.compiledAt %q`, version, compileTime),
|
||||
"-o", "restic", "github.com/restic/restic/cmd/restic",
|
||||
}
|
||||
err = build(gopath, args...)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "build failed: %v\n", err)
|
||||
}
|
||||
|
||||
if !keepGopath {
|
||||
verbosePrintf("remove %v\n", gopath)
|
||||
if err = os.RemoveAll(gopath); err != nil {
|
||||
die("remove GOPATH at %s failed: %v\n", err)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("leaving temporary GOPATH at %v\n", gopath)
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
.PHONY: all clean debug
|
||||
|
||||
# include config file if it exists
|
||||
-include $(CURDIR)/config.mk
|
||||
|
||||
all: restic
|
||||
|
||||
debug: restic.debug
|
||||
|
||||
restic: $(wildcard *.go) $(wildcard ../../*.go) $(wildcard ../../*/*.go)
|
||||
go build -a
|
||||
|
||||
restic.debug: $(wildcard *.go) $(wildcard ../../*.go) $(wildcard ../../*/*.go)
|
||||
go build -a -tags debug -o restic.debug
|
||||
|
||||
clean:
|
||||
go clean
|
||||
rm -f restic restic.debug
|
|
@ -18,7 +18,8 @@ func init() {
|
|||
}
|
||||
|
||||
func (cmd CmdVersion) Execute(args []string) error {
|
||||
fmt.Printf("restic %s on %v\n", version, runtime.Version())
|
||||
fmt.Printf("restic %s\ncompiled at %s with %v\n",
|
||||
version, compiledAt, runtime.Version())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
)
|
||||
|
||||
var version = "compiled manually"
|
||||
var compiledAt = "unknown time"
|
||||
|
||||
type GlobalOptions struct {
|
||||
Repo string `short:"r" long:"repo" description:"Repository directory to backup to/restore from"`
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
VERSION=$(git log --max-count=1 --pretty='%ad-%h' --date=short HEAD 2>/dev/null)
|
||||
|
||||
if [ -n "$VERSION" ]; then
|
||||
if ! sh -c "git diff -s --exit-code && git diff --cached -s --exit-code"; then
|
||||
VERSION+="+"
|
||||
fi
|
||||
else
|
||||
VERSION="unknown version"
|
||||
fi
|
||||
|
||||
echo $VERSION
|
Loading…
Reference in a new issue