Chore: move build command to importable package (#38726)

* move build command to importable package & clean up
pull/38844/head
Kevin Minehart 4 years ago committed by GitHub
parent 68c7d054bf
commit d913e46e37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 466
      build.go
  2. 314
      pkg/build/cmd.go
  3. 2
      pkg/build/docs.go
  4. 34
      pkg/build/exec.go
  5. 101
      pkg/build/fs.go
  6. 17
      pkg/build/git.go
  7. 66
      pkg/build/opts.go
  8. 66
      pkg/build/version.go

@ -3,476 +3,14 @@
package main
import (
"bytes"
"crypto/md5"
"crypto/sha256"
"encoding/json"
"flag"
"fmt"
"go/build"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
)
const (
windows = "windows"
linux = "linux"
)
var (
//versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`)
goarch string
goos string
gocc string
cgo bool
libc string
pkgArch string
version string = "v1"
buildTags []string
// deb & rpm does not support semver so have to handle their version a little differently
linuxPackageVersion string = "v1"
linuxPackageIteration string = ""
race bool
workingDir string
includeBuildId bool = true
buildId string = "0"
serverBinary string = "grafana-server"
cliBinary string = "grafana-cli"
binaries []string = []string{serverBinary, cliBinary}
isDev bool = false
enterprise bool = false
skipRpmGen bool = false
skipDebGen bool = false
printGenVersion bool = false
"github.com/grafana/grafana/pkg/build"
)
func main() {
log.SetOutput(os.Stdout)
log.SetFlags(0)
var buildIdRaw string
var buildTagsRaw string
flag.StringVar(&goarch, "goarch", runtime.GOARCH, "GOARCH")
flag.StringVar(&goos, "goos", runtime.GOOS, "GOOS")
flag.StringVar(&gocc, "cc", "", "CC")
flag.StringVar(&libc, "libc", "", "LIBC")
flag.StringVar(&buildTagsRaw, "build-tags", "", "Sets custom build tags")
flag.BoolVar(&cgo, "cgo-enabled", cgo, "Enable cgo")
flag.StringVar(&pkgArch, "pkg-arch", "", "PKG ARCH")
flag.BoolVar(&race, "race", race, "Use race detector")
flag.BoolVar(&includeBuildId, "includeBuildId", includeBuildId, "IncludeBuildId in package name")
flag.BoolVar(&enterprise, "enterprise", enterprise, "Build enterprise version of Grafana")
flag.StringVar(&buildIdRaw, "buildId", "0", "Build ID from CI system")
flag.BoolVar(&isDev, "dev", isDev, "optimal for development, skips certain steps")
flag.BoolVar(&skipRpmGen, "skipRpm", skipRpmGen, "skip rpm package generation (default: false)")
flag.BoolVar(&skipDebGen, "skipDeb", skipDebGen, "skip deb package generation (default: false)")
flag.BoolVar(&printGenVersion, "gen-version", printGenVersion, "generate Grafana version and output (default: false)")
flag.Parse()
buildId = shortenBuildId(buildIdRaw)
readVersionFromPackageJson()
if pkgArch == "" {
pkgArch = goarch
}
if printGenVersion {
printGeneratedVersion()
return
}
if len(buildTagsRaw) > 0 {
buildTags = strings.Split(buildTagsRaw, ",")
}
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
}
workingDir, _ = os.Getwd()
for _, cmd := range flag.Args() {
switch cmd {
case "setup":
setup()
case "build-srv", "build-server":
clean()
doBuild("grafana-server", "./pkg/cmd/grafana-server", buildTags)
case "build-cli":
clean()
doBuild("grafana-cli", "./pkg/cmd/grafana-cli", buildTags)
case "build":
//clean()
for _, binary := range binaries {
doBuild(binary, "./pkg/cmd/"+binary, buildTags)
}
case "build-frontend":
yarn("build")
case "sha-dist":
shaFilesInDist()
case "latest":
makeLatestDistCopies()
case "clean":
clean()
default:
log.Fatalf("Unknown command %q", cmd)
}
}
}
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",
".linux-amd64-musl.tar.gz": "dist/grafana-latest.linux-x64-musl.tar.gz",
".linux-armv7.tar.gz": "dist/grafana-latest.linux-armv7.tar.gz",
".linux-armv7-musl.tar.gz": "dist/grafana-latest.linux-armv7-musl.tar.gz",
".linux-armv6.tar.gz": "dist/grafana-latest.linux-armv6.tar.gz",
".linux-arm64.tar.gz": "dist/grafana-latest.linux-arm64.tar.gz",
".linux-arm64-musl.tar.gz": "dist/grafana-latest.linux-arm64-musl.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 includeBuildId {
if buildId != "0" {
linuxPackageIteration = fmt.Sprintf("%s%s", buildId, linuxPackageIteration)
} else {
linuxPackageIteration = fmt.Sprintf("%d%s", time.Now().Unix(), linuxPackageIteration)
}
}
}
func yarn(params ...string) {
runPrint(`yarn run`, params...)
}
func genPackageVersion() string {
if includeBuildId {
return fmt.Sprintf("%v-%v", linuxPackageVersion, linuxPackageIteration)
} else {
return version
}
}
func setup() {
args := []string{"install", "-v"}
if goos == windows {
args = append(args, "-buildmode=exe")
}
args = append(args, "./pkg/cmd/grafana-server")
runPrint("go", args...)
}
func printGeneratedVersion() {
fmt.Print(genPackageVersion())
}
func test(pkg string) {
setBuildEnv()
args := []string{"test", "-short", "-timeout", "60s"}
if goos == windows {
args = append(args, "-buildmode=exe")
}
args = append(args, pkg)
runPrint("go", args...)
}
func doBuild(binaryName, pkg string, tags []string) {
libcPart := ""
if libc != "" {
libcPart = fmt.Sprintf("-%s", libc)
}
binary := fmt.Sprintf("./bin/%s-%s%s/%s", goos, goarch, libcPart, binaryName)
if isDev {
//don't include os/arch/libc in output path in dev environment
binary = fmt.Sprintf("./bin/%s", binaryName)
}
if goos == windows {
binary += ".exe"
}
if !isDev {
rmr(binary, binary+".md5")
}
args := []string{"build", "-ldflags", ldflags()}
if goos == windows {
// Work around a linking error on Windows: "export ordinal too large"
args = append(args, "-buildmode=exe")
}
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)
if !isDev {
setBuildEnv()
runPrint("go", "version")
libcPart := ""
if libc != "" {
libcPart = fmt.Sprintf("/%s", libc)
}
fmt.Printf("Targeting %s/%s%s\n", goos, goarch, libcPart)
}
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")
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.buildBranch=%s", getGitBranch()))
if v := os.Getenv("LDFLAGS"); v != "" {
b.WriteString(fmt.Sprintf(" -extldflags \"%s\"", v))
}
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(build.Default.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 cgo {
os.Setenv("CGO_ENABLED", "1")
}
if gocc != "" {
os.Setenv("CC", gocc)
}
}
func getGitBranch() string {
v, err := runError("git", "rev-parse", "--abbrev-ref", "HEAD")
if err != nil {
return "main"
}
return string(v)
}
func getGitSha() string {
v, err := runError("git", "rev-parse", "--short", "HEAD")
if err != nil {
return "unknown-dev"
}
return string(v)
}
func buildStamp() int64 {
// use SOURCE_DATE_EPOCH if set.
if s, _ := strconv.ParseInt(os.Getenv("SOURCE_DATE_EPOCH"), 10, 64); s > 0 {
return s
}
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
}
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()
}
func shortenBuildId(buildId string) string {
buildId = strings.Replace(buildId, "-", "", -1)
if len(buildId) < 9 {
return buildId
}
return buildId[0:8]
os.Exit(build.RunCmd())
}

