Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ dist/
/.venv
/redbot-update
*.exe
**/resources/generated/
resources_windows.syso
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ build-all: build-go build-python

.PHONY: build-go
build-go:
CGO_ENABLED=1 go generate ./...
CGO_ENABLED=1 go build ./...
CGO_ENABLED=1 go build ./go/cmd/redbot-update

Expand Down Expand Up @@ -38,6 +39,7 @@ fmt format reformat: fmt-go fmt-python
.PHONY: fmt-go format-go reformat-go
fmt-go format-go reformat-go:
go fmt ./...
cd ./go/build_tools && go fmt ./...

.PHONY: fmt-python format-python reformat-python
fmt-python format-python reformat-python:
Expand Down
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ module github.com/cog-creators/redbot-update-wrapper
go 1.26

toolchain go1.26.3

tool github.com/josephspurrier/goversioninfo/cmd/goversioninfo

require (
github.com/akavel/rsrc v0.10.2 // indirect
github.com/josephspurrier/goversioninfo v1.7.0 // indirect
)
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw=
github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/josephspurrier/goversioninfo v1.7.0 h1:LQzXOlVm/CtbwJ9/UHl5a2HT0BjcLAwid5gqGd7ZUJ8=
github.com/josephspurrier/goversioninfo v1.7.0/go.mod h1:z9y0r2G6g5jwSJaFE0cxW9to0aeIibK7UYeLx53aQRU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
6 changes: 6 additions & 0 deletions go.work
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
go 1.26.3

use (
.
./go/build_tools
)
85 changes: 85 additions & 0 deletions go/build_tools/generate_versioninfo/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package main

import (
"encoding/json"
"os"
"path/filepath"
"text/template"

"github.com/BurntSushi/toml"
)

const (
resourcesDir = "resources"
baseResourcesDir = resourcesDir + string(filepath.Separator) + "base"
generatedResourcesDir = resourcesDir + string(filepath.Separator) + "generated"
)

type Project struct {
Version string `toml:"version"`
}

type PyProject struct {
Project Project `toml:"project"`
}

func main() {
projectDir := os.Args[1]
projectFile := filepath.Join(projectDir, "pyproject.toml")

var pyproject PyProject
if _, err := toml.DecodeFile(projectFile, &pyproject); err != nil {
panic(err)
}
rawVersion := pyproject.Project.Version
v := parsePythonProjectVersion(rawVersion)

if err := os.MkdirAll(generatedResourcesDir, 0700); err != nil {
panic(err)
}
generateAppManifestFile(v)
generateVersionInfoFile(v)
}

// generate app manifest
func generateAppManifestFile(v PythonProjectVersion) {
t, err := template.ParseFiles(filepath.Join(baseResourcesDir, "app.manifest.tmpl"))
if err != nil {
panic(err)
}
f, err := os.Create(filepath.Join(generatedResourcesDir, "app.manifest"))
if err != nil {
panic(err)
}
defer f.Close()
t.Execute(f, struct{ ProductVersion string }{v.FileVersion().String()})
if err := f.Close(); err != nil {
panic(err)
}
}

// generate versioninfo.json
func generateVersionInfoFile(v PythonProjectVersion) {
data, err := os.ReadFile(filepath.Join(baseResourcesDir, "versioninfo.json"))
if err != nil {
panic(err)
}
versioninfo := map[string]any{}
json.Unmarshal(data, &versioninfo)

fixedFileInfo := versioninfo["FixedFileInfo"].(map[string]any)
fixedFileInfo["FileVersion"] = v.FileVersion()
fixedFileInfo["ProductVersion"] = v.FileVersion()
stringFileInfo := versioninfo["StringFileInfo"].(map[string]any)
stringFileInfo["FileVersion"] = v.String()
stringFileInfo["ProductVersion"] = v.String()

data, err = json.Marshal(versioninfo)
if err != nil {
panic(err)
}
err = os.WriteFile(filepath.Join(generatedResourcesDir, "versioninfo.json"), data, 0600)
if err != nil {
panic(err)
}
}
15 changes: 15 additions & 0 deletions go/build_tools/generate_versioninfo/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import "strconv"

type Int interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}

func ParseInt[T Int](s string) T {
i, err := strconv.Atoi(s)
if err != nil {
panic(err)
}
return T(i)
}
77 changes: 77 additions & 0 deletions go/build_tools/generate_versioninfo/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package main

import (
"fmt"
"regexp"
)

type ReleaseLevel string

