Merge pull request #39 from lyyyuna/goc-14

fix #14
This commit is contained in:
qiniu-bot 2020-06-17 15:25:27 +08:00 committed by GitHub
commit 4c7721b0e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 446 additions and 100 deletions

View File

@ -17,6 +17,8 @@
package cmd
import (
"log"
"github.com/qiniu/goc/pkg/build"
"github.com/qiniu/goc/pkg/cover"
"github.com/spf13/cobra"
@ -27,9 +29,7 @@ var buildCmd = &cobra.Command{
Short: "Do cover for all go files and execute go build command",
Long: `
First of all, this build command will copy the project code and its necessary dependencies to a temporary directory, then do cover for the target in this temporary directory, finally go build command will be executed and binaries generated to their original place.
To pass original go build flags to goc command, place them after "--", see examples below for reference.
`,
`,
Example: `
# Build the current binary with cover variables injected. The binary will be generated in the current folder.
goc build
@ -38,21 +38,13 @@ goc build
goc build --center=http://127.0.0.1:7777
# Build the current binary with cover variables injected, and redirect output to /to/this/path.
goc build -- -o /to/this/path
goc build --output /to/this/path
# Build the current binary with cover variables injected, and set necessary build flags: -ldflags "-extldflags -static" -tags="embed kodo".
goc build -- -ldflags "-extldflags -static" -tags="embed kodo"
goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'"
`,
Run: func(cmd *cobra.Command, args []string) {
gocBuild := build.NewBuild(buildFlags, packages, buildOutput)
// remove temporary directory if needed
defer gocBuild.Clean()
// doCover with original buildFlags, with new GOPATH( tmp:original )
// in the tmp directory
cover.Execute(buildFlags, gocBuild.NewGOPATH, gocBuild.TmpDir, mode, center)
// do install in the temporary directory
gocBuild.Build()
return
runBuild()
},
}
@ -63,3 +55,21 @@ func init() {
buildCmd.Flags().StringVar(&buildOutput, "output", "", "it forces build to write the resulting executable or object to the named output file or directory")
rootCmd.AddCommand(buildCmd)
}
func runBuild() {
gocBuild, err := build.NewBuild(buildFlags, packages, buildOutput)
if err != nil {
log.Fatalf("Fail to NewBuild: %v", err)
}
// remove temporary directory if needed
defer gocBuild.Clean()
// doCover with original buildFlags, with new GOPATH( tmp:original )
// in the tmp directory
cover.Execute(buildFlags, gocBuild.NewGOPATH, gocBuild.TmpDir, mode, center)
// do install in the temporary directory
err = gocBuild.Build()
if err != nil {
log.Fatalf("Fail to build: %v", err)
}
return
}

61
cmd/build_test.go Normal file
View File

@ -0,0 +1,61 @@
/*
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 cmd
import (
"github.com/stretchr/testify/assert"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
)
var baseDir string
func init() {
baseDir, _ = os.Getwd()
}
func TestGeneratedBinary(t *testing.T) {
startTime := time.Now()
workingDir := filepath.Join(baseDir, "../tests/samples/simple_project")
gopath := ""
os.Chdir(workingDir)
os.Setenv("GOPATH", gopath)
os.Setenv("GO111MODULE", "on")
buildFlags, packages, buildOutput = "", ".", ""
runBuild()
obj := filepath.Join(".", "simple-project")
fInfo, err := os.Lstat(obj)
assert.Equal(t, err, nil, "the binary should be generated.")
assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one")
cmd := exec.Command("go", "tool", "objdump", "simple-project")
cmd.Dir = workingDir
out, _ := cmd.CombinedOutput()
cnt := strings.Count(string(out), "main.registerSelf")
assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary")
cnt = strings.Count(string(out), "GoCover")
assert.Equal(t, cnt > 0, true, "GoCover varibale should be in the binary")
}

View File

@ -19,6 +19,7 @@ package cmd
import (
"github.com/qiniu/goc/pkg/build"
"github.com/qiniu/goc/pkg/cover"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@ -27,8 +28,6 @@ var installCmd = &cobra.Command{
Short: "Do cover for all go files and execute go install command",
Long: `
First of all, this install command will copy the project code and its necessary dependencies to a temporary directory, then do cover for the target in this temporary directory, finally go install command will be executed and binaries generated to their original place.
To pass original go build flags to goc command, place them after "--", see examples below for reference.
`,
Example: `
# Install all binaries with cover variables injected. The binary will be installed in $GOPATH/bin or $HOME/go/bin if directory existed.
@ -41,14 +40,7 @@ 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) {
gocBuild := build.NewInstall(buildFlags, packages)
// remove temporary directory if needed
defer gocBuild.Clean()
// doCover with original buildFlags, with new GOPATH( tmp:original )
// in the tmp directory
cover.Execute(buildFlags, gocBuild.NewGOPATH, gocBuild.TmpDir, mode, center)
// do install in the temporary directory
gocBuild.Install()
runInstall()
},
}
@ -56,3 +48,21 @@ func init() {
addBuildFlags(installCmd.Flags())
rootCmd.AddCommand(installCmd)
}
func runInstall() {
gocBuild, err := build.NewInstall(buildFlags, packages)
if err != nil {
log.Fatalf("Fail to NewInstall: %v", err)
}
// remove temporary directory if needed
defer gocBuild.Clean()
// doCover with original buildFlags, with new GOPATH( tmp:original )
// in the tmp directory
cover.Execute(buildFlags, gocBuild.NewGOPATH, gocBuild.TmpDir, mode, center)
// do install in the temporary directory
err = gocBuild.Install()
if err != nil {
log.Fatalf("Fail to install: %v", err)
}
return
}