@ -0,0 +1,314 @@
package build
import (
"bytes"
"flag"
"fmt"
"go/build"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"time"
)
const (
GoOSWindows = "windows"
GoOSLinux = "linux"
ServerBinary = "grafana-server"
CLIBinary = "grafana-cli"
)
var binaries = []string{ServerBinary, CLIBinary}
func logError(message string, err error) int {
log.Println(message, err)
return 1
}
// RunCmd runs the build command and returns the exit code
func RunCmd() int {
opts := BuildOptsFromFlags()
wd, err := os.Getwd()
if err != nil {
return logError("Error getting working directory", err)
}
packageJSON, err := OpenPackageJSON(wd)
if err != nil {
return logError("Error opening package json", err)
}
version, iteration := LinuxPackageVersion(packageJSON.Version, opts.buildID)
if opts.printGenVersion {
fmt.Print(genPackageVersion(version, iteration))
return 0
}
log.Printf("Version: %s, Linux Version: %s, Package Iteration: %s\n", version, version, iteration)
if flag.NArg() == 0 {
log.Println("Usage: go run build.go build")
return 1
}
for _, cmd := range flag.Args() {
switch cmd {
case "setup":
setup(opts.goos)
case "build-srv", "build-server":
if !opts.isDev {
clean(opts)
}
if err := doBuild("grafana-server", "./pkg/cmd/grafana-server", opts); err != nil {
log.Println(err)
return 1
}
case "build-cli":
clean(opts)
if err := doBuild("grafana-cli", "./pkg/cmd/grafana-cli", opts); err != nil {
log.Println(err)
return 1
}
case "build":
//clean()
for _, binary := range binaries {
log.Println("building binaries", cmd)
// Can't use filepath.Join here because filepath.Join calls filepath.Clean, which removes the `./` from this path, which upsets `go build`
if err := doBuild(binary, fmt.Sprintf("./pkg/cmd/%s", binary), opts); err != nil {
log.Println(err)
return 1
}
}
case "build-frontend":
yarn("build")
case "sha-dist":
if err := shaDir("dist"); err != nil {
return logError("error packaging dist directory", err)
}
case "latest":
makeLatestDistCopies()
case "clean":
clean(opts)
default:
log.Println("Unknown command", cmd)
return 1
}
}
return 0
}
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",
".linux-amd64-musl.tar.gz": "dist/grafana-latest.linux-x64-musl.tar.gz",
".linux-armv7.tar.gz": "dist/grafana-latest.linux-armv7.tar.gz",
".linux-armv7-musl.tar.gz": "dist/grafana-latest.linux-armv7-musl.tar.gz",
".linux-armv6.tar.gz": "dist/grafana-latest.linux-armv6.tar.gz",
".linux-arm64.tar.gz": "dist/grafana-latest.linux-arm64.tar.gz",
".linux-arm64-musl.tar.gz": "dist/grafana-latest.linux-arm64-musl.tar.gz",
}
for _, file := range files {
for extension, fullName := range latestMapping {
if strings.HasSuffix(file.Name(), extension) {
if _, err := runError("cp", path.Join("dist", file.Name()), fullName); err != nil {
log.Println("error running cp command:", err)
}
}
}
}
}
func yarn(params ...string) {
runPrint(`yarn run`, params...)
}
func genPackageVersion(version string, iteration string) string {
if iteration != "" {
return fmt.Sprintf("%v-%v", version, iteration)
} else {
return version
}
}
func setup(goos string) {
args := []string{"install", "-v"}
if goos == GoOSWindows {
args = append(args, "-buildmode=exe")
}
args = append(args, "./pkg/cmd/grafana-server")
runPrint("go", args...)
}
func doBuild(binaryName, pkg string, opts BuildOpts) error {
log.Println("building", binaryName, pkg)
libcPart := ""
if opts.libc != "" {
libcPart = fmt.Sprintf("-%s", opts.libc)
}
binary := fmt.Sprintf("./bin/%s", binaryName)
//don't include os/arch/libc in output path in dev environment
if !opts.isDev {
binary = fmt.Sprintf("./bin/%s-%s%s/%s", opts.goos, opts.goarch, libcPart, binaryName)
}
if opts.goos == GoOSWindows {
binary += ".exe"
}
if !opts.isDev {
rmr(binary, binary+".md5")
}
lf, err := ldflags(opts)
if err != nil {
return err
}
args := []string{"build", "-ldflags", lf}
if opts.goos == GoOSWindows {
// Work around a linking error on Windows: "export ordinal too large"
args = append(args, "-buildmode=exe")
}
if len(opts.buildTags) > 0 {
args = append(args, "-tags", strings.Join(opts.buildTags, ","))
}
if opts.race {
args = append(args, "-race")
}
args = append(args, "-o", binary)
args = append(args, pkg)
runPrint("go", args...)
if opts.isDev {
return nil
}
if err := setBuildEnv(opts); err != nil {
return err
}
runPrint("go", "version")
libcPart = ""
if opts.libc != "" {
libcPart = fmt.Sprintf("/%s", opts.libc)
}
fmt.Printf("Targeting %s/%s%s\n", opts.goos, opts.goarch, libcPart)
// Create an md5 checksum of the binary, to be included in the archive for
// automatic upgrades.
return md5File(binary)
}
func ldflags(opts BuildOpts) (string, error) {
buildStamp, err := buildStamp()
if err != nil {
return "", err
}
var b bytes.Buffer
b.WriteString("-w")
b.WriteString(fmt.Sprintf(" -X main.version=%s", opts.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.buildBranch=%s", getGitBranch()))
if v := os.Getenv("LDFLAGS"); v != "" {
b.WriteString(fmt.Sprintf(" -extldflags \"%s\"", v))
}
return b.String(), nil
}
func setBuildEnv(opts BuildOpts) error {
if err := os.Setenv("GOOS", opts.goos); err != nil {
return err
}
if opts.goos == GoOSWindows {
// require windows >=7
if err := os.Setenv("CGO_CFLAGS", "-D_WIN32_WINNT=0x0601"); err != nil {
return err
}
}
if opts.goarch != "amd64" || opts.goos != GoOSLinux {
// needed for all other archs
opts.cgo = true
}
if strings.HasPrefix(opts.goarch, "armv") {
if err := os.Setenv("GOARCH", "arm"); err != nil {
return err
}
if err := os.Setenv("GOARM", opts.goarch[4:]); err != nil {
return err
}
} else {
if err := os.Setenv("GOARCH", opts.goarch); err != nil {
return err
}
}
if opts.cgo {
if err := os.Setenv("CGO_ENABLED", "1"); err != nil {
return err
}
}
if opts.gocc == "" {
return nil
}
return os.Setenv("CC", opts.gocc)
}
func buildStamp() (int64, error) {
// use SOURCE_DATE_EPOCH if set.
if v, ok := os.LookupEnv("SOURCE_DATE_EPOCH"); ok {
return strconv.ParseInt(v, 10, 64)
}
bs, err := runError("git", "show", "-s", "--format=%ct")
if err != nil {
return time.Now().Unix(), nil
}
return strconv.ParseInt(string(bs), 10, 64)
}
func clean(opts BuildOpts) {
rmr("dist")
rmr("tmp")
rmr(filepath.Join(build.Default.GOPATH, fmt.Sprintf("pkg/%s_%s/github.com/grafana", opts.goos, opts.goarch)))
}

@ -0,0 +1,2 @@
// Package build contains the command / functions for the Grafana build process used when running the "build" target in the makefile
package build

@ -0,0 +1,34 @@
package build
import (
"bytes"
"log"
"os"
"os/exec"
"strings"
)
func runError(cmd string, args ...string) ([]byte, error) {
// Can ignore gosec G204 because this function is not used in Grafana, only in the build process.
//nolint:gosec
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, " "))
// Can ignore gosec G204 because this function is not used in Grafana, only in the build process.
//nolint:gosec
ecmd := exec.Command(cmd, args...)
ecmd.Stdout = os.Stdout
ecmd.Stderr = os.Stderr
err := ecmd.Run()
if err != nil {
log.Fatal(err)
}
}

