From 0b5a078d39df65e3b7873c032d2e76712aeffd24 Mon Sep 17 00:00:00 2001 From: chai2010 Date: Mon, 26 Aug 2024 06:43:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=9E=E6=BB=9A=E5=88=B0=20v0.14.0=20?= =?UTF-8?q?=E6=89=93=E5=8C=85=E6=A8=A1=E5=BC=8F,=20=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E8=80=83=E8=99=91=20brew=20=E7=AD=89=E6=94=AF=E6=8C=81(?= =?UTF-8?q?=E4=BE=9D=E7=84=B6=E6=8E=A5=E5=8F=97=E5=A4=96=E9=83=A8PR)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yml | 28 ++- .goreleaser.yml | 86 -------- builder/main.go | 363 ++++++++++++++++++++++++++++++++++ waroot/changelog.md | 1 - 4 files changed, 384 insertions(+), 94 deletions(-) delete mode 100644 .goreleaser.yml create mode 100644 builder/main.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 53a0e043..8d6fe153 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,12 +34,26 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: + # go1.21 support wasip1/wasm go-version: 1.21 - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v4 + + - run: go run ./builder + + - name: Run Releaser + uses: ncipollo/release-action@v1 with: - distribution: goreleaser - version: latest - args: release --clean - env: - GITHUB_TOKEN: ${{ secrets.WA_DEPLOY }} + token: ${{ secrets.WA_DEPLOY }} + artifacts: "_output/*.zip,_output/*.checksums.txt" + + - name: 'Login to GitHub Container Registry' + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{github.actor}} + password: ${{secrets.WA_DEPLOY_DOCKER}} + + - name: 'Build Wa Image' + run: | + go build + docker build . --tag ghcr.io/wa-lang/wa:${{ github.ref_name }} + docker push ghcr.io/wa-lang/wa:${{ github.ref_name }} diff --git a/.goreleaser.yml b/.goreleaser.yml deleted file mode 100644 index 0d4150f7..00000000 --- a/.goreleaser.yml +++ /dev/null @@ -1,86 +0,0 @@ -# This is an example .goreleaser.yml file with some sane defaults. -# Make sure to check the documentation at http://goreleaser.com -before: - hooks: - - go version -builds: - - id: default - env: - - CGO_ENABLED=0 - goos: - - linux - - windows - - darwin - goarch: - - amd64 - - arm64 - # 使用 ldflags="-s -w" 去掉符号表和调试信息,以减少发布包的大小 - ldflags: - - -s - - -w - ignore: - - goos: linux - goarch: arm64 - - goos: windows - goarch: arm64 - main: . -archives: - - id: default - builds: - - default - name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" - format_overrides: - - goos: windows - format: zip -checksum: - name_template: 'checksums.txt' -changelog: - use: github - sort: asc - filters: - exclude: - - '^docs:' - - '^test:' - -release: - github: - owner: wa-lang - name: wa - draft: false - footer: | - Homepage https://wa-lang.org - -brews: - - tap: - owner: wa-lang - name: homebrew-tap - url_template: "https://github.com/wa-lang/wa/releases/download/{{ .Tag }}/{{ .ArtifactName }}" - download_strategy: CurlDownloadStrategy - # Git author used to commit to the repository. - # Defaults are shown. - commit_author: - name: GoReleaser Bot - email: goreleaser@carlosbecker.com - folder: HomebrewFormula - homepage: "https://github.com/wa-lang/wa" - description: "The Wa Programming Language" - license: "AGPL-3.0 license" - skip_upload: false - test: | - system "#{bin}/wa" - -scoop: - url_template: "https://github.com/wa-lang/wa/releases/download/{{ .Tag }}/{{ .ArtifactName }}" - bucket: - owner: wa-lang - name: scoop-bucket - branch: master - token: "{{ .Env.GITHUB_TOKEN }}" - folder: Scoops - commit_author: - name: goreleaserbot - email: bot@goreleaser.com - commit_msg_template: "Scoop update for {{ .ProjectName }} version {{ .Tag }}" - homepage: "http://github.com/wa-lang/wa" - description: "The Wa Programming Language" - license: AGPL-3.0 license diff --git a/builder/main.go b/builder/main.go new file mode 100644 index 00000000..cebb189c --- /dev/null +++ b/builder/main.go @@ -0,0 +1,363 @@ +// 版权 @2024 凹语言 作者。保留所有权利。 + +// go1.21 support wasip1/wasm + +// 凹语言打包程序: Windows/Linux/macOS/wasm +package main + +import ( + "archive/zip" + "bytes" + "crypto/md5" + "flag" + "fmt" + "io" + "io/fs" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + + "wa-lang.org/wa/internal/3rdparty/gover" + "wa-lang.org/wa/internal/version" + "wa-lang.org/wa/waroot" +) + +const ( + darwin = "darwin" + linux = "linux" + windows = "windows" + wasip1 = "wasip1" + + amd64 = "amd64" + arm64 = "arm64" + wasm = "wasm" +) + +var ( + flagOutputDir = flag.String("output", "_output", "set output dir") +) + +func init() { + log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime) +} + +func main() { + flag.Parse() + b := &Builder{Output: *flagOutputDir} + b.GenAll() +} + +type Builder struct { + Output string // 目标的根目录 +} + +func NewBuilder(outputDir string) *Builder { + return &Builder{Output: outputDir} +} + +func (p *Builder) GenAll() { + waRoot_darwin_amd64 := p.getWarootPath(darwin, arm64) + waRoot_darwin_arm64 := p.getWarootPath(darwin, amd64) + waRoot_linux_amd64 := p.getWarootPath(linux, amd64) + waRoot_windows_amd64 := p.getWarootPath(windows, amd64) + waRoot_wasip1_wasm := p.getWarootPath(wasip1, wasm) + + waRoot_docker := fmt.Sprintf("%s/wa-docker-linux-amd64", p.Output) + waRoot_wasip1 := fmt.Sprintf("%s/wa-wasip1", p.Output) + + p.genWarootFiles(waRoot_darwin_amd64) + p.genWarootFiles(waRoot_darwin_arm64) + p.genWarootFiles(waRoot_linux_amd64) + p.genWarootFiles(waRoot_windows_amd64) + + if isWasip1Enabled() { + p.genWarootFiles(waRoot_wasip1_wasm) + } + + p.genWaExe() + + os.RemoveAll(waRoot_docker) + cpDir(waRoot_docker, waRoot_linux_amd64) + + if isWasip1Enabled() { + os.RemoveAll(waRoot_wasip1) + cpDir(waRoot_wasip1, waRoot_wasip1_wasm) + } + + p.zipDir(waRoot_darwin_amd64) + p.zipDir(waRoot_darwin_arm64) + p.zipDir(waRoot_linux_amd64) + p.zipDir(waRoot_windows_amd64) + + if isWasip1Enabled() { + p.zipDir(waRoot_wasip1_wasm) + } + + os.RemoveAll(waRoot_darwin_amd64) + os.RemoveAll(waRoot_darwin_arm64) + os.RemoveAll(waRoot_linux_amd64) // keep for build docker image + os.RemoveAll(waRoot_windows_amd64) + + if isWasip1Enabled() { + os.RemoveAll(waRoot_wasip1_wasm) + } + + p.genChecksums() +} + +func (p *Builder) genChecksums() { + paths := []string{ + p.getWarootPath(darwin, arm64), + p.getWarootPath(darwin, amd64), + p.getWarootPath(linux, amd64), + p.getWarootPath(windows, amd64), + } + if isWasip1Enabled() { + paths = append(paths, p.getWarootPath(wasip1, wasm)) + } + var buf bytes.Buffer + for _, path := range paths { + data, err := os.ReadFile(path + ".zip") + if err != nil { + panic(err) + } + fmt.Fprintf(&buf, "%x MD5(%s)\n", md5.Sum(data), filepath.Base(path)+".zip") + } + + os.WriteFile( + filepath.Join(p.Output, "wa-"+version.Version+".checksums.txt"), + buf.Bytes(), + 0666, + ) +} + +func (p *Builder) genWaExe() { + CGO_ENABLED := "CGO_ENABLED=0" + + // wasip1/wasm + if isWasip1Enabled() { + waRootPath := p.getWarootPath(wasip1, wasm) + dstpath := filepath.Join(waRootPath, "bin", "wa.wasm") + + cmd := exec.Command("go", "build", "-o", dstpath, "wa-lang.org/wa") + cmd.Env = append([]string{"GOOS=" + wasip1, "GOARCH=" + wasm, "CGO_ENABLED=0"}, os.Environ()...) + if output, err := cmd.CombinedOutput(); err != nil { + fmt.Print(string(output)) + panic(err) + } + } + + // darwin/arm64 + { + waRootPath := p.getWarootPath(darwin, arm64) + dstpath := filepath.Join(waRootPath, "bin", "wa") + + cmd := exec.Command("go", "build", "-o", dstpath, "wa-lang.org/wa") + cmd.Env = append([]string{"GOOS=" + darwin, "GOARCH=" + arm64, CGO_ENABLED}, os.Environ()...) + if output, err := cmd.CombinedOutput(); err != nil { + fmt.Print(string(output)) + panic(err) + } + } + + // darwin/amd64 + { + waRootPath := p.getWarootPath(darwin, amd64) + dstpath := filepath.Join(waRootPath, "bin", "wa") + + cmd := exec.Command("go", "build", "-o", dstpath, "wa-lang.org/wa") + cmd.Env = append([]string{"GOOS=" + darwin, "GOARCH=" + amd64, CGO_ENABLED}, os.Environ()...) + if output, err := cmd.CombinedOutput(); err != nil { + fmt.Print(string(output)) + panic(err) + } + } + + // ubuntu + { + waRootPath := p.getWarootPath(linux, amd64) + dstpath := filepath.Join(waRootPath, "bin", "wa") + + cmd := exec.Command("go", "build", "-o", dstpath, "wa-lang.org/wa") + cmd.Env = append([]string{"GOOS=" + linux, "GOARCH=" + amd64, CGO_ENABLED}, os.Environ()...) + if output, err := cmd.CombinedOutput(); err != nil { + fmt.Print(string(output)) + panic(err) + } + } + + // windows + { + waRootPath := p.getWarootPath(windows, amd64) + dstpath := filepath.Join(waRootPath, "bin", "wa.exe") + + cmd := exec.Command("go", "build", "-o", dstpath, "wa-lang.org/wa") + cmd.Env = append([]string{"GOOS=" + windows, "GOARCH=" + amd64, CGO_ENABLED}, os.Environ()...) + if output, err := cmd.CombinedOutput(); err != nil { + fmt.Print(string(output)) + panic(err) + } + } +} + +func (p *Builder) genWarootFiles(waRootPath string) error { + os.RemoveAll(waRootPath) + os.MkdirAll(waRootPath, 0777) + warootfs := waroot.GetRootFS() + err := fs.WalkDir(waroot.GetRootFS(), ".", func(path string, d fs.DirEntry, err error) error { + if d == nil || d.IsDir() { + return nil + } + if err != nil { + return err + } + + data, err := fs.ReadFile(warootfs, path) + if err != nil { + return err + } + + dstpath := filepath.Join(waRootPath, path) + os.MkdirAll(filepath.Dir(dstpath), 0777) + + // 跳过忽略的文件 + if s := filepath.Base(path); s == "_keep" || s == ".keep" { + return nil + } + if strings.HasSuffix(path, ".go") { + return nil + } + + f, err := os.Create(dstpath) + if err != nil { + return err + } + defer f.Close() + + if _, err := f.Write(data); err != nil { + return err + } + return nil + }) + if err != nil { + return err + } + + return nil +} + +func (p *Builder) zipDir(dir string) { + file, err := os.Create(dir + ".zip") + if err != nil { + panic(err) + } + defer file.Close() + + w := zip.NewWriter(file) + defer w.Close() + + err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + fileInfo, err := file.Stat() + if err != nil { + return err + } + + // 需要保留可执行等标志信息 + header, err := zip.FileInfoHeader(fileInfo) + if err != nil { + return err + } + + relpath, err := filepath.Rel(dir, path) + if err != nil { + return err + } + + header.Name = filepath.Join("wa", relpath) + header.Method = zip.Deflate + + f, err := w.CreateHeader(header) + if err != nil { + return err + } + + _, err = io.Copy(f, file) + if err != nil { + return err + } + + return nil + }) + if err != nil { + panic(err) + } +} + +func (p *Builder) getWarootPath(waos, waarch string) string { + return fmt.Sprintf("%s/wa_%s_%s-%s", p.Output, version.Version, waos, waarch) +} + +func isWasip1Enabled() bool { + goversion := strings.TrimPrefix(runtime.Version(), "go") + return gover.Compare(goversion, "1.21") >= 0 +} + +func cpDir(dst, src string) (total int) { + entryList, err := os.ReadDir(src) + if err != nil && !os.IsExist(err) { + log.Fatal("cpDir: ", err) + } + for _, entry := range entryList { + if entry.IsDir() { + cpDir(dst+"/"+entry.Name(), src+"/"+entry.Name()) + } else { + srcFname := filepath.Clean(src + "/" + entry.Name()) + dstFname := filepath.Clean(dst + "/" + entry.Name()) + + cpFile(dstFname, srcFname) + total++ + } + } + return +} + +func cpFile(dst, src string) { + err := os.MkdirAll(filepath.Dir(dst), 0777) + if err != nil && !os.IsExist(err) { + log.Fatal("cpFile: ", err) + } + fsrc, err := os.Open(src) + if err != nil { + log.Fatal("cpFile: ", err) + } + defer fsrc.Close() + + fi, err := fsrc.Stat() + if err != nil { + log.Fatal("cpFile: ", err) + } + + fdst, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fi.Mode()) + if err != nil { + log.Fatal("cpFile: ", err) + } + defer fdst.Close() + if _, err = io.Copy(fdst, fsrc); err != nil { + log.Fatal("cpFile: ", err) + } +} diff --git a/waroot/changelog.md b/waroot/changelog.md index 5573b32e..77c53075 100644 --- a/waroot/changelog.md +++ b/waroot/changelog.md @@ -2,7 +2,6 @@ - (dev) - 完善 `wa lsp` 子命令 (TODO) - - 恢复 `brew` 打包支持 - v0.15.0 (2024-08-25) - 增加 wasm4 游戏平台支持 - Playground 依赖的 `wa.wasm` 编译环境升级到 Go1.21 (兼顾 wasip1 编译)