Merge pull request #143 from tongjingran/buildCopy
optimize the file copy strategy of `goc build`
This commit is contained in:
commit
b97f5f683f
@ -133,8 +133,11 @@ func (b *Build) determineOutputDir(outputDir string) (string, error) {
|
|||||||
targetName := ""
|
targetName := ""
|
||||||
for _, pkg := range b.Pkgs {
|
for _, pkg := range b.Pkgs {
|
||||||
if pkg.Name == "main" {
|
if pkg.Name == "main" {
|
||||||
_, file := filepath.Split(pkg.Target)
|
if pkg.Target != "" {
|
||||||
targetName = file
|
targetName = filepath.Base(pkg.Target)
|
||||||
|
} else {
|
||||||
|
targetName = filepath.Base(pkg.Dir)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,27 +20,9 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/otiai10/copy"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"golang.org/x/mod/modfile"
|
"golang.org/x/mod/modfile"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *Build) cpGoModulesProject() {
|
|
||||||
for _, v := range b.Pkgs {
|
|
||||||
if v.Name == "main" {
|
|
||||||
dst := b.TmpDir
|
|
||||||
src := v.Module.Dir
|
|
||||||
|
|
||||||
if err := copy.Copy(src, dst); err != nil {
|
|
||||||
log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateGoModFile rewrites the go.mod file in the temporary directory,
|
// updateGoModFile rewrites the go.mod file in the temporary directory,
|
||||||
// if it has a 'replace' directive, and the directive has a relative local path
|
// if it has a 'replace' directive, and the directive has a relative local path
|
||||||
// it will be rewritten with a absolute path.
|
// it will be rewritten with a absolute path.
|
||||||
|
@ -45,6 +45,7 @@ func TestModProjectCopyWithUnexistedDir(t *testing.T) {
|
|||||||
Module: &cover.ModulePublic{
|
Module: &cover.ModulePublic{
|
||||||
Dir: "not exied, ia mas duser", // not real one, should fail copy
|
Dir: "not exied, ia mas duser", // not real one, should fail copy
|
||||||
},
|
},
|
||||||
|
GoFiles: []string{"empty.go"},
|
||||||
}
|
}
|
||||||
pkgs["another"] = &cover.Package{}
|
pkgs["another"] = &cover.Package{}
|
||||||
b := &Build{
|
b := &Build{
|
||||||
@ -52,7 +53,7 @@ func TestModProjectCopyWithUnexistedDir(t *testing.T) {
|
|||||||
Pkgs: pkgs,
|
Pkgs: pkgs,
|
||||||
}
|
}
|
||||||
|
|
||||||
output := captureOutput(b.cpGoModulesProject)
|
output := captureOutput(b.cpProject)
|
||||||
assert.Equal(t, strings.Contains(output, "Failed to Copy"), true)
|
assert.Equal(t, strings.Contains(output, "Failed to Copy"), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ import (
|
|||||||
"github.com/qiniu/goc/pkg/cover"
|
"github.com/qiniu/goc/pkg/cover"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *Build) cpLegacyProject() {
|
func (b *Build) cpProject() {
|
||||||
visited := make(map[string]bool)
|
visited := make(map[string]bool)
|
||||||
for k, v := range b.Pkgs {
|
for k, v := range b.Pkgs {
|
||||||
dst := filepath.Join(b.TmpDir, "src", k)
|
dst := filepath.Join(b.TmpDir, "src", k)
|
||||||
@ -37,55 +37,63 @@ func (b *Build) cpLegacyProject() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := copy.Copy(src, dst); err != nil {
|
if err := b.copyDir(v); err != nil {
|
||||||
log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
visited[src] = true
|
|
||||||
|
|
||||||
b.cpDepPackages(v, visited)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// only cp dependency in root(current gopath),
|
|
||||||
// skip deps in other GOPATHs
|
|
||||||
func (b *Build) cpDepPackages(pkg *cover.Package, visited map[string]bool) {
|
|
||||||
gopath := pkg.Root
|
|
||||||
for _, dep := range pkg.Deps {
|
|
||||||
src := filepath.Join(gopath, "src", dep)
|
|
||||||
// Check if copied
|
|
||||||
if _, ok := visited[src]; ok {
|
|
||||||
// Skip if already copied
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Check if we can found in the root gopath
|
|
||||||
_, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
dst := filepath.Join(b.TmpDir, "src", dep)
|
|
||||||
|
|
||||||
if err := copy.Copy(src, dst); err != nil {
|
|
||||||
log.Errorf("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
|
visited[src] = true
|
||||||
}
|
}
|
||||||
}
|
if b.IsMod {
|
||||||
|
|
||||||
func (b *Build) cpNonStandardLegacy() {
|
|
||||||
for _, v := range b.Pkgs {
|
for _, v := range b.Pkgs {
|
||||||
if v.Name == "main" {
|
if v.Name == "main" {
|
||||||
dst := b.TmpDir
|
dst := filepath.Join(b.TmpDir, "go.mod")
|
||||||
src := v.Dir
|
src := filepath.Join(v.Module.Dir, "go.mod")
|
||||||
|
|
||||||
if err := copy.Copy(src, dst); err != nil {
|
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 go mod file from %v to %v, the error is: %v ", src, dst, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = filepath.Join(b.TmpDir, "go.sum")
|
||||||
|
src = filepath.Join(v.Module.Dir, "go.sum")
|
||||||
|
if err := copy.Copy(src, dst); err != nil && !strings.Contains(err.Error(), "no such file or directory") {
|
||||||
|
log.Errorf("Failed to Copy the go mod file from %v to %v, the error is: %v ", src, dst, err)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Build) copyDir(pkg *cover.Package) error {
|
||||||
|
fileList := []string{}
|
||||||
|
dir := pkg.Dir
|
||||||
|
fileList = append(fileList, pkg.GoFiles...)
|
||||||
|
fileList = append(fileList, pkg.CompiledGoFiles...)
|
||||||
|
fileList = append(fileList, pkg.IgnoredGoFiles...)
|
||||||
|
fileList = append(fileList, pkg.CFiles...)
|
||||||
|
fileList = append(fileList, pkg.CXXFiles...)
|
||||||
|
fileList = append(fileList, pkg.MFiles...)
|
||||||
|
fileList = append(fileList, pkg.HFiles...)
|
||||||
|
fileList = append(fileList, pkg.FFiles...)
|
||||||
|
fileList = append(fileList, pkg.SFiles...)
|
||||||
|
fileList = append(fileList, pkg.SwigCXXFiles...)
|
||||||
|
fileList = append(fileList, pkg.SwigFiles...)
|
||||||
|
fileList = append(fileList, pkg.SysoFiles...)
|
||||||
|
for _, file := range fileList {
|
||||||
|
p := filepath.Join(dir, file)
|
||||||
|
var src, root string
|
||||||
|
if pkg.Root == "" {
|
||||||
|
root = b.WorkingDir // use workingDir instead when the root is empty.
|
||||||
|
} else {
|
||||||
|
root = pkg.Root
|
||||||
|
}
|
||||||
|
src = strings.TrimPrefix(pkg.Dir, root) // get the relative path of the files
|
||||||
|
dst := filepath.Join(b.TmpDir, src, file) // it will adapt the case where src is ""
|
||||||
|
if err := copy.Copy(p, dst); err != nil {
|
||||||
|
log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -17,16 +17,37 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/qiniu/goc/pkg/cover"
|
"github.com/qiniu/goc/pkg/cover"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// copy in cpLegacyProject/cpNonStandardLegacy of invalid src, dst name
|
// copy in cpProject of invalid src, dst name
|
||||||
func TestLegacyProjectCopyWithUnexistedDir(t *testing.T) {
|
func TestLegacyProjectCopyWithUnexistedDir(t *testing.T) {
|
||||||
|
pkgs := make(map[string]*cover.Package)
|
||||||
|
pkgs["main"] = &cover.Package{
|
||||||
|
Module: &cover.ModulePublic{
|
||||||
|
Dir: "not exied, ia mas duser", // not real one, should fail copy
|
||||||
|
},
|
||||||
|
Dir: "not exit, iasdfs",
|
||||||
|
Name: "main",
|
||||||
|
GoFiles: []string{"not_exist.go"},
|
||||||
|
}
|
||||||
|
pkgs["another"] = &cover.Package{}
|
||||||
|
b := &Build{
|
||||||
|
TmpDir: "sdfsfev2234444", // not real one, should fail copy
|
||||||
|
Pkgs: pkgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
output := captureOutput(b.cpProject)
|
||||||
|
assert.Equal(t, strings.Contains(output, "Failed to Copy"), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy goMod project without go.mod
|
||||||
|
func TestGoModProjectCopyWithUnexistedModFile(t *testing.T) {
|
||||||
pkgs := make(map[string]*cover.Package)
|
pkgs := make(map[string]*cover.Package)
|
||||||
pkgs["main"] = &cover.Package{
|
pkgs["main"] = &cover.Package{
|
||||||
Module: &cover.ModulePublic{
|
Module: &cover.ModulePublic{
|
||||||
@ -39,33 +60,23 @@ func TestLegacyProjectCopyWithUnexistedDir(t *testing.T) {
|
|||||||
b := &Build{
|
b := &Build{
|
||||||
TmpDir: "sdfsfev2234444", // not real one, should fail copy
|
TmpDir: "sdfsfev2234444", // not real one, should fail copy
|
||||||
Pkgs: pkgs,
|
Pkgs: pkgs,
|
||||||
|
IsMod: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
output := captureOutput(b.cpLegacyProject)
|
output := captureOutput(b.cpProject)
|
||||||
assert.Equal(t, strings.Contains(output, "Failed to Copy"), true)
|
assert.Equal(t, strings.Contains(output, "Failed to Copy the go mod file"), true)
|
||||||
|
|
||||||
output = captureOutput(b.cpNonStandardLegacy)
|
|
||||||
assert.Equal(t, strings.Contains(output, "Failed to Copy"), true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy in cpDepPackages of invalid dst name
|
// copy needed files to tmpDir
|
||||||
func TestDepPackagesCopyWithInvalidDir(t *testing.T) {
|
func TestCopyDir(t *testing.T) {
|
||||||
gopath := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project")
|
wd, _ := os.Getwd()
|
||||||
pkg := &cover.Package{
|
pkg := &cover.Package{Dir: wd, Root: wd, GoFiles: []string{"build.go", "legacy.go"}, CgoFiles: []string{"run.go"}}
|
||||||
Module: &cover.ModulePublic{
|
tmpDir := "/tmp/test/"
|
||||||
Dir: "not exied, ia mas duser",
|
|
||||||
},
|
|
||||||
Root: gopath,
|
|
||||||
Deps: []string{"qiniu.com", "ddfee 2344234"},
|
|
||||||
}
|
|
||||||
b := &Build{
|
b := &Build{
|
||||||
TmpDir: "/", // "/" is invalid dst in Linux, it should fail
|
WorkingDir: "empty",
|
||||||
|
TmpDir: tmpDir,
|
||||||
}
|
}
|
||||||
|
assert.NoError(t, os.MkdirAll(tmpDir, os.ModePerm))
|
||||||
output := captureOutput(func() {
|
defer os.RemoveAll(tmpDir)
|
||||||
visited := make(map[string]bool)
|
assert.NoError(t, b.copyDir(pkg))
|
||||||
|
|
||||||
b.cpDepPackages(pkg, visited)
|
|
||||||
})
|
|
||||||
assert.Equal(t, strings.Contains(output, "Failed to Copy"), true)
|
|
||||||
}
|
}
|
||||||
|
@ -57,13 +57,6 @@ func (b *Build) MvProjectsToTmp() error {
|
|||||||
} else {
|
} else {
|
||||||
b.NewGOPATH = fmt.Sprintf("%v:%v", b.TmpDir, b.OriGOPATH)
|
b.NewGOPATH = fmt.Sprintf("%v:%v", b.TmpDir, b.OriGOPATH)
|
||||||
}
|
}
|
||||||
// fix #14: unable to build project not in GOPATH in legacy mode
|
|
||||||
// this kind of project does not have a pkg.Root value
|
|
||||||
// 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.Infof("New GOPATH: %v", b.NewGOPATH)
|
log.Infof("New GOPATH: %v", b.NewGOPATH)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -97,9 +90,9 @@ func (b *Build) mvProjectsToTmp() error {
|
|||||||
// known cases:
|
// known cases:
|
||||||
// 1. a legacy project, but not in any GOPATH, will cause the b.Root == ""
|
// 1. a legacy project, but not in any GOPATH, will cause the b.Root == ""
|
||||||
if b.IsMod == false && b.Root != "" {
|
if b.IsMod == false && b.Root != "" {
|
||||||
b.cpLegacyProject()
|
b.cpProject()
|
||||||
} else if b.IsMod == true { // go 1.11, 1.12 has no Build.Root
|
} else if b.IsMod == true { // go 1.11, 1.12 has no Build.Root
|
||||||
b.cpGoModulesProject()
|
b.cpProject()
|
||||||
updated, newGoModContent, err := b.updateGoModFile()
|
updated, newGoModContent, err := b.updateGoModFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("fail to generate new go.mod: %v", err)
|
return fmt.Errorf("fail to generate new go.mod: %v", err)
|
||||||
@ -114,9 +107,7 @@ func (b *Build) mvProjectsToTmp() error {
|
|||||||
}
|
}
|
||||||
} else if b.IsMod == false && b.Root == "" {
|
} else if b.IsMod == false && b.Root == "" {
|
||||||
b.TmpWorkingDir = b.TmpDir
|
b.TmpWorkingDir = b.TmpDir
|
||||||
b.cpNonStandardLegacy()
|
b.cpProject()
|
||||||
} else {
|
|
||||||
return fmt.Errorf("unknown project type: %w", ErrShouldNotReached)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("New workingdir in tmp directory in: %v", b.TmpWorkingDir)
|
log.Infof("New workingdir in tmp directory in: %v", b.TmpWorkingDir)
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/qiniu/goc/pkg/cover"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -95,7 +96,7 @@ func TestLegacyProjectNotInGoPATH(t *testing.T) {
|
|||||||
os.Setenv("GO111MODULE", "off")
|
os.Setenv("GO111MODULE", "off")
|
||||||
|
|
||||||
b, _ := NewBuild("", []string{"."}, workingDir, "")
|
b, _ := NewBuild("", []string{"."}, workingDir, "")
|
||||||
if b.OriGOPATH != b.NewGOPATH {
|
if !strings.Contains(b.NewGOPATH, b.OriGOPATH) {
|
||||||
t.Fatalf("New GOPATH should be same with old GOPATH, for this kind of project. New: %v, old: %v", b.NewGOPATH, b.OriGOPATH)
|
t.Fatalf("New GOPATH should be same with old GOPATH, for this kind of project. New: %v, old: %v", b.NewGOPATH, b.OriGOPATH)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,13 +106,32 @@ func TestLegacyProjectNotInGoPATH(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// test traversePkgsList error case
|
// test mvProjectsToTmp failed by traversePkgsList error
|
||||||
func TestTraversePkgsList(t *testing.T) {
|
func TestMvProjectsToTmpFailByTraversePkgsList(t *testing.T) {
|
||||||
b := &Build{
|
b := &Build{
|
||||||
Pkgs: nil,
|
Pkgs: nil,
|
||||||
}
|
}
|
||||||
_, _, err := b.traversePkgsList()
|
err := b.mvProjectsToTmp()
|
||||||
assert.EqualError(t, err, ErrShouldNotReached.Error())
|
assert.Contains(t, err.Error(), ErrShouldNotReached.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// test mvProjectsToTmp failed by getTmpwd error
|
||||||
|
func TestMvProjectsToTmpFailByGetTmpwd(t *testing.T) {
|
||||||
|
pkgs := make(map[string]*cover.Package)
|
||||||
|
pkgs["main"] = &cover.Package{
|
||||||
|
Module: &cover.ModulePublic{
|
||||||
|
Dir: "just for test",
|
||||||
|
Path: "just for test",
|
||||||
|
},
|
||||||
|
Dir: "not exist",
|
||||||
|
Name: "main",
|
||||||
|
}
|
||||||
|
b := &Build{
|
||||||
|
Pkgs: pkgs,
|
||||||
|
WorkingDir: "not exist",
|
||||||
|
}
|
||||||
|
err := b.mvProjectsToTmp()
|
||||||
|
assert.Contains(t, err.Error(), ErrGocShouldExecInProject.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// test getTmpwd error case
|
// test getTmpwd error case
|
||||||
@ -148,3 +168,8 @@ func TestFindWhereToInstall(t *testing.T) {
|
|||||||
expectedPlace := filepath.Join(os.Getenv("HOME"), "go", "bin")
|
expectedPlace := filepath.Join(os.Getenv("HOME"), "go", "bin")
|
||||||
assert.Equal(t, placeToInstall, expectedPlace)
|
assert.Equal(t, placeToInstall, expectedPlace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMvProjectsToTmp(t *testing.T) {
|
||||||
|
b := &Build{TmpDir: "/tmp/test"}
|
||||||
|
fmt.Println(b.MvProjectsToTmp())
|
||||||
|
}
|
||||||
|
@ -85,8 +85,19 @@ type Package struct {
|
|||||||
DepOnly bool `json:"DepOnly,omitempty"` // package is only a dependency, not explicitly listed
|
DepOnly bool `json:"DepOnly,omitempty"` // package is only a dependency, not explicitly listed
|
||||||
|
|
||||||
// Source files
|
// Source files
|
||||||
GoFiles []string `json:"GoFiles,omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||||
CgoFiles []string `json:"CgoFiles,omitempty"` // .go source files that import "C"
|
CgoFiles []string `json:",omitempty"` // .go source files that import "C"
|
||||||
|
CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles
|
||||||
|
IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints
|
||||||
|
CFiles []string `json:",omitempty"` // .c source files
|
||||||
|
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
|
||||||
|
MFiles []string `json:",omitempty"` // .m source files
|
||||||
|
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
|
||||||
|
FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
|
||||||
|
SFiles []string `json:",omitempty"` // .s source files
|
||||||
|
SwigFiles []string `json:",omitempty"` // .swig files
|
||||||
|
SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
|
||||||
|
SysoFiles []string `json:",omitempty"` // .syso system object files added to package
|
||||||
|
|
||||||
// Dependency information
|
// Dependency information
|
||||||
Deps []string `json:"Deps,omitempty"` // all (recursively) imported dependencies
|
Deps []string `json:"Deps,omitempty"` // all (recursively) imported dependencies
|
||||||
|
Loading…
Reference in New Issue
Block a user