goc/pkg/build/build.go

160 lines
4.9 KiB
Go
Raw Normal View History

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
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
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-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
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, " "),
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
// 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)
}
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" {
_, file := filepath.Split(pkg.Target)
targetName = file
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
}
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
if workingDir == "" {
return ErrInvalidWorkingDir
2020-06-13 10:15:51 +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
}