mirror of
https://gitee.com/johng/gf.git
synced 2024-11-29 18:57:44 +08:00
parent
ca242ff401
commit
4b8eaac73f
@ -44,8 +44,9 @@ type cBuild struct {
|
||||
}
|
||||
|
||||
const (
|
||||
cBuildBrief = `cross-building go project for lots of platforms`
|
||||
cBuildEg = `
|
||||
cBuildDefaultFile = "main.go"
|
||||
cBuildBrief = `cross-building go project for lots of platforms`
|
||||
cBuildEg = `
|
||||
gf build main.go
|
||||
gf build main.go --ps public,template
|
||||
gf build main.go --cgo
|
||||
@ -123,7 +124,7 @@ type cBuildInput struct {
|
||||
Arch string `short:"a" name:"arch" brief:"output binary architecture, multiple arch separated with ','"`
|
||||
System string `short:"s" name:"system" brief:"output binary system, multiple os separated with ','"`
|
||||
Output string `short:"o" name:"output" brief:"output binary path, used when building single binary file"`
|
||||
Path string `short:"p" name:"path" brief:"output binary directory path, default is './temp'" d:"./temp"`
|
||||
Path string `short:"p" name:"path" brief:"output binary directory path, default is '.'" d:"."`
|
||||
Extra string `short:"e" name:"extra" brief:"extra custom \"go build\" options"`
|
||||
Mod string `short:"m" name:"mod" brief:"like \"-mod\" option of \"go build\", use \"-m none\" to disable go module"`
|
||||
Cgo bool `short:"c" name:"cgo" brief:"enable or disable cgo feature, it's disabled in default" orphan:"true"`
|
||||
@ -152,12 +153,13 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
|
||||
var (
|
||||
parser = gcmd.ParserFromCtx(ctx)
|
||||
file = parser.GetArg(2).String()
|
||||
file = in.File
|
||||
)
|
||||
if len(file) < 1 {
|
||||
if file == "" {
|
||||
file = parser.GetArg(2).String()
|
||||
// Check and use the main.go file.
|
||||
if gfile.Exists("main.go") {
|
||||
file = "main.go"
|
||||
if gfile.Exists(cBuildDefaultFile) {
|
||||
file = cBuildDefaultFile
|
||||
} else {
|
||||
mlog.Fatal("build file path is empty or main.go not found in current working directory")
|
||||
}
|
||||
@ -239,13 +241,7 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
} else {
|
||||
genv.MustSet("CGO_ENABLED", "0")
|
||||
}
|
||||
var (
|
||||
cmd = ""
|
||||
ext = ""
|
||||
)
|
||||
for system, item := range platformMap {
|
||||
cmd = ""
|
||||
ext = ""
|
||||
if len(customSystems) > 0 && customSystems[0] != "all" && !gstr.InArray(customSystems, system) {
|
||||
continue
|
||||
}
|
||||
@ -258,58 +254,22 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
// For example:
|
||||
// `gf build`
|
||||
// `gf build -o main.exe`
|
||||
if runtime.GOOS == "windows" {
|
||||
ext = ".exe"
|
||||
}
|
||||
var outputPath string
|
||||
if len(in.Output) > 0 {
|
||||
outputPath = "-o " + in.Output
|
||||
} else {
|
||||
outputPath = "-o " + in.Name + ext
|
||||
}
|
||||
cmd = fmt.Sprintf(
|
||||
`go build %s -ldflags "%s" %s %s`,
|
||||
outputPath, ldFlags, in.Extra, file,
|
||||
c.doBinaryBuild(
|
||||
ctx, file,
|
||||
in.Output, in.Path,
|
||||
runtime.GOOS, runtime.GOARCH, in.Name, ldFlags, in.Extra,
|
||||
in.ExitWhenError,
|
||||
true,
|
||||
)
|
||||
} else {
|
||||
// Cross-building, output the compiled binary to specified path.
|
||||
if system == "windows" {
|
||||
ext = ".exe"
|
||||
}
|
||||
genv.MustSet("GOOS", system)
|
||||
genv.MustSet("GOARCH", arch)
|
||||
|
||||
var outputPath string
|
||||
if len(in.Output) > 0 {
|
||||
outputPath = "-o " + in.Output
|
||||
} else {
|
||||
outputPath = fmt.Sprintf(
|
||||
"-o %s/%s/%s%s",
|
||||
in.Path, system+"_"+arch, in.Name, ext,
|
||||
)
|
||||
}
|
||||
cmd = fmt.Sprintf(
|
||||
`go build %s -ldflags "%s" %s%s`,
|
||||
outputPath, ldFlags, in.Extra, file,
|
||||
c.doBinaryBuild(
|
||||
ctx, file,
|
||||
in.Output, in.Path,
|
||||
system, arch, in.Name, ldFlags, in.Extra,
|
||||
in.ExitWhenError,
|
||||
false,
|
||||
)
|
||||
}
|
||||
mlog.Debug(fmt.Sprintf("build for GOOS=%s GOARCH=%s", system, arch))
|
||||
mlog.Debug(cmd)
|
||||
// It's not necessary printing the complete command string.
|
||||
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
|
||||
mlog.Print(cmdShow)
|
||||
if result, err := gproc.ShellExec(ctx, cmd); err != nil {
|
||||
mlog.Printf(
|
||||
"failed to build, os:%s, arch:%s, error:\n%s\n\n%s\n",
|
||||
system, arch, gstr.Trim(result),
|
||||
`you may use command option "--debug" to enable debug info and check the details`,
|
||||
)
|
||||
if in.ExitWhenError {
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
mlog.Debug(gstr.Trim(result))
|
||||
}
|
||||
// single binary building.
|
||||
if len(customSystems) == 0 && len(customArches) == 0 {
|
||||
goto buildDone
|
||||
@ -322,6 +282,68 @@ buildDone:
|
||||
return
|
||||
}
|
||||
|
||||
func (c cBuild) doBinaryBuild(
|
||||
ctx context.Context,
|
||||
filePath string,
|
||||
outputPath, dirPath string,
|
||||
system, arch, name, ldFlags, extra string,
|
||||
exitWhenError bool,
|
||||
singleBuild bool,
|
||||
) {
|
||||
var (
|
||||
cmd string
|
||||
ext string
|
||||
)
|
||||
// Cross-building, output the compiled binary to specified path.
|
||||
if system == "windows" {
|
||||
ext = ".exe"
|
||||
}
|
||||
genv.MustSet("GOOS", system)
|
||||
genv.MustSet("GOARCH", arch)
|
||||
|
||||
if outputPath != "" {
|
||||
outputPath = "-o " + outputPath
|
||||
} else {
|
||||
if dirPath == "" {
|
||||
dirPath = "."
|
||||
} else {
|
||||
dirPath = gstr.TrimRight(dirPath, "/")
|
||||
}
|
||||
if singleBuild {
|
||||
outputPath = fmt.Sprintf(
|
||||
"-o %s/%s%s",
|
||||
dirPath, name, ext,
|
||||
)
|
||||
} else {
|
||||
outputPath = fmt.Sprintf(
|
||||
"-o %s/%s/%s%s",
|
||||
dirPath, system+"_"+arch, name, ext,
|
||||
)
|
||||
}
|
||||
}
|
||||
cmd = fmt.Sprintf(
|
||||
`go build %s -ldflags "%s" %s%s`,
|
||||
outputPath, ldFlags, extra, filePath,
|
||||
)
|
||||
mlog.Debug(fmt.Sprintf("build for GOOS=%s GOARCH=%s", system, arch))
|
||||
mlog.Debug(cmd)
|
||||
// It's not necessary printing the complete command string, filtering ldFlags.
|
||||
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
|
||||
mlog.Print(cmdShow)
|
||||
if result, err := gproc.ShellExec(ctx, cmd); err != nil {
|
||||
mlog.Printf(
|
||||
"failed to build, os:%s, arch:%s, error:\n%s\n\n%s\n",
|
||||
system, arch, gstr.Trim(result),
|
||||
`you may use command option "--debug" to enable debug info and check the details`,
|
||||
)
|
||||
if exitWhenError {
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
mlog.Debug(gstr.Trim(result))
|
||||
}
|
||||
}
|
||||
|
||||
// getBuildInVarStr retrieves and returns the custom build-in variables in configuration
|
||||
// file as json.
|
||||
func (c cBuild) getBuildInVarStr(ctx context.Context, in cBuildInput) string {
|
||||
|
151
cmd/gf/internal/cmd/cmd_z_unit_build_test.go
Normal file
151
cmd/gf/internal/cmd/cmd_z_unit_build_test.go
Normal file
@ -0,0 +1,151 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
func Test_Build_Single(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `single`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryName = `t.test`
|
||||
binaryPath = gtest.DataPath(`build`, `single`, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
File: cBuildDefaultFile,
|
||||
Name: binaryName,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Single_Output(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `single`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryName = `tt`
|
||||
binaryDirPath = gtest.DataPath(`build`, `single`, `tt`)
|
||||
binaryPath = gtest.DataPath(`build`, `single`, `tt`, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryDirPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
Output: "./tt/tt",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Single_Path(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `single`)
|
||||
pwd = gfile.Pwd()
|
||||
dirName = "ttt"
|
||||
binaryName = `main`
|
||||
binaryDirPath = gtest.DataPath(`build`, `single`, dirName)
|
||||
binaryPath = gtest.DataPath(`build`, `single`, dirName, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryDirPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
Path: "ttt",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Single_VarMap(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `varmap`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryName = `main`
|
||||
binaryPath = gtest.DataPath(`build`, `varmap`, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
VarMap: map[string]interface{}{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
},
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
|
||||
result, err := gproc.ShellExec(ctx, binaryPath)
|
||||
t.AssertNil(err)
|
||||
t.Assert(gstr.Contains(result, `a: 1`), true)
|
||||
t.Assert(gstr.Contains(result, `b: 2`), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Multiple(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `multiple`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryDirPath = gtest.DataPath(`build`, `multiple`, `temp`)
|
||||
binaryPathLinux = gtest.DataPath(`build`, `multiple`, `temp`, `v1.1`, `linux_amd64`, `ttt`)
|
||||
binaryPathWindows = gtest.DataPath(`build`, `multiple`, `temp`, `v1.1`, `windows_amd64`, `ttt.exe`)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryDirPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPathLinux), false)
|
||||
t.Assert(gfile.Exists(binaryPathWindows), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
File: "multiple.go",
|
||||
Name: "ttt",
|
||||
Version: "v1.1",
|
||||
Arch: "amd64",
|
||||
System: "linux, windows",
|
||||
Path: "temp",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPathLinux), true)
|
||||
t.Assert(gfile.Exists(binaryPathWindows), true)
|
||||
})
|
||||
}
|
5
cmd/gf/internal/cmd/testdata/build/multiple/multiple.go
vendored
Normal file
5
cmd/gf/internal/cmd/testdata/build/multiple/multiple.go
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
|
||||
}
|
5
cmd/gf/internal/cmd/testdata/build/single/main.go
vendored
Normal file
5
cmd/gf/internal/cmd/testdata/build/single/main.go
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
|
||||
}
|
12
cmd/gf/internal/cmd/testdata/build/varmap/go.mod
vendored
Normal file
12
cmd/gf/internal/cmd/testdata/build/varmap/go.mod
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
module github.com/gogf/gf/cmd/gf/cmd/gf/testdata/vardump/v2
|
||||
|
||||
go 1.18
|
||||
|
||||
require github.com/gogf/gf/v2 v2.6.1
|
||||
|
||||
require (
|
||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/gogf/gf/v2 => ../../../../../../../
|
27
cmd/gf/internal/cmd/testdata/build/varmap/go.sum
vendored
Normal file
27
cmd/gf/internal/cmd/testdata/build/varmap/go.sum
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
|
||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
|
||||
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
|
||||
go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
|
||||
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
|
||||
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
13
cmd/gf/internal/cmd/testdata/build/varmap/main.go
vendored
Normal file
13
cmd/gf/internal/cmd/testdata/build/varmap/main.go
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gbuild"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for k, v := range gbuild.Data() {
|
||||
fmt.Printf("%s: %v\n", k, v)
|
||||
}
|
||||
}
|
@ -200,6 +200,9 @@ func (p *Parser) setOptionValue(name, value string) {
|
||||
|
||||
// GetOpt returns the option value named `name` as gvar.Var.
|
||||
func (p *Parser) GetOpt(name string, def ...interface{}) *gvar.Var {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
if v, ok := p.parsedOptions[name]; ok {
|
||||
return gvar.New(v)
|
||||
}
|
||||
@ -211,11 +214,17 @@ func (p *Parser) GetOpt(name string, def ...interface{}) *gvar.Var {
|
||||
|
||||
// GetOptAll returns all parsed options.
|
||||
func (p *Parser) GetOptAll() map[string]string {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
return p.parsedOptions
|
||||
}
|
||||
|
||||
// GetArg returns the argument at `index` as gvar.Var.
|
||||
func (p *Parser) GetArg(index int, def ...string) *gvar.Var {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
if index >= 0 && index < len(p.parsedArgs) {
|
||||
return gvar.New(p.parsedArgs[index])
|
||||
}
|
||||
@ -227,6 +236,9 @@ func (p *Parser) GetArg(index int, def ...string) *gvar.Var {
|
||||
|
||||
// GetArgAll returns all parsed arguments.
|
||||
func (p *Parser) GetArgAll() []string {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
return p.parsedArgs
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user