goc/pkg/build/tmpfolder.go

188 lines
5.1 KiB
Go
Raw Normal View History

/*
2020-05-25 16:19:20 +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
import (
"crypto/sha256"
2020-06-16 05:21:28 +00:00
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/qiniu/goc/pkg/cover"
2020-06-14 11:38:41 +00:00
log "github.com/sirupsen/logrus"
2020-06-15 07:29:49 +00:00
"github.com/spf13/viper"
)
2020-06-18 08:20:54 +00:00
func (b *Build) MvProjectsToTmp() error {
2020-06-12 09:51:10 +00:00
listArgs := []string{"-json"}
if len(b.BuildFlags) != 0 {
listArgs = append(listArgs, b.BuildFlags)
}
listArgs = append(listArgs, "./...")
2020-06-18 08:20:54 +00:00
var err error
b.Pkgs, err = cover.ListPackages(".", strings.Join(listArgs, " "), "")
if err != nil {
log.Errorln(err)
return err
}
2020-06-18 08:20:54 +00:00
err = b.mvProjectsToTmp()
if err != nil {
log.Errorf("Fail to move the project to temporary directory")
return err
}
2020-06-13 10:15:51 +00:00
b.OriGOPATH = os.Getenv("GOPATH")
2020-06-12 09:51:10 +00:00
if b.IsMod == true {
b.NewGOPATH = ""
2020-06-13 10:15:51 +00:00
} else if b.OriGOPATH == "" {
2020-06-12 09:51:10 +00:00
b.NewGOPATH = b.TmpDir
} else {
2020-06-13 10:15:51 +00:00
b.NewGOPATH = fmt.Sprintf("%v:%v", b.TmpDir, b.OriGOPATH)
}
2020-06-14 01:15:48 +00:00
// fix #14: unable to build project not in GOPATH in legacy mode
// this kind of project does not have a pkg.Root value
2020-06-16 06:59:01 +00:00
// go 1.11, 1.12 has no pkg.Root,
// so add b.IsMod == false as secondary judgement
if b.Root == "" && b.IsMod == false {
2020-06-14 01:15:48 +00:00
b.NewGOPATH = b.OriGOPATH
}
2020-06-18 08:20:54 +00:00
log.Infof("New GOPATH: %v", b.NewGOPATH)
return nil
}
2020-06-16 05:21:28 +00:00
func (b *Build) mvProjectsToTmp() error {
b.TmpDir = filepath.Join(os.TempDir(), TmpFolderName(b.WorkingDir))
// Delete previous tmp folder and its content
2020-06-12 09:51:10 +00:00
os.RemoveAll(b.TmpDir)
// Create a new tmp folder
err := os.MkdirAll(filepath.Join(b.TmpDir, "src"), os.ModePerm)
if err != nil {
2020-06-16 05:21:28 +00:00
log.Errorf("Fail to create the temporary build directory. The err is: %v", err)
return err
}
2020-06-12 09:51:10 +00:00
log.Printf("Tmp project generated in: %v", b.TmpDir)
2020-06-16 05:21:28 +00:00
// traverse pkg list to get project meta info
b.IsMod, b.Root, err = b.traversePkgsList()
if errors.Is(err, ErrShouldNotReached) {
return fmt.Errorf("mvProjectsToTmp with a empty project: %w", err)
}
// we should get corresponding working directory in temporary directory
b.TmpWorkingDir, err = b.getTmpwd()
if err != nil {
log.Errorf("fail to get workding directory in temporary directory: %v", err)
2020-06-18 08:20:54 +00:00
return fmt.Errorf("getTmpwd failed with error: %w", err)
2020-06-16 05:21:28 +00:00
}
// issue #14
// if b.Root == "", then the project is non-standard project
// known cases:
// 1. a legacy project, but not in any GOPATH, will cause the b.Root == ""
if b.IsMod == false && b.Root != "" {
2020-06-12 09:51:10 +00:00
b.cpLegacyProject()
2020-06-16 06:59:01 +00:00
} else if b.IsMod == true { // go 1.11, 1.12 has no Build.Root
2020-06-12 09:51:10 +00:00
b.cpGoModulesProject()
2020-06-16 05:21:28 +00:00
} else if b.IsMod == false && b.Root == "" {
b.TmpWorkingDir = b.TmpDir
b.cpNonStandardLegacy()
} else {
return fmt.Errorf("unknown project type: %w", ErrShouldNotReached)
}
2020-06-16 05:21:28 +00:00
log.Infof("New workingdir in tmp directory in: %v", b.TmpWorkingDir)
return nil
}
func TmpFolderName(path string) string {
sum := sha256.Sum256([]byte(path))
h := fmt.Sprintf("%x", sum[:6])
2020-06-18 08:20:54 +00:00
return "goc-build-" + h
}
2020-06-16 05:21:28 +00:00
// traversePkgsList travse the Build.Pkgs list
// return Build.IsMod, tell if the project is a mod project
// return Build.Root:
// 1. the project root if it is a mod project,
// 2. current GOPATH if it is a legacy project,
// 3. some non-standard project, which Build.IsMod == false, Build.Root == nil
func (b *Build) traversePkgsList() (isMod bool, root string, err error) {
2020-06-12 09:51:10 +00:00
for _, v := range b.Pkgs {
2020-06-13 10:15:51 +00:00
// get root
2020-06-16 05:21:28 +00:00
root = v.Root
if v.Module == nil {
2020-06-16 05:21:28 +00:00
return
}
2020-06-16 05:21:28 +00:00
isMod = true
return
}
2020-06-18 08:20:54 +00:00
log.Error(ErrShouldNotReached)
2020-06-16 05:21:28 +00:00
err = ErrShouldNotReached
return
}
2020-06-12 09:51:10 +00:00
// getTmpwd get the corresponding working directory in the temporary working directory
// and store it in the Build.tmpWorkdingDir
2020-06-16 05:21:28 +00:00
func (b *Build) getTmpwd() (string, error) {
2020-06-12 09:51:10 +00:00
for _, pkg := range b.Pkgs {
index := -1
var parentPath string
2020-06-12 09:51:10 +00:00
if b.IsMod == false {
index = strings.Index(b.WorkingDir, pkg.Root)
parentPath = pkg.Root
} else {
index = strings.Index(b.WorkingDir, pkg.Module.Dir)
parentPath = pkg.Module.Dir
}
if index == -1 {
2020-06-16 05:21:28 +00:00
return "", ErrGocShouldExecInProject
}
2020-06-16 05:21:28 +00:00
// b.TmpWorkingDir = filepath.Join(b.TmpDir, path[len(parentPath):])
return filepath.Join(b.TmpDir, b.WorkingDir[len(parentPath):]), nil
}
2020-06-16 05:21:28 +00:00
return "", ErrShouldNotReached
}
2020-06-16 05:21:28 +00:00
func (b *Build) findWhereToInstall() (string, error) {
if GOBIN := os.Getenv("GOBIN"); GOBIN != "" {
2020-06-16 05:21:28 +00:00
return GOBIN, nil
}
2020-06-12 09:51:10 +00:00
if false == b.IsMod {
2020-06-16 05:21:28 +00:00
if b.Root == "" {
return "", ErrNoplaceToInstall
}
2020-06-16 05:21:28 +00:00
return filepath.Join(b.Root, "bin"), nil
}
if b.OriGOPATH != "" {
return filepath.Join(strings.Split(b.OriGOPATH, ":")[0], "bin"), nil
}
2020-06-16 05:21:28 +00:00
return filepath.Join(os.Getenv("HOME"), "go", "bin"), nil
}
2020-06-13 10:15:51 +00:00
2020-06-14 04:43:25 +00:00
// Clean clears up the temporary workspace
func (b *Build) Clean() error {
2020-06-15 07:29:49 +00:00
if !viper.GetBool("debug") {
return os.RemoveAll(b.TmpDir)
}
return nil
2020-06-13 10:15:51 +00:00
}