Skip to content

Commit d9bb010

Browse files
authored
Merge pull request #72 from R1kaB3rN/update
Update process when setting latest UMU-Proton
2 parents 96eaead + b0337ce commit d9bb010

File tree

3 files changed

+145
-4
lines changed

3 files changed

+145
-4
lines changed

umu/umu_dl_util.py

+73-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from umu_log import log
1414
from umu_consts import STEAM_COMPAT
1515
from tempfile import mkdtemp
16+
from threading import Thread
1617

1718
try:
1819
from tarfile import tar_filter
@@ -275,7 +276,39 @@ def _get_latest(
275276

276277
_fetch_proton(env, tmp, files)
277278

278-
_extract_dir(tmp.joinpath(tarball), steam_compat)
279+
# Set latest UMU/GE-Proton
280+
if version == "UMU-Proton":
281+
threads: List[Thread] = []
282+
log.debug("Updating UMU-Proton")
283+
old_versions: List[Path] = sorted(
284+
[
285+
file
286+
for file in steam_compat.glob("*")
287+
if file.name.startswith(("UMU-Proton", "ULWGL-Proton"))
288+
]
289+
)
290+
tar_path: Path = tmp.joinpath(tarball)
291+
292+
# Extract the latest archive and update UMU-Proton
293+
# Will extract and remove the previous stable versions
294+
# Though, ideally, an in-place differential update would be
295+
# performed instead for this job but this will do for now
296+
log.debug("Extracting %s -> %s", tar_path, steam_compat)
297+
extract: Thread = Thread(target=_extract_dir, args=[tar_path, steam_compat])
298+
extract.start()
299+
threads.append(extract)
300+
update: Thread = Thread(
301+
target=_update_proton, args=[proton, steam_compat, old_versions]
302+
)
303+
update.start()
304+
threads.append(update)
305+
for thread in threads:
306+
thread.join()
307+
else:
308+
# For GE-Proton, keep the previous build. Since it's a rebase
309+
# of bleeding edge, regressions are more likely to occur
310+
_extract_dir(tmp.joinpath(tarball), steam_compat)
311+
279312
environ["PROTONPATH"] = steam_compat.joinpath(proton).as_posix()
280313
env["PROTONPATH"] = environ["PROTONPATH"]
281314

@@ -289,7 +322,6 @@ def _get_latest(
289322
tarball: str = files[1][0]
290323

291324
# Digest mismatched
292-
# Refer to the cache for old version next
293325
# Since we do not want the user to use a suspect file, delete it
294326
tmp.joinpath(tarball).unlink(missing_ok=True)
295327
return None
@@ -299,11 +331,49 @@ def _get_latest(
299331

300332
# Exit cleanly
301333
# Clean up extracted data and cache to prevent corruption/errors
302-
# Refer to the cache for old version next
303334
_cleanup(tarball, proton_dir, tmp, steam_compat)
304335
return None
305336
except HTTPException: # Download failed
306337
log.exception("HTTPException")
307338
return None
308339

309340
return env
341+
342+
343+
def _update_proton(proton: str, steam_compat: Path, old_versions: List[Path]) -> None:
344+
"""Create a symbolic link and remove the previous UMU-Proton.
345+
346+
The symbolic link will be used by clients to reference the PROTONPATH
347+
which can be used for tasks such as killing the running wineserver in
348+
the prefix
349+
350+
Assumes that the directories that are named ULWGL/UMU-Proton is ours
351+
and will be removed.
352+
"""
353+
threads: List[Thread] = []
354+
old: Path = None
355+
log.debug("Old: %s", old_versions)
356+
log.debug("Linking UMU-Latest -> %s", proton)
357+
steam_compat.joinpath("UMU-Latest").unlink(missing_ok=True)
358+
steam_compat.joinpath("UMU-Latest").symlink_to(proton)
359+
360+
if not old_versions:
361+
return
362+
363+
old = old_versions.pop()
364+
if old.is_dir():
365+
log.debug("Removing: %s", old)
366+
oldest: Thread = Thread(target=rmtree, args=[old.as_posix()])
367+
oldest.start()
368+
threads.append(oldest)
369+
370+
for proton in old_versions:
371+
if proton.is_dir():
372+
log.debug("Old stable build found")
373+
log.debug("Removing: %s", proton)
374+
sibling: Thread = Thread(target=rmtree, args=[proton.as_posix()])
375+
sibling.start()
376+
threads.append(sibling)
377+
378+
for thread in threads:
379+
thread.join()

umu/umu_test.py

+71
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,77 @@ def test_latest_offline(self):
10121012
self.assertFalse(self.env["PROTONPATH"], "Expected PROTONPATH to be empty")
10131013
self.assertFalse(result, "Expected None to be returned from _get_latest")
10141014

1015+
def test_latest_umu(self):
1016+
"""Test _get_latest when online and when an empty PROTONPATH is set.
1017+
1018+
Tests that the latest UMU-Proton was set to PROTONPATH and old
1019+
stable versions were removed in the process.
1020+
"""
1021+
result = None
1022+
latest = Path("UMU-Proton-9.0-beta16")
1023+
latest.mkdir()
1024+
Path(f"{latest}.sha512sum").touch()
1025+
files = [(f"{latest}.sha512sum", ""), (f"{latest}.tar.gz", "")]
1026+
1027+
# Mock the latest Proton in /tmp
1028+
test_archive = self.test_cache.joinpath(f"{latest}.tar.gz")
1029+
with tarfile.open(test_archive.as_posix(), "w:gz") as tar:
1030+
tar.add(latest.as_posix(), arcname=latest.as_posix())
1031+
1032+
# Mock old versions
1033+
self.test_compat.joinpath("UMU-Proton-9.0-beta15").mkdir()
1034+
self.test_compat.joinpath("UMU-Proton-9.0-beta14").mkdir()
1035+
self.test_compat.joinpath("ULWGL-Proton-8.0-5-2").mkdir()
1036+
1037+
# Create foo files and GE-Proton. We do *not* want unintended
1038+
# removals
1039+
self.test_compat.joinpath("foo").mkdir()
1040+
self.test_compat.joinpath("GE-Proton9-2").mkdir()
1041+
1042+
os.environ["PROTONPATH"] = ""
1043+
1044+
with (
1045+
patch("umu_dl_util._fetch_proton"),
1046+
):
1047+
result = umu_dl_util._get_latest(
1048+
self.env, self.test_compat, self.test_cache, files
1049+
)
1050+
self.assertTrue(result is self.env, "Expected the same reference")
1051+
# Verify the latest was set
1052+
self.assertEqual(
1053+
self.env.get("PROTONPATH"),
1054+
self.test_compat.joinpath(latest).as_posix(),
1055+
"Expected latest to be set",
1056+
)
1057+
# Verify that the old versions were deleted
1058+
self.assertFalse(
1059+
self.test_compat.joinpath("UMU-Proton-9.0-beta15").exists(),
1060+
"Expected old version to be removed",
1061+
)
1062+
self.assertFalse(
1063+
self.test_compat.joinpath("UMU-Proton-9.0-beta14").exists(),
1064+
"Expected old version to be removed",
1065+
)
1066+
self.assertFalse(
1067+
self.test_compat.joinpath("ULWGL-Proton-8.0-5-2").exists(),
1068+
"Expected old version to be removed",
1069+
)
1070+
# Verify foo files survived
1071+
self.assertTrue(
1072+
self.test_compat.joinpath("foo").exists(), "Expected foo to survive"
1073+
)
1074+
self.assertTrue(
1075+
self.test_compat.joinpath("GE-Proton9-2").exists(),
1076+
"Expected GE-Proton9-2 to survive",
1077+
)
1078+
self.assertTrue(
1079+
self.test_compat.joinpath("UMU-Latest").is_symlink(),
1080+
"Expected UMU-Latest symlink",
1081+
)
1082+
1083+
latest.rmdir()
1084+
Path(f"{latest}.sha512sum").unlink()
1085+
10151086
def test_steamcompat_nodir(self):
10161087
"""Test _get_from_steamcompat when Proton doesn't exist in compat dir.
10171088

umu/umu_util.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ def _update_umu(
233233
if not local.joinpath("reaper").is_file():
234234
log.warning("Reaper not found")
235235
copy(root.joinpath("reaper"), local.joinpath("reaper"))
236-
log.console(f"Restored {key} to {val} ...")
236+
log.console(f"Restored {key} to {val}")
237237

238238
# Update
239239
if val != reaper:

0 commit comments

Comments
 (0)