go-hep.org/x/hep@v0.38.1/ci/mk-release.go (about) 1 // Copyright ©2019 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build ignore 6 7 package main 8 9 import ( 10 "bufio" 11 "bytes" 12 "flag" 13 "fmt" 14 "log" 15 "os" 16 "os/exec" 17 "path/filepath" 18 "strings" 19 20 "golang.org/x/sync/errgroup" 21 ) 22 23 func main() { 24 log.SetPrefix("") 25 log.SetFlags(0) 26 27 var ( 28 module = flag.String("module", "go-hep.org/x/hep", "module name to publish") 29 version = flag.String("version", "latest", "module version to publish") 30 repo = flag.String("repo", "git@codeberg.org:go-hep/hep", "VCS URL of repository") 31 ) 32 33 flag.Parse() 34 35 publish(*module, *version, *repo) 36 } 37 38 func publish(module, version, repo string) { 39 doLatest := version == "latest" 40 log.Printf("publishing module=%q, version=%q", module, version) 41 modver := module + "@" + version 42 43 tmp, err := os.MkdirTemp("", "go-hep-release-") 44 if err != nil { 45 log.Fatalf("could not create tmpdir: %+v", err) 46 } 47 defer os.RemoveAll(tmp) 48 49 os.Setenv("GO111MODULE", "on") 50 51 log.Printf("## creating modpub module...") 52 cmd := exec.Command("go", "mod", "init", "modpub") 53 cmd.Dir = tmp 54 cmd.Stderr = log.Writer() 55 cmd.Stdout = log.Writer() 56 err = cmd.Run() 57 if err != nil { 58 log.Fatalf("could not initialize modpub module: %+v", err) 59 } 60 61 log.Printf("## get %q...", modver) 62 cmd = exec.Command("go", "get", "-v", modver) 63 cmd.Dir = tmp 64 cmd.Stderr = log.Writer() 65 cmd.Stdout = log.Writer() 66 err = cmd.Run() 67 if err != nil { 68 log.Fatalf("could not get %q module: %+v", modver, err) 69 } 70 71 log.Printf("## generating main package...") 72 const tmpl = `package main 73 74 import ( 75 _ "%s" 76 ) 77 78 func main() {} 79 ` 80 81 err = os.WriteFile(filepath.Join(tmp, "main.go"), []byte(fmt.Sprintf(tmpl, module)), 0644) 82 if err != nil { 83 log.Fatalf("could not generate main: %+v", err) 84 } 85 86 log.Printf("## mod download %q...", modver) 87 cmd = exec.Command("go", "mod", "download") 88 cmd.Dir = tmp 89 cmd.Stderr = log.Writer() 90 cmd.Stdout = log.Writer() 91 err = cmd.Run() 92 if err != nil { 93 log.Fatalf("could not mod-tidy %q module: %+v", modver, err) 94 } 95 96 log.Printf("## mod tidy %q...", modver) 97 cmd = exec.Command("go", "mod", "tidy") 98 cmd.Dir = tmp 99 cmd.Stderr = log.Writer() 100 cmd.Stdout = log.Writer() 101 err = cmd.Run() 102 if err != nil { 103 log.Fatalf("could not mod-tidy %q module: %+v", modver, err) 104 } 105 106 log.Printf("## go build...") 107 cmd = exec.Command("go", "build", "-v") 108 cmd.Dir = tmp 109 cmd.Stderr = log.Writer() 110 cmd.Stdout = log.Writer() 111 err = cmd.Run() 112 if err != nil { 113 log.Fatalf("could not get %q module: %+v", modver, err) 114 } 115 116 version, err = extractVersion(filepath.Join(tmp, "go.mod"), module) 117 if err != nil { 118 log.Fatalf("could not extract version from modpub module file: %+v", err) 119 } 120 121 buildCmds(module, version, repo) 122 if doLatest { 123 setLatest(version) 124 } 125 } 126 127 func extractVersion(fname, modname string) (string, error) { 128 f, err := os.Open(fname) 129 if err != nil { 130 return "", fmt.Errorf("could not open module file %q: %w", fname, err) 131 } 132 defer f.Close() 133 134 sc := bufio.NewScanner(f) 135 for sc.Scan() { 136 line := sc.Text() 137 if !strings.Contains(line, modname+" ") { 138 continue 139 } 140 141 _, after, ok := strings.Cut(line, modname) 142 if ok { 143 return strings.TrimSpace(after), nil 144 } 145 } 146 147 return "", fmt.Errorf("could not find module %q in modpub %q", modname, fname) 148 } 149 150 func buildCmds(modname, version, repo string) { 151 top, err := os.MkdirTemp("", "go-hep-release-") 152 if err != nil { 153 log.Fatalf("could not create tmp dir: %+v", err) 154 } 155 defer os.RemoveAll(top) 156 157 src := filepath.Join(top, "hep") 158 cmd := exec.Command( 159 "git", "clone", 160 "-b", version, "--depth", "1", 161 repo, 162 src, 163 ) 164 cmd.Dir = top 165 cmd.Stderr = log.Writer() 166 cmd.Stdout = log.Writer() 167 err = cmd.Run() 168 if err != nil { 169 log.Fatalf("could not clone %q: %+v", repo, err) 170 } 171 172 tmp, err := os.MkdirTemp("", "go-hep-release-cmds-") 173 if err != nil { 174 log.Fatalf("could not create tmp dir for build cmds: %+v", err) 175 } 176 defer os.RemoveAll(tmp) 177 178 allpkgs, err := pkgList(src, modname, OSArch{"linux", "amd64"}) 179 if err != nil { 180 log.Fatalf("could not build package list of module %q: %+v", modname, err) 181 } 182 183 for _, osarch := range []struct { 184 os, arch string 185 }{ 186 {"linux", "amd64"}, 187 {"linux", "386"}, 188 {"linux", "arm64"}, 189 {"windows", "amd64"}, 190 {"windows", "386"}, 191 {"darwin", "amd64"}, 192 {"freebsd", "amd64"}, 193 } { 194 var ( 195 grp errgroup.Group 196 ctx = osarch 197 ) 198 grp.SetLimit(4) 199 log.Printf("--> GOOS=%s, GOARCH=%s", ctx.os, ctx.arch) 200 cmds := make([]string, 0, len(allpkgs)) 201 for _, pkg := range allpkgs { 202 if !strings.Contains(pkg, "/cmd") { 203 continue 204 } 205 if strings.Contains(pkg, "/internal") { 206 continue 207 } 208 if _, ok := excludeList[ctx][pkg]; ok { 209 continue 210 } 211 cmds = append(cmds, pkg) 212 } 213 214 tags := "-tags=netgo" 215 log.Printf("--> found %d commands", len(cmds)) 216 for i := range cmds { 217 cmd := cmds[i] 218 grp.Go(func() error { 219 name := fmt.Sprintf("%s-%s_%s.exe", filepath.Base(cmd), ctx.os, ctx.arch) 220 exe := filepath.Join(tmp, name) 221 bld := exec.Command( 222 "go", "build", 223 "-trimpath", 224 "-buildvcs=true", 225 "-o", exe, 226 tags, 227 strings.Replace(cmd, modname, ".", 1), 228 ) 229 bld.Dir = src 230 bld.Env = append([]string{}, os.Environ()...) 231 bld.Env = append(bld.Env, fmt.Sprintf("GOOS=%s", ctx.os), fmt.Sprintf("GOARCH=%s", ctx.arch)) 232 if _, ok := needCgo[filepath.Base(cmd)]; !ok { 233 bld.Env = append(bld.Env, "CGO_ENABLED=0") 234 } 235 out, err := bld.CombinedOutput() 236 if err != nil { 237 log.Printf("could not compile %s: %+v\noutput:\n%s", name, err, out) 238 return err 239 } 240 return nil 241 }) 242 } 243 244 err = grp.Wait() 245 if err != nil { 246 log.Fatalf("could not build commands for %s/%s: %+v", ctx.os, ctx.arch, err) 247 } 248 } 249 250 upload(tmp, version) 251 } 252 253 type OSArch struct { 254 os, arch string 255 } 256 257 func pkgList(dir, module string, ctx OSArch) ([]string, error) { 258 env := append([]string{}, os.Environ()...) 259 env = append(env, fmt.Sprintf("GOOS=%s", ctx.os), fmt.Sprintf("GOARCH=%s", ctx.arch)) 260 261 cmd := exec.Command("go", "mod", "tidy") 262 cmd.Dir = dir 263 cmd.Env = env 264 cmd.Stdout = log.Writer() 265 cmd.Stderr = log.Writer() 266 err := cmd.Run() 267 if err != nil { 268 return nil, fmt.Errorf("could not initialize list: %w", err) 269 } 270 271 out := new(bytes.Buffer) 272 cmd = exec.Command("go", "list", "./...") 273 cmd.Dir = dir 274 cmd.Stdout = out 275 cmd.Stderr = os.Stderr 276 cmd.Stdin = os.Stdin 277 cmd.Env = env 278 279 err = cmd.Run() 280 if err != nil { 281 return nil, fmt.Errorf("could not get package list (%s-%s): %w", ctx.os, ctx.arch, err) 282 } 283 284 var pkgs []string 285 scan := bufio.NewScanner(out) 286 for scan.Scan() { 287 pkg := scan.Text() 288 if strings.Contains(pkg, "vendor") { 289 continue 290 } 291 if !strings.HasPrefix(pkg, module) { 292 continue 293 } 294 pkgs = append(pkgs, pkg) 295 } 296 297 return pkgs, nil 298 } 299 300 func upload(dir string, version string) { 301 cmd := exec.Command("scp", "-r", dir, "root@clrwebgohep.in2p3.fr:/srv/go-hep.org/dist/"+version) 302 cmd.Stdout = os.Stdout 303 cmd.Stderr = os.Stderr 304 err := cmd.Run() 305 if err != nil { 306 log.Fatalf("could not upload binaries to server: %+v", err) 307 } 308 } 309 310 func setLatest(version string) { 311 cmd := exec.Command("ssh", "root@clrwebgohep.in2p3.fr", 312 "--", 313 fmt.Sprintf("/bin/sh -c 'cd /srv/go-hep.org/dist && /bin/rm ./latest && ln -s %s latest'", version), 314 ) 315 cmd.Stdout = os.Stdout 316 cmd.Stderr = os.Stderr 317 err := cmd.Run() 318 if err != nil { 319 log.Fatalf("could not set latest to %q: %+v", version, err) 320 } 321 } 322 323 var excludeList = map[OSArch]map[string]struct{}{ 324 {"linux", "386"}: {}, 325 {"linux", "arm64"}: {}, 326 {"darwin", "amd64"}: {}, 327 {"freebsd", "amd64"}: {}, 328 {"windows", "amd64"}: {}, 329 {"windows", "386"}: {}, 330 } 331 332 var needCgo = map[string]struct{}{}