github.com/klaytn/klaytn@v1.12.1/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 "log" 29 "os" 30 "os/exec" 31 "path" 32 "path/filepath" 33 "runtime" 34 "strings" 35 "text/template" 36 ) 37 38 var DryRunFlag = flag.Bool("n", false, "dry run, don't execute commands") 39 40 // TryRun executes the given command and returns an error if error occurs. 41 func TryRun(cmd *exec.Cmd) error { 42 fmt.Println(">>>", strings.Join(cmd.Args, " ")) 43 if !*DryRunFlag { 44 cmd.Stderr = os.Stderr 45 cmd.Stdout = os.Stdout 46 return cmd.Run() 47 } 48 return nil 49 } 50 51 // TryRunCommand executes the given command and arguments in strings. 52 func TryRunCommand(cmd string, args ...string) { 53 TryRun(exec.Command(cmd, args...)) 54 } 55 56 // MustRun executes the given command and exits the host process for 57 // any error. 58 func MustRun(cmd *exec.Cmd) { 59 if err := TryRun(cmd); err != nil { 60 log.Fatal(err) 61 } 62 } 63 64 func MustRunCommand(cmd string, args ...string) { 65 MustRun(exec.Command(cmd, args...)) 66 } 67 68 // GOPATH returns the value that the GOPATH environment 69 // variable should be set to. 70 func GOPATH() string { 71 if os.Getenv("GOPATH") == "" { 72 log.Fatal("GOPATH is not set") 73 } 74 return os.Getenv("GOPATH") 75 } 76 77 // VERSION returns the content of the VERSION file. 78 func VERSION() string { 79 version, err := os.ReadFile("VERSION") 80 if err != nil { 81 log.Fatal(err) 82 } 83 return string(bytes.TrimSpace(version)) 84 } 85 86 var warnedAboutGit bool 87 88 // RunGit runs a git subcommand and returns its output. 89 // The command must complete successfully. 90 func RunGit(args ...string) string { 91 cmd := exec.Command("git", args...) 92 var stdout, stderr bytes.Buffer 93 cmd.Stdout, cmd.Stderr = &stdout, &stderr 94 if err := cmd.Run(); err == exec.ErrNotFound { 95 if !warnedAboutGit { 96 log.Println("Warning: can't find 'git' in PATH") 97 warnedAboutGit = true 98 } 99 return "" 100 } else if err != nil { 101 log.Fatal(strings.Join(cmd.Args, " "), ": ", err, "\n", stderr.String()) 102 } 103 return strings.TrimSpace(stdout.String()) 104 } 105 106 // readGitFile returns content of file in .git directory. 107 func readGitFile(file string) string { 108 content, err := os.ReadFile(path.Join(".git", file)) 109 if err != nil { 110 return "" 111 } 112 return strings.TrimSpace(string(content)) 113 } 114 115 // Render renders the given template file into outputFile. 116 func Render(templateFile, outputFile string, outputPerm os.FileMode, x interface{}) { 117 tpl := template.Must(template.ParseFiles(templateFile)) 118 render(tpl, outputFile, outputPerm, x) 119 } 120 121 // RenderString renders the given template string into outputFile. 122 func RenderString(templateContent, outputFile string, outputPerm os.FileMode, x interface{}) { 123 tpl := template.Must(template.New("").Parse(templateContent)) 124 render(tpl, outputFile, outputPerm, x) 125 } 126 127 func render(tpl *template.Template, outputFile string, outputPerm os.FileMode, x interface{}) { 128 if err := os.MkdirAll(filepath.Dir(outputFile), 0o755); err != nil { 129 log.Fatal(err) 130 } 131 out, err := os.OpenFile(outputFile, os.O_CREATE|os.O_WRONLY|os.O_EXCL, outputPerm) 132 if err != nil { 133 log.Fatal(err) 134 } 135 if err := tpl.Execute(out, x); err != nil { 136 log.Fatal(err) 137 } 138 if err := out.Close(); err != nil { 139 log.Fatal(err) 140 } 141 } 142 143 // CopyFile copies a file. 144 func CopyFile(dst, src string, mode os.FileMode) { 145 if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil { 146 log.Fatal(err) 147 } 148 destFile, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode) 149 if err != nil { 150 log.Fatal(err) 151 } 152 defer destFile.Close() 153 154 srcFile, err := os.Open(src) 155 if err != nil { 156 log.Fatal(err) 157 } 158 defer srcFile.Close() 159 160 if _, err := io.Copy(destFile, srcFile); err != nil { 161 log.Fatal(err) 162 } 163 } 164 165 // GoTool returns the command that runs a go tool. This uses go from GOROOT instead of PATH 166 // so that go commands executed by build use the same version of Go as the 'host' that runs 167 // build code. e.g. 168 // 169 // /usr/lib/go-1.8/bin/go run build/ci.go ... 170 // 171 // runs using go 1.8 and invokes go 1.8 tools from the same GOROOT. This is also important 172 // because runtime.Version checks on the host should match the tools that are run. 173 func GoTool(tool string, args ...string) *exec.Cmd { 174 args = append([]string{tool}, args...) 175 return exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...) 176 } 177 178 // ExpandPackages expands a packages list if an input contains "...". 179 func ExpandPackages(packages []string) []string { 180 for _, pkg := range packages { 181 if strings.Contains(pkg, "...") { 182 var newPkgs []string 183 184 cmd := GoTool("list", packages...) 185 out, err := cmd.Output() 186 if err != nil { 187 log.Fatalf("package listing failed: %v\n%s", err, string(out)) 188 } 189 190 for _, line := range strings.Split(string(out), "\n") { 191 newPkgs = append(newPkgs, strings.TrimSpace(line)) 192 } 193 return newPkgs 194 } 195 } 196 return packages 197 } 198 199 // ExcludePackages excludes packages having patterns from the passed package slice and 200 // returns a slice including only the remained packages. 201 func ExcludePackages(packages []string, patterns []string) []string { 202 // TODO-Klaytn This exclusion code is a naive implementation. Improve this if it hurts build performance. 203 packages = ExpandPackages(packages) 204 205 for _, pattern := range patterns { 206 var newPkgs []string 207 for _, pkg := range packages { 208 if !strings.Contains(pkg, pattern) { 209 newPkgs = append(newPkgs, pkg) 210 } 211 } 212 packages = newPkgs 213 } 214 return packages 215 }