-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
1,018 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
## Introduction | ||
CLI program and API to automate installation of [GloriousEggroll](https://github.com/GloriousEggroll/)'s [Proton-GE](https://github.com/GloriousEggroll/proton-ge-custom) | ||
|
||
## Installation | ||
Install from Python Package Index | ||
``` | ||
pip install protonup | ||
``` | ||
Install from source | ||
``` | ||
git clone https://github.com/AUNaseef/protonup && cd protonup | ||
python3 setup.py install | ||
``` | ||
|
||
## Usage | ||
Set your installation directory before running the program with `-d "your/compatibilitytools.d/directory"` | ||
|
||
Example: | ||
``` | ||
protonup -d "~/.steam/root/compatibilitytools.d/" | ||
``` | ||
--- | ||
To update to the latest version, just run `protonup` from a command line | ||
|
||
Example: | ||
``` | ||
protonup | ||
``` | ||
--- | ||
Install a specific version with `-t "version tag"` | ||
|
||
Example: | ||
``` | ||
protonup -t 6.5-GE-2 | ||
``` | ||
--- | ||
By default the downloads are stored in a temporary folder. Change it with `-o "custom/downlod/directory"` | ||
|
||
Example: | ||
``` | ||
protonup -o ~/Downloads | ||
``` | ||
--- | ||
List existing installations with `-l` | ||
|
||
Example: | ||
``` | ||
protonup -l | ||
``` | ||
--- | ||
Remove existing installations with `-r "version tag` | ||
|
||
Example: | ||
``` | ||
protonup -r 6.5-GE-2 | ||
``` | ||
--- | ||
Use `--download` to download Proton-GE to the current working directory without installing it, you can override destination with `-o` | ||
|
||
Example: | ||
``` | ||
protonup --download | ||
``` | ||
--- | ||
Use `-y` toggle to carry out actions without any logging or interaction | ||
|
||
Example: | ||
``` | ||
protonup --download -o ~/Downloads -y | ||
``` | ||
--- | ||
### Restart Steam after making changes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
"""ProtonUp - Manage Proton-GE Installations""" | ||
def main(): | ||
from .cli import main | ||
return main() | ||
|
||
from .api import install_directory, installed_versions | ||
from .api import fetch_data, get_proton, remove_proton |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from .cli import main | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
"""ProtonUp API""" | ||
import os | ||
import shutil | ||
from configparser import ConfigParser | ||
import tarfile | ||
import requests | ||
from .utilities import download | ||
from .constants import CONFIG_FILE, PROTONGE_URL, MIB | ||
from .constants import TEMP_DIR, DEFAULT_INSTALL_DIR | ||
|
||
|
||
def fetch_data(tag): | ||
""" | ||
Fetch ProtonGE release information from github | ||
Return Type: dict | ||
Content(s): | ||
'version', date', 'download', 'size', 'checksum' | ||
""" | ||
url = PROTONGE_URL + (f'tags/{tag}' if tag and tag is not 'latest' else 'latest') | ||
data = requests.get(url).json() | ||
if 'tag_name' not in data: | ||
return # invalid tag | ||
|
||
values = {'version': data['tag_name'], 'date': data['published_at'].split('T')[0]} | ||
for asset in data['assets']: | ||
if asset['name'].endswith('sha512sum'): | ||
values['checksum'] = asset['browser_download_url'] | ||
elif asset['name'].endswith('tar.gz'): | ||
values['download'] = asset['browser_download_url'] | ||
values['size'] = asset['size'] | ||
return values | ||
|
||
|
||
def install_directory(target=None): | ||
""" | ||
Custom install directory | ||
Return Type: str | ||
""" | ||
config = ConfigParser() | ||
if target and target.lower() != 'get': | ||
if target.lower() == 'default': | ||
target = DEFAULT_INSTALL_DIR | ||
if not target.endswith('/'): | ||
target += '/' | ||
if not config.has_section('protonup'): | ||
config.add_section('protonup') | ||
config['protonup']['installdir'] = target | ||
os.makedirs(os.path.dirname(CONFIG_FILE), exist_ok=True) | ||
with open(CONFIG_FILE, 'w') as file: | ||
config.write(file) | ||
return target | ||
elif os.path.exists(CONFIG_FILE): | ||
config.read(CONFIG_FILE) | ||
if config.has_option('protonup', 'installdir'): | ||
return os.path.expanduser(config['protonup']['installdir']) | ||
else: | ||
return DEFAULT_INSTALL_DIR | ||
|
||
|
||
def installed_versions(): | ||
""" | ||
List of proton installations | ||
Return Type: str[] | ||
""" | ||
installdir = install_directory() | ||
versions_found = [] | ||
|
||
if os.path.exists(installdir): | ||
folders = os.listdir(installdir) | ||
# Find names of directories with proton | ||
for folder in folders: | ||
if os.path.exists(f'{installdir}/{folder}/proton'): | ||
versions_found.append(folder) | ||
|
||
return versions_found | ||
|
||
|
||
def get_proton(version=None, yes=True, dl_only=False, output=None): | ||
"""Download and (optionally) install Proton""" | ||
installdir = install_directory() | ||
data = fetch_data(tag=version) | ||
|
||
if not data or 'download' not in data: | ||
if not yes: | ||
print('[ERROR] invalid tag / binary not found') | ||
return False # invalid tag or no download link | ||
|
||
protondir = installdir + 'Proton-' + data['version'] | ||
|
||
if os.path.exists(protondir) and not dl_only: | ||
# TODO: Check if data['hash'] matches installation | ||
if not yes: | ||
print(f"[INFO] Proton-{data['version']} already installed") | ||
return False | ||
|
||
if not yes: | ||
print(f"Ready to download Proton-{data['version']}", | ||
f"\nSize : {round(data['size']/MIB, 2)} MiB", | ||
f"\nPublished : {data['date']}") | ||
if not input("Continue? (Y/N): ") in ['y', 'Y']: | ||
return | ||
|
||
# Prepare destination | ||
destination = output if output else (os.getcwd() if dl_only else TEMP_DIR) | ||
if not destination.endswith('/'): | ||
destination += '/' | ||
destination += data['download'].split('/')[-1] | ||
destination = os.path.expanduser(destination) | ||
|
||
download(url=data['download'], destination=destination, show_progress=not yes) | ||
# TODO: Check if data['hash'] matches the downloaded file | ||
|
||
# Installation | ||
if not dl_only: | ||
if os.path.exists(protondir): | ||
shutil.rmtree(protondir) | ||
tarfile.open(destination, "r:gz").extractall(install_directory()) | ||
if not yes: | ||
print('[INFO] Installed in: ' + protondir) | ||
elif not yes: | ||
print('[INFO] Dowloaded to: ' + destination) | ||
|
||
shutil.rmtree(TEMP_DIR, ignore_errors=True) | ||
|
||
|
||
def remove_proton(version=None, yes=True): | ||
"""Uninstall existing proton installation""" | ||
target = install_directory() + "Proton-" + version | ||
if os.path.exists(target): | ||
if yes or input(f'Do you want to remove {version}? (y/n) : ') in ['y', 'Y']: | ||
shutil.rmtree(install_directory() + 'Proton-' + version) | ||
else: | ||
return False | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
"""ProtonUp CLI""" | ||
import sys | ||
import argparse | ||
from .api import install_directory, installed_versions | ||
from .api import get_proton, remove_proton | ||
from .utilities import folder_size | ||
from .constants import TEMP_DIR, MIB | ||
|
||
|
||
def parse_arguments(): | ||
"""Parse commandline arguments""" | ||
parser = argparse.ArgumentParser(usage="%(prog)s", description="Manage Proton-GE Installations", | ||
epilog="GPLv3 - Repo : https://github.com/AUNaseef/protonup") | ||
parser.add_argument('-t', '--tag', type=str, default=None, help='install a specific version') | ||
parser.add_argument('-l', '--list', action='store_true', help='list installed version') | ||
parser.add_argument('-r', '--rem', type=str, default=None, metavar='TAG', | ||
help='remove existing installations') | ||
parser.add_argument('-o', '--output', type=str, default=None, metavar='DIR', | ||
help='set download directory') | ||
parser.add_argument('-d', '--dir', type=str, default=None, help='set installation directory') | ||
parser.add_argument('-y', '--yes', action='store_true', help='disable prompts and logs') | ||
parser.add_argument('--download', action='store_true', help='download only') | ||
return parser.parse_args() | ||
|
||
|
||
def main(): | ||
"""Start here""" | ||
args = parse_arguments() | ||
if args.dir: | ||
print(f"Install directory set to '{install_directory(args.dir)}'") | ||
if args.tag or not (args.rem or args.list or args.dir): | ||
get_proton(version=args.tag, yes=args.yes, dl_only=args.download, | ||
output=args.output) | ||
if args.rem: | ||
if not remove_proton(version=args.rem, yes=args.yes): | ||
print('Proton-{version} not installed') | ||
if args.list: | ||
for item in installed_versions(): | ||
print(f"{item} - {round(folder_size(install_directory() + item)/MIB, 2)} MiB") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
"""Constant Values""" | ||
import os | ||
CONFIG_FILE = os.path.expanduser('~/.config/protonup/config.ini') | ||
DEFAULT_INSTALL_DIR = os.path.expanduser('~/.steam/root/compatibilitytools.d/') | ||
TEMP_DIR = '/tmp/protonup/' | ||
PROTONGE_URL = 'https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/' | ||
MIB = 1048576 # One mebibyte in bytes | ||
BUFFER_SIZE = 65536 # Work with 64 kb chunks |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
"""Utilities""" | ||
import os | ||
import sys | ||
import hashlib | ||
import requests | ||
from .constants import MIB, BUFFER_SIZE | ||
|
||
|
||
def download(url, destination, show_progress=False): | ||
"""Download files""" | ||
try: | ||
file = requests.get(url, stream=True) | ||
except OSError: | ||
return False | ||
|
||
if show_progress: | ||
f_size = int(file.headers.get('content-length')) | ||
f_size_mib = round(f_size / MIB, 2) | ||
c_count = f_size / BUFFER_SIZE | ||
c_current = 1 | ||
destination = os.path.expanduser(destination) | ||
os.makedirs(os.path.dirname(destination), exist_ok=True) | ||
with open(destination, 'wb') as dest: | ||
for chunk in file.iter_content(chunk_size=BUFFER_SIZE): | ||
if chunk: | ||
dest.write(chunk) | ||
dest.flush() | ||
if show_progress: | ||
progress = min(round((c_current / c_count) * 100, 2), 100.00) | ||
downloaded = round((c_current * BUFFER_SIZE) / MIB, 2) | ||
sys.stdout.write(f'\rDownloaded {progress}% - {downloaded} MiB/{f_size_mib} MiB') | ||
c_current += 1 | ||
if show_progress: | ||
sys.stdout.write('\n') | ||
return True | ||
|
||
|
||
def get_sha512(filename): | ||
sha512sum = hashlib.sha512() | ||
with open(filename, 'rb') as file: | ||
while True: | ||
data = file.read(BUFFER_SIZE) | ||
if not data: | ||
break | ||
sha512sum.update(data) | ||
return sha512sum.hexdigest() | ||
|
||
|
||
def folder_size(folder): | ||
"""Calculate the size of a folder""" | ||
size = 0 | ||
for root, dirs, files in os.walk(folder, onerror=None): | ||
for file in files: | ||
size += os.path.getsize(os.path.join(root, file)) | ||
return size |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[build-system] | ||
requires = ["setuptools", "wheel"] | ||
build-backend = "setuptools.build_meta" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[metadata] | ||
name = protonup | ||
version = 0.0.2 | ||
description = Manage Proton-GE Installations | ||
long_description = file: README.md | ||
long_description_content_type = text/markdown | ||
url = https://github.com/AUNaseef/protonup | ||
author = Naseef | ||
license = GPL-3.0 | ||
license_files = | ||
LICENSE | ||
|
||
[options] | ||
packages = find: | ||
install_requires = | ||
requests | ||
python_requires = >3.6 | ||
|
||
[options.entry_points] | ||
console_scripts = | ||
protonup = protonup:main | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import setuptools | ||
setuptools.setup() |