2020-06-12 09:51:10 +00:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
|
2020-06-13 10:15:51 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
2020-06-13 12:11:09 +00:00
|
|
|
"strings"
|
2020-06-13 13:22:00 +00:00
|
|
|
|
|
|
|
"github.com/qiniu/goc/pkg/cover"
|
|
|
|
log "github.com/sirupsen/logrus"
|
2020-06-13 10:15:51 +00:00
|
|
|
)
|
2020-06-12 09:51:10 +00:00
|
|
|
|
|
|
|
// Build is to describe the building/installing process of a goc build/install
|
|
|
|
type Build struct {
|
2020-06-13 10:15:51 +00:00
|
|
|
Pkgs map[string]*cover.Package // Pkg list parsed from "go list -json ./..." command
|
|
|
|
NewGOPATH string // the new GOPATH
|
|
|
|
OriGOPATH string // the original GOPATH
|
2020-06-18 09:03:14 +00:00
|
|
|
WorkingDir string // the working directory
|
2020-06-13 10:15:51 +00:00
|
|
|
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
|
2020-06-16 05:21:28 +00:00
|
|
|
Root string
|
2020-06-16 06:59:01 +00:00
|
|
|
// go 1.11, go 1.12 has no Root
|
2020-06-16 05:21:28 +00:00
|
|
|
// Project Root:
|
|
|
|
// 1. legacy, root == GOPATH
|
|
|
|
// 2. mod, root == go.mod Dir
|
2020-09-29 12:20:53 +00:00
|
|
|
ModRoot string // path for go.mod
|
|
|
|
ModRootPath string // import path for the whole project
|
|
|
|
Target string // the binary name that go build generate
|
2020-06-14 11:38:41 +00:00
|
|
|
// keep compatible with go commands:
|
|
|
|
// go run [build flags] [-exec xprog] package [arguments...]
|
|
|
|
// go build [-o output] [-i] [build flags] [packages]
|
|
|
|
// go install [-i] [build flags] [packages]
|
|
|
|
BuildFlags string // Build flags
|
|
|
|
Packages string // Packages that needs to build
|
|
|
|
GoRunExecFlag string // for the -exec flags in go run command
|
|
|
|
GoRunArguments string // for the '[arguments]' parameters in go run command
|
2020-09-29 12:20:53 +00:00
|
|
|
|
|
|
|
OneMainPackage bool // whether this build is a go build or go install? true: build, false: install
|
|
|
|
GlobalCoverVarImportPath string // Importpath for storing cover variables
|
|
|
|
GlobalCoverVarFilePath string // Importpath for storing cover variables
|
2020-06-12 09:51:10 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 10:15:51 +00:00
|
|
|
// NewBuild creates a Build struct which can build from goc temporary directory,
|
|
|
|
// and generate binary in current working directory
|
2020-06-18 09:03:14 +00:00
|
|
|
func NewBuild(buildflags string, args []string, workingDir string, outputDir string) (*Build, error) {
|
|
|
|
if err := checkParameters(args, workingDir); err != nil {
|
|
|
|
return nil, err
|
2020-06-18 08:20:54 +00:00
|
|
|
}
|
2020-06-13 10:15:51 +00:00
|
|
|
// buildflags = buildflags + " -o " + outputDir
|
|
|
|
b := &Build{
|
2020-06-12 09:51:10 +00:00
|
|
|
BuildFlags: buildflags,
|
2020-06-18 08:20:54 +00:00
|
|
|
Packages: strings.Join(args, " "),
|
2020-06-18 09:03:14 +00:00
|
|
|
WorkingDir: workingDir,
|
2020-06-12 09:51:10 +00:00
|
|
|
}
|
2020-06-13 10:15:51 +00:00
|
|
|
if false == b.validatePackageForBuild() {
|
2020-06-16 05:21:28 +00:00
|
|
|
log.Errorln(ErrWrongPackageTypeForBuild)
|
|
|
|
return nil, ErrWrongPackageTypeForBuild
|
2020-06-13 10:15:51 +00:00
|
|
|
}
|
2020-06-18 08:20:54 +00:00
|
|
|
if err := b.MvProjectsToTmp(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-06-16 05:21:28 +00:00
|
|
|
dir, err := b.determineOutputDir(outputDir)
|
|
|
|
b.Target = dir
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return b, nil
|
2020-06-13 10:15:51 +00:00
|
|
|
}
|
|
|
|
|
2020-07-26 09:03:47 +00:00
|
|
|
// Build calls 'go build' tool to do building
|
2020-06-16 05:21:28 +00:00
|
|
|
func (b *Build) Build() error {
|
2020-06-13 10:15:51 +00:00
|
|
|
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
|
2020-06-16 05:21:28 +00:00
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
cmd.Stderr = os.Stderr
|
2020-06-13 10:15:51 +00:00
|
|
|
|
|
|
|
if b.NewGOPATH != "" {
|
|
|
|
// Change to temp GOPATH for go install command
|
|
|
|
cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", b.NewGOPATH))
|
|
|
|
}
|
|
|
|
|
2020-06-13 12:11:09 +00:00
|
|
|
log.Printf("go build cmd is: %v", cmd.Args)
|
2020-06-16 05:21:28 +00:00
|
|
|
err := cmd.Start()
|
2020-06-13 10:15:51 +00:00
|
|
|
if err != nil {
|
2020-06-18 08:20:54 +00:00
|
|
|
return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err)
|
2020-06-16 05:21:28 +00:00
|
|
|
}
|
|
|
|
if err = cmd.Wait(); err != nil {
|
2020-06-18 08:20:54 +00:00
|
|
|
return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err)
|
2020-06-13 10:15:51 +00:00
|
|
|
}
|
2020-06-18 08:20:54 +00:00
|
|
|
log.Infoln("Go build exit successful.")
|
2020-06-16 05:21:28 +00:00
|
|
|
return nil
|
2020-06-12 09:51:10 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 10:15:51 +00:00
|
|
|
// determineOutputDir, as we only allow . as package name,
|
|
|
|
// the binary name is always same as the directory name of current directory
|
2020-06-16 05:21:28 +00:00
|
|
|
func (b *Build) determineOutputDir(outputDir string) (string, error) {
|
2020-06-13 13:22:00 +00:00
|
|
|
if b.TmpDir == "" {
|
2020-07-26 09:46:35 +00:00
|
|
|
return "", fmt.Errorf("can only be called after Build.MvProjectsToTmp(): %w", ErrEmptyTempWorkingDir)
|
2020-06-13 13:22:00 +00:00
|
|
|
}
|
2020-06-14 04:43:25 +00:00
|
|
|
|
2020-07-10 13:49:10 +00:00
|
|
|
// fix #43
|
|
|
|
if outputDir != "" {
|
|
|
|
abs, err := filepath.Abs(outputDir)
|
|
|
|
if err != nil {
|
2020-07-17 07:16:23 +00:00
|
|
|
return "", fmt.Errorf("Fail to transform the path: %v to absolute path: %v", outputDir, err)
|
|
|
|
|
2020-07-10 13:49:10 +00:00
|
|
|
}
|
|
|
|
return abs, nil
|
|
|
|
}
|
2020-07-10 03:05:54 +00:00
|
|
|
// fix #43
|
|
|
|
// use target name from `go list -json ./...` of the main module
|
|
|
|
targetName := ""
|
|
|
|
for _, pkg := range b.Pkgs {
|
|
|
|
if pkg.Name == "main" {
|
2020-12-22 07:22:17 +00:00
|
|
|
_, file := filepath.Split(pkg.Target)
|
|
|
|
targetName = file
|
2020-07-10 03:05:54 +00:00
|
|
|
break
|
2020-06-13 13:22:00 +00:00
|
|
|
}
|
2020-06-13 10:15:51 +00:00
|
|
|
}
|
2020-07-10 03:05:54 +00:00
|
|
|
|
|
|
|
return filepath.Join(b.WorkingDir, targetName), nil
|
2020-06-13 10:15:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// validatePackageForBuild only allow . as package name
|
|
|
|
func (b *Build) validatePackageForBuild() bool {
|
2020-06-18 08:20:54 +00:00
|
|
|
if b.Packages == "." || b.Packages == "" {
|
2020-06-13 10:15:51 +00:00
|
|
|
return true
|
2020-06-14 11:38:41 +00:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-06-18 09:03:14 +00:00
|
|
|
func checkParameters(args []string, workingDir string) error {
|
|
|
|
if len(args) > 1 {
|
|
|
|
log.Errorln(ErrTooManyArgs)
|
|
|
|
return ErrTooManyArgs
|
2020-06-14 11:38:41 +00:00
|
|
|
}
|
2020-06-15 07:54:36 +00:00
|
|
|
|
2020-06-18 09:03:14 +00:00
|
|
|
if workingDir == "" {
|
|
|
|
return ErrInvalidWorkingDir
|
2020-06-13 10:15:51 +00:00
|
|
|
}
|
2020-06-18 10:08:48 +00:00
|
|
|
|
|
|
|
log.Infof("Working directory: %v", workingDir)
|
2020-06-18 08:20:54 +00:00
|
|
|
return nil
|
2020-06-13 10:15:51 +00:00
|
|
|
}
|