refactor build/install command

This commit is contained in:
lyyyuna 2020-06-13 18:15:51 +08:00
parent b017346ab4
commit 3717c2d29f
20 changed files with 167 additions and 189 deletions

View File

@ -17,14 +17,7 @@
package cmd
import (
"flag"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/qiniu/goc/pkg/build"
"github.com/spf13/cobra"
)
@ -50,74 +43,22 @@ goc build -- -o /to/this/path
goc build -- -ldflags "-extldflags -static" -tags="embed kodo"
`,
Run: func(cmd *cobra.Command, args []string) {
gocbuild := build.NewBuild(buildFlags, packages, buildOutput)
// remove temporary directory if needed
defer gocbuild.RemoveTmpDir()
// doCover with original buildFlags, with new GOPATH( tmp:original )
// in the tmp directory
doCover(buildFlags, gocbuild.NewGOPATH, gocbuild.TmpDir)
// do install in the temporary directory
gocbuild.Build()
return
/*
gocbuild := build.NewInstall(buildFlags, packages)
newgopath, newwd, tmpdir, _ := gocbuild.MvProjectsToTmp()
doCover("args", newgopath, tmpdir)
newArgs, modified := modifyOutputArg(args)
doBuild(newArgs, newgopath, newwd)
// if not modified
// find the binary in temp build dir
// and copy them into original dir
if false == modified {
// build.MvBinaryToOri(pkgs, tmpdir)
}
*/
},
}
var buildOutput string
func init() {
addBuildFlags(buildCmd.Flags())
buildCmd.Flags().StringVar(&buildOutput, "output", "", "it forces build to write the resulting executable or object to the named output file or directory")
rootCmd.AddCommand(buildCmd)
}
func doBuild(args []string, newgopath string, newworkingdir string) {
log.Println("Go building in temp...")
newArgs := []string{"build"}
newArgs = append(newArgs, args...)
cmd := exec.Command("go", newArgs...)
cmd.Dir = newworkingdir
if newgopath != "" {
// Change to temp GOPATH for go install command
cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", newgopath))
}
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("Fail to execute: go build %v. The error is: %v, the stdout/stderr is: %v", strings.Join(args, " "), err, string(out))
}
log.Println("Go build exit successful.")
}
// As we build in the temp build dir, we have to modify the "-o output",
// if output is a relative path, transform it to abspath
func modifyOutputArg(args []string) (newArgs []string, modified bool) {
var output string
fs := flag.NewFlagSet("goc-build", flag.PanicOnError)
fs.StringVar(&output, "o", "", "output dir")
// parse the go args after "--"
fs.Parse(args)
// skip if output is not present
if output == "" {
modified = false
newArgs = args
return
}
abs, err := filepath.Abs(output)
if err != nil {
log.Fatalf("Fail to transform the path: %v to absolute path, the error is: %v", output, err)
}
// the second -o arg will overwrite the first one
newArgs = append(args, "-o", abs)
modified = true
return
}

View File

@ -18,7 +18,7 @@ package cmd
import (
"fmt"
"log"
log "github.com/sirupsen/logrus"
"os"
"github.com/qiniu/goc/pkg/cover"

View File

@ -19,7 +19,7 @@ package cmd
import (
"fmt"
"github.com/spf13/viper"
"log"
log "github.com/sirupsen/logrus"
"os"
"strings"

View File

@ -17,7 +17,7 @@
package cmd
import (
"log"
log "github.com/sirupsen/logrus"
"github.com/qiniu/goc/pkg/cover"
"github.com/spf13/cobra"

View File

@ -41,11 +41,12 @@ goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'"
`,
Run: func(cmd *cobra.Command, args []string) {
gocbuild := build.NewInstall(buildFlags, packages)
gocbuild.MvProjectsToTmp()
// remove temporary directory if needed
defer gocbuild.RemoveTmpDir()
// doCover with original buildFlags, with new GOPATH( tmp:original )
// in the tmp directory
doCover(buildFlags, gocbuild.NewGOPATH, gocbuild.TmpDir)
//
// do install in the temporary directory
gocbuild.Install()
},
}

View File

