From 087431f02912cead52cc9a563aae85ba85009383 Mon Sep 17 00:00:00 2001 From: aarzilli Date: Mon, 28 May 2018 20:28:39 +0200 Subject: [PATCH] Makefile: replace makefile with a script We were using our makefile not for the intended purpose of makefiles but to multiplex a series of small scripts. We can easily achieve the same result in a more reasonable programming language and as a bonus we don't need to install a version of make on windows anymore. Additionally our test script had become fairly complicated and will become even more complicated when testing of PIE buildmode is introduced. Allows the tests to run on Windows without having to install Mingw (although we still want it installed so that we can run cgo tests on Windows). Fixes building when GOPATH isn't set. Fixes #759 --- Makefile | 102 ++------------ cmd/dlv/dlv_test.go | 24 ++-- scripts/make.go | 323 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+), 106 deletions(-) create mode 100644 scripts/make.go diff --git a/Makefile b/Makefile index ea7a9072..59fde3af 100644 --- a/Makefile +++ b/Makefile @@ -1,104 +1,24 @@ .DEFAULT_GOAL=test -UNAME=$(shell uname) -PREFIX=github.com/derekparker/delve -GOPATH=$(shell go env GOPATH) -GOVERSION=$(shell go version) -BUILD_SHA=$(shell git rev-parse HEAD) -LLDB_SERVER=$(shell which lldb-server) -ifeq "$(UNAME)" "Darwin" - BUILD_FLAGS=-ldflags="-s -X main.Build=$(BUILD_SHA)" -else - BUILD_FLAGS=-ldflags="-X main.Build=$(BUILD_SHA)" -endif - -# Workaround for GO15VENDOREXPERIMENT bug (https://github.com/golang/go/issues/11659) -ALL_PACKAGES=$(shell go list ./... | grep -v /vendor/ | grep -v /scripts) - -# We must compile with -ldflags="-s" to omit -# DWARF info on OSX when compiling with the -# 1.5 toolchain. Otherwise the resulting binary -# will be malformed once we codesign it and -# unable to execute. -# See https://github.com/golang/go/issues/11887#issuecomment-126117692. -ifeq "$(UNAME)" "Darwin" - TEST_FLAGS=-count 1 -exec=$(shell pwd)/scripts/testsign - export PROCTEST=lldb - DARWIN="true" -else - TEST_FLAGS=-count 1 -endif - -# If we're on OSX make sure the proper CERT env var is set. check-cert: -ifneq "$(TRAVIS)" "true" -ifdef DARWIN -ifeq "$(CERT)" "" - scripts/gencert.sh || (echo "An error occurred when generating and installing a new certificate"; exit 1) - CERT = dlv-cert -endif -endif -endif + @go run scripts/make.go check-cert -build: check-cert - go build $(BUILD_FLAGS) github.com/derekparker/delve/cmd/dlv -ifdef DARWIN -ifdef CERT - codesign -s "$(CERT)" ./dlv -endif -endif +build: + @go run scripts/make.go build -install: check-cert - go install $(BUILD_FLAGS) github.com/derekparker/delve/cmd/dlv -ifdef DARWIN -ifneq "$(GOBIN)" "" - codesign -s "$(CERT)" $(GOBIN)/dlv -else - codesign -s "$(CERT)" $(GOPATH)/bin/dlv -endif -endif +install: + @go run scripts/make.go install -test: check-cert -ifeq "$(TRAVIS)" "true" -ifdef DARWIN - sudo -E go test -p 1 -count 1 -v $(ALL_PACKAGES) -else - go test -p 1 $(TEST_FLAGS) $(BUILD_FLAGS) $(ALL_PACKAGES) -endif -else - go test -p 1 $(TEST_FLAGS) $(BUILD_FLAGS) $(ALL_PACKAGES) -endif -ifneq "$(shell which lldb-server 2>/dev/null)" "" - @echo - @echo 'Testing LLDB backend (proc)' - go test $(TEST_FLAGS) $(BUILD_FLAGS) $(PREFIX)/pkg/proc -backend=lldb - @echo - @echo 'Testing LLDB backend (integration)' - go test $(TEST_FLAGS) $(BUILD_FLAGS) $(PREFIX)/service/test -backend=lldb - @echo - @echo 'Testing LLDB backend (terminal)' - go test $(TEST_FLAGS) $(BUILD_FLAGS) $(PREFIX)/pkg/terminal -backend=lldb -endif -ifneq "$(shell which rr 2>/dev/null)" "" - @echo - @echo 'Testing Mozilla RR backend (proc)' - go test $(TEST_FLAGS) $(BUILD_FLAGS) $(PREFIX)/pkg/proc -backend=rr - @echo - @echo 'Testing Mozilla RR backend (integration)' - go test $(TEST_FLAGS) $(BUILD_FLAGS) $(PREFIX)/service/test -backend=rr - @echo - @echo 'Testing Mozilla RR backend (terminal)' - go test $(TEST_FLAGS) $(BUILD_FLAGS) $(PREFIX)/pkg/terminal -backend=rr -endif +test: + @go run scripts/make.go test test-proc-run: - go test $(TEST_FLAGS) $(BUILD_FLAGS) -test.v -test.run="$(RUN)" -backend=$(BACKEND) $(PREFIX)/pkg/proc + @go run scripts/make.go test -s proc -r $(RUN) test-integration-run: - go test $(TEST_FLAGS) $(BUILD_FLAGS) -test.run="$(RUN)" -backend=$(BACKEND) $(PREFIX)/service/test + @go run scripts/make.go test -s service/test -r ($RUN) -vendor: glide.yaml - @glide up -v - @glide-vc --use-lock-file --no-tests --only-code +vendor: + @go run scripts/make.go vendor .PHONY: vendor test-integration-run test-proc-run test check-cert install build diff --git a/cmd/dlv/dlv_test.go b/cmd/dlv/dlv_test.go index a50ce235..807ec67f 100644 --- a/cmd/dlv/dlv_test.go +++ b/cmd/dlv/dlv_test.go @@ -59,28 +59,22 @@ func goPath(name string) string { func TestBuild(t *testing.T) { const listenAddr = "localhost:40573" var err error - makedir := filepath.Join(goPath("GOPATH"), "src", "github.com", "derekparker", "delve") - for _, makeProgram := range []string{"make", "mingw32-make"} { - var out []byte - cmd := exec.Command(makeProgram, "build") - cmd.Dir = makedir - out, err = cmd.CombinedOutput() - if err == nil { - break - } else { - t.Logf("makefile error %s (%s): %v", makeProgram, makedir, err) - t.Logf("output %s", string(out)) - } + + cmd := exec.Command("go", "run", "scripts/make.go", "build") + cmd.Dir = filepath.Join(goPath("GOPATH"), "src", "github.com", "derekparker", "delve") + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("makefile error: %v\noutput %s\n", err, string(out)) } - assertNoError(err, t, "make") - dlvbin := filepath.Join(makedir, "dlv") + + dlvbin := filepath.Join(cmd.Dir, "dlv") defer os.Remove(dlvbin) fixtures := protest.FindFixturesDir() buildtestdir := filepath.Join(fixtures, "buildtest") - cmd := exec.Command(dlvbin, "debug", "--headless=true", "--listen="+listenAddr, "--api-version=2", "--backend="+testBackend, "--log", "--log-output=debugger,rpc") + cmd = exec.Command(dlvbin, "debug", "--headless=true", "--listen="+listenAddr, "--api-version=2", "--backend="+testBackend, "--log", "--log-output=debugger,rpc") cmd.Dir = buildtestdir stderr, err := cmd.StderrPipe() assertNoError(err, t, "stderr pipe") diff --git a/scripts/make.go b/scripts/make.go new file mode 100644 index 00000000..f730000b --- /dev/null +++ b/scripts/make.go @@ -0,0 +1,323 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "sort" + "strings" + + "github.com/spf13/cobra" +) + +const DelveMainPackagePath = "github.com/derekparker/delve/cmd/dlv" + +var Verbose bool +var TestSet, TestRegex, TestBackend string + +func NewMakeCommands() *cobra.Command { + RootCommand := &cobra.Command{ + Use: "make.go", + Short: "make script for delve.", + } + + RootCommand.AddCommand(&cobra.Command{ + Use: "check-cert", + Short: "Check certificate for macOS.", + Run: checkCertCmd, + }) + + RootCommand.AddCommand(&cobra.Command{ + Use: "build", + Short: "Build delve", + Run: func(cmd *cobra.Command, args []string) { + checkCertCmd(nil, nil) + execute("go", "build", buildFlags(), DelveMainPackagePath) + if runtime.GOOS == "darwin" && os.Getenv("CERT") != "" { + codesign("./dlv") + } + }, + }) + + RootCommand.AddCommand(&cobra.Command{ + Use: "install", + Short: "Installs delve", + Run: func(cmd *cobra.Command, args []string) { + checkCertCmd(nil, nil) + execute("go", "install", buildFlags(), DelveMainPackagePath) + if runtime.GOOS == "darwin" { + codesign(installedExecutablePath()) + } + }, + }) + + test := &cobra.Command{ + Use: "test", + Short: "Tests delve", + Long: `Tests delve. + +Use the flags -s, -r and -b to specify which tests to run. Specifying nothing is equivalent to: + + go run scripts/make.go test -s all -b default + go run scripts/make.go test -s basic -b lldb + go run scripts/make.go test -s basic -b rr + +with lldb and rr tests only run if the relevant programs are installed.`, + Run: testCmd, + } + test.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "Verbose tests") + test.PersistentFlags().StringVarP(&TestSet, "test-set", "s", "", `Select the set of tests to run, one of either: + all tests all packages + basic tests proc, integration and terminal + integration tests github.com/derekparker/delve/service/test + package-name test the specified package only +`) + test.PersistentFlags().StringVarP(&TestRegex, "test-run", "r", "", `Only runs the tests matching the specified regex. This option can only be specified if testset is a single package`) + test.PersistentFlags().StringVarP(&TestBackend, "test-backend", "b", "", `Runs tests for the specified backend only, one of either: + default the default backend + lldb lldb backend + rr rr backend + +This option can only be specified if testset is basic or a single package.`) + + RootCommand.AddCommand(test) + + RootCommand.AddCommand(&cobra.Command{ + Use: "vendor", + Short: "vendors dependencies", + Run: func(cmd *cobra.Command, args []string) { + execute("glide", "up", "-v") + execute("glide-vc", "--use-lock-file", "--no-tests", "--only-code") + }, + }) + + return RootCommand +} + +func checkCertCmd(cmd *cobra.Command, args []string) { + // If we're on OSX make sure the proper CERT env var is set. + if os.Getenv("TRAVIS") == "true" || runtime.GOOS != "darwin" || os.Getenv("CERT") != "" { + return + } + + x := exec.Command("scripts/gencert.sh") + err := x.Run() + if x.ProcessState != nil && !x.ProcessState.Success() { + fmt.Printf("An error occurred when generating and installing a new certificate\n") + os.Exit(1) + } + if err != nil { + log.Fatal(err) + } + os.Setenv("CERT", "dlv-cert") +} + +func strflatten(v []interface{}) []string { + r := []string{} + for _, s := range v { + switch s := s.(type) { + case []string: + r = append(r, s...) + case string: + if s != "" { + r = append(r, s) + } + } + } + return r +} + +func executeq(cmd string, args ...interface{}) { + x := exec.Command(cmd, strflatten(args)...) + x.Stdout = os.Stdout + x.Stderr = os.Stderr + x.Env = os.Environ() + err := x.Run() + if x.ProcessState != nil && !x.ProcessState.Success() { + os.Exit(1) + } + if err != nil { + log.Fatal(err) + } +} + +func execute(cmd string, args ...interface{}) { + fmt.Printf("%s %s\n", cmd, strings.Join(quotemaybe(strflatten(args)), " ")) + executeq(cmd, args...) +} + +func quotemaybe(args []string) []string { + for i := range args { + if strings.Index(args[i], " ") >= 0 { + args[i] = fmt.Sprintf("%q", args[i]) + } + } + return args +} + +func getoutput(cmd string, args ...interface{}) string { + x := exec.Command(cmd, strflatten(args)...) + x.Env = os.Environ() + out, err := x.CombinedOutput() + if err != nil { + log.Fatal(err) + } + if !x.ProcessState.Success() { + os.Exit(1) + } + return string(out) +} + +func codesign(path string) { + execute("codesign", "-s", os.Getenv("CERT"), path) +} + +func installedExecutablePath() string { + if gobin := os.Getenv("GOBIN"); gobin != "" { + return filepath.Join(gobin, "dlv") + } + gopath := strings.Split(getoutput("go", "env", "GOPATH"), ":") + return filepath.Join(gopath[0], "dlv") +} + +func buildFlags() []string { + buildSHA, err := exec.Command("git", "rev-parse", "HEAD").CombinedOutput() + if err != nil { + log.Fatal(err) + } + ldFlags := "-X main.Build=" + strings.TrimSpace(string(buildSHA)) + if runtime.GOOS == "darwin" { + ldFlags = "-s " + ldFlags + } + return []string{fmt.Sprintf("-ldflags=%s", ldFlags)} +} + +func testFlags() []string { + wd, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + testFlags := []string{"-count", "1", "-p", "1"} + if Verbose { + testFlags = append(testFlags, "-v") + } + if runtime.GOOS == "darwin" { + testFlags = append(testFlags, "-exec="+wd+"/scripts/testsign") + } + return testFlags +} + +func testCmd(cmd *cobra.Command, args []string) { + checkCertCmd(nil, nil) + + if os.Getenv("TRAVIS") == "true" && runtime.GOOS == "darwin" { + os.Setenv("PROCTEST", "lldb") + executeq("sudo", "-E", "go", "test", testFlags(), allPackages()) + return + } + + if TestSet == "" && TestBackend == "" { + if TestRegex != "" { + fmt.Printf("Can not use --test-run without --test-set\n") + os.Exit(1) + } + + fmt.Println("Testing default backend") + testCmdIntl("all", "", "default") + if inpath("lldb-server") { + fmt.Println("\nTesting LLDB backend") + testCmdIntl("basic", "", "lldb") + } + if inpath("rr") { + fmt.Println("\nTesting RR backend") + testCmdIntl("basic", "", "rr") + } + return + } + + if TestSet == "" { + TestSet = "all" + } + + if TestBackend == "" { + TestBackend = "default" + } + + testCmdIntl(TestSet, TestRegex, TestBackend) +} + +func testCmdIntl(testSet, testRegex, testBackend string) { + testPackages := testSetToPackages(testSet) + if len(testPackages) == 0 { + fmt.Printf("Unknown test set %q\n", testSet) + os.Exit(1) + } + + if testRegex != "" && len(testPackages) != 1 { + fmt.Printf("Can not use test-run with test set %q\n", testSet) + os.Exit(1) + } + + backendFlag := "" + if testBackend != "" && testBackend != "default" { + if testSet != "basic" && len(testPackages) != 1 { + fmt.Printf("Can not use test-backend with test set %q\n", testSet) + os.Exit(1) + } + backendFlag = "-backend=" + testBackend + } + + if len(testPackages) > 3 { + execute("go", "test", testFlags(), buildFlags(), testPackages, backendFlag) + } else if testRegex != "" { + execute("go", "test", testFlags(), buildFlags(), testPackages, "-run="+testRegex, backendFlag) + } else { + execute("go", "test", testFlags(), buildFlags(), testPackages, backendFlag) + } +} + +func testSetToPackages(testSet string) []string { + switch testSet { + case "", "all": + return allPackages() + + case "basic": + return []string{"github.com/derekparker/delve/pkg/proc", "github.com/derekparker/delve/service/test", "github.com/derekparker/delve/pkg/terminal"} + + case "integration": + return []string{"github.com/derekparker/delve/service/test"} + + default: + for _, pkg := range allPackages() { + if pkg == testSet || strings.HasSuffix(pkg, "/"+testSet) { + return []string{pkg} + } + } + return nil + } +} + +func inpath(exe string) bool { + path, _ := exec.LookPath(exe) + return path != "" +} + +func allPackages() []string { + r := []string{} + for _, dir := range strings.Split(getoutput("go", "list", "./..."), "\n") { + dir = strings.TrimSpace(dir) + if dir == "" || strings.Contains(dir, "/vendor/") || strings.Contains(dir, "/scripts") { + continue + } + r = append(r, dir) + } + sort.Strings(r) + return r +} + +func main() { + NewMakeCommands().Execute() +} -- GitLab