Compare commits
17 Commits
improve-lo
...
main
Author | SHA1 | Date | |
---|---|---|---|
718eace492 | |||
ca77c609cd | |||
502ca7a4f2 | |||
7397fae6f4 | |||
a07958563a | |||
c80204579f | |||
11909e8502 | |||
8ec2cc6da2 | |||
14db7719a3 | |||
d03c5ee7cc | |||
704570d4a7 | |||
49b696c898 | |||
4e22ca8714 | |||
a973508d92 | |||
8edd61dbba | |||
eafc55f67c | |||
bc80ca2c9c |
@@ -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
|
||||
|
6
Makefile
6
Makefile
@@ -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..."
|
||||
|
34
README.md
34
README.md
@@ -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
24
go.mod
@@ -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
125
go.sum
@@ -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
19
main.go
@@ -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()
|
||||
})
|
||||
|
@@ -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...)
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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
|
||||
|
||||
@@ -16,10 +16,9 @@ import (
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
)
|
||||
|
||||
var EnableMetalHud = false // Default to disabled
|
||||
var CustomEnvVars = "" // Custom environment variables
|
||||
var EnableVanillaTweaks = false // Default to disabled
|
||||
var AutoDeleteWdb = false // Default to disabled
|
||||
var EnableMetalHud = false // Default to disabled
|
||||
var CustomEnvVars = "" // Custom environment variables
|
||||
var AutoDeleteWdb = false // Default to disabled
|
||||
|
||||
// Terminal state management
|
||||
var (
|
||||
@@ -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,29 +200,12 @@ 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...")
|
||||
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.")
|
||||
// Use 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
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
126
pkg/log/logging.go
Normal 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)
|
||||
}
|
@@ -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,92 +82,96 @@ 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.RemoveAll(targetRosettaX87Dir); err != nil {
|
||||
debug.Printf("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)
|
||||
paths.PatchesAppliedEpoch = false
|
||||
updateAllStatuses()
|
||||
return
|
||||
}
|
||||
|
||||
rosettaFilesToCopy := map[string]string{
|
||||
"rosettax87/rosettax87": filepath.Join(targetRosettaX87Dir, "rosettax87"),
|
||||
"rosettax87/libRuntimeRosettax87": filepath.Join(targetRosettaX87Dir, "libRuntimeRosettax87"),
|
||||
}
|
||||
|
||||
for resourceName, destPath := range rosettaFilesToCopy {
|
||||
debug.Printf("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)
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
destinationFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("failed to create destination file %s: %v", destPath, err)
|
||||
dialog.ShowError(errors.New(errMsg), myWindow)
|
||||
debug.Println(errMsg)
|
||||
paths.PatchesAppliedEpoch = false
|
||||
updateAllStatuses()
|
||||
return
|
||||
rosettaFilesToCopy := map[string]string{
|
||||
"rosettax87/rosettax87": filepath.Join(targetRosettaX87Dir, "rosettax87"),
|
||||
"rosettax87/libRuntimeRosettax87": filepath.Join(targetRosettaX87Dir, "libRuntimeRosettax87"),
|
||||
}
|
||||
|
||||
_, err = io.Copy(destinationFile, bytes.NewReader(resource.Content()))
|
||||
if err != nil {
|
||||
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)
|
||||
paths.PatchesAppliedEpoch = false
|
||||
updateAllStatuses()
|
||||
return
|
||||
}
|
||||
destinationFile.Close()
|
||||
|
||||
if filepath.Base(destPath) == "rosettax87" {
|
||||
debug.Printf("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)
|
||||
for resourceName, destPath := range rosettaFilesToCopy {
|
||||
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
|
||||
}
|
||||
|
||||
destinationFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("failed to create destination file %s: %v", destPath, err)
|
||||
dialog.ShowError(errors.New(errMsg), myWindow)
|
||||
log.Debug(errMsg)
|
||||
paths.PatchesAppliedEpoch = false
|
||||
updateAllStatuses()
|
||||
return
|
||||
}
|
||||
|
||||
_, err = io.Copy(destinationFile, bytes.NewReader(resource.Content()))
|
||||
if err != nil {
|
||||
destinationFile.Close()
|
||||
errMsg := fmt.Sprintf("failed to copy bundled resource %s to %s: %v", resourceName, destPath, err)
|
||||
dialog.ShowError(errors.New(errMsg), myWindow)
|
||||
log.Debug(errMsg)
|
||||
paths.PatchesAppliedEpoch = false
|
||||
updateAllStatuses()
|
||||
return
|
||||
}
|
||||
destinationFile.Close()
|
||||
|
||||
if filepath.Base(destPath) == "rosettax87" {
|
||||
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)
|
||||
log.Debug(errMsg)
|
||||
paths.PatchesAppliedEpoch = false
|
||||
updateAllStatuses()
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Debugf("Successfully copied %s to %s", resourceName, destPath)
|
||||
}
|
||||
debug.Printf("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
|
||||
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 {
|
||||
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, err := epoch.Update(paths.EpochPath, true, true, false)
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("failed to update Epoch files: %v", err)
|
||||
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.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)
|
||||
})
|
||||
}
|
||||
log.Printf("Successfully updated %d Epoch files", stats.Updated)
|
||||
debug.Println("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
|
||||
}
|
||||
|
15
pkg/patching/patching_test.go
Normal file
15
pkg/patching/patching_test.go
Normal 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)
|
||||
}
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
)
|
||||
|
||||
@@ -222,11 +299,11 @@ func showTroubleshootingPopup() {
|
||||
troubleshootingCloseButton = widget.NewButton("Close", func() {})
|
||||
|
||||
popupContent := container.NewBorder(
|
||||
nil, // top
|
||||
nil, // top
|
||||
container.NewCenter(troubleshootingCloseButton), // bottom
|
||||
nil, // left
|
||||
nil, // right
|
||||
container.NewPadded(scrollContainer), // center
|
||||
nil, // left
|
||||
nil, // right
|
||||
container.NewPadded(scrollContainer), // center
|
||||
)
|
||||
|
||||
windowSize := currentWindow.Content().Size()
|
||||
|
@@ -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)
|
||||
}
|
||||
if stats.Outdated == 0 {
|
||||
debug.Println("Nothing is outdated")
|
||||
epochPatchesApplied = true
|
||||
stats := epoch.Update(paths.EpochPath, false, true, true)
|
||||
if stats.Error != nil {
|
||||
log.Error(stats.Error.Error())
|
||||
} else {
|
||||
if stats.Outdated == 0 {
|
||||
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
|
||||
}
|
||||
|
||||
|
@@ -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() {
|
||||
|
@@ -28,9 +28,10 @@ var (
|
||||
stopServiceButton *widget.Button
|
||||
|
||||
// Option checkboxes
|
||||
metalHudCheckbox *widget.Check
|
||||
showTerminalCheckbox *widget.Check
|
||||
autoDeleteWdbCheckbox *widget.Check
|
||||
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
|
||||
)
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user