11
11
from umu_plugins import enable_zenity
12
12
from socket import gaierror
13
13
from umu_log import log
14
- from umu_consts import STEAM_COMPAT , UMU_CACHE
14
+ from umu_consts import STEAM_COMPAT
15
+ from tempfile import mkdtemp
15
16
16
17
try :
17
18
from tarfile import tar_filter
@@ -29,34 +30,26 @@ def get_umu_proton(env: Dict[str, str]) -> Union[Dict[str, str]]:
29
30
fallback
30
31
"""
31
32
files : List [Tuple [str , str ]] = []
33
+ tmp : Path = Path (mkdtemp ())
32
34
33
- UMU_CACHE .mkdir (exist_ok = True , parents = True )
34
35
STEAM_COMPAT .mkdir (exist_ok = True , parents = True )
35
36
36
- # Prioritize the Steam compat
37
- if _get_from_steamcompat (env , STEAM_COMPAT , UMU_CACHE ):
38
- return env
39
-
40
37
try :
38
+ log .debug ("Sending request to api.github.com" )
41
39
files = _fetch_releases ()
42
40
except gaierror :
43
41
pass # User is offline
44
42
45
- # Use the latest Proton in the cache if it exists
46
- if _get_from_cache (env , STEAM_COMPAT , UMU_CACHE , files , True ):
47
- return env
48
-
49
- # Download the latest if Proton is not in Steam compat
50
- # If the digests mismatched, refer to the cache in the next block
51
- if _get_latest (env , STEAM_COMPAT , UMU_CACHE , files ):
43
+ # Download the latest Proton
44
+ if _get_latest (env , STEAM_COMPAT , tmp , files ):
52
45
return env
53
46
54
- # Refer to an old version previously downloaded
55
- # Reached on digest mismatch, user interrupt or download failure/no internet
56
- if _get_from_cache (env , STEAM_COMPAT , UMU_CACHE , files , False ):
47
+ # When offline or an error occurs, use the first Proton in
48
+ # compatibilitytools.d
49
+ if _get_from_steamcompat (env , STEAM_COMPAT ):
57
50
return env
58
51
59
- # No internet and cache/ compat tool is empty, just return and raise an
52
+ # No internet and compat tool is empty, just return and raise an
60
53
# exception from the caller
61
54
return env
62
55
@@ -68,10 +61,14 @@ def _fetch_releases() -> List[Tuple[str, str]]:
68
61
conn : HTTPConnection = HTTPSConnection (
69
62
"api.github.com" , timeout = 30 , context = create_default_context ()
70
63
)
64
+ repo : str = "/repos/Open-Wine-Components/umu-proton/releases"
65
+
66
+ if environ .get ("PROTONPATH" ) == "GE-Proton" :
67
+ repo = "/repos/GloriousEggroll/proton-ge-custom/releases"
71
68
72
69
conn .request (
73
70
"GET" ,
74
- "/repos/Open-Wine-Components/umu-proton/releases" ,
71
+ repo ,
75
72
headers = {
76
73
"Accept" : "application/vnd.github+json" ,
77
74
"X-GitHub-Api-Version" : "2022-11-28" ,
@@ -92,12 +89,14 @@ def _fetch_releases() -> List[Tuple[str, str]]:
92
89
93
90
for asset in assets :
94
91
if (
95
- "name" in asset
92
+ asset . get ( "name" )
96
93
and (
97
- asset [ "name" ] .endswith ("sum" )
94
+ asset . get ( "name" ) .endswith ("sum" )
98
95
or (
99
- asset ["name" ].endswith ("tar.gz" )
100
- and asset ["name" ].startswith (("umu-proton" , "ULWGL-Proton" ))
96
+ asset .get ("name" ).endswith ("tar.gz" )
97
+ and asset .get ("name" ).startswith (
98
+ ("umu-proton" , "ULWGL-Proton" , "GE-Proton" )
99
+ )
101
100
)
102
101
)
103
102
and "browser_download_url" in asset
@@ -119,7 +118,7 @@ def _fetch_releases() -> List[Tuple[str, str]]:
119
118
120
119
121
120
def _fetch_proton (
122
- env : Dict [str , str ], steam_compat : Path , cache : Path , files : List [Tuple [str , str ]]
121
+ env : Dict [str , str ], steam_compat : Path , tmp : Path , files : List [Tuple [str , str ]]
123
122
) -> Dict [str , str ]:
124
123
"""Download the latest umu-proton and set it as PROTONPATH."""
125
124
hash , hash_url = files [0 ]
@@ -144,7 +143,7 @@ def _fetch_proton(
144
143
f"github.com returned the status: { resp .status } "
145
144
)
146
145
raise HTTPException (err )
147
- with cache .joinpath (hash ).open (mode = "wb" ) as file :
146
+ with tmp .joinpath (hash ).open (mode = "wb" ) as file :
148
147
file .write (resp .read ())
149
148
150
149
# Proton
@@ -156,7 +155,7 @@ def _fetch_proton(
156
155
"--silent" ,
157
156
proton_url ,
158
157
"--output-dir" ,
159
- cache .as_posix (),
158
+ tmp .as_posix (),
160
159
]
161
160
162
161
msg : str = f"Downloading { proton_dir } ..."
@@ -176,21 +175,21 @@ def _fetch_proton(
176
175
f"github.com returned the status: { resp .status } "
177
176
)
178
177
raise HTTPException (err )
179
- with cache .joinpath (proton ).open (mode = "wb" ) as file :
178
+ with tmp .joinpath (proton ).open (mode = "wb" ) as file :
180
179
file .write (resp .read ())
181
180
182
181
log .console ("Completed." )
183
182
184
- with cache .joinpath (proton ).open (mode = "rb" ) as file :
183
+ with tmp .joinpath (proton ).open (mode = "rb" ) as file :
185
184
if (
186
185
sha512 (file .read ()).hexdigest ()
187
- != cache .joinpath (hash ).read_text ().split (" " )[0 ]
186
+ != tmp .joinpath (hash ).read_text ().split (" " )[0 ]
188
187
):
189
188
err : str = "Digests mismatched.\n Falling back to cache ..."
190
189
raise ValueError (err )
191
190
log .console (f"{ proton } : SHA512 is OK" )
192
191
193
- _extract_dir (cache .joinpath (proton ), steam_compat )
192
+ _extract_dir (tmp .joinpath (proton ), steam_compat )
194
193
environ ["PROTONPATH" ] = steam_compat .joinpath (proton_dir ).as_posix ()
195
194
env ["PROTONPATH" ] = environ ["PROTONPATH" ]
196
195
@@ -208,6 +207,8 @@ def _extract_dir(proton: Path, steam_compat: Path) -> None:
208
207
log .warning ("Archive will be extracted insecurely" )
209
208
210
209
log .console (f"Extracting { proton } -> { steam_compat } ..." )
210
+ # TODO: Rather than extracting all of the contents, we should prefer
211
+ # the difference (e.g., rsync)
211
212
tar .extractall (path = steam_compat .as_posix ()) # noqa: S202
212
213
log .console ("Completed." )
213
214
@@ -228,9 +229,13 @@ def _cleanup(tarball: str, proton: str, cache: Path, steam_compat: Path) -> None
228
229
229
230
230
231
def _get_from_steamcompat (
231
- env : Dict [str , str ], steam_compat : Path , cache : Path
232
+ env : Dict [str , str ], steam_compat : Path
232
233
) -> Union [Dict [str , str ], None ]:
233
- """Refer to Steam compat folder for any existing Proton directories."""
234
+ """Refer to Steam compat folder for any existing Proton directories.
235
+
236
+ Executed when an error occurs when retrieving and setting the latest
237
+ Proton
238
+ """
234
239
for proton in sorted (
235
240
[
236
241
proton
@@ -248,57 +253,8 @@ def _get_from_steamcompat(
248
253
return None
249
254
250
255
251
- def _get_from_cache (
252
- env : Dict [str , str ],
253
- steam_compat : Path ,
254
- cache : Path ,
255
- files : List [Tuple [str , str ]],
256
- use_latest : bool = True ,
257
- ) -> Union [Dict [str , str ], None ]:
258
- """Refer to umu cache directory.
259
-
260
- Use the latest in the cache when present. When download fails, use an old version
261
- Older Proton versions are only referred to when: digests mismatch, user
262
- interrupt, or download failure/no internet
263
- """
264
- resource : Tuple [Path , str ] = None # Path to the archive and its file name
265
-
266
- for tarball in [
267
- tarball
268
- for tarball in cache .glob ("*.tar.gz" )
269
- if tarball .name .startswith ("umu-proton" )
270
- or tarball .name .startswith ("ULWGL-Proton" )
271
- ]:
272
- # Online
273
- if files and tarball == cache .joinpath (files [1 ][0 ]) and use_latest :
274
- resource = (tarball , tarball .name )
275
- break
276
- # Offline, download interrupt, digest mismatch
277
- if not files or not use_latest :
278
- resource = (tarball , tarball .name )
279
- break
280
-
281
- if not resource :
282
- return None
283
-
284
- path , name = resource
285
- proton : str = name [: name .find (".tar.gz" )] # Proton dir
286
- try :
287
- log .console (f"{ name } found in: { path } " )
288
- _extract_dir (path , steam_compat )
289
- log .console (f"Using { proton } " )
290
- environ ["PROTONPATH" ] = steam_compat .joinpath (proton ).as_posix ()
291
- env ["PROTONPATH" ] = environ ["PROTONPATH" ]
292
- return env
293
- except KeyboardInterrupt :
294
- if steam_compat .joinpath (proton ).is_dir ():
295
- log .console (f"Purging { proton } in { steam_compat } ..." )
296
- rmtree (steam_compat .joinpath (proton ).as_posix ())
297
- raise
298
-
299
-
300
256
def _get_latest (
301
- env : Dict [str , str ], steam_compat : Path , cache : Path , files : List [Tuple [str , str ]]
257
+ env : Dict [str , str ], steam_compat : Path , tmp : Path , files : List [Tuple [str , str ]]
302
258
) -> Union [Dict [str , str ], None ]:
303
259
"""Download the latest Proton for new installs -- empty cache and Steam compat.
304
260
@@ -308,11 +264,25 @@ def _get_latest(
308
264
return None
309
265
310
266
try :
311
- log .console ("Fetching latest release ..." )
312
267
tarball : str = files [1 ][0 ]
268
+ sums : str = files [0 ][0 ]
313
269
proton : str = tarball [: tarball .find (".tar.gz" )]
314
- _fetch_proton (env , steam_compat , cache , files )
315
- log .console (f"Using { proton } " )
270
+ version : str = (
271
+ "GE-Proton" if environ .get ("PROTONPATH" ) == "GE-Proton" else "umu-proton"
272
+ )
273
+
274
+ if steam_compat .joinpath (proton ).is_dir ():
275
+ log .console (f"{ version } is up to date" )
276
+ environ ["PROTONPATH" ] = steam_compat .joinpath (proton ).as_posix ()
277
+ env ["PROTONPATH" ] = environ ["PROTONPATH" ]
278
+ return env
279
+
280
+ _fetch_proton (env , steam_compat , tmp , files )
281
+ log .debug ("Removing: %s" , tarball )
282
+ log .debug ("Removing: %s" , sums )
283
+ tmp .joinpath (tarball ).unlink (missing_ok = True )
284
+ tmp .joinpath (sums ).unlink (missing_ok = True )
285
+ log .console (f"Using { version } ({ proton } )" )
316
286
env ["PROTONPATH" ] = environ ["PROTONPATH" ]
317
287
except ValueError :
318
288
log .exception ("Exception" )
@@ -321,7 +291,7 @@ def _get_latest(
321
291
# Digest mismatched
322
292
# Refer to the cache for old version next
323
293
# Since we do not want the user to use a suspect file, delete it
324
- cache .joinpath (tarball ).unlink (missing_ok = True )
294
+ tmp .joinpath (tarball ).unlink (missing_ok = True )
325
295
return None
326
296
except KeyboardInterrupt :
327
297
tarball : str = files [1 ][0 ]
@@ -330,7 +300,7 @@ def _get_latest(
330
300
# Exit cleanly
331
301
# Clean up extracted data and cache to prevent corruption/errors
332
302
# Refer to the cache for old version next
333
- _cleanup (tarball , proton_dir , cache , steam_compat )
303
+ _cleanup (tarball , proton_dir , tmp , steam_compat )
334
304
return None
335
305
except HTTPException : # Download failed
336
306
return None
0 commit comments