| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | package main |
| |
|
| | import ( |
| | "archive/tar" |
| | "archive/zip" |
| | "compress/flate" |
| | "compress/gzip" |
| | "crypto/sha256" |
| | "flag" |
| | "fmt" |
| | "io" |
| | "io/fs" |
| | "log" |
| | "os" |
| | "path" |
| | "path/filepath" |
| | "runtime" |
| | "strings" |
| | "time" |
| |
|
| | "cmd/internal/telemetry/counter" |
| | ) |
| |
|
| | func usage() { |
| | fmt.Fprintf(os.Stderr, "usage: distpack\n") |
| | os.Exit(2) |
| | } |
| |
|
| | const ( |
| | modPath = "golang.org/toolchain" |
| | modVersionPrefix = "v0.0.1" |
| | ) |
| |
|
| | var ( |
| | goroot string |
| | gohostos string |
| | gohostarch string |
| | goos string |
| | goarch string |
| | ) |
| |
|
| | func main() { |
| | log.SetPrefix("distpack: ") |
| | log.SetFlags(0) |
| | counter.Open() |
| | flag.Usage = usage |
| | flag.Parse() |
| | counter.Inc("distpack/invocations") |
| | counter.CountFlags("distpack/flag:", *flag.CommandLine) |
| | if flag.NArg() != 0 { |
| | usage() |
| | } |
| |
|
| | |
| | goroot = runtime.GOROOT() |
| | if goroot == "" { |
| | log.Fatalf("missing $GOROOT") |
| | } |
| | gohostos = runtime.GOOS |
| | gohostarch = runtime.GOARCH |
| | goos = os.Getenv("GOOS") |
| | if goos == "" { |
| | goos = gohostos |
| | } |
| | goarch = os.Getenv("GOARCH") |
| | if goarch == "" { |
| | goarch = gohostarch |
| | } |
| | goosUnderGoarch := goos + "_" + goarch |
| | goosDashGoarch := goos + "-" + goarch |
| | exe := "" |
| | if goos == "windows" { |
| | exe = ".exe" |
| | } |
| | version, versionTime := readVERSION(goroot) |
| |
|
| | |
| | base, err := NewArchive(goroot) |
| | if err != nil { |
| | log.Fatal(err) |
| | } |
| | base.SetTime(versionTime) |
| | base.SetMode(mode) |
| | base.Remove( |
| | ".git/**", |
| | ".gitattributes", |
| | ".github/**", |
| | ".gitignore", |
| | "VERSION.cache", |
| | "misc/cgo/*/_obj/**", |
| | "**/.DS_Store", |
| | "**/*.exe~", |
| | |
| | "src/cmd/dist/dist", |
| | "src/cmd/dist/dist.exe", |
| | ) |
| |
|
| | |
| | |
| | srcArch := base.Clone() |
| | srcArch.Remove( |
| | "bin/**", |
| | "pkg/**", |
| |
|
| | |
| | "src/cmd/go/internal/cfg/zdefaultcc.go", |
| | "src/go/build/zcgo.go", |
| | "src/internal/runtime/sys/zversion.go", |
| | "src/time/tzdata/zzipdata.go", |
| |
|
| | |
| | "src/cmd/cgo/zdefaultcc.go", |
| | "src/cmd/internal/objabi/zbootstrap.go", |
| | "src/internal/buildcfg/zbootstrap.go", |
| |
|
| | |
| | "src/cmd/go/internal/cfg/zosarch.go", |
| | ) |
| | srcArch.AddPrefix("go") |
| | testSrc(srcArch) |
| |
|
| | |
| | binArch := base.Clone() |
| | binArch.Filter(func(name string) bool { |
| | |
| | if strings.HasPrefix(name, "bin/") { |
| | return false |
| | } |
| | |
| | if strings.HasPrefix(name, "pkg/") { |
| | |
| | if strings.HasPrefix(name, "pkg/include/") { |
| | return true |
| | } |
| | |
| | if !strings.HasPrefix(name, "pkg/tool/") { |
| | return false |
| | } |
| | |
| | if !strings.HasPrefix(name, "pkg/tool/"+goosUnderGoarch+"/") { |
| | return false |
| | } |
| | |
| | switch strings.TrimSuffix(path.Base(name), ".exe") { |
| | default: |
| | return false |
| | |
| | case "asm", "cgo", "compile", "cover", "fix", "link", "preprofile", "vet": |
| | } |
| | } |
| | return true |
| | }) |
| |
|
| | |
| | |
| | |
| | binExes := []string{ |
| | "go", |
| | "gofmt", |
| | } |
| | crossBin := "bin" |
| | if goos != gohostos || goarch != gohostarch { |
| | crossBin = "bin/" + goosUnderGoarch |
| | } |
| | for _, b := range binExes { |
| | name := "bin/" + b + exe |
| | src := filepath.Join(goroot, crossBin, b+exe) |
| | info, err := os.Stat(src) |
| | if err != nil { |
| | log.Fatal(err) |
| | } |
| | binArch.Add(name, src, info) |
| | } |
| | binArch.Sort() |
| | binArch.SetTime(versionTime) |
| | binArch.SetMode(mode) |
| |
|
| | zipArch := binArch.Clone() |
| | zipArch.AddPrefix("go") |
| | testZip(zipArch) |
| |
|
| | |
| | |
| | modArch := binArch.Clone() |
| | modArch.Remove( |
| | "api/**", |
| | "doc/**", |
| | "misc/**", |
| | "test/**", |
| | ) |
| | modVers := modVersionPrefix + "-" + version + "." + goosDashGoarch |
| | modArch.AddPrefix(modPath + "@" + modVers) |
| | modArch.RenameGoMod() |
| | modArch.Sort() |
| | testMod(modArch) |
| |
|
| | |
| | distpack := func(name string) string { |
| | return filepath.Join(goroot, "pkg/distpack", name) |
| | } |
| | if err := os.MkdirAll(filepath.Join(goroot, "pkg/distpack"), 0777); err != nil { |
| | log.Fatal(err) |
| | } |
| |
|
| | writeTgz(distpack(version+".src.tar.gz"), srcArch) |
| |
|
| | if goos == "windows" { |
| | writeZip(distpack(version+"."+goos+"-"+goarch+".zip"), zipArch) |
| | } else { |
| | writeTgz(distpack(version+"."+goos+"-"+goarch+".tar.gz"), zipArch) |
| | } |
| |
|
| | writeZip(distpack(modVers+".zip"), modArch) |
| | writeFile(distpack(modVers+".mod"), |
| | []byte(fmt.Sprintf("module %s\n", modPath))) |
| | writeFile(distpack(modVers+".info"), |
| | []byte(fmt.Sprintf("{%q:%q, %q:%q}\n", |
| | "Version", modVers, |
| | "Time", versionTime.Format(time.RFC3339)))) |
| | } |
| |
|
| | |
| | func mode(name string, _ fs.FileMode) fs.FileMode { |
| | if strings.HasPrefix(name, "bin/") || |
| | strings.HasPrefix(name, "pkg/tool/") || |
| | strings.HasSuffix(name, ".bash") || |
| | strings.HasSuffix(name, ".sh") || |
| | strings.HasSuffix(name, ".pl") || |
| | strings.HasSuffix(name, ".rc") { |
| | return 0o755 |
| | } else if ok, _ := amatch("**/go_?*_?*_exec", name); ok { |
| | return 0o755 |
| | } |
| | return 0o644 |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func readVERSION(goroot string) (version string, t time.Time) { |
| | data, err := os.ReadFile(filepath.Join(goroot, "VERSION")) |
| | if err != nil { |
| | log.Fatal(err) |
| | } |
| | version, rest, _ := strings.Cut(string(data), "\n") |
| | for line := range strings.SplitSeq(rest, "\n") { |
| | f := strings.Fields(line) |
| | if len(f) == 0 { |
| | continue |
| | } |
| | switch f[0] { |
| | default: |
| | log.Fatalf("VERSION: unexpected line: %s", line) |
| | case "time": |
| | if len(f) != 2 { |
| | log.Fatalf("VERSION: unexpected time line: %s", line) |
| | } |
| | t, err = time.ParseInLocation(time.RFC3339, f[1], time.UTC) |
| | if err != nil { |
| | log.Fatalf("VERSION: bad time: %s", err) |
| | } |
| | } |
| | } |
| | return version, t |
| | } |
| |
|
| | |
| | func writeFile(name string, data []byte) { |
| | if err := os.WriteFile(name, data, 0666); err != nil { |
| | log.Fatal(err) |
| | } |
| | reportHash(name) |
| | } |
| |
|
| | |
| | |
| | |
| | func check[T any](x T, err error) T { |
| | check1(err) |
| | return x |
| | } |
| |
|
| | |
| | |
| | |
| | func check1(err error) { |
| | if err != nil { |
| | panic(err) |
| | } |
| | } |
| |
|
| | |
| | func writeTgz(name string, a *Archive) { |
| | out, err := os.Create(name) |
| | if err != nil { |
| | log.Fatal(err) |
| | } |
| |
|
| | var f File |
| | defer func() { |
| | if err := recover(); err != nil { |
| | extra := "" |
| | if f.Name != "" { |
| | extra = " " + f.Name |
| | } |
| | log.Fatalf("writing %s%s: %v", name, extra, err) |
| | } |
| | }() |
| |
|
| | zw := check(gzip.NewWriterLevel(out, gzip.BestCompression)) |
| | tw := tar.NewWriter(zw) |
| |
|
| | |
| | |
| | |
| | var dirMode fs.FileMode |
| | var mtime time.Time |
| | for _, f := range a.Files { |
| | dirMode = fs.ModeDir | f.Mode | (f.Mode&0444)>>2 |
| | mtime = f.Time |
| | break |
| | } |
| |
|
| | |
| | |
| | |
| | haveDir := map[string]bool{".": true} |
| | var mkdirAll func(string) |
| | mkdirAll = func(dir string) { |
| | if dir == "/" { |
| | panic("mkdirAll /") |
| | } |
| | if haveDir[dir] { |
| | return |
| | } |
| | haveDir[dir] = true |
| | mkdirAll(path.Dir(dir)) |
| | df := &File{ |
| | Name: dir + "/", |
| | Time: mtime, |
| | Mode: dirMode, |
| | } |
| | h := check(tar.FileInfoHeader(df.Info(), "")) |
| | h.Name = dir + "/" |
| | if err := tw.WriteHeader(h); err != nil { |
| | panic(err) |
| | } |
| | } |
| |
|
| | for _, f = range a.Files { |
| | h := check(tar.FileInfoHeader(f.Info(), "")) |
| | mkdirAll(path.Dir(f.Name)) |
| | h.Name = f.Name |
| | if err := tw.WriteHeader(h); err != nil { |
| | panic(err) |
| | } |
| | r := check(os.Open(f.Src)) |
| | check(io.Copy(tw, r)) |
| | check1(r.Close()) |
| | } |
| | f.Name = "" |
| | check1(tw.Close()) |
| | check1(zw.Close()) |
| | check1(out.Close()) |
| | reportHash(name) |
| | } |
| |
|
| | |
| | func writeZip(name string, a *Archive) { |
| | out, err := os.Create(name) |
| | if err != nil { |
| | log.Fatal(err) |
| | } |
| |
|
| | var f File |
| | defer func() { |
| | if err := recover(); err != nil { |
| | extra := "" |
| | if f.Name != "" { |
| | extra = " " + f.Name |
| | } |
| | log.Fatalf("writing %s%s: %v", name, extra, err) |
| | } |
| | }() |
| |
|
| | zw := zip.NewWriter(out) |
| | zw.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) { |
| | return flate.NewWriter(out, flate.BestCompression) |
| | }) |
| | for _, f = range a.Files { |
| | h := check(zip.FileInfoHeader(f.Info())) |
| | h.Name = f.Name |
| | h.Method = zip.Deflate |
| | w := check(zw.CreateHeader(h)) |
| | r := check(os.Open(f.Src)) |
| | check(io.Copy(w, r)) |
| | check1(r.Close()) |
| | } |
| | f.Name = "" |
| | check1(zw.Close()) |
| | check1(out.Close()) |
| | reportHash(name) |
| | } |
| |
|
| | func reportHash(name string) { |
| | f, err := os.Open(name) |
| | if err != nil { |
| | log.Fatal(err) |
| | } |
| | h := sha256.New() |
| | io.Copy(h, f) |
| | f.Close() |
| | fmt.Printf("distpack: %x %s\n", h.Sum(nil)[:8], filepath.Base(name)) |
| | } |
| |
|