get current working directory only once

This commit is contained in:
lyyyuna 2020-06-18 17:03:14 +08:00
parent 2a8d444043
commit 7916d1ee68
14 changed files with 113 additions and 92 deletions

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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
}

View File

@ -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()

View File

@ -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")
)

View File

@ -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)

View File

@ -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()

View File

@ -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)

52
pkg/build/run.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}