goc/pkg/build/tmpfolder.go

192 lines
5.3 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-13 10:15:51 +00:00
func (b *Build) MvProjectsToTmp() {
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-12 09:51:10 +00:00
b.Pkgs = cover.ListPackages(".", strings.Join(listArgs, " "), "")
2020-06-12 09:51:10 +00:00
b.mvProjectsToTmp()
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-12 09:51:10 +00:00
log.Printf("New GOPATH: %v", b.NewGOPATH)
return
}
2020-06-16 05:21:28 +00:00
func (b *Build) mvProjectsToTmp() error {
path, err := os.Getwd()
if err != nil {
2020-06-16 05:21:28 +00:00
log.Errorf("Cannot get current working directory, the error is: %v", err)
return err
}
2020-06-12 09:51:10 +00:00
b.TmpDir = filepath.Join(os.TempDir(), TmpFolderName(path))
// Delete previous tmp folder and its content
2020-06-12 09:51:10 +00:00
os.RemoveAll(b.TmpDir)
// Create a new tmp folder
2020-06-12 09:51:10 +00:00
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)
return fmt.Errorf("fail to get workding directory in temporary directory: %w", err)
}
// 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])
return "goc-" + 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-16 05:21:28 +00:00
log.Error("should not reach here")
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 {
path, err := os.Getwd()
if err != nil {
2020-06-16 05:21:28 +00:00
log.Errorf("cannot get current working directory: %v", err)
return "", fmt.Errorf("cannot get current working directory: %w", err)
}
index := -1
var parentPath string
2020-06-12 09:51:10 +00:00
if b.IsMod == false {
index = strings.Index(path, pkg.Root)
parentPath = pkg.Root
} else {
index = strings.Index(path, 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, path[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
}
// old GOPATH dir
GOPATH := os.Getenv("GOPATH")
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 GOPATH != "" {
2020-06-16 05:21:28 +00:00
return filepath.Join(strings.Split(GOPATH, ":")[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
}