17 Commits

Author SHA1 Message Date
718eace492 1.0.9 2025-07-25 21:57:35 -07:00
ca77c609cd fix size check 2025-07-25 21:56:32 -07:00
502ca7a4f2 1.0.8 2025-07-25 21:48:20 -07:00
7397fae6f4 change pathing 2025-07-25 21:47:46 -07:00
a07958563a 1.0.7 2025-07-25 21:25:29 -07:00
c80204579f change how to check for dependencies 2025-07-25 21:25:01 -07:00
11909e8502 1.0.6 2025-07-25 19:03:52 -07:00
8ec2cc6da2 clarify README 2025-07-25 15:02:20 -07:00
14db7719a3 Add option to build rosettax87 locally (#9)
Reviewed-on: #9
2025-07-25 22:00:00 +00:00
d03c5ee7cc troubleshooting updates 2025-07-25 12:21:47 -07:00
704570d4a7 Update known issues 2025-07-25 13:44:38 +00:00
49b696c898 1.0.3 2025-07-24 12:13:53 -07:00
4e22ca8714 remove MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS 2025-07-24 10:38:26 -07:00
a973508d92 Fix chmodding 2025-07-24 09:03:44 -07:00
8edd61dbba fix updating (#8)
Fixes #6

Reviewed-on: #8
2025-07-24 15:48:21 +00:00
eafc55f67c fix dir perms (#7)
Fixes #4

Reviewed-on: #7
2025-07-24 15:40:04 +00:00
bc80ca2c9c Improve logging (#2)
Reviewed-on: #2
2025-07-24 15:30:33 +00:00
25 changed files with 705 additions and 400 deletions

View File

@@ -2,5 +2,5 @@
Icon = "Icon.png"
Name = "EpochSilicon"
ID = "com.burkey.epochsilicon"
Version = "1.0.0"
Build = 3
Version = "1.0.9"
Build = 31

View File

@@ -19,11 +19,7 @@ build: build-dev
build-release:
@rm -rf ./EpochSilicon.app
@echo "Building optimized release version..."
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build \
-ldflags="-s -w -X main.appVersion=$$(grep Version FyneApp.toml | cut -d'"' -f2)" \
-trimpath \
-tags=release \
-o epochsilicon .
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -trimpath -tags=release -o epochsilicon .
@echo "Packaging with fyne..."
GOOS=darwin GOARCH=arm64 fyne package --release --executable epochsilicon
@echo "Copying additional resources to app bundle..."

View File

@@ -4,6 +4,8 @@
A user-friendly launcher for Project Epoch on Apple Silicon Macs, with one-click patching of winerosetta, rosettax87 and d9vk.
**This software is currently in active development, there WILL be bugs and constant updates as Epoch rolls out**
## Features
* **Apple Silicon Compatibility:** Runs 32-bit DirectX9 World of Warcraft (v3.3.5a) on M1/M2/M3/M4 Macs without "illegal instruction" errors.
@@ -16,7 +18,7 @@ A user-friendly launcher for Project Epoch on Apple Silicon Macs, with one-click
## Known Issues
- For one tester, it took up to a minute for Wow to start after hitting the "Play" button. This is currently being investigated.
- For some users, it can take up to a minute for Wow to start after hitting the "Play" button. A possible fix is described in the Troubleshooting section, please let @Battlehammer know on the Epoch discord if this works for you
## Usage
@@ -48,23 +50,37 @@ Before you begin, ensure you have the following:
* Click "Patch Epoch".
* Click "Patch CrossOver".
* Status indicators will turn green once patching is successful for each.
6. **Start RosettaX87 Service**:
5. **Start RosettaX87 Service**:
* Click "Start Service" and enter your sudo password when prompted.
* This will run the RosettaX87 service in the background and is required for launching the game.
* The service will automatically stop when you close the launcher.
7. **Configure Options (Optional)**:
6. **Configure Options (Optional)**:
* **Enable Metal Hud**: Shows FPS counter in-game.
* **Show Terminal**: Displays terminal output during game launch for debugging.
8. **Launch Game**:
* **Advanced Logging**: Enables debugging logs, located in `$HOME/Library/Application Support/EpochSilicon`. Enable this setting if you are generating logs for troubleshooting
7. **Launch Game**:
* Once both paths are set, both components are patched, and the RosettaX87 service is running, the "Launch Game" button will become active. Click it.
9. **Enjoy**: Experience a VM free, smoother Project Epoch on your Apple Silicon Mac!
8. **Enjoy**: Experience a VM free, smoother Project Epoch on your Apple Silicon Mac!
## Troubleshooting / FAQ
### The game closes instantly when I try to login
Make sure you login to Epoch with your username, not your email. Using your email will cause the game to close with no error message
### The Patch Epoch step is taking forever
The initial patch download is quite large and can take a while if your internet is slow. The app will tell you when it's done.
### After I click Play, the game takes a minute to load
This appears to be a problem with using a built-in version of `rosettax87`. In order to fix this, you must compile it yourself.
1. Install Xcode command line tools by opening a terminal and typing `xcode-select --install` and following the prompts
2. Setup [Homebrew](https://brew.sh/) if you don't have it already
3. Install Cmake by opening a terminal and enter `brew install cmake`. Cmake must be installed through Homebrew
3. Run EpochSilicon and click the `Troubleshooting` button
4. Find the line that says `Build Rosettax87 locally` and click the `Build` button, following the prompts
### My resolution is super blown up and I can't see the whole screen
Wine does that on first launch if you have a large widescreen monitor.
@@ -108,9 +124,7 @@ TBD
## Bundled Binaries
The `rosettax87` and `winerosetta` components included in this application are precompiled for convenience. If you prefer, you can compile them yourself by following the instructions provided by Lifeisawful on the official repositories:
[https://github.com/Lifeisawful/winerosetta](https://github.com/Lifeisawful/winerosetta)
[https://github.com/Lifeisawful/rosettax87](https://github.com/Lifeisawful/rosettax87)
The `rosettax87` and `winerosetta` components included in this application are precompiled for convenience. You can compile them yourself by following the instructions provided above in the Troubleshooting section
## License
@@ -124,5 +138,5 @@ All credit for the core translation layer `winerosetta` and `rosettax87` goes to
[https://github.com/Lifeisawful/rosettax87](https://github.com/Lifeisawful/rosettax87)
EpochSilicon is a fork of [https://turtlesilicon.github.io/](TurtleSilicon), credit for the base of the application goes to tairasu.
EpochSilicon is a fork of [https://turtlesilicon.github.io/](TurtleSilicon), credit for the base of the application goes to [**@tairasu**](https://github.com/tairasu)

24
go.mod
View File

@@ -6,41 +6,61 @@ toolchain go1.24.5
require (
fyne.io/fyne/v2 v2.6.1
git.burkey.co/eburk/epochcli v0.0.0-20250721041733-516a1f9b570e
git.burkey.co/eburk/epochcli v0.0.0-20250724135717-365171fddc6b
github.com/Masterminds/semver/v3 v3.4.0
github.com/go-git/go-git/v6 v6.0.0-20250725064440-209d7ec3c0b2
github.com/rs/zerolog v1.34.0
github.com/zalando/go-keyring v0.2.6
gopkg.in/natefinch/lumberjack.v2 v2.2.1
howett.net/plist v1.0.1
)
require (
al.essio.dev/pkg/shellescape v1.6.0 // indirect
dario.cat/mergo v1.0.1 // indirect
fyne.io/systray v1.11.0 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.3.0 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/danieljoos/wincred v1.2.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fredbi/uri v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fyne-io/gl-js v0.2.0 // indirect
github.com/fyne-io/glfw-js v0.3.0 // indirect
github.com/fyne-io/image v0.1.1 // indirect
github.com/fyne-io/oksvg v0.1.0 // indirect
github.com/go-git/gcfg/v2 v2.0.2 // indirect
github.com/go-git/go-billy/v6 v6.0.0-20250627091229-31e2a16eef30 // indirect
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20250301202403-da16c1255728 // indirect
github.com/go-text/render v0.2.0 // indirect
github.com/go-text/typesetting v0.3.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/hack-pad/go-indexeddb v0.3.2 // indirect
github.com/hack-pad/safejs v0.1.1 // indirect
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/nicksnyder/go-i18n/v2 v2.6.0 // indirect
github.com/pjbgf/sha1cd v0.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rymdport/portal v0.4.2 // indirect
github.com/sergi/go-diff v1.4.0 // indirect
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/yuin/goldmark v1.7.12 // indirect
github.com/yuin/goldmark v1.7.13 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b // indirect
golang.org/x/image v0.29.0 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/sys v0.34.0 // indirect

125
go.sum
View File

@@ -1,131 +1,168 @@
al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho=
al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA=
al.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
fyne.io/fyne/v2 v2.6.1 h1:kjPJD4/rBS9m2nHJp+npPSuaK79yj6ObMTuzR6VQ1Is=
fyne.io/fyne/v2 v2.6.1/go.mod h1:YZt7SksjvrSNJCwbWFV32WON3mE1Sr7L41D29qMZ/lU=
fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg=
fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
git.burkey.co/eburk/epochcli v0.0.0-20250721033741-54cc1d9a552e h1:TiiZEnc7E3/wJ86qHckGoNht0snSUpQyY2cjxRUSs3Q=
git.burkey.co/eburk/epochcli v0.0.0-20250721033741-54cc1d9a552e/go.mod h1:DgybCn9/LpJwvkrsyea9N2nWy/wuDgo6jkpOWYkTH3c=
git.burkey.co/eburk/epochcli v0.0.0-20250721041340-6b6dbdda99e2 h1:89rNJ5p6gYJPZkeJM8nyRHMMgHErfVz8SdLcGiqEyBM=
git.burkey.co/eburk/epochcli v0.0.0-20250721041340-6b6dbdda99e2/go.mod h1:DgybCn9/LpJwvkrsyea9N2nWy/wuDgo6jkpOWYkTH3c=
git.burkey.co/eburk/epochcli v0.0.0-20250721041733-516a1f9b570e h1:WN1jlnC3sc/2ix70bzMPpzsPdsE/pqUIR/Vw8cVEkw8=
git.burkey.co/eburk/epochcli v0.0.0-20250721041733-516a1f9b570e/go.mod h1:DgybCn9/LpJwvkrsyea9N2nWy/wuDgo6jkpOWYkTH3c=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
git.burkey.co/eburk/epochcli v0.0.0-20250724135717-365171fddc6b h1:fPDSiwJI3PzaU5utiurrnpNIv6IYj+CcUmwCzVcunsU=
git.burkey.co/eburk/epochcli v0.0.0-20250724135717-365171fddc6b/go.mod h1:DgybCn9/LpJwvkrsyea9N2nWy/wuDgo6jkpOWYkTH3c=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0=
github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8=
github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fyne-io/gl-js v0.1.0 h1:8luJzNs0ntEAJo+8x8kfUOXujUlP8gB3QMOxO2mUdpM=
github.com/fyne-io/gl-js v0.1.0/go.mod h1:ZcepK8vmOYLu96JoxbCKJy2ybr+g1pTnaBDdl7c3ajI=
github.com/fyne-io/gl-js v0.2.0 h1:+EXMLVEa18EfkXBVKhifYB6OGs3HwKO3lUElA0LlAjs=
github.com/fyne-io/gl-js v0.2.0/go.mod h1:ZcepK8vmOYLu96JoxbCKJy2ybr+g1pTnaBDdl7c3ajI=
github.com/fyne-io/glfw-js v0.2.0 h1:8GUZtN2aCoTPNqgRDxK5+kn9OURINhBEBc7M4O1KrmM=
github.com/fyne-io/glfw-js v0.2.0/go.mod h1:Ri6te7rdZtBgBpxLW19uBpp3Dl6K9K/bRaYdJ22G8Jk=
github.com/fyne-io/glfw-js v0.3.0 h1:d8k2+Y7l+zy2pc7wlGRyPfTgZoqDf3AI4G+2zOWhWUk=
github.com/fyne-io/glfw-js v0.3.0/go.mod h1:Ri6te7rdZtBgBpxLW19uBpp3Dl6K9K/bRaYdJ22G8Jk=
github.com/fyne-io/image v0.1.1 h1:WH0z4H7qfvNUw5l4p3bC1q70sa5+YWVt6HCj7y4VNyA=
github.com/fyne-io/image v0.1.1/go.mod h1:xrfYBh6yspc+KjkgdZU/ifUC9sPA5Iv7WYUBzQKK7JM=
github.com/fyne-io/oksvg v0.1.0 h1:7EUKk3HV3Y2E+qypp3nWqMXD7mum0hCw2KEGhI1fnBw=
github.com/fyne-io/oksvg v0.1.0/go.mod h1:dJ9oEkPiWhnTFNCmRgEze+YNprJF7YRbpjgpWS4kzoI=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-git/gcfg/v2 v2.0.2 h1:MY5SIIfTGGEMhdA7d7JePuVVxtKL7Hp+ApGDJAJ7dpo=
github.com/go-git/gcfg/v2 v2.0.2/go.mod h1:/lv2NsxvhepuMrldsFilrgct6pxzpGdSRC13ydTLSLs=
github.com/go-git/go-billy/v6 v6.0.0-20250627091229-31e2a16eef30 h1:4KqVJTL5eanN8Sgg3BV6f2/QzfZEFbCd+rTak1fGRRA=
github.com/go-git/go-billy/v6 v6.0.0-20250627091229-31e2a16eef30/go.mod h1:snwvGrbywVFy2d6KJdQ132zapq4aLyzLMgpo79XdEfM=
github.com/go-git/go-git-fixtures/v5 v5.1.0 h1:b8cWxDLTk0s09Ihm9x1HvNGUzxUVlRwIH7EAM0gGDKg=
github.com/go-git/go-git-fixtures/v5 v5.1.0/go.mod h1:CdmU0oQeDuy4Xh8V0i9Ym+vsTkgDDPKEiofBFEVT+aE=
github.com/go-git/go-git/v6 v6.0.0-20250725064440-209d7ec3c0b2 h1:F7u1fj/kU3+amqn25xkiMn77oh7hw0Ac7fKnZh7lqeA=
github.com/go-git/go-git/v6 v6.0.0-20250725064440-209d7ec3c0b2/go.mod h1:gI6xSrrkXH4EKP38iovrsY2EYf2XDU3DrIZRshlNDm0=
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA=
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20250301202403-da16c1255728 h1:RkGhqHxEVAvPM0/R+8g7XRwQnHatO0KAuVcwHo8q9W8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20250301202403-da16c1255728/go.mod h1:SyRD8YfuKk+ZXlDqYiqe1qMSqjNgtHzBTG810KUagMc=
github.com/go-text/render v0.2.0 h1:LBYoTmp5jYiJ4NPqDc2pz17MLmA3wHw1dZSVGcOdeAc=
github.com/go-text/render v0.2.0/go.mod h1:CkiqfukRGKJA5vZZISkjSYrcdtgKQWRa2HIzvwNN5SU=
github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8=
github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M=
github.com/go-text/typesetting v0.3.0 h1:OWCgYpp8njoxSRpwrdd1bQOxdjOXDj9Rqart9ML4iF4=
github.com/go-text/typesetting v0.3.0/go.mod h1:qjZLkhRgOEYMhU9eHBr3AR4sfnGJvOXNLt8yRAySFuY=
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0=
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/hack-pad/go-indexeddb v0.3.2 h1:DTqeJJYc1usa45Q5r52t01KhvlSN02+Oq+tQbSBI91A=
github.com/hack-pad/go-indexeddb v0.3.2/go.mod h1:QvfTevpDVlkfomY498LhstjwbPW6QC4VC/lxYb0Kom0=
github.com/hack-pad/safejs v0.1.0 h1:qPS6vjreAqh2amUqj4WNG1zIw7qlRQJ9K10eDKMCnE8=
github.com/hack-pad/safejs v0.1.0/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio=
github.com/hack-pad/safejs v0.1.1 h1:d5qPO0iQ7h2oVtpzGnLExE+Wn9AtytxIfltcS2b9KD8=
github.com/hack-pad/safejs v0.1.1/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio=
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 h1:wMeVzrPO3mfHIWLZtDcSaGAe2I4PW9B/P5nMkRSwCAc=
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade h1:FmusiCI1wHw+XQbvL9M+1r/C3SPqKrmBaIOYwVfQoDE=
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M=
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk=
github.com/nicksnyder/go-i18n/v2 v2.5.1/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ=
github.com/nicksnyder/go-i18n/v2 v2.6.0 h1:C/m2NNWNiTB6SK4Ao8df5EWm3JETSTIGNXBpMJTxzxQ=
github.com/nicksnyder/go-i18n/v2 v2.6.0/go.mod h1:88sRqr0C6OPyJn0/KRNaEz1uWorjxIKP7rUUcvycecE=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pjbgf/sha1cd v0.4.0 h1:NXzbL1RvjTUi6kgYZCX3fPwwl27Q1LJndxtUDVfJGRY=
github.com/pjbgf/sha1cd v0.4.0/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
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/rymdport/portal v0.4.1 h1:2dnZhjf5uEaeDjeF/yBIeeRo6pNI2QAKm7kq1w/kbnA=
github.com/rymdport/portal v0.4.1/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU=
github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY=
github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA=
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s=
github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI=
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b h1:QoALfVG9rhQ/M7vYDScfPdWjGL9dlsVVM5VGh7aKoAA=
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
golang.org/x/image v0.29.0 h1:HcdsyR4Gsuys/Axh0rDEmlBmB68rW1U9BUdB3UVHsas=
golang.org/x/image v0.29.0/go.mod h1:RVJROnf3SLK8d26OW91j4FrIHGbsJ8QnbEocVTOWQDA=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=

19
main.go
View File

@@ -1,18 +1,21 @@
package main
import (
"epochsilicon/pkg/debug"
"epochsilicon/pkg/log"
"epochsilicon/pkg/service"
"epochsilicon/pkg/ui"
"epochsilicon/pkg/utils"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"github.com/Masterminds/semver/v3"
"strings"
)
const appVersion = "1.0.0"
const appVersion = "1.0.9"
func main() {
log.SetupLogging()
PEApp := app.NewWithID("com.burkey.epochsilicon")
PEWindow := PEApp.NewWindow("EpochSilicon v" + appVersion)
PEWindow.Resize(fyne.NewSize(650, 500))
@@ -20,23 +23,23 @@ func main() {
go func() {
prefs, _ := utils.LoadPrefs()
updateInfo, updateAvailable, err := utils.CheckForUpdateWithAssets(appVersion)
updateInfo, updateAvailable, err := utils.CheckForUpdateWithAssets(semver.MustParse(appVersion))
if err != nil {
debug.Printf("Failed to check for updates: %v", err)
log.Debugf("Failed to check for updates: %v", err)
return
}
if !updateAvailable {
debug.Printf("No updates available")
log.Debugf("No updates available")
return
}
latestVersion := strings.TrimPrefix(updateInfo.TagName, "v")
debug.Printf("Update available: current=%s, latest=%s", appVersion, latestVersion)
log.Debugf("Update available: current=%s, latest=%s", appVersion, latestVersion)
// Skip if user has suppressed this version
if prefs.SuppressedUpdateVersion == latestVersion {
debug.Printf("Update suppressed by user: %s", latestVersion)
log.Debugf("Update suppressed by user: %s", latestVersion)
return
}
@@ -49,7 +52,7 @@ func main() {
// Set up cleanup when window closes
PEWindow.SetCloseIntercept(func() {
debug.Println("Application closing, cleaning up RosettaX87 service...")
log.Debug("Application closing, cleaning up RosettaX87 service...")
service.CleanupService()
PEApp.Quit()
})

View File

@@ -1,15 +0,0 @@
//go:build !release
package debug
import "log"
// Printf logs with fmt.Printf style formatting in debug builds
func Printf(format string, v ...interface{}) {
log.Printf(format, v...)
}
// Println logs with fmt.Println style in debug builds
func Println(v ...interface{}) {
log.Println(v...)
}

View File

@@ -1,13 +0,0 @@
//go:build release
package debug
// Printf is a no-op in release builds
func Printf(format string, v ...interface{}) {
// No-op in release builds to reduce binary size
}
// Println is a no-op in release builds
func Println(v ...interface{}) {
// No-op in release builds to reduce binary size
}

View File

@@ -2,13 +2,13 @@ package launcher
import (
"bufio"
"epochsilicon/pkg/log"
"fmt"
"os"
"os/exec"
"path/filepath"
"sync"
"epochsilicon/pkg/debug"
"epochsilicon/pkg/paths" // Corrected import path
"epochsilicon/pkg/utils" // Corrected import path
@@ -18,7 +18,6 @@ import (
var EnableMetalHud = false // Default to disabled
var CustomEnvVars = "" // Custom environment variables
var EnableVanillaTweaks = false // Default to disabled
var AutoDeleteWdb = false // Default to disabled
// Terminal state management
@@ -41,7 +40,7 @@ func runGameIntegrated(parentWindow fyne.Window, shellCmd string) error {
// Parse the shell command to extract components
// The shellCmd format is: cd <path> && <envVars> <rosettaExec> <wineloader> <wowExe>
debug.Printf("Parsing shell command: %s", shellCmd)
log.Debugf("Parsing shell command: %s", shellCmd)
// Create the command without context cancellation
cmd := exec.Command("sh", "-c", shellCmd)
@@ -71,7 +70,7 @@ func runGameIntegrated(parentWindow fyne.Window, shellCmd string) error {
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
line := scanner.Text()
debug.Printf("GAME STDOUT: %s", line)
log.WineLoggerStdout(line)
}
}()
@@ -79,7 +78,7 @@ func runGameIntegrated(parentWindow fyne.Window, shellCmd string) error {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
line := scanner.Text()
debug.Printf("GAME STDERR: %s", line)
log.WineLoggerStderr(line)
}
}()
@@ -93,9 +92,9 @@ func runGameIntegrated(parentWindow fyne.Window, shellCmd string) error {
}()
if err := cmd.Wait(); err != nil {
debug.Printf("Game process ended with error: %v", err)
log.Debugf("Game process ended with error: %v", err)
} else {
debug.Println("Game process ended successfully")
log.Debug("Game process ended successfully")
}
}()
@@ -103,7 +102,7 @@ func runGameIntegrated(parentWindow fyne.Window, shellCmd string) error {
}
func LaunchGame(myWindow fyne.Window) {
debug.Println("Launch Game button clicked")
log.Debug("Launch Game button clicked")
if paths.CrossoverPath == "" {
dialog.ShowError(fmt.Errorf("CrossOver path not set. Please set it in the patcher."), myWindow)
@@ -132,7 +131,7 @@ func LaunchGame(myWindow fyne.Window) {
}
gameMutex.Unlock()
debug.Println("Preparing to launch EpochSilicon...")
log.Debug("Preparing to launch EpochSilicon...")
wowExePath := filepath.Join(paths.EpochPath, "Project-Epoch.exe")
@@ -163,20 +162,20 @@ func continueLaunch(myWindow fyne.Window, wowExePath string) {
if AutoDeleteWdb {
wdbPath := filepath.Join(paths.EpochPath, "WDB")
if utils.DirExists(wdbPath) {
debug.Printf("Auto-deleting WDB directory: %s", wdbPath)
log.Debugf("Auto-deleting WDB directory: %s", wdbPath)
if err := os.RemoveAll(wdbPath); err != nil {
debug.Printf("Warning: failed to auto-delete WDB directory: %v", err)
log.Debugf("Warning: failed to auto-delete WDB directory: %v", err)
// Don't block the launch, just log the error
} else {
debug.Printf("Successfully auto-deleted WDB directory")
log.Debugf("Successfully auto-deleted WDB directory")
}
} else {
debug.Printf("WDB directory not found, nothing to delete")
log.Debugf("WDB directory not found, nothing to delete")
}
}
// Since RosettaX87 service is already running, we can directly launch WoW
debug.Println("RosettaX87 service is running. Proceeding to launch WoW.")
log.Debug("RosettaX87 service is running. Proceeding to launch WoW.")
if paths.CrossoverPath == "" || paths.EpochPath == "" {
dialog.ShowError(fmt.Errorf("CrossOver path or Epoch path is not set. Cannot launch WoW."), myWindow)
@@ -189,7 +188,7 @@ func continueLaunch(myWindow fyne.Window, wowExePath string) {
}
// Prepare environment variables
envVars := fmt.Sprintf(`WINEDLLOVERRIDES="d3d9=n,b" MTL_HUD_ENABLED=%s MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=1 DXVK_ASYNC=1`, mtlHudValue)
envVars := fmt.Sprintf(`WINEDLLOVERRIDES="d3d9=n,b" MTL_HUD_ENABLED=%s DXVK_ASYNC=1`, mtlHudValue)
if CustomEnvVars != "" {
envVars = CustomEnvVars + " " + envVars
}
@@ -201,30 +200,13 @@ func continueLaunch(myWindow fyne.Window, wowExePath string) {
utils.QuotePathForShell(wineloader2Path),
utils.QuotePathForShell(wowExePath))
// Check user preference for terminal display
prefs, _ := utils.LoadPrefs()
if prefs.ShowTerminalNormally {
// Use the old method with external Terminal.app
escapedShellCmd := utils.EscapeStringForAppleScript(shellCmd)
cmd2Script := fmt.Sprintf("tell application \"Terminal\" to do script \"%s\"", escapedShellCmd)
debug.Println("Executing WoW launch command via AppleScript...")
if !utils.RunOsascript(cmd2Script, myWindow) {
return
}
debug.Println("Launch command executed. Check the new terminal window.")
} else {
// Use integrated terminal
debug.Printf("Shell command for integrated terminal: %s", shellCmd)
debug.Println("Executing WoW launch command with integrated terminal...")
log.Debugf("Shell command for integrated terminal: %s", shellCmd)
log.Debug("Executing WoW launch command with integrated terminal...")
if err := runGameIntegrated(myWindow, shellCmd); err != nil {
dialog.ShowError(fmt.Errorf("failed to launch game: %v", err), myWindow)
return
}
debug.Println("Game launched with integrated terminal. Check the application logs for output.")
}
}
// IsGameRunning returns true if the game is currently running

View File

@@ -1,13 +1,13 @@
package launcher
import (
"epochsilicon/pkg/log"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"epochsilicon/pkg/debug"
"epochsilicon/pkg/paths"
)
@@ -25,20 +25,20 @@ var RecommendedSettings = map[string]string{
// Returns true if all settings are correctly applied, false otherwise
func CheckRecommendedSettings() bool {
if paths.EpochPath == "" {
debug.Printf("Epoch path not set, cannot check Config.wtf")
log.Debugf("Epoch path not set, cannot check Config.wtf")
return false
}
configPath := filepath.Join(paths.EpochPath, "WTF", "Config.wtf")
if _, err := os.Stat(configPath); os.IsNotExist(err) {
debug.Printf("Config.wtf not found at %s", configPath)
log.Debugf("Config.wtf not found at %s", configPath)
return false
}
content, err := os.ReadFile(configPath)
if err != nil {
debug.Printf("Failed to read Config.wtf: %v", err)
log.Debugf("Failed to read Config.wtf: %v", err)
return false
}
@@ -47,12 +47,12 @@ func CheckRecommendedSettings() bool {
// Check each recommended setting
for setting, expectedValue := range RecommendedSettings {
if !isSettingCorrect(configText, setting, expectedValue) {
debug.Printf("Setting %s not found or incorrect in Config.wtf", setting)
log.Debugf("Setting %s not found or incorrect in Config.wtf", setting)
return false
}
}
debug.Printf("All recommended settings are correctly applied")
log.Debugf("All recommended settings are correctly applied")
return true
}
@@ -91,7 +91,7 @@ func ApplyRecommendedSettings() error {
if content, err := os.ReadFile(configPath); err == nil {
configText = string(content)
} else {
debug.Printf("Config.wtf not found, creating new file")
log.Debugf("Config.wtf not found, creating new file")
configText = ""
}
@@ -105,7 +105,7 @@ func ApplyRecommendedSettings() error {
return fmt.Errorf("failed to write Config.wtf: %v", err)
}
debug.Printf("Successfully applied recommended settings to Config.wtf")
log.Debugf("Successfully applied recommended settings to Config.wtf")
return nil
}
@@ -120,14 +120,14 @@ func updateOrAddSetting(configText, setting, value string) string {
if re.MatchString(configText) {
// Replace existing setting
configText = re.ReplaceAllString(configText, newSetting)
debug.Printf("Updated setting %s to %s", setting, value)
log.Debugf("Updated setting %s to %s", setting, value)
} else {
// Add new setting
if configText != "" && !strings.HasSuffix(configText, "\n") {
configText += "\n"
}
configText += newSetting + "\n"
debug.Printf("Added new setting %s with value %s", setting, value)
log.Debugf("Added new setting %s with value %s", setting, value)
}
return configText

126
pkg/log/logging.go Normal file
View File

@@ -0,0 +1,126 @@
package log
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"gopkg.in/natefinch/lumberjack.v2"
"io"
"os"
"path/filepath"
)
var (
logger zerolog.Logger
Writer io.Writer
)
func SetupLogging() {
// App logs
path, err := getLogfilePath()
if err != nil {
log.Error().Err(err).Str("path", path).Msg("Failed to get log path")
return
}
l := createLogWriter(path, 10, 3)
if l != nil {
Writer = io.MultiWriter(zerolog.ConsoleWriter{Out: os.Stdout}, l)
} else {
Writer = os.Stdout
}
logger = zerolog.New(Writer).With().Timestamp().Logger()
SetLevelInfo()
}
func createLogWriter(path string, maxSize int, maxBackups int) io.Writer {
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
log.Error().Err(err).Str("path", path).Msg("Failed to create log path")
return nil
}
return &lumberjack.Logger{
Filename: path,
MaxSize: maxSize,
MaxBackups: maxBackups,
}
}
func SetLevelDebug() {
logger.Level(zerolog.DebugLevel)
}
func SetLevelInfo() {
logger.Level(zerolog.InfoLevel)
}
func getLogfilePath() (string, error) {
dir, err := os.UserConfigDir()
if err != nil {
return "", err
}
return filepath.Join(dir, "EpochSilicon", "epochsilicon.log"), nil
}
func getWineLogfilePath() (string, error) {
dir, err := os.UserConfigDir()
if err != nil {
return "", err
}
return filepath.Join(dir, "EpochSilicon", "epochsilicon.log"), nil
}
func Debug(msg string) {
logger.Debug().Msg(msg)
}
func Debugf(format string, args ...interface{}) {
logger.Debug().Msgf(format, args...)
}
func Info(msg string) {
logger.Info().Msg(msg)
}
func Infof(format string, args ...interface{}) {
logger.Info().Msgf(format, args...)
}
func Warn(msg string) {
logger.Warn().Msg(msg)
}
func Warnf(format string, args ...interface{}) {
logger.Warn().Msgf(format, args...)
}
func Error(msg string) {
logger.Error().Msg(msg)
}
func Errorf(format string, args ...interface{}) {
logger.Error().Msgf(format, args...)
}
func Fatal(msg string) {
logger.Fatal().Msg(msg)
}
func Fatalf(format string, args ...interface{}) {
logger.Fatal().Msgf(format, args...)
}
func Panic(msg string) {
logger.Panic().Msg(msg)
}
func Panicf(format string, args ...interface{}) {
logger.Panic().Msgf(format, args...)
}
func WineLoggerStdout(msg string) {
logger.Info().Msgf("WINE STDOUT: %s", msg)
}
func WineLoggerStderr(msg string) {
logger.Info().Msgf("WINE STDERR: %s", msg)
}

View File

@@ -2,18 +2,18 @@ package patching
import (
"bytes"
"epochsilicon/pkg/log"
"errors"
"fmt"
"git.burkey.co/eburk/epochcli/pkg/epoch"
"github.com/go-git/go-git/v6"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"epochsilicon/pkg/debug"
"epochsilicon/pkg/paths" // Corrected import path
"epochsilicon/pkg/utils" // Corrected import path
@@ -21,8 +21,13 @@ import (
"fyne.io/fyne/v2/dialog"
)
const (
CmakePath = "/opt/homebrew/bin/cmake"
ClangPath = "/usr/bin/clang"
)
func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
debug.Println("Patch Epoch clicked")
log.Debug("Patch Epoch clicked")
if paths.EpochPath == "" {
dialog.ShowError(fmt.Errorf("Epoch path not set. Please set it first."), myWindow)
return
@@ -38,25 +43,25 @@ func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
}
for resourceName, destPath := range filesToCopy {
debug.Printf("Processing resource: %s to %s", resourceName, destPath)
log.Debugf("Processing resource: %s to %s", resourceName, destPath)
// Check if file already exists and has correct size
if utils.PathExists(destPath) && utils.CompareFileWithBundledResource(destPath, resourceName) {
debug.Printf("File %s already exists with correct size, skipping copy", destPath)
log.Debugf("File %s already exists with correct size, skipping copy", destPath)
continue
}
if utils.PathExists(destPath) {
debug.Printf("File %s exists but has incorrect size, updating...", destPath)
log.Debugf("File %s exists but has incorrect size, updating...", destPath)
} else {
debug.Printf("File %s does not exist, creating...", destPath)
log.Debugf("File %s does not exist, creating...", destPath)
}
resource, err := fyne.LoadResourceFromPath(resourceName)
if err != nil {
errMsg := fmt.Sprintf("failed to open bundled resource %s: %v", resourceName, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
paths.PatchesAppliedEpoch = false
updateAllStatuses()
return
@@ -66,7 +71,7 @@ func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
if err != nil {
errMsg := fmt.Sprintf("failed to create destination file %s: %v", destPath, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
paths.PatchesAppliedEpoch = false
updateAllStatuses()
return
@@ -77,22 +82,25 @@ func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
if err != nil {
errMsg := fmt.Sprintf("failed to copy bundled resource %s to %s: %v", resourceName, destPath, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
paths.PatchesAppliedEpoch = false
updateAllStatuses()
return
}
debug.Printf("Successfully copied %s to %s", resourceName, destPath)
log.Debugf("Successfully copied %s to %s", resourceName, destPath)
}
debug.Printf("Preparing rosettax87 directory at: %s", targetRosettaX87Dir)
if _, err := os.Stat(filepath.Join(paths.EpochPath, "rosettax87")); err == nil {
log.Debugf("rosettax87 path already exists, skipping copy")
} else {
log.Debugf("Preparing rosettax87 directory at: %s", targetRosettaX87Dir)
if err := os.RemoveAll(targetRosettaX87Dir); err != nil {
debug.Printf("Warning: could not remove existing rosettax87 folder '%s': %v", targetRosettaX87Dir, err)
log.Debugf("Warning: could not remove existing rosettax87 folder '%s': %v", targetRosettaX87Dir, err)
}
if err := os.MkdirAll(targetRosettaX87Dir, 0755); err != nil {
errMsg := fmt.Sprintf("failed to create directory %s: %v", targetRosettaX87Dir, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
paths.PatchesAppliedEpoch = false
updateAllStatuses()
return
@@ -104,12 +112,12 @@ func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
}
for resourceName, destPath := range rosettaFilesToCopy {
debug.Printf("Processing rosetta resource: %s to %s", resourceName, destPath)
log.Debugf("Processing rosetta resource: %s to %s", resourceName, destPath)
resource, err := fyne.LoadResourceFromPath(resourceName)
if err != nil {
errMsg := fmt.Sprintf("failed to open bundled resource %s: %v", resourceName, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
paths.PatchesAppliedEpoch = false
updateAllStatuses()
return
@@ -119,7 +127,7 @@ func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
if err != nil {
errMsg := fmt.Sprintf("failed to create destination file %s: %v", destPath, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
paths.PatchesAppliedEpoch = false
updateAllStatuses()
return
@@ -130,7 +138,7 @@ func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
destinationFile.Close()
errMsg := fmt.Sprintf("failed to copy bundled resource %s to %s: %v", resourceName, destPath, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
paths.PatchesAppliedEpoch = false
updateAllStatuses()
return
@@ -138,31 +146,32 @@ func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
destinationFile.Close()
if filepath.Base(destPath) == "rosettax87" {
debug.Printf("Setting execute permission for %s", destPath)
log.Debugf("Setting execute permission for %s", destPath)
if err := os.Chmod(destPath, 0755); err != nil {
errMsg := fmt.Sprintf("failed to set execute permission for %s: %v", destPath, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
paths.PatchesAppliedEpoch = false
updateAllStatuses()
return
}
}
debug.Printf("Successfully copied %s to %s", resourceName, destPath)
log.Debugf("Successfully copied %s to %s", resourceName, destPath)
}
}
debug.Printf("Checking dlls.txt file at: %s", dllsTextFile)
log.Debugf("Checking dlls.txt file at: %s", dllsTextFile)
winerosettaEntry := "winerosetta.dll"
needsWinerosettaUpdate := true
if fileContentBytes, err := os.ReadFile(dllsTextFile); err == nil {
fileContent := string(fileContentBytes)
if strings.Contains(fileContent, winerosettaEntry) {
debug.Printf("dlls.txt already contains %s", winerosettaEntry)
log.Debugf("dlls.txt already contains %s", winerosettaEntry)
needsWinerosettaUpdate = false
}
} else {
debug.Printf("dlls.txt not found, will create a new one")
log.Debugf("dlls.txt not found, will create a new one")
}
if needsWinerosettaUpdate {
@@ -173,7 +182,7 @@ func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
if err != nil {
errMsg := fmt.Sprintf("failed to read dlls.txt for update: %v", err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
}
}
@@ -187,39 +196,54 @@ func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
if needsWinerosettaUpdate {
if !strings.Contains(updatedContent, winerosettaEntry+"\n") {
updatedContent += winerosettaEntry + "\n"
debug.Printf("Adding %s to dlls.txt", winerosettaEntry)
log.Debugf("Adding %s to dlls.txt", winerosettaEntry)
}
}
if err := os.WriteFile(dllsTextFile, []byte(updatedContent), 0644); err != nil {
errMsg := fmt.Sprintf("failed to update dlls.txt: %v", err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
} else {
debug.Printf("Successfully updated dlls.txt")
log.Debugf("Successfully updated dlls.txt")
}
}
debug.Println("Downloading updates from Project Epoch servers.")
log.Debug("Downloading updates from Project Epoch servers.")
// TODO: Change from dialog to pulsing animation
dialog.ShowInformation("Downloading patches", "Downloading patches for Project Epoch, this will take some time. Please wait until the status changes to \"Patched\"", myWindow)
paths.DownloadingPatches = true
go func() {
stats, err := epoch.Update(paths.EpochPath, true, true, false)
log.Debug("Attempting to download Epoch patches...")
// Ensure permissions on Data directory is correct
err := os.Chmod(filepath.Join(paths.EpochPath, "Data"), 0755)
if err != nil {
errMsg := fmt.Sprintf("failed to update Epoch files: %v", err)
msg := fmt.Sprintf("Failed to set Data directory permissions: %v", err)
log.Error(msg)
dialog.ShowInformation("Error", msg, myWindow)
} else {
log.Debug("Successfully set Data directory permissions")
}
go func() {
stats := epoch.Update(paths.EpochPath, true, true, false)
if stats.Error != nil {
errMsg := fmt.Sprintf("failed to update Epoch files: %v", stats.Error)
fyne.Do(func() {
dialog.ShowError(errors.New(errMsg), myWindow)
})
paths.DownloadingPatches = false
log.Println(errMsg)
log.Error(errMsg)
} else {
for _, msg := range stats.LogMessages {
log.Debug(msg)
}
log.Printf("Successfully updated %d Epoch files", stats.Updated)
debug.Println("Epoch patching with bundled resources completed successfully.")
log.Infof("Successfully updated %d Epoch files", stats.Updated)
log.Debug("Epoch patching with bundled resources completed successfully.")
fyne.Do(func() {
dialog.ShowInformation("Success", "Epoch patching process completed.", myWindow)
})
}
fyne.DoAndWait(func() {
paths.DownloadingPatches = false
updateAllStatuses()
@@ -229,7 +253,7 @@ func PatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
}
func PatchCrossOver(myWindow fyne.Window, updateAllStatuses func()) {
debug.Println("Patch CrossOver clicked")
log.Debug("Patch CrossOver clicked")
if paths.CrossoverPath == "" {
dialog.ShowError(fmt.Errorf("CrossOver path not set. Please set it first."), myWindow)
return
@@ -246,52 +270,52 @@ func PatchCrossOver(myWindow fyne.Window, updateAllStatuses func()) {
return
}
debug.Printf("Copying %s to %s", wineloaderOrig, wineloaderCopy)
log.Debugf("Copying %s to %s", wineloaderOrig, wineloaderCopy)
if err := utils.CopyFile(wineloaderOrig, wineloaderCopy); err != nil {
errMsg := fmt.Sprintf("failed to copy wineloader: %v", err)
if strings.Contains(err.Error(), "operation not permitted") {
errMsg += "\n\nSolution: Open System Settings, go to Privacy & Security > App Management, and enable EpochSilicon."
}
dialog.ShowError(fmt.Errorf(errMsg), myWindow)
dialog.ShowError(fmt.Errorf("%s", errMsg), myWindow)
paths.PatchesAppliedCrossOver = false
updateAllStatuses()
return
}
debug.Printf("Executing: codesign --remove-signature %s", wineloaderCopy)
log.Debugf("Executing: codesign --remove-signature %s", wineloaderCopy)
cmd := exec.Command("codesign", "--remove-signature", wineloaderCopy)
combinedOutput, err := cmd.CombinedOutput()
if err != nil {
derrMsg := fmt.Sprintf("failed to remove signature from %s: %v\nOutput: %s", wineloaderCopy, err, string(combinedOutput))
dialog.ShowError(errors.New(derrMsg), myWindow)
debug.Println(derrMsg)
log.Debug(derrMsg)
paths.PatchesAppliedCrossOver = false
if err := os.Remove(wineloaderCopy); err != nil {
debug.Printf("Warning: failed to cleanup wineloader2 after codesign failure: %v", err)
log.Debugf("Warning: failed to cleanup wineloader2 after codesign failure: %v", err)
}
updateAllStatuses()
return
}
debug.Printf("codesign output: %s", string(combinedOutput))
log.Debugf("codesign output: %s", string(combinedOutput))
debug.Printf("Setting execute permissions for %s", wineloaderCopy)
log.Debugf("Setting execute permissions for %s", wineloaderCopy)
if err := os.Chmod(wineloaderCopy, 0755); err != nil {
errMsg := fmt.Sprintf("failed to set executable permissions for %s: %v", wineloaderCopy, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
paths.PatchesAppliedCrossOver = false
updateAllStatuses()
return
}
debug.Println("CrossOver patching completed successfully.")
log.Debug("CrossOver patching completed successfully.")
paths.PatchesAppliedCrossOver = true
dialog.ShowInformation("Success", "CrossOver patching process completed.", myWindow)
updateAllStatuses()
}
func UnpatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
debug.Println("Unpatch Epoch clicked")
log.Debug("Unpatch Epoch clicked")
if paths.EpochPath == "" {
dialog.ShowError(fmt.Errorf("Epoch path not set. Please set it first."), myWindow)
return
@@ -305,13 +329,13 @@ func UnpatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
// Remove the rosettaX87 directory
if utils.DirExists(rosettaX87DirPath) {
debug.Printf("Removing directory: %s", rosettaX87DirPath)
log.Debugf("Removing directory: %s", rosettaX87DirPath)
if err := os.RemoveAll(rosettaX87DirPath); err != nil {
errMsg := fmt.Sprintf("failed to remove directory %s: %v", rosettaX87DirPath, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
} else {
debug.Printf("Successfully removed directory: %s", rosettaX87DirPath)
log.Debugf("Successfully removed directory: %s", rosettaX87DirPath)
}
}
@@ -319,25 +343,25 @@ func UnpatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
filesToRemove := []string{winerosettaDllPath, d3d9DllPath}
for _, file := range filesToRemove {
if utils.PathExists(file) {
debug.Printf("Removing file: %s", file)
log.Debugf("Removing file: %s", file)
if err := os.Remove(file); err != nil {
errMsg := fmt.Sprintf("failed to remove file %s: %v", file, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
} else {
debug.Printf("Successfully removed file: %s", file)
log.Debugf("Successfully removed file: %s", file)
}
}
}
// Update dlls.txt file - remove winerosetta.dll
if utils.PathExists(dllsTextFile) {
debug.Printf("Updating dlls.txt file: %s", dllsTextFile)
log.Debugf("Updating dlls.txt file: %s", dllsTextFile)
content, err := os.ReadFile(dllsTextFile)
if err != nil {
errMsg := fmt.Sprintf("failed to read dlls.txt file: %v", err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
} else {
lines := strings.Split(string(content), "\n")
filteredLines := make([]string, 0, len(lines))
@@ -353,21 +377,21 @@ func UnpatchEpoch(myWindow fyne.Window, updateAllStatuses func()) {
if err := os.WriteFile(dllsTextFile, []byte(updatedContent), 0644); err != nil {
errMsg := fmt.Sprintf("failed to update dlls.txt file: %v", err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
} else {
debug.Printf("Successfully updated dlls.txt file")
log.Debugf("Successfully updated dlls.txt file")
}
}
}
debug.Println("Epoch unpatching completed successfully.")
log.Debug("Epoch unpatching completed successfully.")
paths.PatchesAppliedEpoch = false
dialog.ShowInformation("Success", "Epoch unpatching process completed.", myWindow)
updateAllStatuses()
}
func UnpatchCrossOver(myWindow fyne.Window, updateAllStatuses func()) {
debug.Println("Unpatch CrossOver clicked")
log.Debug("Unpatch CrossOver clicked")
if paths.CrossoverPath == "" {
dialog.ShowError(fmt.Errorf("CrossOver path not set. Please set it first."), myWindow)
return
@@ -376,21 +400,21 @@ func UnpatchCrossOver(myWindow fyne.Window, updateAllStatuses func()) {
wineloaderCopy := filepath.Join(paths.CrossoverPath, "Contents", "SharedSupport", "CrossOver", "CrossOver-Hosted Application", "wineloader2")
if utils.PathExists(wineloaderCopy) {
debug.Printf("Removing file: %s", wineloaderCopy)
log.Debugf("Removing file: %s", wineloaderCopy)
if err := os.Remove(wineloaderCopy); err != nil {
errMsg := fmt.Sprintf("failed to remove file %s: %v", wineloaderCopy, err)
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
updateAllStatuses()
return
} else {
debug.Printf("Successfully removed file: %s", wineloaderCopy)
log.Debugf("Successfully removed file: %s", wineloaderCopy)
}
} else {
debug.Printf("File not found to remove: %s", wineloaderCopy)
log.Debugf("File not found to remove: %s", wineloaderCopy)
}
debug.Println("CrossOver unpatching completed successfully.")
log.Debug("CrossOver unpatching completed successfully.")
paths.PatchesAppliedCrossOver = false
dialog.ShowInformation("Success", "CrossOver unpatching process completed.", myWindow)
updateAllStatuses()
@@ -407,14 +431,14 @@ func updateOrAddConfigSetting(configText, setting, value string) string {
if re.MatchString(configText) {
// Replace existing setting
configText = re.ReplaceAllString(configText, newSetting)
debug.Printf("Updated setting %s to %s", setting, value)
log.Debugf("Updated setting %s to %s", setting, value)
} else {
// Add new setting
if configText != "" && !strings.HasSuffix(configText, "\n") {
configText += "\n"
}
configText += newSetting + "\n"
debug.Printf("Added new setting %s with value %s", setting, value)
log.Debugf("Added new setting %s with value %s", setting, value)
}
return configText
@@ -428,7 +452,7 @@ func removeConfigSetting(configText, setting string) string {
if re.MatchString(configText) {
configText = re.ReplaceAllString(configText, "")
debug.Printf("Removed setting %s from config", setting)
log.Debugf("Removed setting %s from config", setting)
}
return configText
@@ -448,3 +472,42 @@ func isConfigSettingCorrect(configText, setting, expectedValue string) bool {
currentValue := matches[1]
return currentValue == expectedValue
}
func BuildRosetta() (string, string, error) {
tmpDir, err := os.MkdirTemp("", "rosettax87")
if err != nil {
return "", "", fmt.Errorf("failed to create temporary directory: %v", err)
}
clonedDir := filepath.Join(tmpDir, "rosettax87")
_, err = git.PlainClone(clonedDir, &git.CloneOptions{
URL: "https://github.com/fputs/rosettax87",
Progress: os.Stdout,
RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
SingleBranch: true,
})
if err != nil {
return "", "", fmt.Errorf("failed to clone repository: %v", err)
}
cmd := exec.Command(CmakePath, "-B", "build")
cmd.Dir = clonedDir
err = cmd.Run()
if err != nil {
return "", "", fmt.Errorf("failed to create build files: %v", err)
}
cmd = exec.Command(CmakePath, "--build", "build")
cmd.Dir = clonedDir
err = cmd.Run()
if err != nil {
return "", "", fmt.Errorf("failed to build rosettax87: %v", err)
}
buildDir := filepath.Join(clonedDir, "build")
rosettax87Path := filepath.Join(buildDir, "rosettax87")
librosettaPath := filepath.Join(buildDir, "libRuntimeRosettax87")
return rosettax87Path, librosettaPath, nil
}

View File

@@ -0,0 +1,15 @@
package patching
import (
"fmt"
"testing"
)
func TestBuildRosetta(t *testing.T) {
rp, lp, err := BuildRosetta()
if err != nil {
t.Error(err)
}
fmt.Println("exe path:", rp)
fmt.Println("lib path:", lp)
}

View File

@@ -1,8 +1,8 @@
package paths
import (
"epochsilicon/pkg/log"
"fmt"
"log"
"os"
"path/filepath"
@@ -33,7 +33,7 @@ func SelectCrossOverPath(myWindow fyne.Window, crossoverPathLabel *widget.RichTe
return
}
if uri == nil {
log.Println("CrossOver path selection cancelled.")
log.Info("CrossOver path selection cancelled.")
updateAllStatuses()
return
}
@@ -41,14 +41,14 @@ func SelectCrossOverPath(myWindow fyne.Window, crossoverPathLabel *widget.RichTe
if filepath.Ext(selectedPath) == ".app" && utils.DirExists(selectedPath) {
CrossoverPath = selectedPath
PatchesAppliedCrossOver = false
log.Println("CrossOver path set to:", CrossoverPath)
log.Infof("CrossOver path set to:", CrossoverPath)
// Save to prefs
prefs, _ := utils.LoadPrefs()
prefs.CrossOverPath = selectedPath
utils.SavePrefs(prefs)
} else {
dialog.ShowError(fmt.Errorf("invalid selection: '%s'. Please select a valid .app bundle", selectedPath), myWindow)
log.Println("Invalid CrossOver path selected:", selectedPath)
log.Infof("Invalid CrossOver path selected:", selectedPath)
}
updateAllStatuses()
}, myWindow)
@@ -61,7 +61,7 @@ func SelectEpochPath(myWindow fyne.Window, epochPathLabel *widget.RichText, upda
return
}
if uri == nil {
log.Println("Epoch path selection cancelled.")
log.Info("Epoch path selection cancelled.")
updateAllStatuses()
return
}
@@ -69,14 +69,14 @@ func SelectEpochPath(myWindow fyne.Window, epochPathLabel *widget.RichText, upda
if utils.DirExists(selectedPath) {
EpochPath = selectedPath
PatchesAppliedEpoch = false
log.Println("Epoch path set to:", EpochPath)
log.Infof("Epoch path set to:", EpochPath)
// Save to prefs
prefs, _ := utils.LoadPrefs()
prefs.EpochPath = selectedPath
utils.SavePrefs(prefs)
} else {
dialog.ShowError(fmt.Errorf("invalid selection: '%s' is not a valid directory", selectedPath), myWindow)
log.Println("Invalid Epoch path selected:", selectedPath)
log.Infof("Invalid Epoch path selected:", selectedPath)
}
updateAllStatuses()
}, myWindow)
@@ -102,7 +102,7 @@ func CheckDefaultCrossOverPath() {
if CrossoverPath == "" {
if info, err := os.Stat(DefaultCrossOverPath); err == nil && info.IsDir() {
CrossoverPath = DefaultCrossOverPath
log.Println("Pre-set CrossOver to default:", DefaultCrossOverPath)
log.Infof("Pre-set CrossOver to default:", DefaultCrossOverPath)
}
}
}

View File

@@ -2,8 +2,8 @@ package service
import (
"bytes"
"epochsilicon/pkg/log"
"fmt"
"log"
"os/exec"
"path/filepath"
"strings"
@@ -27,7 +27,7 @@ var (
// CleanupExistingServices kills any existing rosettax87 processes
func CleanupExistingServices() error {
log.Println("Cleaning up any existing rosettax87 processes...")
log.Info("Cleaning up any existing rosettax87 processes...")
// Find all rosettax87 processes
cmd := exec.Command("pgrep", "-f", "rosettax87")
@@ -49,16 +49,16 @@ func CleanupExistingServices() error {
err := killCmd.Run()
if err != nil {
// If regular kill fails, try with sudo (but this might fail too)
log.Printf("Regular kill failed for process %s, trying sudo: %v", pid, err)
log.Infof("Regular kill failed for process %s, trying sudo: %v", pid, err)
sudoKillCmd := exec.Command("sudo", "kill", "-9", pid)
err2 := sudoKillCmd.Run()
if err2 != nil {
log.Printf("Failed to kill process %s with sudo: %v", pid, err2)
log.Infof("Failed to kill process %s with sudo: %v", pid, err2)
} else {
log.Printf("Killed existing rosettax87 process with sudo: %s", pid)
log.Infof("Killed existing rosettax87 process with sudo: %s", pid)
}
} else {
log.Printf("Killed existing rosettax87 process: %s", pid)
log.Infof("Killed existing rosettax87 process: %s", pid)
}
}
@@ -77,7 +77,7 @@ func isRosettaSocketActive() bool {
// StartRosettaX87Service starts the RosettaX87 service with sudo privileges
func StartRosettaX87Service(myWindow fyne.Window, updateAllStatuses func()) {
log.Println("Starting RosettaX87 service...")
log.Info("Starting RosettaX87 service...")
if paths.EpochPath == "" {
dialog.ShowError(fmt.Errorf("Epoch path not set. Please set it first"), myWindow)
@@ -103,7 +103,7 @@ func StartRosettaX87Service(myWindow fyne.Window, updateAllStatuses func()) {
// Load user preferences
prefs, err := utils.LoadPrefs()
if err != nil {
log.Printf("Failed to load preferences: %v", err)
log.Infof("Failed to load preferences: %v", err)
prefs = &utils.UserPrefs{} // Use default prefs
}
@@ -163,7 +163,7 @@ func StartRosettaX87Service(myWindow fyne.Window, updateAllStatuses func()) {
if shouldSavePassword {
// Save password to keychain
if err := utils.SaveSudoPassword(password); err != nil {
log.Printf("Failed to save password to keychain: %v", err)
log.Infof("Failed to save password to keychain: %v", err)
// Don't block the service start, just log the error
}
} else {
@@ -174,7 +174,7 @@ func StartRosettaX87Service(myWindow fyne.Window, updateAllStatuses func()) {
// Update preferences
prefs.SaveSudoPassword = shouldSavePassword
if err := utils.SavePrefs(prefs); err != nil {
log.Printf("Failed to save preferences: %v", err)
log.Infof("Failed to save preferences: %v", err)
}
// Close the dialog
@@ -191,13 +191,13 @@ func StartRosettaX87Service(myWindow fyne.Window, updateAllStatuses func()) {
err := startServiceWithPassword(rosettaX87Dir, rosettaX87Exe, password)
paths.ServiceStarting = false
if err != nil {
log.Printf("Failed to start RosettaX87 service: %v", err)
log.Infof("Failed to start RosettaX87 service: %v", err)
fyne.Do(func() {
dialog.ShowError(fmt.Errorf("failed to start RosettaX87 service: %v", err), myWindow)
})
ServiceRunning = false
} else {
log.Println("RosettaX87 service started successfully")
log.Info("RosettaX87 service started successfully")
ServiceRunning = true
}
fyne.Do(func() {
@@ -215,7 +215,7 @@ func StartRosettaX87Service(myWindow fyne.Window, updateAllStatuses func()) {
passwordContainer,
func(confirmed bool) {
if !confirmed {
log.Println("Service start cancelled by user")
log.Info("Service start cancelled by user")
return
}
confirmFunc()
@@ -263,7 +263,7 @@ func startServiceWithPassword(workingDir, executable, password string) error {
stderrOutput := stderr.String()
stdoutOutput := stdout.String()
log.Printf("Password test - Exit code: %v, Stderr: %q, Stdout: %q", err, stderrOutput, stdoutOutput)
log.Infof("Password test - Exit code: %v, Stderr: %q, Stdout: %q", err, stderrOutput, stdoutOutput)
// Check for authentication failure indicators
if strings.Contains(stderrOutput, "Sorry, try again") ||
@@ -283,7 +283,7 @@ func startServiceWithPassword(workingDir, executable, password string) error {
}
// If we get here, the password is correct, now start the actual service
log.Println("Password validated successfully, starting rosettax87 service...")
log.Info("Password validated successfully, starting rosettax87 service...")
cmd := exec.Command("sudo", "-S", executable)
cmd.Dir = workingDir
@@ -325,25 +325,25 @@ func startServiceWithPassword(workingDir, executable, password string) error {
if cmd.ProcessState != nil && cmd.ProcessState.Exited() {
stderrOutput := stderr.String()
stdoutOutput := stdout.String()
log.Printf("Process exited - Stdout: %q, Stderr: %q", stdoutOutput, stderrOutput)
log.Infof("Process exited - Stdout: %q, Stderr: %q", stdoutOutput, stderrOutput)
return fmt.Errorf("process exited prematurely with code: %d. Stderr: %s", cmd.ProcessState.ExitCode(), stderrOutput)
}
// Verify the service is actually listening
time.Sleep(1 * time.Second)
if !isRosettaSocketActive() {
log.Printf("Service started but socket not active - Stdout: %q, Stderr: %q", stdout.String(), stderr.String())
log.Infof("Service started but socket not active - Stdout: %q, Stderr: %q", stdout.String(), stderr.String())
cmd.Process.Kill()
return fmt.Errorf("service started but is not listening on socket")
}
log.Printf("RosettaX87 service started successfully with PID: %d", servicePID)
log.Infof("RosettaX87 service started successfully with PID: %d", servicePID)
return nil
}
// StopRosettaX87Service stops the running RosettaX87 service
func StopRosettaX87Service(myWindow fyne.Window, updateAllStatuses func()) {
log.Println("Stopping RosettaX87 service...")
log.Info("Stopping RosettaX87 service...")
if !ServiceRunning {
dialog.ShowInformation("Service Status", "RosettaX87 service is not running.", myWindow)
@@ -354,11 +354,11 @@ func StopRosettaX87Service(myWindow fyne.Window, updateAllStatuses func()) {
// Send SIGTERM to gracefully stop the process
err := serviceCmd.Process.Signal(syscall.SIGTERM)
if err != nil {
log.Printf("Failed to send SIGTERM to process: %v", err)
log.Infof("Failed to send SIGTERM to process: %v", err)
// Try SIGKILL as fallback
err = serviceCmd.Process.Kill()
if err != nil {
log.Printf("Failed to kill process: %v", err)
log.Infof("Failed to kill process: %v", err)
dialog.ShowError(fmt.Errorf("failed to stop service: %v", err), myWindow)
return
}
@@ -370,7 +370,7 @@ func StopRosettaX87Service(myWindow fyne.Window, updateAllStatuses func()) {
ServiceRunning = false
serviceCmd = nil
servicePID = 0
log.Println("RosettaX87 service stopped")
log.Info("RosettaX87 service stopped")
fyne.Do(func() {
dialog.ShowInformation("Service Stopped", "RosettaX87 service has been stopped.", myWindow)
updateAllStatuses()
@@ -407,7 +407,7 @@ func IsServiceRunning() bool {
// CleanupService ensures the service is stopped when the application exits
func CleanupService() {
log.Println("Cleaning up RosettaX87 service on application exit...")
log.Info("Cleaning up RosettaX87 service on application exit...")
CleanupExistingServices()
ServiceRunning = false
serviceCmd = nil

View File

@@ -1,11 +1,11 @@
package ui
import (
"epochsilicon/pkg/log"
"net/url"
"strings"
"time"
"epochsilicon/pkg/debug"
"epochsilicon/pkg/launcher"
"epochsilicon/pkg/patching"
"epochsilicon/pkg/service"
@@ -27,7 +27,7 @@ func createOptionsComponents() {
prefs, _ := utils.LoadPrefs()
prefs.EnableMetalHud = checked
utils.SavePrefs(prefs)
debug.Printf("Metal HUD enabled: %v", launcher.EnableMetalHud)
log.Debugf("Metal HUD enabled: %v", launcher.EnableMetalHud)
})
metalHudCheckbox.SetChecked(prefs.EnableMetalHud)
launcher.EnableMetalHud = prefs.EnableMetalHud
@@ -37,17 +37,32 @@ func createOptionsComponents() {
prefs, _ := utils.LoadPrefs()
prefs.ShowTerminalNormally = checked
utils.SavePrefs(prefs)
debug.Printf("Show terminal normally: %v", checked)
log.Debugf("Show terminal normally: %v", checked)
})
showTerminalCheckbox.SetChecked(prefs.ShowTerminalNormally)
advancedLoggingCheckbox = widget.NewCheck("Advanced Logging", func(checked bool) {
// Save to preferences
prefs, _ := utils.LoadPrefs()
prefs.AdvancedLogging = checked
utils.SavePrefs(prefs)
log.Debugf("Advanced logging set to %v", checked)
if checked {
log.SetLevelDebug()
} else {
log.SetLevelInfo()
}
})
advancedLoggingCheckbox.SetChecked(prefs.AdvancedLogging)
autoDeleteWdbCheckbox = widget.NewCheck("Auto-delete WDB directory on launch", func(checked bool) {
launcher.AutoDeleteWdb = checked
// Save to preferences
prefs, _ := utils.LoadPrefs()
prefs.AutoDeleteWdb = checked
utils.SavePrefs(prefs)
debug.Printf("Auto-delete WDB enabled: %v", launcher.AutoDeleteWdb)
log.Debugf("Auto-delete WDB enabled: %v", launcher.AutoDeleteWdb)
})
autoDeleteWdbCheckbox.SetChecked(prefs.AutoDeleteWdb)
launcher.AutoDeleteWdb = prefs.AutoDeleteWdb
@@ -69,7 +84,7 @@ func createOptionsComponents() {
prefs, _ := utils.LoadPrefs()
prefs.EnvironmentVariables = text
utils.SavePrefs(prefs)
debug.Printf("Environment variables updated: %v", launcher.CustomEnvVars)
log.Debugf("Environment variables updated: %v", launcher.CustomEnvVars)
}
}
@@ -122,11 +137,11 @@ func createBottomBar(myWindow fyne.Window) fyne.CanvasObject {
})
// Git button
gitButton := widget.NewButton("Source Code", func() {
gitButton := widget.NewButton("Website", func() {
githubURL := "https://git.burkey.co/eburk/epochsilicon"
parsedURL, err := url.Parse(githubURL)
if err != nil {
debug.Printf("Error parsing git URL: %v", err)
log.Debugf("Error parsing git URL: %v", err)
return
}
fyne.CurrentApp().OpenURL(parsedURL)
@@ -198,7 +213,7 @@ func createWineRegistryComponents() {
}()
if err := utils.SetOptionAsAltEnabled(true); err != nil {
debug.Printf("Failed to enable Option-as-Alt mapping: %v", err)
log.Debugf("Failed to enable Option-as-Alt mapping: %v", err)
// Update UI on main thread
fyne.Do(func() {
stopPulsingEffect()
@@ -206,7 +221,7 @@ func createWineRegistryComponents() {
})
time.Sleep(2 * time.Second) // Show error briefly
} else {
debug.Printf("Successfully enabled Option-as-Alt mapping")
log.Debugf("Successfully enabled Option-as-Alt mapping")
// Update preferences
prefs, _ := utils.LoadPrefs()
prefs.RemapOptionAsAlt = true
@@ -240,7 +255,7 @@ func createWineRegistryComponents() {
}()
if err := utils.SetOptionAsAltEnabled(false); err != nil {
debug.Printf("Failed to disable Option-as-Alt mapping: %v", err)
log.Debugf("Failed to disable Option-as-Alt mapping: %v", err)
// Update UI on main thread
fyne.Do(func() {
stopPulsingEffect()
@@ -248,7 +263,7 @@ func createWineRegistryComponents() {
})
time.Sleep(2 * time.Second) // Show error briefly
} else {
debug.Printf("Successfully disabled Option-as-Alt mapping")
log.Debugf("Successfully disabled Option-as-Alt mapping")
// Update preferences
prefs, _ := utils.LoadPrefs()
prefs.RemapOptionAsAlt = false

View File

@@ -1,7 +1,7 @@
package ui
import (
"epochsilicon/pkg/debug"
"epochsilicon/pkg/log"
"epochsilicon/pkg/paths"
"fyne.io/fyne/v2"
@@ -34,7 +34,7 @@ func createLogoContainer() fyne.CanvasObject {
// Load the application logo
logoResource, err := fyne.LoadResourceFromPath("Icon.png")
if err != nil {
debug.Printf("Warning: could not load logo: %v", err)
log.Debugf("Warning: could not load logo: %v", err)
}
// Create the logo image with a smaller fixed size since we have a header now

View File

@@ -1,15 +1,18 @@
package ui
import (
"epochsilicon/pkg/log"
"epochsilicon/pkg/patching"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/widget"
"os"
"os/exec"
"path/filepath"
"strings"
"howett.net/plist"
@@ -30,6 +33,7 @@ func showOptionsPopup() {
generalContainer := container.NewVBox(
generalTitle,
widget.NewSeparator(),
advancedLoggingCheckbox,
metalHudCheckbox,
showTerminalCheckbox,
autoDeleteWdbCheckbox,
@@ -197,12 +201,84 @@ func showTroubleshootingPopup() {
}, currentWindow).Show()
})
// --- Build Rosettax87 Locally ---
buildRosettaButton = widget.NewButton("Build", func() {
msg := "Building rosettax87 on your computer may speed up launch times. This requires xcode-commandline-tools and Cmake to be installed. See the instructions at https://git.burkey.co/eburk/epochsilicon/README.md\n\n"
msg += "Click YES to start the build process. This could take up to a minute depending on the the speed of your Mac. A popup will let you know when the files have been built and copied to the right place."
dialog.NewConfirm("Build rosettax87", msg, func(confirm bool) {
if confirm {
// Check for dependencies
if err := exec.Command(patching.ClangPath, "--version").Run(); err != nil {
m := fmt.Errorf("xcode command line tools are not installed on your computer. Click the Website button in the app and read the instructions on building rosettax87 before trying again. Error: %v", err)
log.Error(m.Error())
dialog.ShowError(m, currentWindow)
return
}
if err := exec.Command(patching.CmakePath, "--version").Run(); err != nil {
m := fmt.Errorf("Cmake is not installed on your computer. Click the Website button in the app and read the instructions on building rosettax87 before trying again. Error: %v", err)
log.Error(m.Error())
dialog.ShowError(m, currentWindow)
return
}
xPath, lPath, err := patching.BuildRosetta()
if err != nil {
m := fmt.Errorf("Error building rosettax87: %v\nClick Website for information on getting help", err)
log.Error(m.Error())
dialog.ShowError(m, currentWindow)
return
}
d := filepath.Join(paths.EpochPath, "rosettax87")
if err = os.RemoveAll(d); err != nil {
m := fmt.Errorf("Error removing existing rosettax87 directory: %v", err)
log.Error(m.Error())
dialog.ShowError(m, currentWindow)
return
}
if err = os.MkdirAll(d, 0755); err != nil {
m := fmt.Errorf("Error creating existing rosettax87 directory: %v", err)
log.Error(m.Error())
dialog.ShowError(m, currentWindow)
return
}
pathMap := map[string]string{
xPath: filepath.Join(paths.EpochPath, "rosettax87", "rosettax87"),
lPath: filepath.Join(paths.EpochPath, "rosettax87", "libRuntimeRosettax87"),
}
for srcPath, destPath := range pathMap {
fBytes, err := os.ReadFile(srcPath)
if err != nil {
errMsg := fmt.Sprintf("failed to read source file %s: %v", srcPath, err)
dialog.ShowError(errors.New(errMsg), currentWindow)
log.Debug(errMsg)
return
}
err = os.WriteFile(destPath, fBytes, 0755)
if err != nil {
errMsg := fmt.Sprintf("failed to write file %s: %v", destPath, err)
dialog.ShowError(errors.New(errMsg), currentWindow)
log.Debug(errMsg)
return
}
log.Debugf("Successfully copied %s to %s", srcPath, destPath)
}
dialog.ShowInformation("Build Successful", "Rosettax87 installed successfully.", currentWindow)
}
}, currentWindow).Show()
})
troubleshootingTitle := widget.NewLabel("Troubleshooting")
troubleshootingTitle.TextStyle = fyne.TextStyle{Bold: true}
rowCrossover := container.NewBorder(nil, nil, widget.NewLabel("CrossOver version:"), crossoverStatusShort, nil)
rowWDB := container.NewBorder(nil, nil, widget.NewLabel("Delete WDB directory (cache):"), wdbDeleteButton, nil)
rowWine := container.NewBorder(nil, nil, widget.NewLabel("Delete Wine prefixes (~/.wine & Epoch/.wine):"), wineDeleteButton, nil)
rowBuildRosetta := container.NewBorder(nil, nil, widget.NewLabel("Build Rosettax87 locally:"), buildRosettaButton, nil)
appMgmtNote := widget.NewLabel("Please ensure EpochSilicon is enabled in System Settings > Privacy & Security > App Management.")
appMgmtNote.Wrapping = fyne.TextWrapWord
appMgmtNote.TextStyle = fyne.TextStyle{Italic: true}
@@ -214,6 +290,7 @@ func showTroubleshootingPopup() {
crossoverStatusDetail,
rowWDB,
rowWine,
rowBuildRosetta,
appMgmtNote,
)

View File

@@ -1,7 +1,7 @@
package ui
import (
"epochsilicon/pkg/debug"
"epochsilicon/pkg/log"
"git.burkey.co/eburk/epochcli/pkg/epoch"
"os"
"path/filepath"
@@ -108,26 +108,24 @@ func updateEpochStatus() {
// Check for Epoch-specific files
epochPatchesApplied := false
stats, err := epoch.Update(paths.EpochPath, false, true, true)
if err != nil {
debug.Printf("Failed to get download Epoch patches: %v", err)
}
stats := epoch.Update(paths.EpochPath, false, true, true)
if stats.Error != nil {
log.Error(stats.Error.Error())
} else {
if stats.Outdated == 0 {
debug.Println("Nothing is outdated")
epochPatchesApplied = true
}
}
// Check if patched files have the correct size (matches bundled versions)
winerosettaDllCorrectSize := utils.CompareFileWithBundledResource(winerosettaDllPath, "winerosetta/winerosetta.dll")
d3d9DllCorrectSize := utils.CompareFileWithBundledResource(d3d9DllPath, "winerosetta/d3d9.dll")
rosettaX87CorrectSize := utils.CompareFileWithBundledResource(rosettaX87ExePath, "rosettax87/rosettax87")
libRuntimeRosettaX87CorrectSize := utils.CompareFileWithBundledResource(libRuntimeRosettaX87Path, "rosettax87/libRuntimeRosettax87")
if utils.PathExists(winerosettaDllPath) && utils.PathExists(d3d9DllPath) &&
utils.DirExists(rosettaX87DirPath) && utils.PathExists(rosettaX87ExePath) &&
utils.PathExists(libRuntimeRosettaX87Path) && dllsFileValid &&
winerosettaDllCorrectSize && d3d9DllCorrectSize &&
rosettaX87CorrectSize && libRuntimeRosettaX87CorrectSize && epochPatchesApplied {
epochPatchesApplied {
paths.PatchesAppliedEpoch = true
}

View File

@@ -1,11 +1,11 @@
package ui
import (
"epochsilicon/pkg/log"
"fmt"
"strings"
"time"
"epochsilicon/pkg/debug"
"epochsilicon/pkg/utils"
"fyne.io/fyne/v2"
@@ -105,7 +105,7 @@ func ShowUpdateDialog(updateInfo *utils.UpdateInfo, currentVersion string, myWin
if err != nil {
progressLabel.SetText(fmt.Sprintf("Download failed: %v", err))
debug.Printf("Download failed: %v", err)
log.Debugf("Download failed: %v", err)
// Re-enable close button
d.SetButtons([]fyne.CanvasObject{
@@ -123,7 +123,7 @@ func ShowUpdateDialog(updateInfo *utils.UpdateInfo, currentVersion string, myWin
err = utils.InstallUpdate(downloadPath)
if err != nil {
progressLabel.SetText(fmt.Sprintf("Installation failed: %v", err))
debug.Printf("Installation failed: %v", err)
log.Debugf("Installation failed: %v", err)
// Re-enable close button
fyne.DoAndWait(func() {

View File

@@ -31,6 +31,7 @@ var (
metalHudCheckbox *widget.Check
showTerminalCheckbox *widget.Check
autoDeleteWdbCheckbox *widget.Check
advancedLoggingCheckbox *widget.Check
// Recommended settings button
applyRecommendedSettingsButton *widget.Button
@@ -60,6 +61,7 @@ var (
crossoverVersionStatusLabel *widget.RichText
wdbDeleteButton *widget.Button
wineDeleteButton *widget.Button
buildRosettaButton *widget.Button
appMgmtPermissionButton *widget.Button
troubleshootingCloseButton *widget.Button
)

View File

@@ -1,8 +1,8 @@
package utils
import (
"epochsilicon/pkg/log"
"fmt"
"log"
"github.com/zalando/go-keyring"
)
@@ -23,7 +23,7 @@ func SaveSudoPassword(password string) error {
return fmt.Errorf("failed to save password to keychain: %v", err)
}
log.Println("Password saved securely to keychain")
log.Info("Password saved securely to keychain")
return nil
}
@@ -52,7 +52,7 @@ func DeleteSudoPassword() error {
return fmt.Errorf("failed to delete password from keychain: %v", err)
}
log.Println("Password removed from keychain")
log.Info("Password removed from keychain")
return nil
}

View File

@@ -16,6 +16,7 @@ type UserPrefs struct {
RemapOptionAsAlt bool `json:"remap_option_as_alt"`
AutoDeleteWdb bool `json:"auto_delete_wdb"`
EnableMetalHud bool `json:"enable_metal_hud"`
AdvancedLogging bool `json:"advanced_logging"`
}
func getPrefsPath() (string, error) {

View File

@@ -2,8 +2,10 @@ package utils
import (
"encoding/json"
"epochsilicon/pkg/log"
"errors"
"fmt"
"github.com/Masterminds/semver/v3"
"io"
"net/http"
"os"
@@ -11,8 +13,6 @@ import (
"path/filepath"
"strings"
"epochsilicon/pkg/debug"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/dialog"
)
@@ -104,16 +104,16 @@ func CopyDir(src string, dst string) error {
// RunOsascript runs an AppleScript command using osascript.
func RunOsascript(scriptString string, myWindow fyne.Window) bool {
debug.Printf("Executing AppleScript: %s", scriptString)
log.Debugf("Executing AppleScript: %s", scriptString)
cmd := exec.Command("osascript", "-e", scriptString)
output, err := cmd.CombinedOutput()
if err != nil {
errMsg := fmt.Sprintf("AppleScript failed: %v\nOutput: %s", err, string(output))
dialog.ShowError(errors.New(errMsg), myWindow)
debug.Println(errMsg)
log.Debug(errMsg)
return false
}
debug.Printf("osascript output: %s", string(output))
log.Debugf("osascript output: %s", string(output))
return true
}
@@ -129,25 +129,6 @@ func QuotePathForShell(path string) string {
return fmt.Sprintf(`"%s"`, path)
}
func CheckForUpdate(currentVersion string) (latestVersion, releaseNotes string, updateAvailable bool, err error) {
resp, err := http.Get("https://api.github.com/repos/tairasu/EpochSilicon/releases/latest")
if err != nil {
return "", "", false, err
}
defer resp.Body.Close()
var data struct {
TagName string `json:"tag_name"`
Body string `json:"body"`
}
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return "", "", false, err
}
latest := strings.TrimPrefix(data.TagName, "v")
return latest, data.Body, latest != currentVersion, nil
}
// UpdateInfo contains information about the latest release
type UpdateInfo struct {
TagName string `json:"tag_name"`
@@ -162,7 +143,7 @@ type Asset struct {
}
// CheckForUpdateWithAssets returns update information including download assets
func CheckForUpdateWithAssets(currentVersion string) (*UpdateInfo, bool, error) {
func CheckForUpdateWithAssets(currentVersion *semver.Version) (*UpdateInfo, bool, error) {
resp, err := http.Get("https://git.burkey.co/api/v1/repos/eburk/epochsilicon/releases/latest")
if err != nil {
return nil, false, err
@@ -192,8 +173,11 @@ func CheckForUpdateWithAssets(currentVersion string) (*UpdateInfo, bool, error)
return nil, false, fmt.Errorf("failed to parse JSON response: %v. Response: %s", err, bodyStr[:min(200, len(bodyStr))])
}
latest := strings.TrimPrefix(updateInfo.TagName, "v")
updateAvailable := latest != currentVersion
latest, err := semver.NewVersion(updateInfo.TagName)
if err != nil {
return nil, false, fmt.Errorf("failed to parse semver: %v", err)
}
updateAvailable := latest.GreaterThan(currentVersion)
return &updateInfo, updateAvailable, nil
}
@@ -264,14 +248,14 @@ func InstallUpdate(dmgPath string) error {
}
// Mount the DMG and parse the mount point from plist output
debug.Printf("Mounting DMG: %s", dmgPath)
log.Debugf("Mounting DMG: %s", dmgPath)
mountCmd := exec.Command("hdiutil", "attach", dmgPath, "-nobrowse", "-plist")
mountOutput, err := mountCmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to mount DMG: %v, output: %s", err, string(mountOutput))
}
debug.Printf("Mount output: %s", string(mountOutput))
log.Debugf("Mount output: %s", string(mountOutput))
mountPoint := ""
@@ -292,7 +276,7 @@ func InstallUpdate(dmgPath string) error {
end := strings.Index(nextLine, "</string>")
if start >= 8 && end > start {
mountPoint = nextLine[start:end]
debug.Printf("Found mount point in plist: %s", mountPoint)
log.Debugf("Found mount point in plist: %s", mountPoint)
break
}
}
@@ -301,7 +285,7 @@ func InstallUpdate(dmgPath string) error {
// Fallback: try without -plist flag for simpler output
if mountPoint == "" {
debug.Printf("Plist parsing failed, trying simple mount")
log.Debugf("Plist parsing failed, trying simple mount")
// Unmount first if something was mounted
exec.Command("hdiutil", "detach", dmgPath, "-force").Run()
@@ -321,7 +305,7 @@ func InstallUpdate(dmgPath string) error {
for i := len(parts) - 1; i >= 0; i-- {
if strings.HasPrefix(parts[i], "/Volumes/") {
mountPoint = parts[i]
debug.Printf("Found mount point in simple output: %s", mountPoint)
log.Debugf("Found mount point in simple output: %s", mountPoint)
break
}
}
@@ -336,11 +320,11 @@ func InstallUpdate(dmgPath string) error {
return fmt.Errorf("could not find mount point. Mount output: %s", string(mountOutput))
}
debug.Printf("Using mount point: %s", mountPoint)
log.Debugf("Using mount point: %s", mountPoint)
defer func() {
// Unmount the DMG
debug.Printf("Unmounting DMG from: %s", mountPoint)
log.Debugf("Unmounting DMG from: %s", mountPoint)
unmountCmd := exec.Command("hdiutil", "detach", mountPoint, "-force")
unmountCmd.Run()
}()
@@ -354,7 +338,7 @@ func InstallUpdate(dmgPath string) error {
newAppPath = exactPath
} else {
// Search for any .app bundle in the mount point
debug.Printf("EpochSilicon.app not found at exact path, searching for .app bundles")
log.Debugf("EpochSilicon.app not found at exact path, searching for .app bundles")
entries, err := os.ReadDir(mountPoint)
if err != nil {
return fmt.Errorf("failed to read DMG contents: %v", err)
@@ -363,7 +347,7 @@ func InstallUpdate(dmgPath string) error {
for _, entry := range entries {
if entry.IsDir() && strings.HasSuffix(entry.Name(), ".app") {
candidatePath := filepath.Join(mountPoint, entry.Name())
debug.Printf("Found .app bundle: %s", candidatePath)
log.Debugf("Found .app bundle: %s", candidatePath)
newAppPath = candidatePath
break
}
@@ -374,11 +358,11 @@ func InstallUpdate(dmgPath string) error {
return fmt.Errorf("no .app bundle found in DMG at %s", mountPoint)
}
debug.Printf("Found app to install: %s", newAppPath)
log.Debugf("Found app to install: %s", newAppPath)
// Create backup of current app
backupPath := currentAppPath + ".backup"
debug.Printf("Creating backup: %s -> %s", currentAppPath, backupPath)
log.Debugf("Creating backup: %s -> %s", currentAppPath, backupPath)
// Remove old backup if it exists
if PathExists(backupPath) {
@@ -390,16 +374,16 @@ func InstallUpdate(dmgPath string) error {
}
// Remove current app
debug.Printf("Removing current app: %s", currentAppPath)
log.Debugf("Removing current app: %s", currentAppPath)
if err := os.RemoveAll(currentAppPath); err != nil {
return fmt.Errorf("failed to remove current app: %v", err)
}
// Copy new app
debug.Printf("Installing new app: %s -> %s", newAppPath, currentAppPath)
log.Debugf("Installing new app: %s -> %s", newAppPath, currentAppPath)
if err := CopyDir(newAppPath, currentAppPath); err != nil {
// Try to restore backup on failure
debug.Printf("Installation failed, restoring backup")
log.Debugf("Installation failed, restoring backup")
os.RemoveAll(currentAppPath)
CopyDir(backupPath, currentAppPath)
return fmt.Errorf("failed to install new app: %v", err)
@@ -408,25 +392,25 @@ func InstallUpdate(dmgPath string) error {
// Fix executable permissions for the main binary
executablePath := filepath.Join(currentAppPath, "Contents", "MacOS", "epochsilicon")
if PathExists(executablePath) {
debug.Printf("Setting executable permissions for: %s", executablePath)
log.Debugf("Setting executable permissions for: %s", executablePath)
if err := os.Chmod(executablePath, 0755); err != nil {
debug.Printf("Warning: failed to set executable permissions: %v", err)
log.Debugf("Warning: failed to set executable permissions: %v", err)
// Don't fail the entire update for this, but log it
}
} else {
debug.Printf("Warning: executable not found at expected path: %s", executablePath)
log.Debugf("Warning: executable not found at expected path: %s", executablePath)
}
// Remove backup on success
os.RemoveAll(backupPath)
debug.Printf("Update installed successfully")
log.Debugf("Update installed successfully")
return nil
}
// TestDMGMount tests DMG mounting and returns mount point and app path for debugging
func TestDMGMount(dmgPath string) (string, string, error) {
debug.Printf("Testing DMG mount: %s", dmgPath)
log.Debugf("Testing DMG mount: %s", dmgPath)
// Mount the DMG with verbose output to better parse mount point
mountCmd := exec.Command("hdiutil", "attach", dmgPath, "-nobrowse", "-plist")
@@ -435,7 +419,7 @@ func TestDMGMount(dmgPath string) (string, string, error) {
return "", "", fmt.Errorf("failed to mount DMG: %v, output: %s", err, string(mountOutput))
}
debug.Printf("Mount output: %s", string(mountOutput))
log.Debugf("Mount output: %s", string(mountOutput))
// Parse mount output to get mount point
mountPoint := ""
@@ -460,7 +444,7 @@ func TestDMGMount(dmgPath string) (string, string, error) {
// Second try: use hdiutil info to get mount points if first method failed
if mountPoint == "" {
debug.Printf("First mount point detection failed, trying hdiutil info")
log.Debugf("First mount point detection failed, trying hdiutil info")
infoCmd := exec.Command("hdiutil", "info", "-plist")
infoOutput, infoErr := infoCmd.CombinedOutput()
if infoErr == nil {
@@ -481,7 +465,7 @@ func TestDMGMount(dmgPath string) (string, string, error) {
return "", "", fmt.Errorf("could not find mount point. Mount output: %s", string(mountOutput))
}
debug.Printf("Using mount point: %s", mountPoint)
log.Debugf("Using mount point: %s", mountPoint)
// Find the app in the mounted DMG
var newAppPath string
@@ -492,7 +476,7 @@ func TestDMGMount(dmgPath string) (string, string, error) {
newAppPath = exactPath
} else {
// Search for any .app bundle in the mount point
debug.Printf("EpochSilicon.app not found at exact path, searching for .app bundles")
log.Debugf("EpochSilicon.app not found at exact path, searching for .app bundles")
entries, err := os.ReadDir(mountPoint)
if err != nil {
// Unmount before returning error
@@ -503,7 +487,7 @@ func TestDMGMount(dmgPath string) (string, string, error) {
for _, entry := range entries {
if entry.IsDir() && strings.HasSuffix(entry.Name(), ".app") {
candidatePath := filepath.Join(mountPoint, entry.Name())
debug.Printf("Found .app bundle: %s", candidatePath)
log.Debugf("Found .app bundle: %s", candidatePath)
newAppPath = candidatePath
break
}
@@ -511,7 +495,7 @@ func TestDMGMount(dmgPath string) (string, string, error) {
}
// Unmount after testing
debug.Printf("Unmounting test DMG from: %s", mountPoint)
log.Debugf("Unmounting test DMG from: %s", mountPoint)
exec.Command("hdiutil", "detach", mountPoint, "-force").Run()
if newAppPath == "" {
@@ -531,14 +515,14 @@ func CompareFileWithBundledResource(filePath, resourceName string) bool {
// Get file info for the existing file
fileInfo, err := os.Stat(filePath)
if err != nil {
debug.Printf("Failed to stat file %s: %v", filePath, err)
log.Debugf("Failed to stat file %s: %v", filePath, err)
return false
}
// Load the bundled resource
resource, err := fyne.LoadResourceFromPath(resourceName)
if err != nil {
debug.Printf("Failed to load bundled resource %s: %v", resourceName, err)
log.Debugf("Failed to load bundled resource %s: %v", resourceName, err)
return false
}
@@ -546,7 +530,7 @@ func CompareFileWithBundledResource(filePath, resourceName string) bool {
fileSize := fileInfo.Size()
resourceSize := int64(len(resource.Content()))
debug.Printf("Comparing file sizes - %s: %d bytes vs bundled %s: %d bytes",
log.Debugf("Comparing file sizes - %s: %d bytes vs bundled %s: %d bytes",
filePath, fileSize, resourceName, resourceSize)
return fileSize == resourceSize

View File

@@ -1,8 +1,8 @@
package utils
import (
"epochsilicon/pkg/log"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
@@ -74,7 +74,7 @@ reg add "%s" /v "RightOptionIsAlt" /t REG_SZ /d "Y" /f
return fmt.Errorf("batch registry add failed: %v, output: %s", err, string(output))
}
log.Printf("Successfully enabled Option-as-Alt mapping in Wine registry (optimized)")
log.Infof("Successfully enabled Option-as-Alt mapping in Wine registry (optimized)")
return nil
}
@@ -102,7 +102,7 @@ reg delete "%s" /v "RightOptionIsAlt" /f 2>nul
return fmt.Errorf("batch registry delete failed: %v, output: %s", err, string(output))
}
log.Printf("Successfully disabled Option-as-Alt mapping in Wine registry (optimized)")
log.Infof("Successfully disabled Option-as-Alt mapping in Wine registry (optimized)")
return nil
}
@@ -110,7 +110,7 @@ reg delete "%s" /v "RightOptionIsAlt" /f 2>nul
func CheckOptionAsAltEnabled() bool {
homeDir, err := os.UserHomeDir()
if err != nil {
log.Printf("Failed to get user home directory: %v", err)
log.Infof("Failed to get user home directory: %v", err)
return false
}
@@ -118,7 +118,7 @@ func CheckOptionAsAltEnabled() bool {
// Check if CrossOver wine loader exists
if !PathExists(wineLoaderPath) {
log.Printf("CrossOver wine loader not found at: %s", wineLoaderPath)
log.Infof("CrossOver wine loader not found at: %s", wineLoaderPath)
return false
}
@@ -133,18 +133,18 @@ func CheckOptionAsAltEnabled() bool {
func CheckOptionAsAltEnabledFast() bool {
regPath, err := GetWineUserRegPath()
if err != nil {
log.Printf("Failed to get Wine registry path: %v", err)
log.Infof("Failed to get Wine registry path: %v", err)
return false
}
if !PathExists(regPath) {
log.Printf("Wine user.reg file not found at: %s", regPath)
log.Infof("Wine user.reg file not found at: %s", regPath)
return false
}
content, err := os.ReadFile(regPath)
if err != nil {
log.Printf("Failed to read Wine registry file: %v", err)
log.Infof("Failed to read Wine registry file: %v", err)
return false
}
@@ -191,12 +191,12 @@ func SetOptionAsAltEnabled(enabled bool) error {
} else {
err := setRegistryValuesOptimized(winePrefix, false)
if err != nil {
log.Printf("Wine registry disable failed: %v", err)
log.Infof("Wine registry disable failed: %v", err)
}
err2 := setRegistryValuesFast(false)
if err2 != nil {
log.Printf("File-based cleanup failed: %v", err2)
log.Infof("File-based cleanup failed: %v", err2)
}
if err != nil {
@@ -334,7 +334,7 @@ func addOptionAsAltSettingsFast(regPath string, lines []string) error {
return fmt.Errorf("failed to write registry file: %v", err)
}
log.Printf("Successfully enabled Option-as-Alt mapping in Wine registry (fast method)")
log.Infof("Successfully enabled Option-as-Alt mapping in Wine registry (fast method)")
return nil
}
@@ -342,7 +342,7 @@ func addOptionAsAltSettingsFast(regPath string, lines []string) error {
func removeOptionAsAltSettingsFast(regPath string, lines []string) error {
if !PathExists(regPath) {
// File doesn't exist, nothing to remove
log.Printf("Successfully disabled Option-as-Alt mapping in Wine registry (no file to modify)")
log.Infof("Successfully disabled Option-as-Alt mapping in Wine registry (no file to modify)")
return nil
}
@@ -369,7 +369,7 @@ func removeOptionAsAltSettingsFast(regPath string, lines []string) error {
return fmt.Errorf("failed to write registry file: %v", err)
}
log.Printf("Successfully disabled Option-as-Alt mapping in Wine registry (fast method)")
log.Infof("Successfully disabled Option-as-Alt mapping in Wine registry (fast method)")
return nil
}