@ -0,0 +1,101 @@
package build
import (
"crypto/md5"
"crypto/sha256"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
)
func logAndClose(c io.Closer) {
if err := c.Close(); err != nil {
log.Println("error closing:", err)
}
}
func shaDir(dir string) error {
return filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
if path == dir {
return nil
}
if strings.Contains(path, ".sha256") {
return nil
}
if err := shaFile(path); err != nil {
log.Printf("Failed to create sha file. error: %v\n", err)
}
return nil
})
}
func shaFile(file string) error {
// Can ignore gosec G304 because this function is not used in Grafana, only in the build process.
//nolint:gosec
r, err := os.Open(file)
if err != nil {
return err
}
defer logAndClose(r)
h := sha256.New()
_, err = io.Copy(h, r)
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()
}
func md5File(file string) error {
// Can ignore gosec G304 because this function is not used in Grafana, only in the build process.
//nolint:gosec
fd, err := os.Open(file)
if err != nil {
return err
}
defer logAndClose(fd)
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()
}
// basically `rm -r`s the list of files provided
func rmr(paths ...string) {
for _, path := range paths {
log.Println("rm -r", path)
if err := os.RemoveAll(path); err != nil {
log.Println("error deleting folder", path, "error:", err)
}
}
}

@ -0,0 +1,17 @@
package build
func getGitBranch() string {
v, err := runError("git", "rev-parse", "--abbrev-ref", "HEAD")
if err != nil {
return "main"
}
return string(v)
}
func getGitSha() string {
v, err := runError("git", "rev-parse", "--short", "HEAD")
if err != nil {
return "unknown-dev"
}
return string(v)
}

