Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python3
- #
- # This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
- # https://creativecommons.org/licenses/by-nc-nd/4.0/
- #
- import hashlib
- import json
- import os
- import re
- import subprocess
- import sys
- from pathlib import Path
- from typing import Union, List
- WINE_VERSIONS = {
- "6.16.r3.gf3b03ce5": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/884173115398176768/debuntu-wine-tkg-staging-fsync-git-6.16.r3.gf3b03ce5.7z",
- "hash": {
- "type": "sha512",
- "value": "e0e1bc6ecc0226f2a2f8e1ddbff28d36b5836c2ff2e50f733fbb86fcaacb50097f6f47281801c91b8412801a993a354b4aca24978eb2d86e7f64ee2fcf543b43"
- }
- },
- "6.17.r0.g5f19a815": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/886180600703250453/debuntu-wine-tkg-staging-fsync-git-6.17.r0.g5f19a815.7z",
- "hash": {
- "type": "sha512",
- "value": "bd64593b2f3a01942bc5c6c5ee6aa654f5cce30c76e4a83397611286cd74feaf7ba8fb6fba99f145bb4d9eed523a1d007cc4d845d5324b07a40700dcf1655a3b"
- }
- },
- "6.18.r0.gf8851f16": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/891630589671796786/debuntu-wine-tkg-staging-fsync-git-6.18.r0.gf8851f16.7z",
- "hash": {
- "type": "sha512",
- "value": "223f81f559e84f1b1915bdb71470dfed2648ddf60650e9c1ee6680f325cd7ebf73b1b98e0ab3d3348a069bba36775acffd157403aa453a3bf14f268500ed0dbe"
- }
- },
- "6.20.r0.g3fb6eb99": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/901364156597428274/debuntu-wine-tkg-staging-fsync-git-6.20.r0.g3fb6eb99.7z",
- "hash": {
- "type": "sha512",
- "value": "8a20ccf11ae4e63c9bf382437e8dad7bc02041884784624b84152b93beb849463276e4503a674339586a4a75a541e6c49b2aab0110a13c80ce36249bc124e73e"
- }
- },
- "6.22.r0.ga703038b": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/912141274805575710/debuntu-wine-tkg-staging-fsync-git-6.22.r0.ga703038b.7z",
- "hash": {
- "type": "sha512",
- "value": "88112abe39c03a76dbfb8c64e0f48d02576c6920114e46141d096f947e5f1c774051022fd6d0101e333cd30de810b4d3435d66184fb752da4870954e8c419cac"
- }
- },
- "7.0rc1.r0.g544f90da": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/920772054784016444/debuntu-wine-tkg-staging-fsync-git-7.0rc1.r0.g544f90da.7z",
- "hash": {
- "type": "sha512",
- "value": "ca1da05759622762e1e54bae1d067387aa98fa31073f6b52c51f76a6f5c23f1b7d03fdb6dfb35d2c29609a5fc19e0a64c6f034fc67b47d6f4094ad529d97641a"
- }
- },
- "7.0rc2.r0.g8f579c4e": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/922274716096528494/debuntu-wine-tkg-staging-fsync-git-7.0rc2.r0.g8f579c4e.7z",
- "hash": {
- "type": "sha512",
- "value": "66d32f90af8f5de11ace6b930dd5a989a8f0a5d9e09244da81adfad2bb68bbe596e8259ecec49682c34fcaa03ce2e98501b05c35a8a1da7d9881c97599eb7fbe"
- }
- },
- "7.0rc4.r1.g98c906f8": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/928092680603435029/debuntu-wine-tkg-staging-fsync-git-7.0rc4.r1.g98c906f8.7z",
- "hash": {
- "type": "sha512",
- "value": "2451843024f195295a73e656cb3e683de4a1eb94765a70d9c59be3de3580652dc11bb0bc8080b7f63238c0c14c763f2af62b6a270726fa6441e35e84634dee7b"
- }
- },
- "7.0rc6.r0.g0111d074": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/932136639168380928/debuntu-wine-tkg-staging-fsync-git-7.0rc6.r0.g0111d074.7z",
- "hash": {
- "type": "sha512",
- "value": "3e30e65abeee8f15b5c7547fb4232b611be27aa6505746cd25b4cc24b389b097443a5446b4d52c2d8ea4dd1415c09262f3595a1f03375d0102c4e47a81a7b5ea"
- }
- },
- "7.0.r1.g95bf6698": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/934769842832146494/debuntu-wine-tkg-staging-fsync-git-7.0.r1.g95bf6698.7z",
- "hash": {
- "type": "sha512",
- "value": "f28fe737a358b5a9b6d89e3baef85e6168a23598eb327c378a2a284bc2fd959331e8637a64db59be75db35d79ab815e2688055d3de5544c9b653e5907389a2b6"
- }
- },
- "7.1.r2.gc437a01e": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/937332523380379678/debuntu-wine-tkg-staging-fsync-git-7.1.r2.gc437a01e.7z",
- "hash": {
- "type": "sha512",
- "value": "9b0da4604525b88f2ed353780211a4d78c464326cffdd2d7dfdc5d487a3c9631de9f0197c2f63bd9c1475e5e48ff7d9783e9648582aa8dc29b58d6e62f617c49"
- }
- },
- "7.2.r0.g68441b1d": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/943053350528778240/debuntu-wine-tkg-staging-fsync-git-7.2.r0.g68441b1d.7z",
- "hash": {
- "type": "sha512",
- "value": "78a5227807eb1af4656f4e31f2989c87eabd4754319f44d8b4b9db02a34b75569c2a0b401e5378eb215b56324f8cd8a7f7661f9e5a82bb33d667542f5b838ec6"
- }
- },
- "7.6.r14.g6b4b9f1b": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/967108819849199667/debuntu-wine-tkg-staging-fsync-git-7.6.r14.g6b4b9f1b.7z",
- "hash": {
- "type": "sha512",
- "value": "eaa52d360e92eb7715b0db8b414ba0ba15b4cba8e168355ada5d171d6c0f47b4ef8f85fe433e39a152d239b9d03fbe4a9c11851c86415d65c4cd2658560faf49"
- }
- },
- "7.7.r0.g9df73ee3": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/967687344796893285/debuntu-wine-tkg-staging-fsync-git-7.7.r0.g9df73ee3.7z",
- "hash": {
- "type": "sha512",
- "value": "019ce0d97f7b6f504db51954bc79761d078062c1a7b69f349de380b2a9c9081de11b6f1cabe9665cbcee28ebb9a20cd57519bc0dc795401d80a6b55a04efe3ed"
- }
- },
- "7.20.r1.gbd2608b1": {
- "url": "https://cdn.discordapp.com/attachments/858117357897121822/1038216311198715934/debuntu-wine-tkg-staging-fsync-git-7.20.r1.gbd2608b1.7z",
- "hash": {
- "type": "sha512",
- "value": "c992cf277feae8a64969371c6c46d3e15a742791ba100092f6deec2e7048c322b9f1bc0f807421659d4f50591bd70b84e5521b9f61c47842bcb63b06edb6d80f"
- }
- }
- }
- def use_version():
- return "7.20.r1.gbd2608b1"
- class bcolors:
- HEADER = '\033[95m'
- OKBLUE = '\033[94m'
- OKCYAN = '\033[96m'
- OKGREEN = '\033[92m'
- WARNING = '\033[93m'
- FAIL = '\033[91m'
- ENDC = '\033[0m'
- BOLD = '\033[1m'
- UNDERLINE = '\033[4m'
- def info(msg: str):
- print(f"{bcolors.BOLD}>> {bcolors.OKBLUE}{msg}{bcolors.ENDC}{bcolors.ENDC}")
- def warn(msg: str):
- print(f"{bcolors.BOLD}>> {bcolors.WARNING}{msg}{bcolors.ENDC}{bcolors.ENDC}")
- def success_message(msg: str):
- print(f"{bcolors.BOLD}>>> {bcolors.OKGREEN}{msg}{bcolors.ENDC}{bcolors.ENDC}")
- def error_out(msg: str):
- print(
- f"{bcolors.BOLD}>>> {bcolors.FAIL}{msg}{bcolors.ENDC}{bcolors.ENDC}",
- file=sys.stderr
- )
- print(
- f"{bcolors.BOLD}>>> {bcolors.FAIL}Quitting script due to an error.{bcolors.ENDC}{bcolors.ENDC}",
- file=sys.stderr
- )
- sys.exit(-1)
- def info_on_call(message: str):
- def decorator(fn):
- def wrapper(*args, **kwargs):
- args_as_string = json.dumps(list(map(str, args)))
- kwargs_as_string = json.dumps(dict(zip(map(str, kwargs.keys()), map(str, kwargs.values()))))
- info(f"* {message} :: {bcolors.WARNING}{args_as_string} :: {kwargs_as_string}{bcolors.ENDC}")
- return_value = fn(*args, **kwargs)
- info(f"* {bcolors.OKGREEN}{str(return_value)}{bcolors.ENDC}")
- return return_value
- return wrapper
- return decorator
- def download_data():
- return WINE_VERSIONS.get(use_version())
- def download_url():
- return download_data()["url"]
- def filename():
- return download_url().split("/")[-1]
- def download_hash_algorithm():
- return download_data()["hash"]["type"]
- def download_hash_value():
- return download_data()["hash"]["value"]
- def download_path() -> Path:
- return Path("/", "tmp", filename())
- def share_grapejuice_path() -> Path:
- return Path(os.environ["HOME"]).resolve() / ".local" / "share" / "grapejuice"
- def grapejuice_user_path() -> Path:
- return share_grapejuice_path() / "user"
- def wine_target_path() -> Path:
- p = grapejuice_user_path() / "wine-download"
- p.mkdir(parents=True, exist_ok=True)
- return p
- def find_latest_previous_wine_server() -> Union[Path, None]:
- candidates = list(
- sorted(
- filter(
- lambda p: f"bin{os.sep}wineserver" in str(p),
- wine_target_path().rglob("wineserver")
- )
- )
- )
- if len(candidates) == 0:
- return None
- return candidates[-1]
- def grapejuice_settings_path() -> Path:
- return Path(os.environ["HOME"]).resolve() / ".config" / "brinkervii" / "grapejuice" / "user_settings.json"
- @info_on_call("Hashing file")
- def hash_file(path: Path, algorithm: str, block_size: int = 4096) -> str:
- h = hashlib.new(algorithm)
- with path.open("rb") as fp:
- data = True
- while data:
- data = fp.read(block_size)
- h.update(data)
- return h.hexdigest().lower().strip()
- @info_on_call("Locating system binary")
- def which(binary_name: str, path_extra: List[Union[Path, str]] = None) -> Union[Path, None]:
- path = list(map(str, [] if path_extra is None else path_extra))
- path.extend(os.environ.get("PATH", "").split(":"))
- for d in path:
- d = d.strip()
- if not d:
- continue
- d = Path(d).resolve()
- file = d / binary_name
- if file.exists() and (file.is_file() or file.is_symlink()):
- return file
- return None
- def stop_wine_server():
- info("Stopping Wine server")
- prefixes_directory = share_grapejuice_path() / "prefixes"
- if prefixes_directory.exists():
- info("Using Grapejuice 4+ prefix configuration")
- prefix_list = list(filter(Path.is_dir, prefixes_directory.glob("*")))
- else:
- info("Using Grapejuice <= 3 prefix directory")
- prefix_list = [share_grapejuice_path() / "wineprefix"]
- for prefix_path in prefix_list:
- wine_server_path = find_latest_previous_wine_server() or which("wineserver")
- if wine_server_path is None:
- info("Could not find wineserver, so it is not being stopped")
- return
- if prefix_path.exists() and prefix_path.is_dir():
- try:
- subprocess.call([str(wine_server_path), "-k"], env={"WINEPREFIX": str(prefix_path)})
- except Exception as e:
- warn(f"Failed to stop wineserver: {str(e)}")
- pass
- def wget_bin():
- p = which("wget")
- if p is None:
- error_out("The 'wget' binary is not present on your system, please install wget.")
- return p
- @info_on_call("Downloading file using wget")
- def wget(url: str, download_location: Path, hash_algorithm: str, file_hash: str):
- if download_location.exists():
- if download_location.is_dir():
- error_out(f"The wine download location {download_location} is a directory and cannot be written to. "
- f"Please move or delete the directory.")
- else:
- hash_value = hash_file(download_location, hash_algorithm)
- if hash_value == file_hash:
- return
- else:
- warn(f"File exists at {download_location}, but the file hash does not match. Attempting redownload.")
- subprocess.check_call([str(wget_bin()), url, "-O", str(download_location)])
- hash_value = hash_file(download_location, hash_algorithm)
- if hash_value != file_hash:
- error_out(f"The Wine build was downloaded to {download_location}. However, the file hash does not match. "
- f"Please make sure the download has finished and that your internet connection is secure!")
- def seven_zip_bin() -> Path:
- p = which("7z") or which("7za")
- if p is None:
- error_out("The '7z' binary is not present on your system, please install 7z (the package is called 'p7zip' or "
- "'p7zip-full' on most distributions).")
- return p
- @info_on_call("Locating file in 7z archive")
- def find_wine_binary_in_7z(source: Path) -> str:
- listing = subprocess.check_output([str(seven_zip_bin()), "l", str(source)]).decode("UTF-8")
- candidates = list(filter(lambda s: s.strip("\r").strip().endswith("bin/wine"), listing.split("\n")))
- assert len(candidates) == 1, "Invalid archive, invalid number of wine binary candidates"
- m = re.split(r"\s+", candidates[0])
- p = m[-1]
- assert p.endswith("bin/wine"), "Got an invalid wine binary path from archive"
- return p
- @info_on_call("Unarchiving 7z archive")
- def unarchive_7z(source: Path, target: Path):
- subprocess.check_call([str(seven_zip_bin()), "x", "-y", "-o" + str(target), str(source)])
- @info_on_call("Updating Grapejuice settings")
- def update_grapejuice_settings(wine_binary_path: str):
- if not grapejuice_settings_path().exists():
- error_out("The Grapejuice settings file does not exist. Please open and close Grapejuice one time.")
- with grapejuice_settings_path().open("r") as fp:
- data = json.load(fp)
- full_wine_binary_path = wine_target_path() / wine_binary_path
- settings_version = next(
- filter(
- None,
- [
- data.get("__version__", None),
- data.get("version", None)
- ]
- ),
- 0
- )
- if settings_version >= 2:
- info("Got Grapejuice 4+ user_settings")
- wine_home = full_wine_binary_path.parent.parent
- wine_bin = wine_home / "bin"
- if not wine_bin.exists():
- error_out(f"Invalid wine_home: {wine_home}")
- for prefix in data.get("wineprefixes", []):
- prefix["wine_home"] = str(wine_home)
- data["default_wine_home"] = str(wine_home)
- else:
- info("Got Grapejuice < 4 user_settings")
- data["wine_binary"] = str(full_wine_binary_path)
- with grapejuice_settings_path().open("w") as fp:
- json.dump(data, fp, indent=2)
- def main():
- info("Starting installation process")
- stop_wine_server()
- download_location = download_path()
- wget(download_url(), download_location, download_hash_algorithm(), download_hash_value())
- info("Processing archive")
- wine_binary_path = find_wine_binary_in_7z(download_location)
- unarchive_7z(download_location, wine_target_path())
- update_grapejuice_settings(wine_binary_path)
- stop_wine_server()
- info("Done")
- success_message("Wine-TKG installation has succeeded!")
- if __name__ == '__main__':
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement