Merge pull request #95 from lyyyuna/goc-92

add support for go.mod contains replace directive
This commit is contained in:
qiniu-bot 2020-08-12 17:07:46 +08:00 committed by GitHub
commit baeb4e27d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 178 additions and 5 deletions

1
go.mod
View File

@ -16,6 +16,7 @@ require (
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.6.2 github.com/spf13/viper v1.6.2
github.com/stretchr/testify v1.5.1 github.com/stretchr/testify v1.5.1
golang.org/x/mod v0.3.0
golang.org/x/net v0.0.0-20200625001655-4c5254603344 golang.org/x/net v0.0.0-20200625001655-4c5254603344
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/tools v0.0.0-20200730221956-1ac65761fe2c golang.org/x/tools v0.0.0-20200730221956-1ac65761fe2c

1
go.sum
View File

@ -822,6 +822,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

View File

@ -41,7 +41,8 @@ type Build struct {
// Project Root: // Project Root:
// 1. legacy, root == GOPATH // 1. legacy, root == GOPATH
// 2. mod, root == go.mod Dir // 2. mod, root == go.mod Dir
Target string // the binary name that go build generate ModRoot string // path for go.mod
Target string // the binary name that go build generate
// keep compatible with go commands: // keep compatible with go commands:
// go run [build flags] [-exec xprog] package [arguments...] // go run [build flags] [-exec xprog] package [arguments...]
// go build [-o output] [-i] [build flags] [packages] // go build [-o output] [-i] [build flags] [packages]

View File

@ -17,8 +17,12 @@
package build package build
import ( import (
"io/ioutil"
"path/filepath"
"github.com/otiai10/copy" "github.com/otiai10/copy"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"golang.org/x/mod/modfile"
) )
func (b *Build) cpGoModulesProject() { func (b *Build) cpGoModulesProject() {
@ -36,3 +40,51 @@ func (b *Build) cpGoModulesProject() {
} }
} }
} }
// updateGoModFile rewrites the go.mod file in the temporary directory,
// if it has a 'replace' directive, and the directive has a relative local path
// it will be rewritten with a absolute path.
// ex.
// suppose original project is located at /path/to/aa/bb/cc, go.mod contains a directive:
// 'replace github.com/qiniu/bar => ../home/foo/bar'
// after the project is copied to temporary directory, it should be rewritten as
// 'replace github.com/qiniu/bar => /path/to/aa/bb/home/foo/bar'
func (b *Build) updateGoModFile() (updateFlag bool, newModFile []byte, err error) {
tempModfile := filepath.Join(b.TmpDir, "go.mod")
buf, err := ioutil.ReadFile(tempModfile)
if err != nil {
return
}
oriGoModFile, err := modfile.Parse(tempModfile, buf, nil)
if err != nil {
return
}
updateFlag = false
for index := range oriGoModFile.Replace {
replace := oriGoModFile.Replace[index]
oldPath := replace.Old.Path
oldVersion := replace.Old.Version
newPath := replace.New.Path
newVersion := replace.New.Version
// replace to a local filesystem does not have a version
// absolute path no need to rewrite
if newVersion == "" && !filepath.IsAbs(newPath) {
var absPath string
fullPath := filepath.Join(b.ModRoot, newPath)
absPath, _ = filepath.Abs(fullPath)
// DropReplace & AddReplace will not return error
// so no need to check the error
_ = oriGoModFile.DropReplace(oldPath, oldVersion)
_ = oriGoModFile.AddReplace(oldPath, oldVersion, absPath, newVersion)
updateFlag = true
}
}
oriGoModFile.Cleanup()
// Format will not return error, so ignore the returned error
// func (f *File) Format() ([]byte, error) {
// return Format(f.Syntax), nil
// }
newModFile, _ = oriGoModFile.Format()
return
}

View File