var (
ReleaseLevelAlpha ReleaseLevel = "a"
ReleaseLevelBeta ReleaseLevel = "b"
ReleaseLevelReleaseCandidate ReleaseLevel = "rc"
ReleaseLevelFinal ReleaseLevel = ""

pythonProjectVersionRegexp = regexp.MustCompile(
`(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:(a|b|rc)(0|[1-9]\d*))?`,
)
pythonSerialToFileVersionMap = map[ReleaseLevel]uint16{
ReleaseLevelAlpha: 0x2000,
ReleaseLevelBeta: 0x4000,
ReleaseLevelReleaseCandidate: 0x6000,
ReleaseLevelFinal: 0x8000,
}
)

type FileVersion struct {
Major uint16
Minor uint16
Patch uint16
Build uint16
}

func (fv FileVersion) String() string {
return fmt.Sprintf("%v.%v.%v.%v", fv.Major, fv.Minor, fv.Patch, fv.Build)
}

type PythonProjectVersion struct {
Major uint16
Minor uint16
Micro uint16
ReleaseLevel ReleaseLevel
Serial uint8
}

func parsePythonProjectVersion(v string) PythonProjectVersion {
matches := pythonProjectVersionRegexp.FindStringSubmatch(v)
if matches == nil {
panic("could not parse Python project version")
}
ppv := PythonProjectVersion{}
ppv.Major = ParseInt[uint16](matches[1])
ppv.Minor = ParseInt[uint16](matches[2])
ppv.Micro = ParseInt[uint16](matches[3])
ppv.ReleaseLevel = ReleaseLevel(matches[4])
if matches[5] != "" {
ppv.Serial = ParseInt[uint8](matches[5])
}
return ppv
}

func (ppv PythonProjectVersion) String() string {
baseVersion := fmt.Sprintf("%v.%v.%v", ppv.Major, ppv.Minor, ppv.Micro)
if ppv.ReleaseLevel == ReleaseLevelFinal {
return baseVersion
}
return fmt.Sprintf("%v%v%v", baseVersion, ppv.ReleaseLevel, ppv.Serial)
}

func (ppv PythonProjectVersion) FileVersion() FileVersion {
return FileVersion{
Major: ppv.Major,
Minor: ppv.Minor,
Patch: ppv.Micro,
Build: pythonSerialToFileVersionMap[ppv.ReleaseLevel] | uint16(ppv.Serial),
}
}
5 changes: 5 additions & 0 deletions go/build_tools/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/cog-creators/redbot-update-wrapper/go/build_tools

go 1.26.3

require github.com/BurntSushi/toml v1.6.0
2 changes: 2 additions & 0 deletions go/build_tools/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
3 changes: 3 additions & 0 deletions go/cmd/redbot-update/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:generate go run ../../build_tools/generate_versioninfo ../../..
//go:generate go tool github.com/josephspurrier/goversioninfo/cmd/goversioninfo -o resources_windows.syso resources/generated/versioninfo.json

package main

import (
Expand Down
11 changes: 11 additions & 0 deletions go/cmd/redbot-update/resources/base/app.manifest.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="{{ .ProductVersion }}" name="redbot-update.exe" type="win32" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
23 changes: 23 additions & 0 deletions go/cmd/redbot-update/resources/base/versioninfo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"FixedFileInfo": {
"FileFlagsMask": "3f",
"FileFlags ": "00",
"FileOS": "040004",
"FileType": "01",
"FileSubType": "00"
},
"StringFileInfo": {
"Comments": "",
"CompanyName": "Cog Creators",
"FileDescription": "redbot-update wrapper",
"InternalName": "redbot-update.exe",
"LegalCopyright": "Copyright (c) 2026 Cog Creators (https://github.com/Cog-Creators)",
"LegalTrademarks": "",
"OriginalFilename": "redbot-update.exe",
"PrivateBuild": "",
"ProductName": "redbot-update wrapper",
"SpecialBuild": ""
},
"IconPath": "resources/cog-creators.ico",
"ManifestPath": "resources/generated/app.manifest"
}
Binary file added go/cmd/redbot-update/resources/cog-creators.ico
Binary file not shown.
6 changes: 6 additions & 0 deletions hatch_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ def dependencies(self) -> List[str]:

def initialize(self, version: str, build_data: Dict[str, Any]) -> None:
if self.target_name == "sdist":
go_bin_args = _get_go_bin_args(prefer_system=not self._force_use_go_bin)
generate_command = (*go_bin_args, "generate", "./go/cmd/redbot-update")

self.app.display_info("Generating redbot-update resources")
subprocess.check_call(generate_command)
self.app.display_success("Generated redbot-update resources")
return

if version == "editable":
Expand Down