@ -20,7 +20,7 @@ import (
"bytes"
"fmt"
"io"
"log"
log "github.com/sirupsen/logrus"
"os"
"github.com/qiniu/goc/pkg/cover"

View File

@ -17,10 +17,13 @@
package cmd
import (
"io/ioutil"
"log"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"io/ioutil"
"path/filepath"
"runtime"
"strconv"
)
var rootCmd = &cobra.Command{
@ -32,7 +35,17 @@ Find more information at:
https://github.com/qiniu/goc
`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
log.SetFlags(log.LstdFlags | log.Lshortfile)
log.SetReportCaller(true)
log.SetFormatter(&log.TextFormatter{
FullTimestamp: true,
CallerPrettyfier: func(f *runtime.Frame) (string, string) {
dirname, filename := filepath.Split(f.File)
lastelem := filepath.Base(dirname)
filename = filepath.Join(lastelem, filename)
line := strconv.Itoa(f.Line)
return "", "[" + filename + ":" + line + "]"
},
})
if debugGoc == false {
// we only need log in debug mode
log.SetOutput(ioutil.Discard)
@ -43,6 +56,7 @@ Find more information at:
func init() {
rootCmd.PersistentFlags().BoolVar(&debugGoc, "debuggoc", false, "turn goc into debug mode")
rootCmd.PersistentFlags().MarkHidden("debuggoc")
viper.BindPFlags(rootCmd.PersistentFlags())
}
// Execute the goc tool

2
go.mod
View File

@ -14,7 +14,7 @@ require (
github.com/onsi/gomega v1.8.1
github.com/otiai10/copy v1.0.2
github.com/qiniu/api.v7/v7 v7.5.0
github.com/sirupsen/logrus v1.4.2
github.com/sirupsen/logrus v1.6.0
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.6.2

3
go.sum
View File

@ -461,6 +461,7 @@ github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQ
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
@ -652,6 +653,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=

View File

@ -1,77 +0,0 @@
/*
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
import (
"log"
"os"
"path/filepath"
"github.com/otiai10/copy"
"github.com/qiniu/goc/pkg/cover"
)
func (b *Build) MvBinaryToOri(pkgs map[string]*cover.Package) {
for _, pkg := range b.Pkgs {
if pkg.Name == "main" {
_, binaryTarget := filepath.Split(pkg.Target)
binaryTmpPath := filepath.Join(b.TmpWorkingDir)
if false == checkIfFileExist(binaryTmpPath) {
continue
}
curwd, err := os.Getwd()
if err != nil {
log.Fatalf("Cannot get current working directoy, the error is: %v", err)
}
binaryOriPath := filepath.Join(curwd, binaryTarget)
if checkIfFileExist(binaryOriPath) {
// if we have file in the original place with same name,
// but this file is not a binary,
// then we skip it
if false == checkIfExecutable(binaryOriPath) {
log.Printf("Skipping binary: %v, as we find a file in the original place with same name but not executable.", binaryOriPath)
continue
}
}
log.Printf("Generating binary: %v", binaryOriPath)
if err = copy.Copy(binaryTmpPath, binaryOriPath); err != nil {
log.Println(err)
}
}
}
}
func checkIfExecutable(path string) bool {
fileInfo, err := os.Lstat(path)
if err != nil {
return false
}
return fileInfo.Mode()&0100 != 0
}
func checkIfFileExist(path string) bool {
fileInfo, err := os.Stat(path)
if os.IsNotExist(err) {
return false
}
return !fileInfo.IsDir()
}

View File

@ -16,25 +16,87 @@
package build
import "github.com/qiniu/goc/pkg/cover"
import (
"fmt"
"github.com/qiniu/goc/pkg/cover"
log "github.com/sirupsen/logrus"
"os"
"os/exec"
"path/filepath"
)
// Build is to describe the building/installing process of a goc build/install
type Build struct {
Pkgs map[string]*cover.Package //
NewGOPATH string
OriGOPATH string
TmpDir string
TmpWorkingDir string
IsMod bool
BuildFlags string
Packages string
Root string // Project Root
Pkgs map[string]*cover.Package // Pkg list parsed from "go list -json ./..." command
NewGOPATH string // the new GOPATH
OriGOPATH string // the original GOPATH
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
BuildFlags string // Build flags
Packages string // Packages that needs to build
Root string // Project Root
Target string // the binary name that go build generate
}
func NewInstall(buildflags string, packages string) *Build {
return &Build{
// NewBuild creates a Build struct which can build from goc temporary directory,
// and generate binary in current working directory
func NewBuild(buildflags string, packages string, outputDir string) *Build {
// buildflags = buildflags + " -o " + outputDir
b := &Build{
BuildFlags: buildflags,
Packages: packages,
Packages: packages,
}
if false == b.validatePackageForBuild() {
log.Fatalln("packages only support \".\"")
}
b.Target = b.determineOutputDir(outputDir)
b.MvProjectsToTmp()
return b
}
func (b *Build) Build() {
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
if b.NewGOPATH != "" {
// Change to temp GOPATH for go install command
cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", b.NewGOPATH))
}
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("Fail to execute: %v. The error is: %v, the stdout/stderr is: %v", cmd.Args, err, string(out))
}
log.Println("Go build exit successful.")
}
// determineOutputDir, as we only allow . as package name,
// the binary name is always same as the directory name of current directory
func (b *Build) determineOutputDir(outputDir string) string {
curWorkingDir, err := os.Getwd()
if err != nil {
log.Fatalf("Cannot get current working directory, the err: %v.", err)
}
// if
if outputDir == "" {
return curWorkingDir
}
abs, err := filepath.Abs(outputDir)
if err != nil {
log.Fatalf("Fail to transform the path: %v to absolute path, the error is: %v", outputDir, err)
}
return abs
}
// validatePackageForBuild only allow . as package name
func (b *Build) validatePackageForBuild() bool {
if b.Packages == "." {
return true
} else {
return false
}
}

View File

@ -17,7 +17,8 @@
package build
import (
"log"
log "github.com/sirupsen/logrus"
"github.com/otiai10/copy"
)

View File

@ -18,14 +18,27 @@ package build
import (
"fmt"
"log"
log "github.com/sirupsen/logrus"
"os"
"os/exec"
)
// NewInstall creates a Build struct which can install from goc temporary directory
func NewInstall(buildflags string, packages string) *Build {
b := &Build{
BuildFlags: buildflags,
Packages: packages,
}
if false == b.validatePackageForInstall() {
log.Fatalln("packages only support . and ./...")
}
b.MvProjectsToTmp()
return b
}
func (b *Build) Install() {
log.Println("Go building in temp...")
cmd := exec.Command("/bin/bash", "-c", "go install " + b.BuildFlags + " " + b.Packages)
cmd := exec.Command("/bin/bash", "-c", "go install "+b.BuildFlags+" "+b.Packages)
cmd.Dir = b.TmpWorkingDir
// Change the temp GOBIN, to force binary install to original place
@ -42,3 +55,11 @@ func (b *Build) Install() {
}
log.Printf("Go install successful. Binary installed in: %v", b.findWhereToInstall())
}
func (b *Build) validatePackageForInstall() bool {
if b.Packages == "." || b.Packages == "./..." {
return true
} else {
return false
}
}

View File

@ -17,7 +17,7 @@
package build
import (
"log"
log "github.com/sirupsen/logrus"
"os"
"path/filepath"

View File

@ -19,7 +19,8 @@ package build
import (
"crypto/sha256"
"fmt"
"log"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
"os"
"path/filepath"
"strings"
@ -27,7 +28,7 @@ import (
"github.com/qiniu/goc/pkg/cover"
)
func (b *Build) MvProjectsToTmp() (newGopath string, newWorkingDir string, tmpBuildDir string, pkgs map[string]*cover.Package) {
func (b *Build) MvProjectsToTmp() {
listArgs := []string{"-json"}
if len(b.BuildFlags) != 0 {
listArgs = append(listArgs, b.BuildFlags)
@ -36,13 +37,13 @@ func (b *Build) MvProjectsToTmp() (newGopath string, newWorkingDir string, tmpBu
b.Pkgs = cover.ListPackages(".", strings.Join(listArgs, " "), "")
b.mvProjectsToTmp()
oriGopath := os.Getenv("GOPATH")
b.OriGOPATH = os.Getenv("GOPATH")
if b.IsMod == true {
b.NewGOPATH = ""
} else if oriGopath == "" {
} else if b.OriGOPATH == "" {
b.NewGOPATH = b.TmpDir
} else {
b.NewGOPATH = fmt.Sprintf("%v:%v", b.TmpDir, oriGopath)
b.NewGOPATH = fmt.Sprintf("%v:%v", b.TmpDir, b.OriGOPATH)
}
log.Printf("New GOPATH: %v", b.NewGOPATH)
return
@ -88,6 +89,8 @@ func TmpFolderName(path string) string {
// false go mod
func (b *Build) checkIfLegacyProject() bool {
for _, v := range b.Pkgs {
// get root
b.Root = v.Root
if v.Module == nil {
return true
}
@ -145,3 +148,12 @@ func (b *Build) findWhereToInstall() string {
}
return filepath.Join(os.Getenv("HOME"), "go", "bin")
}
func (b *Build) RemoveTmpDir() {
debuggoc := viper.GetBool("debuggoc")
if debuggoc == false {
if b.TmpDir != "" {
os.RemoveAll(b.TmpDir)
}
}
}

View File

@ -22,9 +22,9 @@ import (
"crypto/sha256"
"encoding/json"
"fmt"
log "github.com/sirupsen/logrus"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
@ -115,7 +115,7 @@ type PackageError struct {
// ListPackages list all packages under specific via go list command
// The argument newgopath is if you need to go list in a different GOPATH
func ListPackages(dir string, args string, newgopath string) map[string]*Package {
cmd := exec.Command("/bin/bash", "-c", "go list " + args)
cmd := exec.Command("/bin/bash", "-c", "go list "+args)
log.Printf("go list cmd is: %v", cmd.Args)
cmd.Dir = dir
if newgopath != "" {
@ -123,7 +123,7 @@ func ListPackages(dir string, args string, newgopath string) map[string]*Package
}
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("excute `go list -json ./...` command failed, err: %v, out: %v", err, string(out))
log.Fatalf("excute `go list -json ./...` command failed, err: %v, out: %v", err, string(out))
}
dec := json.NewDecoder(bytes.NewReader(out))

View File

@ -18,7 +18,7 @@ package cover
import (
"fmt"
"log"
log "github.com/sirupsen/logrus"
"os"
"os/exec"
"path/filepath"

View File

@ -21,7 +21,7 @@ import (
"fmt"
"io"
"io/ioutil"
"log"
log "github.com/sirupsen/logrus"
"net"
"net/http"
"net/url"

View File

@ -19,7 +19,7 @@ package cover
import (
"bufio"
"fmt"
"log"
log "github.com/sirupsen/logrus"
"os"
"strings"
"sync"

View File

@ -19,7 +19,7 @@ package qiniu
import (
"encoding/json"
"fmt"
"log"
log "github.com/sirupsen/logrus"
"os"
"path"
"sort"