2021-09-02 09:48:11 +00:00
|
|
|
|
/*
|
|
|
|
|
Copyright 2021 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2021-09-02 06:36:41 +00:00
|
|
|
|
package build
|
|
|
|
|
|
|
|
|
|
import (
|
2024-11-19 03:32:10 +00:00
|
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/ar0c/goc/v2/pkg/log"
|
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
|
"github.com/spf13/pflag"
|
2021-09-02 06:36:41 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var buildUsage string = `Usage:
|
|
|
|
|
goc build [-o output] [build flags] [packages] [goc flags]
|
|
|
|
|
|
|
|
|
|
[build flags] are same with go official command, you can copy them here directly.
|
|
|
|
|
|
|
|
|
|
The [goc flags] can be placed in anywhere in the command line.
|
|
|
|
|
However, other flags' order are same with the go official command.
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
var installUsage string = `Usage:
|
|
|
|
|
goc install [-o output] [build flags] [packages] [goc flags]
|
|
|
|
|
|
|
|
|
|
[build flags] are same with go official command, you can copy them here directly.
|
|
|
|
|
|
|
|
|
|
The [goc flags] can be placed in anywhere in the command line.
|
|
|
|
|
However, other flags' order are same with the go official command.
|
|
|
|
|
`
|
|
|
|
|
|
2021-09-09 08:17:24 +00:00
|
|
|
|
var runUsage string = `Usage:
|
|
|
|
|
goc run [build flags] [goc flags] [packages] [arguments...]
|
|
|
|
|
|
|
|
|
|
[build flags] are same with go official command, you can copy them here directly.
|
|
|
|
|
|
|
|
|
|
The [goc flags] can be placed in anywhere in the command line.
|
|
|
|
|
However, other flags' order are same with the go official command.
|
|
|
|
|
`
|
|
|
|
|
|
2021-09-02 06:36:41 +00:00
|
|
|
|
const (
|
2024-11-19 03:32:10 +00:00
|
|
|
|
GO_BUILD = iota
|
|
|
|
|
GO_INSTALL
|
2021-09-02 06:36:41 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// CustomParseCmdAndArgs 因为关闭了 cobra 的解析功能,需要手动构造并解析 goc flags
|
|
|
|
|
func CustomParseCmdAndArgs(cmd *cobra.Command, args []string) *pflag.FlagSet {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
// 首先解析 cobra 定义的 flag
|
|
|
|
|
allFlagSets := cmd.Flags()
|
|
|
|
|
// 因为 args 里面含有 go 的 flag,所以需要忽略解析 go flag 的错误
|
|
|
|
|
allFlagSets.Init("GOC", pflag.ContinueOnError)
|
|
|
|
|
// 忽略 go flag 在 goc 中的解析错误
|
|
|
|
|
allFlagSets.ParseErrorsWhitelist = pflag.ParseErrorsWhitelist{
|
|
|
|
|
UnknownFlags: true,
|
|
|
|
|
}
|
|
|
|
|
allFlagSets.Parse(args)
|
|
|
|
|
|
|
|
|
|
return allFlagSets
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// buildCmdArgsParse parse both go flags and goc flags, it rewrite go flags if
|
|
|
|
|
// necessary, and returns all non-flag arguments.
|
|
|
|
|
//
|
|
|
|
|
// 吞下 [packages] 之前所有的 flags.
|
|
|
|
|
func (b *Build) buildCmdArgsParse() {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
args := b.Args
|
|
|
|
|
cmdType := b.BuildType
|
|
|
|
|
allFlagSets := b.FlagSets
|
|
|
|
|
|
|
|
|
|
// 重写 help
|
|
|
|
|
helpFlag := allFlagSets.Lookup("help")
|
|
|
|
|
|
|
|
|
|
if helpFlag.Changed {
|
|
|
|
|
if cmdType == GO_BUILD {
|
|
|
|
|
printGoHelp(buildUsage)
|
|
|
|
|
} else if cmdType == GO_INSTALL {
|
|
|
|
|
printGoHelp(installUsage)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
os.Exit(0)
|
|
|
|
|
}
|
|
|
|
|
// 删除 help flag
|
|
|
|
|
args = findAndDelHelpFlag(args)
|
|
|
|
|
|
|
|
|
|
// 必须手动调用
|
|
|
|
|
// 由于关闭了 cobra 的 flag parse,root PersistentPreRun 调用时,log.NewLogger 并没有拿到 debug 值
|
|
|
|
|
log.NewLogger(b.Debug)
|
|
|
|
|
|
|
|
|
|
// 删除 cobra 定义的 flag
|
|
|
|
|
allFlagSets.Visit(func(f *pflag.Flag) {
|
|
|
|
|
args = findAndDelGocFlag(args, f.Name, f.Value.String())
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 然后解析 go 的 flag
|
|
|
|
|
goFlagSets := flag.NewFlagSet("GO", flag.ContinueOnError)
|
|
|
|
|
addBuildFlags(goFlagSets)
|
|
|
|
|
addOutputFlags(goFlagSets)
|
|
|
|
|
err := goFlagSets.Parse(args)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("%v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 找出设置的 go flag
|
|
|
|
|
curWd, err := os.Getwd()
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("fail to get current working directory: %v", err)
|
|
|
|
|
}
|
|
|
|
|
flags := make([]string, 0)
|
|
|
|
|
goFlagSets.Visit(func(f *flag.Flag) {
|
|
|
|
|
// 将用户指定 -o 改成绝对目录
|
|
|
|
|
if f.Name == "o" {
|
|
|
|
|
outputDir := f.Value.String()
|
|
|
|
|
outputDir, err := filepath.Abs(outputDir)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("output flag is not valid: %v", err)
|
|
|
|
|
}
|
|
|
|
|
flags = append(flags, "-o", outputDir)
|
|
|
|
|
} else {
|
|
|
|
|
if _, ok := booleanFlags[f.Name]; !ok {
|
|
|
|
|
flags = append(flags, "-"+f.Name, f.Value.String())
|
|
|
|
|
} else {
|
|
|
|
|
flags = append(flags, "-"+f.Name)
|
|
|
|
|
}
|
|
|
|
|
if f.Name == "mod" {
|
|
|
|
|
if f.Value.String() == "vendor" {
|
|
|
|
|
b.IsVendorMod = true
|
|
|
|
|
} else {
|
|
|
|
|
b.IsVendorMod = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Goflags = flags
|
|
|
|
|
b.CurWd = curWd
|
|
|
|
|
b.GoArgs = goFlagSets.Args()
|
|
|
|
|
return
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-09 08:17:24 +00:00
|
|
|
|
func (b *Build) runCmdArgsParse() {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
args := b.Args
|
|
|
|
|
allFlagSets := b.FlagSets
|
2021-09-09 08:17:24 +00:00
|
|
|
|
|
2024-11-19 03:32:10 +00:00
|
|
|
|
// 重写 help
|
|
|
|
|
helpFlag := allFlagSets.Lookup("help")
|
2021-09-09 08:17:24 +00:00
|
|
|
|
|
2024-11-19 03:32:10 +00:00
|
|
|
|
if helpFlag.Changed {
|
|
|
|
|
printGoHelp(runUsage)
|
|
|
|
|
os.Exit(0)
|
|
|
|
|
}
|
2021-09-09 08:17:24 +00:00
|
|
|
|
|
2024-11-19 03:32:10 +00:00
|
|
|
|
// 删除 help flag
|
|
|
|
|
args = findAndDelHelpFlag(args)
|
2021-09-09 08:17:24 +00:00
|
|
|
|
|
2024-11-19 03:32:10 +00:00
|
|
|
|
// 必须手动调用
|
|
|
|
|
// 由于关闭了 cobra 的 flag parse,root PersistentPreRun 调用时,log.NewLogger 并没有拿到 debug 值
|
|
|
|
|
log.NewLogger(b.Debug)
|
2021-09-09 08:17:24 +00:00
|
|
|
|
|
2024-11-19 03:32:10 +00:00
|
|
|
|
curWd, err := os.Getwd()
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("fail to get current working directory: %v", err)
|
|
|
|
|
}
|
|
|
|
|
b.CurWd = curWd
|
2021-09-09 08:17:24 +00:00
|
|
|
|
|
2024-11-19 03:32:10 +00:00
|
|
|
|
// 获取除 goc flags 之外的 args
|
|
|
|
|
// 删除 cobra 定义的 flag
|
|
|
|
|
allFlagSets.Visit(func(f *pflag.Flag) {
|
|
|
|
|
args = findAndDelGocFlag(args, f.Name, f.Value.String())
|
|
|
|
|
})
|
2021-09-09 08:17:24 +00:00
|
|
|
|
|
2024-11-19 03:32:10 +00:00
|
|
|
|
b.GoArgs = args
|
2021-09-09 08:17:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-02 06:36:41 +00:00
|
|
|
|
func findAndDelGocFlag(a []string, x string, v string) []string {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
new := make([]string, 0, len(a))
|
|
|
|
|
x = "--" + x
|
|
|
|
|
x_v := x + "=" + v
|
|
|
|
|
for i := 0; i < len(a); i++ {
|
|
|
|
|
if a[i] == "--gocdebug" {
|
|
|
|
|
// debug 是 bool,就一个元素
|
|
|
|
|
continue
|
|
|
|
|
} else if a[i] == x {
|
|
|
|
|
// 有 goc flag 长这样 --mode watch
|
|
|
|
|
i++
|
|
|
|
|
continue
|
|
|
|
|
} else if a[i] == x_v {
|
|
|
|
|
// 有 goc flag 长这样 --mode=watch
|
|
|
|
|
continue
|
|
|
|
|
} else {
|
|
|
|
|
// 剩下的是 go flag
|
|
|
|
|
new = append(new, a[i])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func findAndDelHelpFlag(a []string) []string {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
new := make([]string, 0, len(a))
|
|
|
|
|
for _, v := range a {
|
|
|
|
|
if v == "--help" || v == "-h" {
|
|
|
|
|
continue
|
|
|
|
|
} else {
|
|
|
|
|
new = append(new, v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type goConfig struct {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
BuildA bool
|
|
|
|
|
BuildBuildmode string // -buildmode flag
|
|
|
|
|
BuildMod string // -mod flag
|
|
|
|
|
BuildModReason string // reason -mod flag is set, if set by default
|
|
|
|
|
BuildI bool // -i flag
|
|
|
|
|
BuildLinkshared bool // -linkshared flag
|
|
|
|
|
BuildMSan bool // -msan flag
|
|
|
|
|
BuildN bool // -n flag
|
|
|
|
|
BuildO string // -o flag
|
|
|
|
|
BuildP int // -p flag
|
|
|
|
|
BuildPkgdir string // -pkgdir flag
|
|
|
|
|
BuildRace bool // -race flag
|
|
|
|
|
BuildToolexec string // -toolexec flag
|
|
|
|
|
BuildToolchainName string
|
|
|
|
|
BuildToolchainCompiler func() string
|
|
|
|
|
BuildToolchainLinker func() string
|
|
|
|
|
BuildTrimpath bool // -trimpath flag
|
|
|
|
|
BuildV bool // -v flag
|
|
|
|
|
BuildWork bool // -work flag
|
|
|
|
|
BuildX bool // -x flag
|
|
|
|
|
// from buildcontext
|
|
|
|
|
Installsuffix string // -installSuffix
|
|
|
|
|
BuildTags string // -tags
|
|
|
|
|
// from load
|
|
|
|
|
BuildAsmflags string
|
|
|
|
|
BuildCompiler string
|
|
|
|
|
BuildGcflags string
|
|
|
|
|
BuildGccgoflags string
|
|
|
|
|
BuildLdflags string
|
|
|
|
|
|
|
|
|
|
// mod related
|
|
|
|
|
ModCacheRW bool
|
|
|
|
|
ModFile string
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var goflags goConfig
|
2022-02-21 12:15:52 +00:00
|
|
|
|
var booleanFlags map[string]struct{} = make(map[string]struct{})
|
2021-09-02 06:36:41 +00:00
|
|
|
|
|
|
|
|
|
func addBuildFlags(cmdSet *flag.FlagSet) {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
cmdSet.BoolVar(&goflags.BuildA, "a", false, "")
|
|
|
|
|
booleanFlags["a"] = struct{}{}
|
|
|
|
|
cmdSet.BoolVar(&goflags.BuildN, "n", false, "")
|
|
|
|
|
booleanFlags["n"] = struct{}{}
|
|
|
|
|
cmdSet.IntVar(&goflags.BuildP, "p", 4, "")
|
|
|
|
|
cmdSet.BoolVar(&goflags.BuildV, "v", false, "")
|
|
|
|
|
booleanFlags["v"] = struct{}{}
|
|
|
|
|
cmdSet.BoolVar(&goflags.BuildX, "x", false, "")
|
|
|
|
|
booleanFlags["x"] = struct{}{}
|
|
|
|
|
cmdSet.StringVar(&goflags.BuildBuildmode, "buildmode", "default", "")
|
|
|
|
|
cmdSet.StringVar(&goflags.BuildMod, "mod", "", "")
|
|
|
|
|
cmdSet.StringVar(&goflags.Installsuffix, "installsuffix", "", "")
|
|
|
|
|
|
|
|
|
|
// 类型和 go 原生的不一样,这里纯粹是为了 parse 并传递给 go
|
|
|
|
|
cmdSet.StringVar(&goflags.BuildAsmflags, "asmflags", "", "")
|
|
|
|
|
cmdSet.StringVar(&goflags.BuildCompiler, "compiler", "", "")
|
|
|
|
|
cmdSet.StringVar(&goflags.BuildGcflags, "gcflags", "", "")
|
|
|
|
|
cmdSet.StringVar(&goflags.BuildGccgoflags, "gccgoflags", "", "")
|
|
|
|
|
// mod related
|
|
|
|
|
cmdSet.BoolVar(&goflags.ModCacheRW, "modcacherw", false, "")
|
|
|
|
|
booleanFlags["modcacherw"] = struct{}{}
|
|
|
|
|
cmdSet.StringVar(&goflags.ModFile, "modfile", "", "")
|
|
|
|
|
cmdSet.StringVar(&goflags.BuildLdflags, "ldflags", "", "")
|
|
|
|
|
cmdSet.BoolVar(&goflags.BuildLinkshared, "linkshared", false, "")
|
|
|
|
|
booleanFlags["linkshared"] = struct{}{}
|
|
|
|
|
cmdSet.StringVar(&goflags.BuildPkgdir, "pkgdir", "", "")
|
|
|
|
|
cmdSet.BoolVar(&goflags.BuildRace, "race", false, "")
|
|
|
|
|
booleanFlags["race"] = struct{}{}
|
|
|
|
|
cmdSet.BoolVar(&goflags.BuildMSan, "msan", false, "")
|
|
|
|
|
booleanFlags["msan"] = struct{}{}
|
|
|
|
|
cmdSet.StringVar(&goflags.BuildTags, "tags", "", "")
|
|
|
|
|
cmdSet.StringVar(&goflags.BuildToolexec, "toolexec", "", "")
|
|
|
|
|
cmdSet.BoolVar(&goflags.BuildTrimpath, "trimpath", false, "")
|
|
|
|
|
booleanFlags["trimpath"] = struct{}{}
|
|
|
|
|
cmdSet.BoolVar(&goflags.BuildWork, "work", false, "")
|
|
|
|
|
booleanFlags["work"] = struct{}{}
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func addOutputFlags(cmdSet *flag.FlagSet) {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
cmdSet.StringVar(&goflags.BuildO, "o", "", "")
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func printGoHelp(usage string) {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
fmt.Println(usage)
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func printGocHelp(cmd *cobra.Command) {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
flags := cmd.LocalFlags()
|
|
|
|
|
globalFlags := cmd.Parent().PersistentFlags()
|
2021-09-02 06:36:41 +00:00
|
|
|
|
|
2024-11-19 03:32:10 +00:00
|
|
|
|
fmt.Println("Flags:")
|
|
|
|
|
fmt.Println(flags.FlagUsages())
|
2021-09-02 06:36:41 +00:00
|
|
|
|
|
2024-11-19 03:32:10 +00:00
|
|
|
|
fmt.Println("Global Flags:")
|
|
|
|
|
fmt.Println(globalFlags.FlagUsages())
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetPackagesDir parse [pacakges] part of args, it will fatal if error encountered
|
|
|
|
|
//
|
|
|
|
|
// 函数获取 1: [packages] 所在的目录位置,供后续插桩使用。
|
|
|
|
|
//
|
|
|
|
|
// 函数获取 2: 如果参数是 *.go,第一个 .go 文件的文件名。go build 中,二进制名字既可能是目录名也可能是文件名,和参数类型有关。
|
|
|
|
|
//
|
|
|
|
|
// 如果 [packages] 非法(即不符合 go 原生的定义),则返回对应错误
|
|
|
|
|
// 这里只考虑 go mod 的方式
|
|
|
|
|
func (b *Build) getPackagesDir() {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
patterns := b.GoArgs
|
|
|
|
|
packages := make([]string, 0)
|
|
|
|
|
for _, p := range patterns {
|
|
|
|
|
// patterns 只支持两种格式
|
|
|
|
|
// 1. 要么是直接指向某些 .go 文件的相对/绝对路径
|
|
|
|
|
if strings.HasSuffix(p, ".go") {
|
|
|
|
|
if fi, err := os.Stat(p); err == nil && !fi.IsDir() {
|
|
|
|
|
// check if valid
|
|
|
|
|
if err := goFilesPackage(patterns); err != nil {
|
|
|
|
|
log.Fatalf("%v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取相对于 current working directory 对路径
|
|
|
|
|
for _, p := range patterns {
|
|
|
|
|
if filepath.IsAbs(p) {
|
|
|
|
|
relPath, err := filepath.Rel(b.CurWd, p)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("fail to get [packages] relative path from current working directory: %v", err)
|
|
|
|
|
}
|
|
|
|
|
packages = append(packages, relPath)
|
|
|
|
|
} else {
|
|
|
|
|
packages = append(packages, p)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// fix: go build ./xx/main.go 需要转换为
|
|
|
|
|
// go build ./xx/main.go ./xx/goc-cover-agent-apis-auto-generated-11111-22222-bridge.go
|
|
|
|
|
dir := filepath.Dir(packages[0])
|
|
|
|
|
packages = append(packages, filepath.Join(dir, "goc-cover-agent-apis-auto-generated-11111-22222-bridge.go"))
|
|
|
|
|
b.Packages = packages
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. 要么是 import path
|
|
|
|
|
b.Packages = patterns
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// goFilesPackage 对一组 go 文件解析,判断是否合法
|
|
|
|
|
// go 本身还判断语法上是否是同一个 package,goc 这里不做解析
|
|
|
|
|
// 1. 都是 *.go 文件?
|
|
|
|
|
// 2. *.go 文件都在同一个目录?
|
|
|
|
|
// 3. *.go 文件存在?
|
|
|
|
|
func goFilesPackage(gofiles []string) error {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
// 1. 必须都是 *.go 结尾
|
|
|
|
|
for _, f := range gofiles {
|
|
|
|
|
if !strings.HasSuffix(f, ".go") {
|
|
|
|
|
return fmt.Errorf("named files must be .go files: %s", f)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var dir string
|
|
|
|
|
for _, file := range gofiles {
|
|
|
|
|
// 3. 文件都存在?
|
|
|
|
|
fi, err := os.Stat(file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2.1 有可能以 *.go 结尾的目录
|
|
|
|
|
if fi.IsDir() {
|
|
|
|
|
return fmt.Errorf("%s is a directory, should be a Go file", file)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2.2 所有 *.go 必须在同一个目录内
|
|
|
|
|
dir1, _ := filepath.Split(file)
|
|
|
|
|
if dir1 == "" {
|
|
|
|
|
dir1 = "./"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if dir == "" {
|
|
|
|
|
dir = dir1
|
|
|
|
|
} else if dir != dir1 {
|
|
|
|
|
return fmt.Errorf("named files must all be in one directory: have %s and %s", dir, dir1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getDirFromImportPaths return the import path's real abs directory
|
|
|
|
|
//
|
|
|
|
|
// 该函数接收到的只有 dir 或 import path,file 在上一步已被排除
|
|
|
|
|
// 只考虑 go modules 的情况
|
|
|
|
|
func getDirFromImportPaths(patterns []string) (string, error) {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
// no import path, pattern = current wd
|
|
|
|
|
if len(patterns) == 0 {
|
|
|
|
|
wd, err := os.Getwd()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", fmt.Errorf("fail to parse import path: %w", err)
|
|
|
|
|
}
|
|
|
|
|
return wd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 为了简化插桩的逻辑,goc 对 import path 要求必须都在同一个目录
|
|
|
|
|
// 所以干脆只允许一个 pattern 得了 -_-
|
|
|
|
|
// 对于 goc build/run 来说本身就是只能在一个目录内
|
|
|
|
|
// 对于 goc install 来讲,这个行为就和 go install 不同,不过多 import path 较少见 >_<,先忽略
|
|
|
|
|
if len(patterns) > 1 {
|
|
|
|
|
return "", fmt.Errorf("goc only support one import path now")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pattern := patterns[0]
|
|
|
|
|
switch {
|
|
|
|
|
// case isLocalImport(pattern) || filepath.IsAbs(pattern):
|
|
|
|
|
// dir1, err := filepath.Abs(pattern)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern)
|
|
|
|
|
// }
|
|
|
|
|
// if _, err := os.Stat(dir1); err != nil {
|
|
|
|
|
// return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern)
|
|
|
|
|
// }
|
|
|
|
|
// return dir1, nil
|
|
|
|
|
|
|
|
|
|
case strings.Contains(pattern, "..."):
|
|
|
|
|
i := strings.Index(pattern, "...")
|
|
|
|
|
dir, _ := filepath.Split(pattern[:i])
|
|
|
|
|
dir, _ = filepath.Abs(dir)
|
|
|
|
|
if _, err := os.Stat(dir); err != nil {
|
|
|
|
|
return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern)
|
|
|
|
|
}
|
|
|
|
|
return dir, nil
|
|
|
|
|
|
|
|
|
|
case strings.IndexByte(pattern, '@') > 0:
|
|
|
|
|
return "", fmt.Errorf("import path with @ version query is not supported in goc")
|
|
|
|
|
|
|
|
|
|
case isMetaPackage(pattern):
|
|
|
|
|
return "", fmt.Errorf("`std`, `cmd`, `all` import path is not supported by goc")
|
|
|
|
|
|
|
|
|
|
default: // 到这一步认为 pattern 是相对路径或者绝对路径
|
|
|
|
|
dir1, err := filepath.Abs(pattern)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern)
|
|
|
|
|
}
|
|
|
|
|
if _, err := os.Stat(dir1); err != nil {
|
|
|
|
|
return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dir1, nil
|
|
|
|
|
}
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// isLocalImport reports whether the import path is
|
|
|
|
|
// a local import path, like ".", "..", "./foo", or "../foo"
|
|
|
|
|
func isLocalImport(path string) bool {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
return path == "." || path == ".." ||
|
|
|
|
|
strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// isMetaPackage checks if the name is a reserved package name
|
|
|
|
|
func isMetaPackage(name string) bool {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
return name == "std" || name == "cmd" || name == "all"
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// find direct path of current project which contains go.mod
|
|
|
|
|
func findModuleRoot(dir string) string {
|
2024-11-19 03:32:10 +00:00
|
|
|
|
dir = filepath.Clean(dir)
|
|
|
|
|
|
|
|
|
|
// look for enclosing go.mod
|
|
|
|
|
for {
|
|
|
|
|
if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() {
|
|
|
|
|
return dir
|
|
|
|
|
}
|
|
|
|
|
d := filepath.Dir(dir)
|
|
|
|
|
if d == dir {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
dir = d
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ""
|
2021-09-02 06:36:41 +00:00
|
|
|
|
}
|