@ -0,0 +1,66 @@
package build
import (
"flag"
"runtime"
"strings"
)
// BuildOpts are options provided to the build step
type BuildOpts struct {
goarch string
goos string
gocc string
cgo bool
libc string
pkgArch string
version string
buildTags []string
// deb & rpm does not support semver so have to handle their version a little differently
race bool
includeBuildID bool
buildID string
isDev bool
enterprise bool
skipRpmGen bool
skipDebGen bool
printGenVersion bool
}
// BuildOptsFromFlags reads the cmd args to assemble a BuildOpts object. This function calls flag.Parse()
func BuildOptsFromFlags() BuildOpts {
opts := BuildOpts{}
var buildIDRaw string
var buildTagsRaw string
flag.StringVar(&opts.goarch, "goarch", runtime.GOARCH, "GOARCH")
flag.StringVar(&opts.goos, "goos", runtime.GOOS, "GOOS")
flag.StringVar(&opts.gocc, "cc", "", "CC")
flag.StringVar(&opts.libc, "libc", "", "LIBC")
flag.StringVar(&buildTagsRaw, "build-tags", "", "Sets custom build tags")
flag.BoolVar(&opts.cgo, "cgo-enabled", false, "Enable cgo")
flag.StringVar(&opts.pkgArch, "pkg-arch", "", "PKG ARCH")
flag.BoolVar(&opts.race, "race", false, "Use race detector")
flag.BoolVar(&opts.includeBuildID, "includeBuildID", true, "IncludeBuildID in package name")
flag.BoolVar(&opts.enterprise, "enterprise", false, "Build enterprise version of Grafana")
flag.StringVar(&buildIDRaw, "buildID", "0", "Build ID from CI system")
flag.BoolVar(&opts.isDev, "dev", false, "optimal for development, skips certain steps")
flag.BoolVar(&opts.skipRpmGen, "skipRpm", false, "skip rpm package generation (default: false)")
flag.BoolVar(&opts.skipDebGen, "skipDeb", false, "skip deb package generation (default: false)")
flag.BoolVar(&opts.printGenVersion, "gen-version", false, "generate Grafana version and output (default: false)")
flag.Parse()
opts.buildID = shortenBuildID(buildIDRaw)
if len(buildTagsRaw) > 0 {
opts.buildTags = strings.Split(buildTagsRaw, ",")
}
if opts.pkgArch == "" {
opts.pkgArch = opts.goarch
}
return opts
}

