github.com/klaytn/klaytn@v1.10.2/utils/build/util.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2016 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from internal/build/util.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package build
    22  
    23  import (
    24  	"bytes"
    25  	"flag"
    26  	"fmt"
    27  	"io"
    28  	"io/ioutil"
    29  	"log"
    30  	"os"
    31  	"os/exec"
    32  	"path"
    33  	"path/filepath"
    34  	"runtime"
    35  	"strings"
    36  	"text/template"
    37  )
    38  
    39  var DryRunFlag = flag.Bool("n", false, "dry run, don't execute commands")
    40  
    41  // TryRun executes the given command and returns an error if error occurs.
    42  func TryRun(cmd *exec.Cmd) error {
    43  	fmt.Println(">>>", strings.Join(cmd.Args, " "))
    44  	if !*DryRunFlag {
    45  		cmd.Stderr = os.Stderr
    46  		cmd.Stdout = os.Stdout
    47  		return cmd.Run()
    48  	}
    49  	return nil
    50  }
    51  
    52  // TryRunCommand executes the given command and arguments in strings.
    53  func TryRunCommand(cmd string, args ...string) {
    54  	TryRun(exec.Command(cmd, args...))
    55  }
    56  
    57  // MustRun executes the given command and exits the host process for
    58  // any error.
    59  func MustRun(cmd *exec.Cmd) {
    60  	if err := TryRun(cmd); err != nil {
    61  		log.Fatal(err)
    62  	}
    63  }
    64  
    65  func MustRunCommand(cmd string, args ...string) {
    66  	MustRun(exec.Command(cmd, args...))
    67  }
    68  
    69  // GOPATH returns the value that the GOPATH environment
    70  // variable should be set to.
    71  func GOPATH() string {
    72  	if os.Getenv("GOPATH") == "" {
    73  		log.Fatal("GOPATH is not set")
    74  	}
    75  	return os.Getenv("GOPATH")
    76  }
    77  
    78  // VERSION returns the content of the VERSION file.
    79  func VERSION() string {
    80  	version, err := ioutil.ReadFile("VERSION")
    81  	if err != nil {
    82  		log.Fatal(err)
    83  	}
    84  	return string(bytes.TrimSpace(version))
    85  }
    86  
    87  var warnedAboutGit bool
    88  
    89  // RunGit runs a git subcommand and returns its output.
    90  // The command must complete successfully.
    91  func RunGit(args ...string) string {
    92  	cmd := exec.Command("git", args...)
    93  	var stdout, stderr bytes.Buffer
    94  	cmd.Stdout, cmd.Stderr = &stdout, &stderr
    95  	if err := cmd.Run(); err == exec.ErrNotFound {
    96  		if !warnedAboutGit {
    97  			log.Println("Warning: can't find 'git' in PATH")
    98  			warnedAboutGit = true
    99  		}
   100  		return ""
   101  	} else if err != nil {
   102  		log.Fatal(strings.Join(cmd.Args, " "), ": ", err, "\n", stderr.String())
   103  	}
   104  	return strings.TrimSpace(stdout.String())
   105  }
   106  
   107  // readGitFile returns content of file in .git directory.
   108  func readGitFile(file string) string {
   109  	content, err := ioutil.ReadFile(path.Join(".git", file))
   110  	if err != nil {
   111  		return ""
   112  	}
   113  	return strings.TrimSpace(string(content))
   114  }
   115  
   116  // Render renders the given template file into outputFile.
   117  func Render(templateFile, outputFile string, outputPerm os.FileMode, x interface{}) {
   118  	tpl := template.Must(template.ParseFiles(templateFile))
   119  	render(tpl, outputFile, outputPerm, x)
   120  }
   121  
   122  // RenderString renders the given template string into outputFile.
   123  func RenderString(templateContent, outputFile string, outputPerm os.FileMode, x interface{}) {
   124  	tpl := template.Must(template.New("").Parse(templateContent))
   125  	render(tpl, outputFile, outputPerm, x)
   126  }
   127  
   128  func render(tpl *template.Template, outputFile string, outputPerm os.FileMode, x interface{}) {
   129  	if err := os.MkdirAll(filepath.Dir(outputFile), 0o755); err != nil {
   130  		log.Fatal(err)
   131  	}
   132  	out, err := os.OpenFile(outputFile, os.O_CREATE|os.O_WRONLY|os.O_EXCL, outputPerm)
   133  	if err != nil {
   134  		log.Fatal(err)
   135  	}
   136  	if err := tpl.Execute(out, x); err != nil {
   137  		log.Fatal(err)
   138  	}
   139  	if err := out.Close(); err != nil {
   140  		log.Fatal(err)
   141  	}
   142  }
   143  
   144  // CopyFile copies a file.
   145  func CopyFile(dst, src string, mode os.FileMode) {
   146  	if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
   147  		log.Fatal(err)
   148  	}
   149  	destFile, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
   150  	if err != nil {
   151  		log.Fatal(err)
   152  	}
   153  	defer destFile.Close()
   154  
   155  	srcFile, err := os.Open(src)
   156  	if err != nil {
   157  		log.Fatal(err)
   158  	}
   159  	defer srcFile.Close()
   160  
   161  	if _, err := io.Copy(destFile, srcFile); err != nil {
   162  		log.Fatal(err)
   163  	}
   164  }
   165  
   166  // GoTool returns the command that runs a go tool. This uses go from GOROOT instead of PATH
   167  // so that go commands executed by build use the same version of Go as the 'host' that runs
   168  // build code. e.g.
   169  //
   170  //     /usr/lib/go-1.8/bin/go run build/ci.go ...
   171  //
   172  // runs using go 1.8 and invokes go 1.8 tools from the same GOROOT. This is also important
   173  // because runtime.Version checks on the host should match the tools that are run.
   174  func GoTool(tool string, args ...string) *exec.Cmd {
   175  	args = append([]string{tool}, args...)
   176  	return exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
   177  }
   178  
   179  // ExpandPackages expands a packages list if an input contains "...".
   180  func ExpandPackages(packages []string) []string {
   181  	for _, pkg := range packages {
   182  		if strings.Contains(pkg, "...") {
   183  			var newPkgs []string
   184  
   185  			cmd := GoTool("list", packages...)
   186  			out, err := cmd.Output()
   187  			if err != nil {
   188  				log.Fatalf("package listing failed: %v\n%s", err, string(out))
   189  			}
   190  
   191  			for _, line := range strings.Split(string(out), "\n") {
   192  				newPkgs = append(newPkgs, strings.TrimSpace(line))
   193  			}
   194  			return newPkgs
   195  		}
   196  	}
   197  	return packages
   198  }
   199  
   200  // ExcludePackages excludes packages having patterns from the passed package slice and
   201  // returns a slice including only the remained packages.
   202  func ExcludePackages(packages []string, patterns []string) []string {
   203  	// TODO-Klaytn This exclusion code is a naive implementation. Improve this if it hurts build performance.
   204  	packages = ExpandPackages(packages)
   205  
   206  	for _, pattern := range patterns {
   207  		var newPkgs []string
   208  		for _, pkg := range packages {
   209  			if !strings.Contains(pkg, pattern) {
   210  				newPkgs = append(newPkgs, pkg)
   211  			}
   212  		}
   213  		packages = newPkgs
   214  	}
   215  	return packages
   216  }