From 7916d1ee6887a3c7e898f75ce287953fa183f40c Mon Sep 17 00:00:00 2001 From: lyyyuna Date: Thu, 18 Jun 2020 17:03:14 +0800 Subject: [PATCH] get current working directory only once --- cmd/build.go | 12 ++++++--- cmd/build_test.go | 3 +-- cmd/install.go | 12 ++++++--- cmd/install_test.go | 6 ++--- cmd/run.go | 7 ++++- pkg/build/build.go | 45 ++++++++++---------------------- pkg/build/build_test.go | 6 ++--- pkg/build/errors.go | 3 ++- pkg/build/install.go | 8 +++--- pkg/build/install_test.go | 3 +-- pkg/build/legacy.go | 7 ----- pkg/build/run.go | 52 +++++++++++++++++++++++++++++++++++++ pkg/build/tmpfolder.go | 27 +++++-------------- pkg/build/tmpfolder_test.go | 14 ++++------ 14 files changed, 113 insertions(+), 92 deletions(-) create mode 100644 pkg/build/run.go diff --git a/cmd/build.go b/cmd/build.go index 7bbec8f..3a835c6 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -17,6 +17,8 @@ package cmd import ( + "os" + log "github.com/sirupsen/logrus" "github.com/qiniu/goc/pkg/build" @@ -44,7 +46,11 @@ goc build --output /to/this/path goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'" `, Run: func(cmd *cobra.Command, args []string) { - runBuild(args) + wd, err := os.Getwd() + if err != nil { + log.Fatalf("Fail to build: %v", err) + } + runBuild(args, wd) }, } @@ -56,8 +62,8 @@ func init() { rootCmd.AddCommand(buildCmd) } -func runBuild(args []string) { - gocBuild, err := build.NewBuild(buildFlags, args, buildOutput) +func runBuild(args []string, wd string) { + gocBuild, err := build.NewBuild(buildFlags, args, wd, buildOutput) if err != nil { log.Fatalf("Fail to build: %v", err) } diff --git a/cmd/build_test.go b/cmd/build_test.go index 407f8e5..dcf02f6 100644 --- a/cmd/build_test.go +++ b/cmd/build_test.go @@ -39,13 +39,12 @@ func TestGeneratedBinary(t *testing.T) { workingDir := filepath.Join(baseDir, "../tests/samples/simple_project") gopath := "" - os.Chdir(workingDir) os.Setenv("GOPATH", gopath) os.Setenv("GO111MODULE", "on") buildFlags, buildOutput = "", "" args := []string{"."} - runBuild(args) + runBuild(args, workingDir) obj := filepath.Join(".", "simple-project") fInfo, err := os.Lstat(obj) diff --git a/cmd/install.go b/cmd/install.go index be9b7c2..e173715 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -17,6 +17,8 @@ package cmd import ( + "os" + "github.com/qiniu/goc/pkg/build" "github.com/qiniu/goc/pkg/cover" log "github.com/sirupsen/logrus" @@ -40,7 +42,11 @@ goc install --center=http://127.0.0.1:7777 goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'" `, Run: func(cmd *cobra.Command, args []string) { - runInstall(args) + wd, err := os.Getwd() + if err != nil { + log.Fatalf("Fail to build: %v", err) + } + runInstall(args, wd) }, } @@ -49,8 +55,8 @@ func init() { rootCmd.AddCommand(installCmd) } -func runInstall(args []string) { - gocBuild, err := build.NewInstall(buildFlags, args) +func runInstall(args []string, wd string) { + gocBuild, err := build.NewInstall(buildFlags, args, wd) if err != nil { log.Fatalf("Fail to install: %v", err) } diff --git a/cmd/install_test.go b/cmd/install_test.go index a64a221..d18a674 100644 --- a/cmd/install_test.go +++ b/cmd/install_test.go @@ -33,13 +33,12 @@ func TestInstalledBinaryForMod(t *testing.T) { workingDir := filepath.Join(baseDir, "../tests/samples/simple_project") gopath := filepath.Join(baseDir, "../tests/samples/simple_project", "testhome") - os.Chdir(workingDir) os.Setenv("GOPATH", gopath) os.Setenv("GO111MODULE", "on") buildFlags, buildOutput = "", "" args := []string{"."} - runInstall(args) + runInstall(args, workingDir) obj := filepath.Join(gopath, "bin", "simple-project") fInfo, err := os.Lstat(obj) @@ -62,13 +61,12 @@ func TestInstalledBinaryForLegacy(t *testing.T) { workingDir := filepath.Join(baseDir, "../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project") gopath := filepath.Join(baseDir, "../tests/samples/simple_gopath_project") - os.Chdir(workingDir) os.Setenv("GOPATH", gopath) os.Setenv("GO111MODULE", "off") buildFlags, buildOutput = "", "" args := []string{"."} - runInstall(args) + runInstall(args, workingDir) obj := filepath.Join(gopath, "bin", "simple_gopath_project") fInfo, err := os.Lstat(obj) diff --git a/cmd/run.go b/cmd/run.go index ef20668..19d275a 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -20,6 +20,7 @@ import ( "fmt" "io/ioutil" "net" + "os" "github.com/qiniu/goc/pkg/build" "github.com/qiniu/goc/pkg/cover" @@ -36,7 +37,11 @@ It is exactly behave as 'go run .' in addition of some internal goc features.`, goc run . `, Run: func(cmd *cobra.Command, args []string) { - gocBuild, err := build.NewBuild(buildFlags, args, buildOutput) + wd, err := os.Getwd() + if err != nil { + log.Fatalf("Fail to build: %v", err) + } + gocBuild, err := build.NewBuild(buildFlags, args, buildOutput, wd) if err != nil { log.Fatalf("Fail to run: %v", err) } diff --git a/pkg/build/build.go b/pkg/build/build.go index ec743a5..3cb982d 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -32,6 +32,7 @@ type Build struct { Pkgs map[string]*cover.Package // Pkg list parsed from "go list -json ./..." command NewGOPATH string // the new GOPATH OriGOPATH string // the original GOPATH + WorkingDir string // the working directory TmpDir string // the temporary directory to build the project TmpWorkingDir string // the working directory in the temporary directory, which is corresponding to the current directory in the project directory IsMod bool // determine whether it is a Mod project @@ -53,15 +54,15 @@ type Build struct { // NewBuild creates a Build struct which can build from goc temporary directory, // and generate binary in current working directory -func NewBuild(buildflags string, args []string, outputDir string) (*Build, error) { - if len(args) > 1 { - log.Errorln(ErrTooManyArgs) - return nil, ErrTooManyArgs +func NewBuild(buildflags string, args []string, workingDir string, outputDir string) (*Build, error) { + if err := checkParameters(args, workingDir); err != nil { + return nil, err } // buildflags = buildflags + " -o " + outputDir b := &Build{ BuildFlags: buildflags, Packages: strings.Join(args, " "), + WorkingDir: workingDir, } if false == b.validatePackageForBuild() { log.Errorln(ErrWrongPackageTypeForBuild) @@ -113,20 +114,15 @@ func (b *Build) determineOutputDir(outputDir string) (string, error) { log.Errorf("Can only be called after Build.MvProjectsToTmp(): %v", ErrWrongCallSequence) return "", fmt.Errorf("can only be called after Build.MvProjectsToTmp(): %w", ErrWrongCallSequence) } - curWorkingDir, err := os.Getwd() - if err != nil { - log.Errorf("Cannot get current working directory: %v", err) - return "", err - } if outputDir == "" { - _, last := filepath.Split(curWorkingDir) + _, last := filepath.Split(b.WorkingDir) if b.IsMod { // in mod, special rule // replace "_" with "-" in the import path last = strings.ReplaceAll(last, "_", "-") } - return filepath.Join(curWorkingDir, last), nil + return filepath.Join(b.WorkingDir, last), nil } abs, err := filepath.Abs(outputDir) if err != nil { @@ -144,29 +140,14 @@ func (b *Build) validatePackageForBuild() bool { return false } -// Run excutes the main package in addition with the internal goc features -func (b *Build) Run() error { - cmd := exec.Command("/bin/bash", "-c", "go run "+b.BuildFlags+" "+b.GoRunExecFlag+" "+b.Packages+" "+b.GoRunArguments) - cmd.Dir = b.TmpWorkingDir - - if b.NewGOPATH != "" { - // Change to temp GOPATH for go install command - cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", b.NewGOPATH)) +func checkParameters(args []string, workingDir string) error { + if len(args) > 1 { + log.Errorln(ErrTooManyArgs) + return ErrTooManyArgs } - log.Infof("go build cmd is: %v", cmd.Args) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Start() - if err != nil { - log.Errorf("Fail to start command: %v. The error is: %v", cmd.Args, err) - return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) + if workingDir == "" { + return ErrInvalidWorkingDir } - - if err = cmd.Wait(); err != nil { - log.Errorf("Fail to go run: %v. The error is: %v", cmd.Args, err) - return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) - } - return nil } diff --git a/pkg/build/build_test.go b/pkg/build/build_test.go index 853978f..fcc3142 100644 --- a/pkg/build/build_test.go +++ b/pkg/build/build_test.go @@ -29,11 +29,10 @@ func TestInvalidPackage(t *testing.T) { workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") gopath := "" - os.Chdir(workingDir) os.Setenv("GOPATH", gopath) os.Setenv("GO111MODULE", "on") - _, err := NewBuild("", []string{"example.com/simple-project"}, "") + _, err := NewBuild("", []string{"example.com/simple-project"}, "", workingDir) assert.Equal(t, err, ErrWrongPackageTypeForBuild, "the package name should be invalid") } @@ -41,12 +40,11 @@ func TestBasicBuildForModProject(t *testing.T) { workingDir := filepath.Join(baseDir, "../tests/samples/simple_project") gopath := "" - os.Chdir(workingDir) os.Setenv("GOPATH", gopath) os.Setenv("GO111MODULE", "on") buildFlags, args, buildOutput := "", []string{"."}, "" - gocBuild, err := NewBuild(buildFlags, args, buildOutput) + gocBuild, err := NewBuild(buildFlags, args, buildOutput, workingDir) assert.Equal(t, err, nil, "should create temporary directory successfully") err = gocBuild.Build() diff --git a/pkg/build/errors.go b/pkg/build/errors.go index eef49b5..6359434 100644 --- a/pkg/build/errors.go +++ b/pkg/build/errors.go @@ -10,6 +10,7 @@ var ( ErrWrongPackageTypeForInstall = errors.New("packages only support \".\" and \"./...\"") ErrWrongPackageTypeForBuild = errors.New("packages only support \".\"") ErrTooManyArgs = errors.New("too many args") + ErrInvalidWorkingDir = errors.New("the working directory is invalid") ErrWrongCallSequence = errors.New("function should be called in a specified sequence") - ErrNoplaceToInstall = errors.New("no go env") + ErrNoplaceToInstall = errors.New("dont know where to install") ) diff --git a/pkg/build/install.go b/pkg/build/install.go index c6b9fa5..8546e46 100644 --- a/pkg/build/install.go +++ b/pkg/build/install.go @@ -26,14 +26,14 @@ import ( ) // NewInstall creates a Build struct which can install from goc temporary directory -func NewInstall(buildflags string, args []string) (*Build, error) { - if len(args) > 1 { - log.Errorf("Too many args") - return nil, ErrTooManyArgs +func NewInstall(buildflags string, args []string, workingDir string) (*Build, error) { + if err := checkParameters(args, workingDir); err != nil { + return nil, err } b := &Build{ BuildFlags: buildflags, Packages: strings.Join(args, " "), + WorkingDir: workingDir, } if false == b.validatePackageForInstall() { log.Errorln(ErrWrongPackageTypeForInstall) diff --git a/pkg/build/install_test.go b/pkg/build/install_test.go index 8f08b71..9b80bb1 100644 --- a/pkg/build/install_test.go +++ b/pkg/build/install_test.go @@ -12,12 +12,11 @@ func TestBasicInstallForModProject(t *testing.T) { workingDir := filepath.Join(baseDir, "../tests/samples/simple_project") gopath := filepath.Join(baseDir, "../tests/samples/simple_project", "testhome") - os.Chdir(workingDir) os.Setenv("GOPATH", gopath) os.Setenv("GO111MODULE", "on") buildFlags, packages := "", []string{"."} - gocBuild, err := NewInstall(buildFlags, packages) + gocBuild, err := NewInstall(buildFlags, packages, workingDir) assert.Equal(t, err, nil, "should create temporary directory successfully") err = gocBuild.Install() diff --git a/pkg/build/legacy.go b/pkg/build/legacy.go index 6627544..72f5c55 100644 --- a/pkg/build/legacy.go +++ b/pkg/build/legacy.go @@ -50,13 +50,6 @@ func (b *Build) cpLegacyProject() { // only cp dependency in root(current gopath), // skip deps in other GOPATHs func (b *Build) cpDepPackages(pkg *cover.Package, visited map[string]bool) { - /* - oriGOPATH := os.Getenv("GOPATH") - if oriGOPATH == "" { - oriGOPATH = filepath.Join(os.Getenv("HOME"), "go") - } - gopaths := strings.Split(oriGOPATH, ":") - */ gopath := pkg.Root for _, dep := range pkg.Deps { src := filepath.Join(gopath, "src", dep) diff --git a/pkg/build/run.go b/pkg/build/run.go new file mode 100644 index 0000000..43ca1a4 --- /dev/null +++ b/pkg/build/run.go @@ -0,0 +1,52 @@ +/* + Copyright 2020 Qiniu Cloud (qiniu.com) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package build + +import ( + "fmt" + "os" + "os/exec" + + log "github.com/sirupsen/logrus" +) + +// Run excutes the main package in addition with the internal goc features +func (b *Build) Run() error { + cmd := exec.Command("/bin/bash", "-c", "go run "+b.BuildFlags+" "+b.GoRunExecFlag+" "+b.Packages+" "+b.GoRunArguments) + cmd.Dir = b.TmpWorkingDir + + if b.NewGOPATH != "" { + // Change to temp GOPATH for go install command + cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", b.NewGOPATH)) + } + + log.Infof("go build cmd is: %v", cmd.Args) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Start() + if err != nil { + log.Errorf("Fail to start command: %v. The error is: %v", cmd.Args, err) + return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) + } + + if err = cmd.Wait(); err != nil { + log.Errorf("Fail to go run: %v. The error is: %v", cmd.Args, err) + return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) + } + + return nil +} diff --git a/pkg/build/tmpfolder.go b/pkg/build/tmpfolder.go index f9f48a6..1f64fd5 100644 --- a/pkg/build/tmpfolder.go +++ b/pkg/build/tmpfolder.go @@ -67,17 +67,12 @@ func (b *Build) MvProjectsToTmp() error { } func (b *Build) mvProjectsToTmp() error { - path, err := os.Getwd() - if err != nil { - log.Errorf("Cannot get current working directory, the error is: %v", err) - return err - } - b.TmpDir = filepath.Join(os.TempDir(), TmpFolderName(path)) + b.TmpDir = filepath.Join(os.TempDir(), TmpFolderName(b.WorkingDir)) // Delete previous tmp folder and its content os.RemoveAll(b.TmpDir) // Create a new tmp folder - err = os.MkdirAll(filepath.Join(b.TmpDir, "src"), os.ModePerm) + err := os.MkdirAll(filepath.Join(b.TmpDir, "src"), os.ModePerm) if err != nil { log.Errorf("Fail to create the temporary build directory. The err is: %v", err) return err @@ -146,19 +141,13 @@ func (b *Build) traversePkgsList() (isMod bool, root string, err error) { // and store it in the Build.tmpWorkdingDir func (b *Build) getTmpwd() (string, error) { for _, pkg := range b.Pkgs { - path, err := os.Getwd() - if err != nil { - log.Errorf("cannot get current working directory: %v", err) - return "", fmt.Errorf("cannot get current working directory: %w", err) - } - index := -1 var parentPath string if b.IsMod == false { - index = strings.Index(path, pkg.Root) + index = strings.Index(b.WorkingDir, pkg.Root) parentPath = pkg.Root } else { - index = strings.Index(path, pkg.Module.Dir) + index = strings.Index(b.WorkingDir, pkg.Module.Dir) parentPath = pkg.Module.Dir } @@ -166,7 +155,7 @@ func (b *Build) getTmpwd() (string, error) { return "", ErrGocShouldExecInProject } // b.TmpWorkingDir = filepath.Join(b.TmpDir, path[len(parentPath):]) - return filepath.Join(b.TmpDir, path[len(parentPath):]), nil + return filepath.Join(b.TmpDir, b.WorkingDir[len(parentPath):]), nil } return "", ErrShouldNotReached @@ -177,16 +166,14 @@ func (b *Build) findWhereToInstall() (string, error) { return GOBIN, nil } - // old GOPATH dir - GOPATH := os.Getenv("GOPATH") if false == b.IsMod { if b.Root == "" { return "", ErrNoplaceToInstall } return filepath.Join(b.Root, "bin"), nil } - if GOPATH != "" { - return filepath.Join(strings.Split(GOPATH, ":")[0], "bin"), nil + if b.OriGOPATH != "" { + return filepath.Join(strings.Split(b.OriGOPATH, ":")[0], "bin"), nil } return filepath.Join(os.Getenv("HOME"), "go", "bin"), nil } diff --git a/pkg/build/tmpfolder_test.go b/pkg/build/tmpfolder_test.go index 2021c78..81df11c 100644 --- a/pkg/build/tmpfolder_test.go +++ b/pkg/build/tmpfolder_test.go @@ -34,12 +34,10 @@ func TestNewDirParseInLegacyProject(t *testing.T) { workingDir := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project") gopath := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project") - os.Chdir(workingDir) - os.Setenv("GOPATH", gopath) os.Setenv("GO111MODULE", "off") - b, _ := NewInstall("", []string{"."}) + b, _ := NewInstall("", []string{"."}, workingDir) if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) } @@ -48,7 +46,7 @@ func TestNewDirParseInLegacyProject(t *testing.T) { t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir) } - b, _ = NewBuild("", []string{"."}, "") + b, _ = NewBuild("", []string{"."}, "", workingDir) if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) } @@ -62,12 +60,11 @@ func TestNewDirParseInModProject(t *testing.T) { workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") gopath := "" - os.Chdir(workingDir) fmt.Println(gopath) os.Setenv("GOPATH", gopath) os.Setenv("GO111MODULE", "on") - b, _ := NewInstall("", []string{"."}) + b, _ := NewInstall("", []string{"."}, workingDir) if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) } @@ -76,7 +73,7 @@ func TestNewDirParseInModProject(t *testing.T) { t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir) } - b, _ = NewBuild("", []string{"."}, "") + b, _ = NewBuild("", []string{"."}, "", workingDir) if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) } @@ -91,12 +88,11 @@ func TestLegacyProjectNotInGoPATH(t *testing.T) { workingDir := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project") gopath := "" - os.Chdir(workingDir) fmt.Println(gopath) os.Setenv("GOPATH", gopath) os.Setenv("GO111MODULE", "off") - b, _ := NewBuild("", []string{"."}, "") + b, _ := NewBuild("", []string{"."}, "", workingDir) if b.OriGOPATH != b.NewGOPATH { t.Fatalf("New GOPATH should be same with old GOPATH, for this kind of project. New: %v, old: %v", b.NewGOPATH, b.OriGOPATH) }