33package winegdk
44
55import (
6+ "archive/tar"
67 "bufio"
8+ "compress/gzip"
79 "context"
10+ "io"
11+ "net/http"
812 "os"
913 "os/exec"
1014 "path/filepath"
@@ -28,94 +32,63 @@ func Setup(ctx context.Context) string {
2832 return "ERR_BASE_ROOT"
2933 }
3034 application .Get ().Event .Emit (EventSetupStatus , "start" )
31- // Prefer Wine built from WineGDK (local path)
32- wg := filepath .Join (base , "WineGDK" )
33- bd := filepath .Join (wg , "build" )
34- wineBin := func () string {
35- cands := []string {filepath .Join (bd , "wine" ), filepath .Join (bd , "wine64" )}
36- for _ , p := range cands { if fi , err := os .Stat (p ); err == nil && fi .Mode ().IsRegular () { return p } }
37- return ""
38- }()
39- if strings .TrimSpace (wineBin ) == "" {
40- application .Get ().Event .Emit (EventSetupStatus , "deps_warning_wine_missing" )
35+ wineDir := filepath .Join (base , "wine" )
36+ _ = os .MkdirAll (wineDir , 0755 )
37+ url := "https://github.com/Weather-OS/GDK-Proton/releases/download/release/GE-Proton10-25.tar.gz"
38+ tmp := filepath .Join (wineDir , "GE-Proton10-25.tar.gz" )
39+ application .Get ().Event .Emit (EventSetupStatus , "download_start" )
40+ if err := downloadWithProgress (url , tmp , "download" ); err != nil {
41+ application .Get ().Event .Emit (EventSetupError , "ERR_DOWNLOAD" )
42+ return "ERR_DOWNLOAD"
4143 }
42- id := func () string {
43- b , err := os .ReadFile ("/etc/os-release" )
44- if err != nil {
45- return ""
46- }
47- for _ , l := range strings .Split (string (b ), "\n " ) {
48- s := strings .TrimSpace (l )
49- if strings .HasPrefix (s , "ID=" ) {
50- v := strings .TrimPrefix (s , "ID=" )
51- v = strings .Trim (v , "\" '" )
52- return strings .ToLower (strings .TrimSpace (v ))
53- }
54- }
55- return ""
56- }()
57- if id == "arch" {
58- application .Get ().Event .Emit (EventSetupStatus , "deps_warning_arch" )
59- pkgs := "mingw-w64-gcc base-devel git gcc multilib-devel winetricks wine vulkan-icd-loader lib32-vulkan-icd-loader libx11 lib32-libx11 freetype2 lib32-freetype2 mesa lib32-mesa glu lib32-glu alsa-lib lib32-alsa-lib libxrandr lib32-libxrandr libxi lib32-libxi libxext lib32-libxext libxrender lib32-libxrender libxcursor lib32-libxcursor libxinerama lib32-libxinerama libxcomposite lib32-libxcomposite libxfixes lib32-libxfixes libpng lib32-libpng libjpeg-turbo lib32-libjpeg-turbo libtiff lib32-libtiff openal lib32-openal mpg123 lib32-mpg123 sdl2 lib32-sdl2 libxml2 lib32-libxml2 libldap lib32-libldap vulkan-headers cups"
60- application .Get ().Event .Emit (EventSetupStatus , "deps_install_arch" )
61- cmd := exec .Command ("bash" , "-c" , "sudo pacman -S --needed --noconfirm " + pkgs )
62- _ = streamCmd (cmd , "deps" )
63- } else {
64- application .Get ().Event .Emit (EventSetupStatus , "deps_warning_other" )
65- }
66- if _ , err := os .Stat (wg ); err != nil {
67- application .Get ().Event .Emit (EventSetupStatus , "cloning" )
68- cmd := exec .Command ("git" , "clone" , "https://github.com/Weather-OS/WineGDK.git" , wg )
69- if err := streamCmd (cmd , "clone" ); err != nil {
70- application .Get ().Event .Emit (EventSetupError , "ERR_GIT_CLONE" )
71- return "ERR_GIT_CLONE"
72- }
73- } else {
74- application .Get ().Event .Emit (EventSetupStatus , "updating" )
75- _ = streamCmd (exec .Command ("bash" , "-c" , "cd '" + wg + "' && git remote update" ), "update" )
44+ application .Get ().Event .Emit (EventSetupStatus , "extract_start" )
45+ f , err := os .Open (tmp )
46+ if err != nil {
47+ application .Get ().Event .Emit (EventSetupError , "ERR_OPEN_TAR" )
48+ return "ERR_OPEN_TAR"
7649 }
77- needBuild := false
78- if _ , err := os .Stat (wg ); err == nil {
79- chk := exec .Command ("bash" , "-c" , "cd '" + wg + "' && if [ \" $(git rev-parse HEAD)\" = \" $(git rev-parse @{u})\" ]; then echo up_to_date; else echo needs_update; fi" )
80- out , _ := chk .CombinedOutput ()
81- s := strings .ToLower (strings .TrimSpace (string (out )))
82- if s == "needs_update" {
83- application .Get ().Event .Emit (EventSetupStatus , "pulling" )
84- if er := streamCmd (exec .Command ("bash" , "-c" , "cd '" + wg + "' && git pull --rebase" ), "pull" ); er != nil {
85- application .Get ().Event .Emit (EventSetupError , "ERR_GIT_PULL" )
86- return "ERR_GIT_PULL"
87- }
88- needBuild = true
89- }
90- // Build if local wine binary is missing
91- if strings .TrimSpace (wineBin ) == "" {
92- needBuild = true
93- }
94- } else {
95- needBuild = true
50+ defer f .Close ()
51+ gz , err := gzip .NewReader (f )
52+ if err != nil {
53+ application .Get ().Event .Emit (EventSetupError , "ERR_OPEN_GZ" )
54+ return "ERR_OPEN_GZ"
9655 }
97- _ = os .MkdirAll (bd , 0755 )
98- if needBuild {
99- application .Get ().Event .Emit (EventSetupStatus , "configuring" )
100- cfg := exec .Command ("bash" , "-c" , "cd '" + bd + "' && ../configure --enable-win64" )
101- if err := streamCmd (cfg , "configure" ); err != nil {
102- application .Get ().Event .Emit (EventSetupError , "ERR_CONFIGURE" )
103- return "ERR_CONFIGURE"
56+ defer gz .Close ()
57+ tr := tar .NewReader (gz )
58+ for {
59+ hdr , er := tr .Next ()
60+ if er == io .EOF { break }
61+ if er != nil { application .Get ().Event .Emit (EventSetupError , "ERR_EXTRACT" ); return "ERR_EXTRACT" }
62+ name := strings .TrimSpace (hdr .Name )
63+ if name == "" { continue }
64+ parts := strings .SplitN (name , "/" , 2 )
65+ if len (parts ) < 2 { continue }
66+ rel := parts [1 ]
67+ if strings .TrimSpace (rel ) == "" { continue }
68+ outPath := filepath .Join (wineDir , rel )
69+ switch hdr .Typeflag {
70+ case tar .TypeDir :
71+ _ = os .MkdirAll (outPath , os .FileMode (hdr .Mode ))
72+ case tar .TypeReg :
73+ if err := os .MkdirAll (filepath .Dir (outPath ), 0755 ); err != nil { application .Get ().Event .Emit (EventSetupError , "ERR_WRITE_FILE" ); return "ERR_WRITE_FILE" }
74+ of , e2 := os .OpenFile (outPath , os .O_CREATE | os .O_WRONLY | os .O_TRUNC , os .FileMode (hdr .Mode ))
75+ if e2 != nil { application .Get ().Event .Emit (EventSetupError , "ERR_WRITE_FILE" ); return "ERR_WRITE_FILE" }
76+ if _ , e3 := io .Copy (of , tr ); e3 != nil { _ = of .Close (); application .Get ().Event .Emit (EventSetupError , "ERR_WRITE_FILE" ); return "ERR_WRITE_FILE" }
77+ _ = of .Close ()
78+ default :
10479 }
105- application .Get ().Event .Emit (EventSetupStatus , "compiling" )
106- mk := exec .Command ("bash" , "-c" , "cd '" + bd + "' && make -j$(nproc)" )
107- if err := streamCmd (mk , "make" ); err != nil {
108- application .Get ().Event .Emit (EventSetupError , "ERR_MAKE" )
109- return "ERR_MAKE"
80+ application .Get ().Event .Emit (EventSetupProgress , map [string ]interface {}{"phase" : "extract" , "line" : rel })
81+ }
82+ _ = os .Remove (tmp )
83+ wineBin := filepath .Join (wineDir , "files" , "bin" , "wine" )
84+ if _ , err := os .Stat (wineBin ); err != nil {
85+ wow := filepath .Join (wineDir , "files" , "bin-wow64" , "wine" )
86+ if _ , er2 := os .Stat (wow ); er2 == nil {
87+ wineBin = wow
88+ } else {
89+ alt := filepath .Join (wineDir , "files" , "bin" , "wine64" )
90+ if _ , er3 := os .Stat (alt ); er3 == nil { wineBin = alt } else { application .Get ().Event .Emit (EventSetupError , "ERR_WINE_NOT_AVAILABLE" ); return "ERR_WINE_NOT_AVAILABLE" }
11091 }
111- // refresh wineBin after build
112- wineBin = func () string {
113- cands := []string {filepath .Join (bd , "wine" ), filepath .Join (bd , "wine64" )}
114- for _ , p := range cands { if fi , err := os .Stat (p ); err == nil && fi .Mode ().IsRegular () { return p } }
115- return ""
116- }()
117- } else {
118- application .Get ().Event .Emit (EventSetupStatus , "skip_build" )
11992 }
12093 pf := filepath .Join (base , "prefix" )
12194 _ = os .MkdirAll (pf , 0755 )
@@ -129,6 +102,29 @@ func Setup(ctx context.Context) string {
129102 return ""
130103}
131104
105+ func downloadWithProgress (url string , dest string , phase string ) error {
106+ resp , err := http .Get (url )
107+ if err != nil { return err }
108+ defer resp .Body .Close ()
109+ if resp .StatusCode != 200 { return io .ErrUnexpectedEOF }
110+ if err := os .MkdirAll (filepath .Dir (dest ), 0755 ); err != nil { return err }
111+ f , err := os .OpenFile (dest , os .O_CREATE | os .O_WRONLY | os .O_TRUNC , 0644 )
112+ if err != nil { return err }
113+ defer f .Close ()
114+ buf := make ([]byte , 256 * 1024 )
115+ var total int64
116+ for {
117+ n , e := resp .Body .Read (buf )
118+ if n > 0 {
119+ if _ , werr := f .Write (buf [:n ]); werr != nil { return werr }
120+ total += int64 (n )
121+ application .Get ().Event .Emit (EventSetupProgress , map [string ]interface {}{"phase" : phase , "line" : total })
122+ }
123+ if e != nil { if e == io .EOF { break } else { return e } }
124+ }
125+ return nil
126+ }
127+
132128func streamCmd (cmd * exec.Cmd , phase string ) error {
133129 stdout , _ := cmd .StdoutPipe ()
134130 stderr , _ := cmd .StderrPipe ()
0 commit comments