mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 19:00:54 -06:00
473 lines
12 KiB
Go
473 lines
12 KiB
Go
// +build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/md5"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`)
|
|
goarch string
|
|
goos string
|
|
version string = "v1"
|
|
// deb & rpm does not support semver so have to handle their version a little differently
|
|
linuxPackageVersion string = "v1"
|
|
linuxPackageIteration string = ""
|
|
race bool
|
|
workingDir string
|
|
serverBinaryName string = "grafana-server"
|
|
)
|
|
|
|
const minGoVersion = 1.3
|
|
|
|
func main() {
|
|
log.SetOutput(os.Stdout)
|
|
log.SetFlags(0)
|
|
|
|
ensureGoPath()
|
|
readVersionFromPackageJson()
|
|
|
|
log.Printf("Version: %s, Linux Version: %s, Package Iteration: %s\n", version, linuxPackageVersion, linuxPackageIteration)
|
|
|
|
flag.StringVar(&goarch, "goarch", runtime.GOARCH, "GOARCH")
|
|
flag.StringVar(&goos, "goos", runtime.GOOS, "GOOS")
|
|
flag.BoolVar(&race, "race", race, "Use race detector")
|
|
flag.Parse()
|
|
|
|
if flag.NArg() == 0 {
|
|
log.Println("Usage: go run build.go build")
|
|
return
|
|
}
|
|
|
|
workingDir, _ = os.Getwd()
|
|
|
|
for _, cmd := range flag.Args() {
|
|
switch cmd {
|
|
case "setup":
|
|
setup()
|
|
|
|
case "build":
|
|
pkg := "."
|
|
clean()
|
|
build(pkg, []string{})
|
|
|
|
case "test":
|
|
test("./pkg/...")
|
|
grunt("test")
|
|
|
|
case "package":
|
|
//verifyGitRepoIsClean()
|
|
grunt("release")
|
|
createLinuxPackages()
|
|
|
|
case "pkg-rpm":
|
|
grunt("release")
|
|
createRpmPackages()
|
|
|
|
case "pkg-deb":
|
|
grunt("release")
|
|
createDebPackages()
|
|
|
|
case "latest":
|
|
makeLatestDistCopies()
|
|
|
|
case "clean":
|
|
clean()
|
|
|
|
default:
|
|
log.Fatalf("Unknown command %q", cmd)
|
|
}
|
|
}
|
|
}
|
|
|
|
func makeLatestDistCopies() {
|
|
rpmIteration := "-1"
|
|
if linuxPackageIteration != "" {
|
|
rpmIteration = "-" + linuxPackageIteration
|
|
}
|
|
|
|
runError("cp", "dist/grafana_"+version+"_amd64.deb", "dist/grafana_latest_amd64.deb")
|
|
runError("cp", "dist/grafana-"+linuxPackageVersion+rpmIteration+".x86_64.rpm", "dist/grafana-latest-1.x86_64.rpm")
|
|
runError("cp", "dist/grafana-"+version+".linux-x64.tar.gz", "dist/grafana-latest.linux-x64.tar.gz")
|
|
}
|
|
|
|
func readVersionFromPackageJson() {
|
|
reader, err := os.Open("package.json")
|
|
if err != nil {
|
|
log.Fatal("Failed to open package.json")
|
|
return
|
|
}
|
|
defer reader.Close()
|
|
|
|
jsonObj := map[string]interface{}{}
|
|
jsonParser := json.NewDecoder(reader)
|
|
|
|
if err := jsonParser.Decode(&jsonObj); err != nil {
|
|
log.Fatal("Failed to decode package.json")
|
|
}
|
|
|
|
version = jsonObj["version"].(string)
|
|
linuxPackageVersion = version
|
|
linuxPackageIteration = ""
|
|
|
|
// handle pre version stuff (deb / rpm does not support semver)
|
|
parts := strings.Split(version, "-")
|
|
|
|
if len(parts) > 1 {
|
|
linuxPackageVersion = parts[0]
|
|
linuxPackageIteration = parts[1]
|
|
}
|
|
}
|
|
|
|
type linuxPackageOptions struct {
|
|
packageType string
|
|
homeDir string
|
|
binPath string
|
|
configDir string
|
|
configFilePath string
|
|
ldapFilePath string
|
|
etcDefaultPath string
|
|
etcDefaultFilePath string
|
|
initdScriptFilePath string
|
|
systemdServiceFilePath string
|
|
|
|
postinstSrc string
|
|
initdScriptSrc string
|
|
defaultFileSrc string
|
|
systemdFileSrc string
|
|
|
|
depends []string
|
|
}
|
|
|
|
func createDebPackages() {
|
|
createPackage(linuxPackageOptions{
|
|
packageType: "deb",
|
|
homeDir: "/usr/share/grafana",
|
|
binPath: "/usr/sbin/grafana-server",
|
|
configDir: "/etc/grafana",
|
|
configFilePath: "/etc/grafana/grafana.ini",
|
|
ldapFilePath: "/etc/grafana/ldap.toml",
|
|
etcDefaultPath: "/etc/default",
|
|
etcDefaultFilePath: "/etc/default/grafana-server",
|
|
initdScriptFilePath: "/etc/init.d/grafana-server",
|
|
systemdServiceFilePath: "/usr/lib/systemd/system/grafana-server.service",
|
|
|
|
postinstSrc: "packaging/deb/control/postinst",
|
|
initdScriptSrc: "packaging/deb/init.d/grafana-server",
|
|
defaultFileSrc: "packaging/deb/default/grafana-server",
|
|
systemdFileSrc: "packaging/deb/systemd/grafana-server.service",
|
|
|
|
depends: []string{"adduser", "libfontconfig"},
|
|
})
|
|
}
|
|
|
|
func createRpmPackages() {
|
|
createPackage(linuxPackageOptions{
|
|
packageType: "rpm",
|
|
homeDir: "/usr/share/grafana",
|
|
binPath: "/usr/sbin/grafana-server",
|
|
configDir: "/etc/grafana",
|
|
configFilePath: "/etc/grafana/grafana.ini",
|
|
ldapFilePath: "/etc/grafana/ldap.toml",
|
|
etcDefaultPath: "/etc/sysconfig",
|
|
etcDefaultFilePath: "/etc/sysconfig/grafana-server",
|
|
initdScriptFilePath: "/etc/init.d/grafana-server",
|
|
systemdServiceFilePath: "/usr/lib/systemd/system/grafana-server.service",
|
|
|
|
postinstSrc: "packaging/rpm/control/postinst",
|
|
initdScriptSrc: "packaging/rpm/init.d/grafana-server",
|
|
defaultFileSrc: "packaging/rpm/sysconfig/grafana-server",
|
|
systemdFileSrc: "packaging/rpm/systemd/grafana-server.service",
|
|
|
|
depends: []string{"initscripts", "fontconfig"},
|
|
})
|
|
}
|
|
|
|
func createLinuxPackages() {
|
|
createDebPackages()
|
|
createRpmPackages()
|
|
}
|
|
|
|
func createPackage(options linuxPackageOptions) {
|
|
packageRoot, _ := ioutil.TempDir("", "grafana-linux-pack")
|
|
|
|
// create directories
|
|
runPrint("mkdir", "-p", filepath.Join(packageRoot, options.homeDir))
|
|
runPrint("mkdir", "-p", filepath.Join(packageRoot, options.configDir))
|
|
runPrint("mkdir", "-p", filepath.Join(packageRoot, "/etc/init.d"))
|
|
runPrint("mkdir", "-p", filepath.Join(packageRoot, options.etcDefaultPath))
|
|
runPrint("mkdir", "-p", filepath.Join(packageRoot, "/usr/lib/systemd/system"))
|
|
runPrint("mkdir", "-p", filepath.Join(packageRoot, "/usr/sbin"))
|
|
|
|
// copy binary
|
|
runPrint("cp", "-p", filepath.Join(workingDir, "tmp/bin/"+serverBinaryName), filepath.Join(packageRoot, options.binPath))
|
|
// copy init.d script
|
|
runPrint("cp", "-p", options.initdScriptSrc, filepath.Join(packageRoot, options.initdScriptFilePath))
|
|
// copy environment var file
|
|
runPrint("cp", "-p", options.defaultFileSrc, filepath.Join(packageRoot, options.etcDefaultFilePath))
|
|
// copy systemd file
|
|
runPrint("cp", "-p", options.systemdFileSrc, filepath.Join(packageRoot, options.systemdServiceFilePath))
|
|
// copy release files
|
|
runPrint("cp", "-a", filepath.Join(workingDir, "tmp")+"/.", filepath.Join(packageRoot, options.homeDir))
|
|
// remove bin path
|
|
runPrint("rm", "-rf", filepath.Join(packageRoot, options.homeDir, "bin"))
|
|
// copy sample ini file to /etc/grafana
|
|
runPrint("cp", "conf/sample.ini", filepath.Join(packageRoot, options.configFilePath))
|
|
// copy sample ldap toml config file to /etc/grafana/ldap.toml
|
|
runPrint("cp", "conf/ldap.toml", filepath.Join(packageRoot, options.ldapFilePath))
|
|
|
|
args := []string{
|
|
"-s", "dir",
|
|
"--description", "Grafana",
|
|
"-C", packageRoot,
|
|
"--vendor", "Grafana",
|
|
"--url", "http://grafana.org",
|
|
"--license", "\"Apache 2.0\"",
|
|
"--maintainer", "contact@grafana.org",
|
|
"--config-files", options.configFilePath,
|
|
"--config-files", options.ldapFilePath,
|
|
"--config-files", options.initdScriptFilePath,
|
|
"--config-files", options.etcDefaultFilePath,
|
|
"--config-files", options.systemdServiceFilePath,
|
|
"--after-install", options.postinstSrc,
|
|
"--name", "grafana",
|
|
"--version", linuxPackageVersion,
|
|
"-p", "./dist",
|
|
}
|
|
|
|
if linuxPackageIteration != "" {
|
|
args = append(args, "--iteration", linuxPackageIteration)
|
|
}
|
|
|
|
// add dependenciesj
|
|
for _, dep := range options.depends {
|
|
args = append(args, "--depends", dep)
|
|
}
|
|
|
|
args = append(args, ".")
|
|
|
|
fmt.Println("Creating package: ", options.packageType)
|
|
runPrint("fpm", append([]string{"-t", options.packageType}, args...)...)
|
|
}
|
|
|
|
func verifyGitRepoIsClean() {
|
|
rs, err := runError("git", "ls-files", "--modified")
|
|
if err != nil {
|
|
log.Fatalf("Failed to check if git tree was clean, %v, %v\n", string(rs), err)
|
|
return
|
|
}
|
|
count := len(string(rs))
|
|
if count > 0 {
|
|
log.Fatalf("Git repository has modified files, aborting")
|
|
}
|
|
|
|
log.Println("Git repository is clean")
|
|
}
|
|
|
|
func ensureGoPath() {
|
|
if os.Getenv("GOPATH") == "" {
|
|
cwd, err := os.Getwd()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
gopath := filepath.Clean(filepath.Join(cwd, "../../../../"))
|
|
log.Println("GOPATH is", gopath)
|
|
os.Setenv("GOPATH", gopath)
|
|
}
|
|
}
|
|
|
|
func ChangeWorkingDir(dir string) {
|
|
os.Chdir(dir)
|
|
}
|
|
|
|
func grunt(params ...string) {
|
|
runPrint("./node_modules/grunt-cli/bin/grunt", params...)
|
|
}
|
|
|
|
func setup() {
|
|
runPrint("go", "get", "-v", "github.com/tools/godep")
|
|
runPrint("go", "get", "-v", "github.com/blang/semver")
|
|
runPrint("go", "get", "-v", "github.com/mattn/go-sqlite3")
|
|
runPrint("go", "install", "-v", "github.com/mattn/go-sqlite3")
|
|
}
|
|
|
|
func test(pkg string) {
|
|
setBuildEnv()
|
|
runPrint("go", "test", "-short", "-timeout", "60s", pkg)
|
|
}
|
|
|
|
func build(pkg string, tags []string) {
|
|
binary := "./bin/" + serverBinaryName
|
|
if goos == "windows" {
|
|
binary += ".exe"
|
|
}
|
|
|
|
rmr(binary, binary+".md5")
|
|
args := []string{"build", "-ldflags", ldflags()}
|
|
if len(tags) > 0 {
|
|
args = append(args, "-tags", strings.Join(tags, ","))
|
|
}
|
|
if race {
|
|
args = append(args, "-race")
|
|
}
|
|
|
|
args = append(args, "-o", binary)
|
|
args = append(args, pkg)
|
|
setBuildEnv()
|
|
|
|
runPrint("go", "version")
|
|
runPrint("go", args...)
|
|
|
|
// Create an md5 checksum of the binary, to be included in the archive for
|
|
// automatic upgrades.
|
|
err := md5File(binary)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func ldflags() string {
|
|
var b bytes.Buffer
|
|
b.WriteString("-w")
|
|
b.WriteString(fmt.Sprintf(" -X main.version=%s", version))
|
|
b.WriteString(fmt.Sprintf(" -X main.commit=%s", getGitSha()))
|
|
b.WriteString(fmt.Sprintf(" -X main.buildstamp=%d", buildStamp()))
|
|
return b.String()
|
|
}
|
|
|
|
func rmr(paths ...string) {
|
|
for _, path := range paths {
|
|
log.Println("rm -r", path)
|
|
os.RemoveAll(path)
|
|
}
|
|
}
|
|
|
|
func clean() {
|
|
rmr("bin", "Godeps/_workspace/pkg", "Godeps/_workspace/bin")
|
|
rmr("dist")
|
|
rmr("tmp")
|
|
rmr(filepath.Join(os.Getenv("GOPATH"), fmt.Sprintf("pkg/%s_%s/github.com/grafana", goos, goarch)))
|
|
}
|
|
|
|
func setBuildEnv() {
|
|
os.Setenv("GOOS", goos)
|
|
if strings.HasPrefix(goarch, "armv") {
|
|
os.Setenv("GOARCH", "arm")
|
|
os.Setenv("GOARM", goarch[4:])
|
|
} else {
|
|
os.Setenv("GOARCH", goarch)
|
|
}
|
|
if goarch == "386" {
|
|
os.Setenv("GO386", "387")
|
|
}
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
log.Println("Warning: can't determine current dir:", err)
|
|
log.Println("Build might not work as expected")
|
|
}
|
|
os.Setenv("GOPATH", fmt.Sprintf("%s%c%s", filepath.Join(wd, "Godeps", "_workspace"), os.PathListSeparator, os.Getenv("GOPATH")))
|
|
log.Println("GOPATH=" + os.Getenv("GOPATH"))
|
|
}
|
|
|
|
func getGitSha() string {
|
|
v, err := runError("git", "describe", "--always", "--dirty")
|
|
if err != nil {
|
|
return "unknown-dev"
|
|
}
|
|
v = versionRe.ReplaceAllFunc(v, func(s []byte) []byte {
|
|
s[0] = '+'
|
|
return s
|
|
})
|
|
return string(v)
|
|
}
|
|
|
|
func buildStamp() int64 {
|
|
bs, err := runError("git", "show", "-s", "--format=%ct")
|
|
if err != nil {
|
|
return time.Now().Unix()
|
|
}
|
|
s, _ := strconv.ParseInt(string(bs), 10, 64)
|
|
return s
|
|
}
|
|
|
|
func buildArch() string {
|
|
os := goos
|
|
if os == "darwin" {
|
|
os = "macosx"
|
|
}
|
|
return fmt.Sprintf("%s-%s", os, goarch)
|
|
}
|
|
|
|
func run(cmd string, args ...string) []byte {
|
|
bs, err := runError(cmd, args...)
|
|
if err != nil {
|
|
log.Println(cmd, strings.Join(args, " "))
|
|
log.Println(string(bs))
|
|
log.Fatal(err)
|
|
}
|
|
return bytes.TrimSpace(bs)
|
|
}
|
|
|
|
func runError(cmd string, args ...string) ([]byte, error) {
|
|
ecmd := exec.Command(cmd, args...)
|
|
bs, err := ecmd.CombinedOutput()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return bytes.TrimSpace(bs), nil
|
|
}
|
|
|
|
func runPrint(cmd string, args ...string) {
|
|
log.Println(cmd, strings.Join(args, " "))
|
|
ecmd := exec.Command(cmd, args...)
|
|
ecmd.Stdout = os.Stdout
|
|
ecmd.Stderr = os.Stderr
|
|
err := ecmd.Run()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func md5File(file string) error {
|
|
fd, err := os.Open(file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fd.Close()
|
|
|
|
h := md5.New()
|
|
_, err = io.Copy(h, fd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
out, err := os.Create(file + ".md5")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = fmt.Fprintf(out, "%x\n", h.Sum(nil))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return out.Close()
|
|
}
|