@ -18,7 +18,9 @@ package build
import ( import (
"bytes" "bytes"
"errors"
"os" "os"
"path/filepath"
"strings" "strings"
"testing" "testing"
@ -53,3 +55,49 @@ func TestModProjectCopyWithUnexistedDir(t *testing.T) {
output := captureOutput(b.cpGoModulesProject) output := captureOutput(b.cpGoModulesProject)
assert.Equal(t, strings.Contains(output, "Failed to Copy"), true) assert.Equal(t, strings.Contains(output, "Failed to Copy"), true)
} }
// test go mod file udpate
func TestUpdateModFileIfContainsReplace(t *testing.T) {
workingDir := filepath.Join(baseDir, "../../tests/samples/gomod_samples/a")
b := &Build{
TmpDir: workingDir,
ModRoot: "/aa/bb/cc",
}
// replace with relative local file path should be rewrite
updated, newmod, err := b.updateGoModFile()
assert.Equal(t, err, nil)
assert.Equal(t, updated, true)
assert.Contains(t, string(newmod), "replace github.com/qiniu/bar => /aa/bb/home/foo/bar")
// old replace should be removed
assert.NotContains(t, string(newmod), "github.com/qiniu/bar => ../home/foo/bar")
// normal replace should not be rewrite
assert.Contains(t, string(newmod), "github.com/qiniu/bar2 => github.com/baniu/bar3 v1.2.3")
}
// test wrong go mod file
func TestWithWrongGoModFile(t *testing.T) {
// go.mod not exist
workingDir := filepath.Join(baseDir, "../../tests/samples/xxxxxxxxxxxx/a")
b := &Build{
TmpDir: workingDir,
ModRoot: "/aa/bb/cc",
}
updated, _, err := b.updateGoModFile()
assert.Equal(t, errors.Is(err, os.ErrNotExist), true)
assert.Equal(t, updated, false)
// a wrong format go mod
workingDir = filepath.Join(baseDir, "../../tests/samples/gomod_samples/b")
b = &Build{
TmpDir: workingDir,
ModRoot: "/aa/bb/cc",
}
updated, _, err = b.updateGoModFile()
assert.NotEqual(t, err, nil)
assert.Equal(t, updated, false)
}

View File

@ -20,6 +20,7 @@ import (
"crypto/sha256" "crypto/sha256"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -75,10 +76,9 @@ func (b *Build) mvProjectsToTmp() error {
// Create a new tmp folder // 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 { if err != nil {
log.Errorf("Fail to create the temporary build directory. The err is: %v", err) return fmt.Errorf("Fail to create the temporary build directory. The err is: %v", err)
return err
} }
log.Printf("Tmp project generated in: %v", b.TmpDir) log.Infof("Tmp project generated in: %v", b.TmpDir)
// traverse pkg list to get project meta info // traverse pkg list to get project meta info
b.IsMod, b.Root, err = b.traversePkgsList() b.IsMod, b.Root, err = b.traversePkgsList()
@ -89,7 +89,6 @@ func (b *Build) mvProjectsToTmp() error {
// we should get corresponding working directory in temporary directory // we should get corresponding working directory in temporary directory
b.TmpWorkingDir, err = b.getTmpwd() b.TmpWorkingDir, err = b.getTmpwd()
if err != nil { if err != nil {
log.Errorf("fail to get workding directory in temporary directory: %v", err)
return fmt.Errorf("getTmpwd failed with error: %w", err) return fmt.Errorf("getTmpwd failed with error: %w", err)
} }
// issue #14 // issue #14
@ -100,6 +99,18 @@ func (b *Build) mvProjectsToTmp() error {
b.cpLegacyProject() b.cpLegacyProject()
} 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.cpGoModulesProject()
updated, newGoModContent, err := b.updateGoModFile()
if err != nil {
return fmt.Errorf("fail to generate new go.mod: %v", err)
}
if updated {
log.Infoln("go.mod needs rewrite")
tmpModFile := filepath.Join(b.TmpDir, "go.mod")
err := ioutil.WriteFile(tmpModFile, newGoModContent, os.ModePerm)
if err != nil {
return fmt.Errorf("fail to update go.mod: %v", err)
}
}
} 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.cpNonStandardLegacy()
@ -134,6 +145,7 @@ func (b *Build) traversePkgsList() (isMod bool, root string, err error) {
return return
} }
isMod = true isMod = true
b.ModRoot = v.Module.Dir
return return
} }
log.Error(ErrShouldNotReached) log.Error(ErrShouldNotReached)

View File

@ -74,3 +74,16 @@ setup() {
wait $profile_pid wait $profile_pid
} }
@test "test goc build with go.mod project which contains replace directive" {
cd samples/gomod_replace_project
wait_profile_backend "build4" &
profile_pid=$!
run gocc build --debug --debugcisyncfile ci-sync.bak;
info build4 output: $output
[ "$status" -eq 0 ]
wait $profile_pid
}

View File

@ -0,0 +1,7 @@
package foo
import "fmt"
func Bar() {
fmt.Println("foo bar")
}

View File

@ -0,0 +1,4 @@
module qiniu.com/foo
go 1.11

View File

@ -0,0 +1,7 @@
module example.com/simple-project
require qiniu.com/foo v0.0.0
replace qiniu.com/foo => ../gomod_replace_library
go 1.11

View File

@ -0,0 +1,9 @@
package main
import (
"qiniu.com/foo"
)
func main() {
foo.Bar()
}

View File

@ -0,0 +1,11 @@
module example.com/gg/a
replace (
github.com/qiniu/bar => ../home/foo/bar
github.com/qiniu/bar2 => github.com/baniu/bar3 v1.2.3
)
require (
github.com/qiniu/bar v1.0.0
github.com/qiniu/bar2 v1.2.0
)

View File

@ -0,0 +1,7 @@
module example.com/gg/a
replerace github.com/qiniu/bar => ../home/foo/bar
eggrr (
github.com/qiniu/bar v1.0.0
)