83
cmd/install_test.go Normal file
View File

@ -0,0 +1,83 @@
/*
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 cmd
import (
"github.com/stretchr/testify/assert"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
)
func TestInstalledBinaryForMod(t *testing.T) {
startTime := time.Now()
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, buildOutput = "", ".", ""
runInstall()
obj := filepath.Join(gopath, "bin", "simple-project")
fInfo, err := os.Lstat(obj)
assert.Equal(t, err, nil, "the binary should be generated.")
assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one")
cmd := exec.Command("go", "tool", "objdump", "simple-project")
cmd.Dir = workingDir
out, _ := cmd.CombinedOutput()
cnt := strings.Count(string(out), "main.registerSelf")
assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary")
cnt = strings.Count(string(out), "GoCover")
assert.Equal(t, cnt > 0, true, "GoCover varibale should be in the binary")
}
func TestInstalledBinaryForLegacy(t *testing.T) {
startTime := time.Now()
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, packages, buildOutput = "", ".", ""
runInstall()
obj := filepath.Join(gopath, "bin", "simple_gopath_project")
fInfo, err := os.Lstat(obj)
assert.Equal(t, err, nil, "the binary should be generated.")
assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one")
cmd := exec.Command("go", "tool", "objdump", obj)
cmd.Dir = workingDir
out, _ := cmd.CombinedOutput()
cnt := strings.Count(string(out), "main.registerSelf")
assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary")
cnt = strings.Count(string(out), "GoCover")
assert.Equal(t, cnt > 0, true, "GoCover varibale should be in the binary")
}

View File

@ -36,7 +36,7 @@ It is exactly behave as 'go run .' in addition of some internal goc features.`,
goc run .
`,
Run: func(cmd *cobra.Command, args []string) {
gocBuild := build.NewBuild(buildFlags, packages, buildOutput)
gocBuild, _ := build.NewBuild(buildFlags, packages, buildOutput)
gocBuild.GoRunExecFlag = goRunExecFlag
gocBuild.GoRunArguments = goRunArguments
defer gocBuild.Clean()

View File

@ -35,9 +35,12 @@ type Build struct {
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
Root string // Project Root
Root string
// go 1.11, go 1.12 has no Root
// Project Root:
// 1. legacy, root == GOPATH
// 2. mod, root == go.mod Dir
Target string // the binary name that go build generate
// keep compatible with go commands:
// go run [build flags] [-exec xprog] package [arguments...]
// go build [-o output] [-i] [build flags] [packages]
@ -50,26 +53,33 @@ 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, packages string, outputDir string) *Build {
func NewBuild(buildflags string, packages string, outputDir string) (*Build, error) {
// buildflags = buildflags + " -o " + outputDir
b := &Build{
BuildFlags: buildflags,
Packages: packages,
}
if false == b.validatePackageForBuild() {
log.Fatalln("packages only support \".\"")
log.Errorln(ErrWrongPackageTypeForBuild)
return nil, ErrWrongPackageTypeForBuild
}
b.MvProjectsToTmp()
b.Target = b.determineOutputDir(outputDir)
return b
dir, err := b.determineOutputDir(outputDir)
b.Target = dir
if err != nil {
return nil, err
}
return b, nil
}
func (b *Build) Build() {
func (b *Build) Build() error {
log.Infoln("Go building in temp...")
// new -o will overwrite previous ones
b.BuildFlags = b.BuildFlags + " -o " + b.Target
cmd := exec.Command("/bin/bash", "-c", "go build "+b.BuildFlags+" "+b.Packages)
cmd.Dir = b.TmpWorkingDir
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if b.NewGOPATH != "" {
// Change to temp GOPATH for go install command
@ -77,22 +87,30 @@ func (b *Build) Build() {
}
log.Printf("go build cmd is: %v", cmd.Args)
out, err := cmd.CombinedOutput()
err := cmd.Start()
if err != nil {
log.Fatalf("Fail to execute: %v. The error is: %v, the stdout/stderr is: %v", cmd.Args, err, string(out))
log.Errorf("Fail to execute: %v. The error is: %v", cmd.Args, err)
return fmt.Errorf("fail to execute: %v: %w", cmd.Args, err)
}
if err = cmd.Wait(); err != nil {
log.Errorf("go build failed. The error is: %v", err)
return fmt.Errorf("go build faileds: %w", err)
}
log.Println("Go build exit successful.")
return nil
}
// determineOutputDir, as we only allow . as package name,
// the binary name is always same as the directory name of current directory
func (b *Build) determineOutputDir(outputDir string) string {
func (b *Build) determineOutputDir(outputDir string) (string, error) {
if b.TmpDir == "" {
log.Fatalln("Can only be called after Build.MvProjectsToTmp().")
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.Fatalf("Cannot get current working directory, the err: %v.", err)
log.Errorf("Cannot get current working directory: %v", err)
return "", fmt.Errorf("cannot get current working directory: %w", err)
}
if outputDir == "" {
@ -102,13 +120,14 @@ func (b *Build) determineOutputDir(outputDir string) string {
// replace "_" with "-" in the import path
last = strings.ReplaceAll(last, "_", "-")
}
return filepath.Join(curWorkingDir, last)
return filepath.Join(curWorkingDir, last), nil
}
abs, err := filepath.Abs(outputDir)
if err != nil {
log.Fatalf("Fail to transform the path: %v to absolute path, the error is: %v", outputDir, err)
log.Errorf("Fail to transform the path: %v to absolute path: %v", outputDir, err)
return "", fmt.Errorf("fail to transform the path %v to absolute path: %w", outputDir, err)
}
return abs
return abs, nil
}
// validatePackageForBuild only allow . as package name

53
pkg/build/build_test.go Normal file
View File

@ -0,0 +1,53 @@
/*
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 (
"github.com/stretchr/testify/assert"
"os"
"path/filepath"
"testing"
)
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("", "example.com/simple-project", "")
assert.Equal(t, err, ErrWrongPackageTypeForBuild, "the package name should be invalid")
}
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, packages, buildOutput := "", ".", ""
gocBuild, err := NewBuild(buildFlags, packages, buildOutput)
assert.Equal(t, err, nil, "should create temporary directory successfully")
err = gocBuild.Build()
assert.Equal(t, err, nil, "temporary directory should build successfully")
}

14
pkg/build/errors.go Normal file
View File

@ -0,0 +1,14 @@
package build
import (
"errors"
)
var (
ErrShouldNotReached = errors.New("should never be reached")
ErrGocShouldExecInProject = errors.New("goc not executed in project directory")
ErrWrongPackageTypeForInstall = errors.New("packages only support \".\" and \"./...\"")
ErrWrongPackageTypeForBuild = errors.New("packages only support \".\"")
ErrWrongCallSequence = errors.New("function should be called in a specified sequence")
ErrNoplaceToInstall = errors.New("no go env")
)

View File

@ -28,7 +28,7 @@ func (b *Build) cpGoModulesProject() {
src := v.Module.Dir
if err := copy.Copy(src, dst); err != nil {
log.Printf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err)
log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err)
}
break
} else {

View File

@ -25,36 +25,50 @@ import (
)
// NewInstall creates a Build struct which can install from goc temporary directory
func NewInstall(buildflags string, packages string) *Build {
func NewInstall(buildflags string, packages string) (*Build, error) {
b := &Build{
BuildFlags: buildflags,
Packages: packages,
}
if false == b.validatePackageForInstall() {
log.Fatalln("packages only support . and ./...")
log.Errorln(ErrWrongPackageTypeForInstall)
return nil, ErrWrongPackageTypeForInstall
}
b.MvProjectsToTmp()
return b
return b, nil
}
func (b *Build) Install() {
func (b *Build) Install() error {
log.Println("Go building in temp...")
cmd := exec.Command("/bin/bash", "-c", "go install "+b.BuildFlags+" "+b.Packages)
cmd.Dir = b.TmpWorkingDir
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
whereToInstall, err := b.findWhereToInstall()
if err != nil {
// ignore the err
log.Errorf("No place to install: %v", err)
}
// Change the temp GOBIN, to force binary install to original place
cmd.Env = append(os.Environ(), fmt.Sprintf("GOBIN=%v", b.findWhereToInstall()))
cmd.Env = append(os.Environ(), fmt.Sprintf("GOBIN=%v", whereToInstall))
if b.NewGOPATH != "" {
// Change to temp GOPATH for go install command
cmd.Env = append(cmd.Env, fmt.Sprintf("GOPATH=%v", b.NewGOPATH))
}
log.Printf("go install cmd is: %v", cmd.Args)
out, err := cmd.CombinedOutput()
log.Infof("go install cmd is: %v", cmd.Args)
err = cmd.Start()
if err != nil {
log.Fatalf("Fail to execute: %v. The error is: %v, the stdout/stderr is: %v", cmd.Args, err, string(out))
log.Errorf("Fail to execute: %v. The error is: %v", cmd.Args, err)
return fmt.Errorf("fail to execute: %v: %w", cmd.Args, err)
}
log.Printf("Go install successful. Binary installed in: %v", b.findWhereToInstall())
if err = cmd.Wait(); err != nil {
log.Errorf("go install failed. The error is: %v", err)
return fmt.Errorf("go install failed: %w", err)
}
log.Infof("Go install successful. Binary installed in: %v", whereToInstall)
return nil
}
func (b *Build) validatePackageForInstall() bool {

24
pkg/build/install_test.go Normal file
View File

@ -0,0 +1,24 @@
package build
import (
"github.com/stretchr/testify/assert"
"os"
"path/filepath"
"testing"
)
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 := "", "."
gocBuild, err := NewInstall(buildFlags, packages)
assert.Equal(t, err, nil, "should create temporary directory successfully")
err = gocBuild.Install()
assert.Equal(t, err, nil, "temporary directory should build successfully")
}

View File

@ -20,9 +20,10 @@ import (
"os"
"path/filepath"
log "github.com/sirupsen/logrus"
"github.com/otiai10/copy"
"github.com/qiniu/goc/pkg/cover"
log "github.com/sirupsen/logrus"
)
func (b *Build) cpLegacyProject() {
@ -37,7 +38,7 @@ func (b *Build) cpLegacyProject() {
}
if err := copy.Copy(src, dst); err != nil {
log.Printf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err)
log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err)
}
visited[src] = true
@ -73,9 +74,25 @@ func (b *Build) cpDepPackages(pkg *cover.Package, visited map[string]bool) {
dst := filepath.Join(b.TmpDir, "src", dep)
if err := copy.Copy(src, dst); err != nil {
log.Printf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err)
log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err)
}
visited[src] = true
}
}
func (b *Build) cpNonStandardLegacy() {
for _, v := range b.Pkgs {
if v.Name == "main" {
dst := b.TmpDir
src := v.Dir
if err := copy.Copy(src, dst); err != nil {
log.Printf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err)
}
break
} else {
continue
}
}
}

View File

@ -18,6 +18,7 @@ package build
import (
"crypto/sha256"
"errors"
"fmt"
"os"
"path/filepath"
@ -47,17 +48,20 @@ func (b *Build) MvProjectsToTmp() {
}
// fix #14: unable to build project not in GOPATH in legacy mode
// this kind of project does not have a pkg.Root value
if b.Root == "" {
// go 1.11, 1.12 has no pkg.Root,
// so add b.IsMod == false as secondary judgement
if b.Root == "" && b.IsMod == false {
b.NewGOPATH = b.OriGOPATH
}
log.Printf("New GOPATH: %v", b.NewGOPATH)
return
}
func (b *Build) mvProjectsToTmp() {
func (b *Build) mvProjectsToTmp() error {
path, err := os.Getwd()
if err != nil {
log.Fatalf("Cannot get current working directory, the error is: %v", err)
log.Errorf("Cannot get current working directory, the error is: %v", err)
return err
}
b.TmpDir = filepath.Join(os.TempDir(), TmpFolderName(path))
@ -66,20 +70,39 @@ func (b *Build) mvProjectsToTmp() {
// Create a new tmp folder
err = os.MkdirAll(filepath.Join(b.TmpDir, "src"), os.ModePerm)
if err != nil {
log.Fatalf("Fail to create the temporary build directory. The err is: %v", err)
log.Errorf("Fail to create the temporary build directory. The err is: %v", err)
return err
}
log.Printf("Tmp project generated in: %v", b.TmpDir)
// set Build.IsMod flag, so we don't have to call checkIfLegacyProject another time
if b.checkIfLegacyProject() {
b.cpLegacyProject()
} else {
b.IsMod = true
b.cpGoModulesProject()
// traverse pkg list to get project meta info
b.IsMod, b.Root, err = b.traversePkgsList()
if errors.Is(err, ErrShouldNotReached) {
return fmt.Errorf("mvProjectsToTmp with a empty project: %w", err)
}
// we should get corresponding working directory in temporary directory
b.TmpWorkingDir, err = b.getTmpwd()
if err != nil {
log.Errorf("fail to get workding directory in temporary directory: %v", err)
return fmt.Errorf("fail to get workding directory in temporary directory: %w", err)
}
// issue #14
// if b.Root == "", then the project is non-standard project
// known cases:
// 1. a legacy project, but not in any GOPATH, will cause the b.Root == ""
if b.IsMod == false && b.Root != "" {
b.cpLegacyProject()
} else if b.IsMod == true { // go 1.11, 1.12 has no Build.Root
b.cpGoModulesProject()
} else if b.IsMod == false && b.Root == "" {
b.TmpWorkingDir = b.TmpDir
b.cpNonStandardLegacy()
} else {
return fmt.Errorf("unknown project type: %w", ErrShouldNotReached)
}
b.getTmpwd()
log.Printf("New workingdir in tmp directory in: %v", b.TmpWorkingDir)
log.Infof("New workingdir in tmp directory in: %v", b.TmpWorkingDir)
return nil
}
func TmpFolderName(path string) string {
@ -89,29 +112,35 @@ func TmpFolderName(path string) string {
return "goc-" + h
}
// checkIfLegacyProject Check if it is go module project
// true legacy
// false go mod
func (b *Build) checkIfLegacyProject() bool {
// traversePkgsList travse the Build.Pkgs list
// return Build.IsMod, tell if the project is a mod project
// return Build.Root:
// 1. the project root if it is a mod project,
// 2. current GOPATH if it is a legacy project,
// 3. some non-standard project, which Build.IsMod == false, Build.Root == nil
func (b *Build) traversePkgsList() (isMod bool, root string, err error) {
for _, v := range b.Pkgs {
// get root
b.Root = v.Root
root = v.Root
if v.Module == nil {
return true
return
}
return false
isMod = true
return
}
log.Fatalln("Should never be reached....")
return false
log.Error("should not reach here")
err = ErrShouldNotReached
return
}
// getTmpwd get the corresponding working directory in the temporary working directory
// and store it in the Build.tmpWorkdingDir
func (b *Build) getTmpwd() {
func (b *Build) getTmpwd() (string, error) {
for _, pkg := range b.Pkgs {
path, err := os.Getwd()
if err != nil {
log.Fatalf("Cannot get current working directory, the error is: %v", err)
log.Errorf("cannot get current working directory: %v", err)
return "", fmt.Errorf("cannot get current working directory: %w", err)
}
index := -1
@ -125,33 +154,32 @@ func (b *Build) getTmpwd() {
}
if index == -1 {
log.Fatalf("goc install not executed in project directory.")
return "", ErrGocShouldExecInProject
}
b.TmpWorkingDir = filepath.Join(b.TmpDir, path[len(parentPath):])
// log.Printf("New building directory in: %v", tmpwd)
return
// b.TmpWorkingDir = filepath.Join(b.TmpDir, path[len(parentPath):])
return filepath.Join(b.TmpDir, path[len(parentPath):]), nil
}
log.Fatalln("Should never be reached....")
return
return "", ErrShouldNotReached
}
func (b *Build) findWhereToInstall() string {
func (b *Build) findWhereToInstall() (string, error) {
if GOBIN := os.Getenv("GOBIN"); GOBIN != "" {
return GOBIN
return GOBIN, nil
}
// old GOPATH dir
GOPATH := os.Getenv("GOPATH")
if false == b.IsMod {
for _, v := range b.Pkgs {
return filepath.Join(v.Root, "bin")
if b.Root == "" {
return "", ErrNoplaceToInstall
}
return filepath.Join(b.Root, "bin"), nil
}
if GOPATH != "" {
return filepath.Join(strings.Split(GOPATH, ":")[0], "bin")
return filepath.Join(strings.Split(GOPATH, ":")[0], "bin"), nil
}
return filepath.Join(os.Getenv("HOME"), "go", "bin")
return filepath.Join(os.Getenv("HOME"), "go", "bin"), nil
}
// Clean clears up the temporary workspace

View File

@ -24,16 +24,22 @@ import (
"testing"
)
var baseDir string
func init() {
baseDir, _ = os.Getwd()
}
func TestNewDirParseInLegacyProject(t *testing.T) {
workingDir := "../../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project"
gopath, _ := filepath.Abs("../../tests/samples/simple_gopath_project")
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)
fmt.Println(gopath)
os.Setenv("GOPATH", gopath)
os.Setenv("GO111MODULE", "off")
b := NewInstall("", ".")
b, _ := NewInstall("", ".")
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
}
@ -42,7 +48,7 @@ func TestNewDirParseInLegacyProject(t *testing.T) {
t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir)
}
b = NewBuild("", ".", "")
b, _ = NewBuild("", ".", "")
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
}
@ -53,7 +59,7 @@ func TestNewDirParseInLegacyProject(t *testing.T) {
}
func TestNewDirParseInModProject(t *testing.T) {
workingDir := "../../tests/samples/simple_project"
workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project")
gopath := ""
os.Chdir(workingDir)
@ -61,7 +67,7 @@ func TestNewDirParseInModProject(t *testing.T) {
os.Setenv("GOPATH", gopath)
os.Setenv("GO111MODULE", "on")
b := NewInstall("", ".")
b, _ := NewInstall("", ".")
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
}
@ -70,7 +76,7 @@ func TestNewDirParseInModProject(t *testing.T) {
t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir)
}
b = NewBuild("", ".", "")
b, _ = NewBuild("", ".", "")
if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) {
t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir)
}
@ -82,15 +88,21 @@ func TestNewDirParseInModProject(t *testing.T) {
// Test #14
func TestLegacyProjectNotInGoPATH(t *testing.T) {
workingDir := "../../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project"
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("", ".", "")
b, _ := NewBuild("", ".", "")
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)
}
_, err := os.Stat(filepath.Join(b.TmpDir, "main.go"))
if err != nil {
t.Fatalf("There should be a main.go in temporary directory directly, the error: %v", err)
}
}

View File

@ -56,6 +56,7 @@ var _ = Describe("E2E", func() {
testProjDir := filepath.Join(TESTS_ROOT, "samples/simple_project")
cmd := exec.Command("goc", "build", "--debug")
cmd.Dir = testProjDir
cmd.Env = append(os.Environ(), "GO111MODULE=on")
out, err := cmd.CombinedOutput()
Expect(err).To(BeNil(), "goc build on this project should be successful", string(out))

View File

@ -22,4 +22,4 @@ chmod +x /home/runner/tools/e2e.test/e2e.test
export PATH=/home/runner/tools/e2e.test:$PATH
cd e2e
e2e.test ./...
e2e.test -test.v ./...