@ -0,0 +1,66 @@
package build
import (
"encoding/json"
"fmt"
"os"
"strings"
"time"
)
type PackageJSON struct {
Version string `json:"version"`
}
// Opens the package.json file in the provided directory and returns a struct that represents its contents
func OpenPackageJSON(dir string) (PackageJSON, error) {
reader, err := os.Open("package.json")
if err != nil {
return PackageJSON{}, err
}
defer logAndClose(reader)
jsonObj := PackageJSON{}
if err := json.NewDecoder(reader).Decode(&jsonObj); err != nil {
return PackageJSON{}, err
}
return jsonObj, nil
}
// LinuxPackageVersion extracts the linux package version and iteration out of the version string. The version string is likely extracted from the package JSON.
func LinuxPackageVersion(v string, buildID string) (string, string) {
var (
version = v
iteration = ""
)
// handle pre version stuff (deb / rpm does not support semver)
parts := strings.Split(v, "-")
if len(parts) > 1 {
version = parts[0]
iteration = parts[1]
}
if buildID == "" {
return version, iteration
}
// add timestamp to iteration
if buildID != "0" {
iteration = strings.Join([]string{buildID, iteration}, "")
return version, iteration
}
return version, fmt.Sprintf("%d%s", time.Now().Unix(), iteration)
}
func shortenBuildID(buildID string) string {
buildID = strings.Replace(buildID, "-", "", -1)
if len(buildID) < 9 {
return buildID
}
return buildID[0:8]
}
Loading…
Cancel
Save