grafana/build.go

604 lines
14 KiB
Go
Raw Normal View History

// +build ignore
package main
import (
"bytes"
"crypto/md5"
"crypto/sha256"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
)
var (
2018-04-24 11:42:27 -05:00
//versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`)
goarch string
goos string
gocc string
cgo bool
2018-04-24 11:42:27 -05:00
pkgArch 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
2016-09-18 05:07:12 -05:00
phjsToRelease string
workingDir string
includeBuildNumber bool = true
buildNumber int = 0
binaries []string = []string{"grafana-server", "grafana-cli"}
isDev bool = false
enterprise bool = false
)
func main() {
log.SetOutput(os.Stdout)
log.SetFlags(0)
ensureGoPath()
flag.StringVar(&goarch, "goarch", runtime.GOARCH, "GOARCH")
flag.StringVar(&goos, "goos", runtime.GOOS, "GOOS")
2016-09-18 05:07:12 -05:00
flag.StringVar(&gocc, "cc", "", "CC")
flag.BoolVar(&cgo, "cgo-enabled", cgo, "Enable cgo")
2016-09-18 05:07:12 -05:00
flag.StringVar(&pkgArch, "pkg-arch", "", "PKG ARCH")
flag.StringVar(&phjsToRelease, "phjs", "", "PhantomJS binary")
flag.BoolVar(&race, "race", race, "Use race detector")
flag.BoolVar(&includeBuildNumber, "includeBuildNumber", includeBuildNumber, "IncludeBuildNumber in package name")
flag.BoolVar(&enterprise, "enterprise", enterprise, "Build enterprise version of Grafana")
flag.IntVar(&buildNumber, "buildNumber", 0, "Build number from CI system")
flag.BoolVar(&isDev, "dev", isDev, "optimal for development, skips certain steps")
flag.Parse()
readVersionFromPackageJson()
log.Printf("Version: %s, Linux Version: %s, Package Iteration: %s\n", version, linuxPackageVersion, linuxPackageIteration)
if flag.NArg() == 0 {
log.Println("Usage: go run build.go build")
return
}
2015-01-28 06:10:09 -06:00
workingDir, _ = os.Getwd()
for _, cmd := range flag.Args() {
switch cmd {
case "setup":
setup()
case "build-srv":
clean()
build("grafana-server", "./pkg/cmd/grafana-server", []string{})
case "build-cli":
clean()
build("grafana-cli", "./pkg/cmd/grafana-cli", []string{})
case "build-server":
clean()
build("grafana-server", "./pkg/cmd/grafana-server", []string{})
case "build":
//clean()
for _, binary := range binaries {
build(binary, "./pkg/cmd/"+binary, []string{})
}
case "build-frontend":
grunt(gruntBuildArg("build")...)
case "test":
2015-01-28 06:10:09 -06:00
test("./pkg/...")
grunt("test")
2015-01-28 06:10:09 -06:00
case "package":
grunt(gruntBuildArg("build")...)
packageGrafana()
case "package-only":
packageGrafana()
2015-01-28 06:10:09 -06:00
case "pkg-rpm":
2016-09-18 05:07:12 -05:00
grunt(gruntBuildArg("release")...)
createRpmPackages()
2015-12-04 15:55:23 -06:00
case "pkg-deb":
2016-09-18 05:07:12 -05:00
grunt(gruntBuildArg("release")...)
createDebPackages()
case "sha-dist":
shaFilesInDist()
case "latest":
makeLatestDistCopies()
case "clean":
clean()
default:
log.Fatalf("Unknown command %q", cmd)
}
}
}
func packageGrafana() {
platformArg := fmt.Sprintf("--platform=%v", goos)
previousPkgArch := pkgArch
if pkgArch == "" {
pkgArch = goarch
}
postProcessArgs := gruntBuildArg("package")
postProcessArgs = append(postProcessArgs, platformArg)
grunt(postProcessArgs...)
pkgArch = previousPkgArch
if goos == "linux" && goarch == "amd64"{
createLinuxPackages()
}
}
func makeLatestDistCopies() {
files, err := ioutil.ReadDir("dist")
if err != nil {
log.Fatalf("failed to create latest copies. Cannot read from /dist")
}
latestMapping := map[string]string{
"_amd64.deb": "dist/grafana_latest_amd64.deb",
".x86_64.rpm": "dist/grafana-latest-1.x86_64.rpm",
".linux-amd64.tar.gz": "dist/grafana-latest.linux-x64.tar.gz",
}
for _, file := range files {
for extension, fullName := range latestMapping {
if strings.HasSuffix(file.Name(), extension) {
runError("cp", path.Join("dist", file.Name()), fullName)
}
}
}
}
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]
}
// add timestamp to iteration
if includeBuildNumber {
if buildNumber != 0 {
linuxPackageIteration = fmt.Sprintf("%d%s", buildNumber, linuxPackageIteration)
} else {
linuxPackageIteration = fmt.Sprintf("%d%s", time.Now().Unix(), linuxPackageIteration)
}
}
}
type linuxPackageOptions struct {
packageType string
homeDir string
binPath string
serverBinPath string
cliBinPath string
configDir string
ldapFilePath string
etcDefaultPath string
etcDefaultFilePath string
initdScriptFilePath string
systemdServiceFilePath string
postinstSrc string
initdScriptSrc string
defaultFileSrc string
systemdFileSrc string
depends []string
}
2015-04-08 09:58:05 -05:00
func createDebPackages() {
createPackage(linuxPackageOptions{
packageType: "deb",
homeDir: "/usr/share/grafana",
binPath: "/usr/sbin",
configDir: "/etc/grafana",
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",
configDir: "/etc/grafana",
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{"/sbin/service", "fontconfig", "freetype", "urw-fonts"},
})
}
2015-04-08 09:58:05 -05:00
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
for _, binary := range binaries {
runPrint("cp", "-p", filepath.Join(workingDir, "tmp/bin/"+binary), filepath.Join(packageRoot, "/usr/sbin/"+binary))
}
// 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))
2015-04-08 09:58:05 -05:00
// 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))
2015-04-15 08:41:56 -05:00
// remove bin path
runPrint("rm", "-rf", filepath.Join(packageRoot, options.homeDir, "bin"))
args := []string{
"-s", "dir",
"--description", "Grafana",
"-C", packageRoot,
"--url", "https://grafana.com",
"--maintainer", "contact@grafana.com",
"--config-files", options.initdScriptFilePath,
"--config-files", options.etcDefaultFilePath,
"--config-files", options.systemdServiceFilePath,
"--after-install", options.postinstSrc,
"--version", linuxPackageVersion,
"-p", "./dist",
}
name := "grafana"
if enterprise {
name += "-enterprise"
}
args = append(args, "--name", name)
description := "Grafana"
if enterprise {
description += " Enterprise"
}
args = append(args, "--vendor", description)
if !enterprise {
args = append(args, "--license", "\"Apache 2.0\"")
}
if options.packageType == "rpm" {
args = append(args, "--rpm-posttrans", "packaging/rpm/control/posttrans")
}
if options.packageType == "deb" {
args = append(args, "--deb-no-default-config-files")
}
2016-09-18 05:07:12 -05:00
if pkgArch != "" {
args = append(args, "-a", pkgArch)
}
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 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)
}
}
2015-03-04 00:09:59 -06:00
func grunt(params ...string) {
if runtime.GOOS == "windows" {
runPrint(`.\node_modules\.bin\grunt`, params...)
} else {
runPrint("./node_modules/.bin/grunt", params...)
}
2015-01-28 06:10:09 -06:00
}
2016-09-18 05:07:12 -05:00
func gruntBuildArg(task string) []string {
args := []string{task}
if includeBuildNumber {
2017-03-23 05:09:35 -05:00
args = append(args, fmt.Sprintf("--pkgVer=%v-%v", linuxPackageVersion, linuxPackageIteration))
} else {
args = append(args, fmt.Sprintf("--pkgVer=%v", version))
}
2016-09-18 05:07:12 -05:00
if pkgArch != "" {
args = append(args, fmt.Sprintf("--arch=%v", pkgArch))
}
if phjsToRelease != "" {
args = append(args, fmt.Sprintf("--phjsToRelease=%v", phjsToRelease))
}
return args
}
func setup() {
runPrint("go", "get", "-v", "github.com/golang/dep")
2016-09-22 03:33:43 -05:00
runPrint("go", "install", "-v", "./pkg/cmd/grafana-server")
}
func test(pkg string) {
setBuildEnv()
runPrint("go", "test", "-short", "-timeout", "60s", pkg)
}
2016-02-15 07:09:34 -06:00
func build(binaryName, pkg string, tags []string) {
binary := fmt.Sprintf("./bin/%s-%s/%s", goos, goarch, binaryName)
if goos == "windows" {
binary += ".exe"
}
if !isDev {
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)
2015-12-04 04:21:38 -06:00
if !isDev {
setBuildEnv()
runPrint("go", "version")
fmt.Printf("Targeting %s/%s\n", goos, goarch)
}
runPrint("go", args...)
if !isDev {
// 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")
2015-12-01 02:23:30 -06:00
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()))
b.WriteString(fmt.Sprintf(" -X main.enterprise=%t", enterprise))
return b.String()
}
func rmr(paths ...string) {
for _, path := range paths {
log.Println("rm -r", path)
os.RemoveAll(path)
}
}
func clean() {
if isDev {
return
}
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 goos == "windows" {
// require windows >=7
os.Setenv("CGO_CFLAGS", "-D_WIN32_WINNT=0x0601")
}
if goarch != "amd64" || goos != "linux" {
// needed for all other archs
cgo = true
}
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")
}
if cgo {
os.Setenv("CGO_ENABLED", "1")
2016-09-18 05:07:12 -05:00
}
if gocc != "" {
os.Setenv("CC", gocc)
}
}
func getGitSha() string {
v, err := runError("git", "rev-parse", "--short", "HEAD")
if err != nil {
return "unknown-dev"
}
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 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()
}
func shaFilesInDist() {
filepath.Walk("./dist", func(path string, f os.FileInfo, err error) error {
if path == "./dist" {
return nil
}
Simplify comparison to bool constant (gosimple) This fixes: build.go:553:6: should omit comparison to bool constant, can be simplified to !strings.Contains(path, ".sha256") (S1002) pkg/cmd/grafana-cli/commands/ls_command.go:27:5: should omit comparison to bool constant, can be simplified to !pluginDirInfo.IsDir() (S1002) pkg/components/dynmap/dynmap_test.go:24:5: should omit comparison to bool constant, can be simplified to !value (S1002) pkg/components/dynmap/dynmap_test.go:122:14: should omit comparison to bool constant, can be simplified to b (S1002) pkg/components/dynmap/dynmap_test.go:125:14: should omit comparison to bool constant, can be simplified to !b (S1002) pkg/components/dynmap/dynmap_test.go:128:14: should omit comparison to bool constant, can be simplified to !b (S1002) pkg/models/org_user.go:51:5: should omit comparison to bool constant, can be simplified to !(*r).IsValid() (S1002) pkg/plugins/datasource/wrapper/datasource_plugin_wrapper_test.go:77:12: should omit comparison to bool constant, can be simplified to !haveBool (S1002) pkg/services/alerting/conditions/evaluator.go:23:9: should omit comparison to bool constant, can be simplified to !reducedValue.Valid (S1002) pkg/services/alerting/conditions/evaluator.go:48:5: should omit comparison to bool constant, can be simplified to !reducedValue.Valid (S1002) pkg/services/alerting/conditions/evaluator.go:91:5: should omit comparison to bool constant, can be simplified to !reducedValue.Valid (S1002) pkg/services/alerting/conditions/query.go:56:6: should omit comparison to bool constant, can be simplified to !reducedValue.Valid (S1002) pkg/services/alerting/extractor.go:107:20: should omit comparison to bool constant, can be simplified to !enabled.MustBool() (S1002) pkg/services/alerting/notifiers/telegram.go:222:41: should omit comparison to bool constant, can be simplified to this.UploadImage (S1002) pkg/services/sqlstore/apikey.go:58:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/apikey.go:72:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/dashboard.go:66:33: should omit comparison to bool constant, can be simplified to !cmd.Overwrite (S1002) pkg/services/sqlstore/dashboard.go:175:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/dashboard.go:311:13: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/dashboard.go:444:12: should omit comparison to bool constant, can be simplified to !exists (S1002) pkg/services/sqlstore/dashboard.go:472:12: should omit comparison to bool constant, can be simplified to !exists (S1002) pkg/services/sqlstore/dashboard.go:554:32: should omit comparison to bool constant, can be simplified to !cmd.Overwrite (S1002) pkg/services/sqlstore/dashboard_snapshot.go:83:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/plugin_setting.go:39:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/quota.go:34:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/quota.go:111:6: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/quota.go:136:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/quota.go:213:6: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/temp_user.go:129:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/user.go:157:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/user.go:182:5: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/user.go:191:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/user.go:212:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/services/sqlstore/user.go:307:12: should omit comparison to bool constant, can be simplified to !has (S1002) pkg/social/generic_oauth.go:185:5: should omit comparison to bool constant, can be simplified to !s.extractToken(&data, token) (S1002) pkg/tsdb/mssql/mssql.go:148:39: should omit comparison to bool constant, can be simplified to ok (S1002) pkg/tsdb/mssql/mssql.go:212:6: should omit comparison to bool constant, can be simplified to !query.Model.Get("fillNull").MustBool(false) (S1002) pkg/tsdb/mssql/mssql.go:247:56: should omit comparison to bool constant, can be simplified to ok (S1002) pkg/tsdb/mssql/mssql.go:274:7: should omit comparison to bool constant, can be simplified to !exist (S1002) pkg/tsdb/mssql/mssql.go:282:8: should omit comparison to bool constant, can be simplified to !exist (S1002) pkg/tsdb/mysql/mysql.go:221:6: should omit comparison to bool constant, can be simplified to !query.Model.Get("fillNull").MustBool(false) (S1002) pkg/tsdb/mysql/mysql.go:256:56: should omit comparison to bool constant, can be simplified to ok (S1002) pkg/tsdb/mysql/mysql.go:283:7: should omit comparison to bool constant, can be simplified to !exist (S1002) pkg/tsdb/mysql/mysql.go:291:8: should omit comparison to bool constant, can be simplified to !exist (S1002) pkg/tsdb/postgres/postgres.go:134:39: should omit comparison to bool constant, can be simplified to ok (S1002) pkg/tsdb/postgres/postgres.go:201:6: should omit comparison to bool constant, can be simplified to !query.Model.Get("fillNull").MustBool(false) (S1002) pkg/tsdb/postgres/postgres.go:236:56: should omit comparison to bool constant, can be simplified to ok (S1002) pkg/tsdb/postgres/postgres.go:263:7: should omit comparison to bool constant, can be simplified to !exist (S1002) pkg/tsdb/postgres/postgres.go:271:8: should omit comparison to bool constant, can be simplified to !exist (S1002)
2018-04-16 13:12:59 -05:00
if !strings.Contains(path, ".sha256") {
err := shaFile(path)
if err != nil {
log.Printf("Failed to create sha file. error: %v\n", err)
}
}
return nil
})
}
func shaFile(file string) error {
fd, err := os.Open(file)
if err != nil {
return err
}
defer fd.Close()
h := sha256.New()
_, err = io.Copy(h, fd)
if err != nil {
return err
}
out, err := os.Create(file + ".sha256")
if err != nil {
return err
}
_, err = fmt.Fprintf(out, "%x\n", h.Sum(nil))
if err != nil {
return err
}
return out.Close()
}