From bd5224c1a1b9f73caf2bd91dc5a8b3044277de2d Mon Sep 17 00:00:00 2001 From: Nikhil Badyal Date: Sat, 5 Aug 2023 17:21:16 +0530 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Per=20app=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- main.py | 77 ++++-------------- src/app.py | 94 ++++++++++++++++++++++ src/config.py | 35 +++----- src/downloader/apkmirror.py | 4 - src/downloader/download.py | 23 ++++-- src/downloader/github.py | 11 ++- src/downloader/utils.py | 59 -------------- src/parser.py | 42 +++------- src/patches.py | 156 ++++++++---------------------------- src/utils.py | 26 ++++++ 11 files changed, 222 insertions(+), 307 deletions(-) create mode 100644 src/app.py diff --git a/.gitignore b/.gitignore index 5ef80a1..aba434d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ venv /revanced-cache/ changelog.md .idea -*patches.json +*.json diff --git a/main.py b/main.py index b1b4869..071edac 100644 --- a/main.py +++ b/main.py @@ -6,86 +6,39 @@ from loguru import logger from src.config import RevancedConfig from src.downloader.factory import DownloaderFactory -from src.downloader.utils import download_revanced from src.parser import Parser from src.patches import Patches -from src.utils import AppNotFound, PatcherDownloadFailed +from src.utils import AppNotFound, PatchesJsonFailed, check_java def main() -> None: """Entry point.""" + from src.app import APP + env = Env() config = RevancedConfig(env) + check_java(config.dry_run) - patcher = Patches(config) - try: - download_revanced(config, patcher) - except PatcherDownloadFailed as e: - logger.error(f"Failed to download {e}") - sys.exit(1) - - logger.info(f"Will Patch only {patcher.config.apps}") - for app in patcher.config.apps: + logger.info(f"Will Patch only {config.apps}") + for app in config.apps: + logger.info("Trying to build %s" % app) try: - logger.info("Trying to build %s" % app) + app = APP(app_name=app, config=config) + patcher = Patches(config, app) parser = Parser(patcher, config) - app_all_patches, version, is_experimental = patcher.get_app_configs(app) + app_all_patches = patcher.get_app_configs(app) patcher.include_exclude_patch(app, parser, app_all_patches) downloader = DownloaderFactory.create_downloader( - app=app, patcher=patcher, config=config + app=app.app_name, patcher=patcher, config=config ) - downloader.download(version, app) - config.app_versions[app] = version - logger.info(f"Downloaded {app}, version {version}") - parser.patch_app(app=app, version=version, is_experimental=is_experimental) + downloader.download(app.app_version, app.app_name) + parser.patch_app(app) except AppNotFound as e: logger.info(f"Invalid app requested to build {e}") + except PatchesJsonFailed: + logger.exception("Patches.json not found") except Exception as e: logger.exception(f"Failed to build {app} because of {e}") - if len(config.alternative_youtube_patches) and "youtube" in config.apps: - for alternative_patch in config.alternative_youtube_patches: - parser = Parser(patcher, config) - app_all_patches, version, is_experimental = patcher.get_app_configs( - "youtube" - ) - patcher.include_exclude_patch("youtube", parser, app_all_patches) - was_inverted = parser.invert_patch(alternative_patch) - if was_inverted: - logger.info( - f"Rebuilding youtube with inverted {alternative_patch} patch." - ) - parser.patch_app( - app="youtube", - version=config.app_versions.get("youtube", "latest"), - is_experimental=is_experimental, - output_prefix="-" + alternative_patch + "-", - ) - else: - logger.info( - f"Skipping Rebuilding youtube as {alternative_patch} patch was not found." - ) - if len(config.alternative_youtube_music_patches) and "youtube_music" in config.apps: - for alternative_patch in config.alternative_youtube_music_patches: - parser = Parser(patcher, config) - app_all_patches, version, is_experimental = patcher.get_app_configs( - "youtube_music" - ) - patcher.include_exclude_patch("youtube_music", parser, app_all_patches) - was_inverted = parser.invert_patch(alternative_patch) - if was_inverted: - logger.info( - f"Rebuilding youtube music with inverted {alternative_patch} patch." - ) - parser.patch_app( - app="youtube_music", - version=config.app_versions.get("youtube_music", "latest"), - is_experimental=is_experimental, - output_prefix="-" + alternative_patch + "-", - ) - else: - logger.info( - f"Skipping Rebuilding youtube music as {alternative_patch} patch was not found." - ) if __name__ == "__main__": diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..00337cb --- /dev/null +++ b/src/app.py @@ -0,0 +1,94 @@ +"""Class to represent apk to be patched.""" +import concurrent +import hashlib +import pathlib +from concurrent.futures import ThreadPoolExecutor +from typing import Dict + +from loguru import logger + +from src.config import RevancedConfig +from src.utils import PatcherDownloadFailed, slugify + + +class APP(object): + """Patched APK.""" + + def __init__(self, app_name: str, config: RevancedConfig): + self.app_name = app_name + self.app_version = config.env.str(f"{app_name}_VERSION".upper(), None) + self.experiment = False + self.cli_dl = config.env.str(f"{app_name}_CLI_DL".upper(), config.global_cli_dl) + self.patches_dl = config.env.str( + f"{app_name}_PATCHES_DL".upper(), config.global_patches_dl + ) + self.integrations_dl = config.env.str( + f"{app_name}_INTEGRATION_DL".upper(), config.global_integrations_dl + ) + self.exclude_request = config.env.list(f"EXCLUDE_PATCH_{app_name}".upper(), []) + self.include_request = config.env.list(f"INCLUDE_PATCH_{app_name}".upper(), []) + self.resource: Dict[str, str] = {} + self.no_of_patches = 0 + self.download_patch_resources(config) + + def get_output_file_name(self) -> str: + """Get output file appended with version.""" + return f"Re-{self.app_name}-{slugify(self.app_version)}.apk" + + def set_recommended_version(self, version: str, exp: bool = False) -> None: + """Update if cooking non-recommended.""" + self.app_version = version + self.experiment = exp + + def __str__(self: "APP") -> str: + attrs = vars(self) + return ", ".join("%s: %s" % item for item in attrs.items()) + + @staticmethod + def download(url: str, config: RevancedConfig, assets_filter: str = None) -> str: # type: ignore + """Downloader.""" + from src.downloader.download import Downloader + + url = url.strip() + if url.startswith("https://github"): + from src.downloader.github import Github + + url = Github.patch_resource(url, assets_filter)[0] + extension = pathlib.Path(url).suffix + file_name = APP.generate_filename(url) + extension + Downloader(None, config).direct_download(url, file_name) # type: ignore + return file_name + + def download_patch_resources(self, config: RevancedConfig) -> None: + """Download resource for patching.""" + logger.info("Downloading resources for patching.") + # Create a list of resource download tasks + download_tasks = [ + ("cli", self.cli_dl, config), + ("integrations", self.integrations_dl, config), + ("patches", self.patches_dl, config, ".*jar"), + ("patches_json", self.patches_dl, config, ".*json"), + ] + + # Using a ThreadPoolExecutor for parallelism + with ThreadPoolExecutor() as executor: + futures = { + resource_name: executor.submit(self.download, *args) + for resource_name, *args in download_tasks + } + + # Wait for all tasks to complete + concurrent.futures.wait(futures.values()) + + # Retrieve results from completed tasks + for resource_name, future in futures.items(): + try: + self.resource[resource_name] = future.result() + except Exception as e: + raise PatcherDownloadFailed(f"An exception occurred: {e}") + + @staticmethod + def generate_filename(url: str) -> str: + """Get file name from url.""" + encoded_url: str = hashlib.sha256(url.encode()).hexdigest() + return encoded_url diff --git a/src/config.py b/src/config.py index d7b3471..39f657b 100644 --- a/src/config.py +++ b/src/config.py @@ -1,23 +1,27 @@ """Revanced Configurations.""" from pathlib import Path -from typing import Dict, List +from typing import List from environs import Env from requests import Session from src.utils import default_build +default_cli = "https://github.com/revanced/revanced-cli/releases/latest" +default_patches = "https://github.com/revanced/revanced-patches/releases/latest" +default_integrations = ( + "https://github.com/revanced/revanced-integrations/releases/latest" +) + class RevancedConfig(object): """Revanced Configurations.""" def __init__(self, env: Env) -> None: - self.app_versions: Dict[str, str] = {} self.env = env self.temp_folder = Path("apks") self.session = Session() self.session.headers["User-Agent"] = "anything" - self.build_extended = env.bool("BUILD_EXTENDED", False) self.apk_mirror = "https://www.apkmirror.com" self.upto_down = [ "spotify", @@ -34,27 +38,7 @@ class RevancedConfig(object): self.keystore_name = env.str("KEYSTORE_FILE_NAME", "revanced.keystore") self.ci_test = env.bool("CI_TEST", False) self.apps = env.list("PATCH_APPS", default_build) - self.extended_apps: List[str] = ["youtube", "youtube_music", "microg", "reddit"] - self.rip_libs_apps: List[str] = ["youtube"] - self.normal_cli_jar = "revanced-cli.jar" - self.normal_patches_jar = "revanced-patches.jar" - self.normal_integrations_apk = "revanced-integrations.apk" - self.normal_options_json = "options.json" - self.cli_jar = ( - f"inotia00-{self.normal_cli_jar}" - if self.build_extended - else self.normal_cli_jar - ) - self.patches_jar = ( - f"inotia00-{self.normal_patches_jar}" - if self.build_extended - else self.normal_patches_jar - ) - self.integrations_apk = ( - f"inotia00-{self.normal_integrations_apk}" - if self.build_extended - else self.normal_integrations_apk - ) + self.rip_libs_apps: List[str] = [] self.apk_mirror_urls = { "reddit": f"{self.apk_mirror}/apk/redditinc/reddit/", "twitter": f"{self.apk_mirror}/apk/x-corp/twitter/", @@ -97,3 +81,6 @@ class RevancedConfig(object): self.existing_downloaded_apks = env.list("EXISTING_DOWNLOADED_APKS", []) self.personal_access_token = env.str("PERSONAL_ACCESS_TOKEN", None) self.dry_run = env.bool("DRY_RUN", False) + self.global_cli_dl = env.str("GLOBAL_CLI_DL", default_cli) + self.global_patches_dl = env.str("GLOBAL_CLI_DL", default_patches) + self.global_integrations_dl = env.str("GLOBAL_CLI_DL", default_integrations) diff --git a/src/downloader/apkmirror.py b/src/downloader/apkmirror.py index 4a80527..d0975af 100644 --- a/src/downloader/apkmirror.py +++ b/src/downloader/apkmirror.py @@ -30,7 +30,6 @@ class ApkMirror(Downloader): "p.notes:nth-child(3) > span:nth-child(1) > a:nth-child(1)" ).attributes["href"] self._download(self.config.apk_mirror + href, f"{app}.apk") - logger.debug("Finished Extracting link and downloading") def get_download_page(self, parser: LexborHTMLParser, main_page: str) -> str: """Function to get the download page in apk_mirror. @@ -67,7 +66,6 @@ class ApkMirror(Downloader): :param version: Version of the application to download :return: Version of downloaded apk """ - logger.debug(f"Trying to download {app},specific version {version}") version = version.replace(".", "-") main_page = f"{self.config.apk_mirror_version_urls.get(app)}-{version}-release/" parser = LexborHTMLParser( @@ -75,7 +73,6 @@ class ApkMirror(Downloader): ) download_page = self.get_download_page(parser, main_page) self.extract_download_link(download_page, app) - logger.debug(f"Downloaded {app} apk from apkmirror_specific_version") def latest_version(self, app: str, **kwargs: Any) -> None: """Function to download whatever the latest version of app from @@ -105,4 +102,3 @@ class ApkMirror(Downloader): parser = LexborHTMLParser(self.config.session.get(main_page).text) download_page = self.get_download_page(parser, main_page) self.extract_download_link(download_page, app) - logger.debug(f"Downloaded {app} apk from apkmirror_specific_version in rt") diff --git a/src/downloader/download.py b/src/downloader/download.py index 0dbe4e3..6960048 100644 --- a/src/downloader/download.py +++ b/src/downloader/download.py @@ -1,5 +1,6 @@ """Downloader Class.""" import os +from pathlib import Path from queue import PriorityQueue from time import perf_counter from typing import Any, Tuple @@ -23,14 +24,20 @@ class Downloader(object): self.config = config self.patcher = patcher - def _download(self, url: str, file_name: str) -> None: - if ( - os.path.exists(self.config.temp_folder.joinpath(file_name)) - or self.config.dry_run - ): + @staticmethod + def file_status_check(file_name: Path, dry_run: bool, url: str) -> bool: + """Check if file already exists.""" + if os.path.exists(file_name) or dry_run: logger.debug( - f"Skipping download of {file_name}. File already exists or dry running." + f"Skipping download of {file_name} from {url}. File already exists or dry running." ) + return True + return False + + def _download(self, url: str, file_name: str) -> None: + if self.file_status_check( + self.config.temp_folder.joinpath(file_name), self.config.dry_run, url + ): return logger.info(f"Trying to download {file_name} from {url}") self._QUEUE_LENGTH += 1 @@ -99,3 +106,7 @@ class Downloader(object): self.specific_version(app, version) else: self.latest_version(app, **kwargs) + + def direct_download(self, dl: str, file_name: str) -> None: + """Download from DL.""" + self._download(dl, file_name) diff --git a/src/downloader/github.py b/src/downloader/github.py index 91046c2..8121959 100644 --- a/src/downloader/github.py +++ b/src/downloader/github.py @@ -1,7 +1,8 @@ """Github Downloader.""" -from typing import Dict +from typing import Dict, List import requests +from lastversion import latest from loguru import logger from src.downloader.download import Downloader @@ -41,3 +42,11 @@ class Github(Downloader): download_url = response.json()["assets"][0]["browser_download_url"] update_changelog(f"{owner}/{repo_name}", response.json()) self._download(download_url, file_name=app) + + @staticmethod + def patch_resource(repo_url: str, assets_filter: str) -> list[str]: + """Fetch patch resource from repo url.""" + latest_resource_version: List[str] = latest( + repo_url, assets_filter=assets_filter, output_format="assets" + ) + return latest_resource_version diff --git a/src/downloader/utils.py b/src/downloader/utils.py index 6a62436..667199b 100644 --- a/src/downloader/utils.py +++ b/src/downloader/utils.py @@ -1,63 +1,4 @@ """Utility class.""" -import os -from concurrent.futures import ThreadPoolExecutor, as_completed -from loguru import logger - -from src.config import RevancedConfig -from src.patches import Patches -from src.utils import PatcherDownloadFailed implement_method = "Please implement the method" - - -def download_revanced(config: RevancedConfig, patcher: Patches) -> None: - """Download Revanced and Extended Patches, Integration and CLI.""" - from src.downloader.factory import DownloaderFactory - - if os.path.exists("changelog.md") and not config.dry_run: - logger.debug("Deleting old changelog.md") - os.remove("changelog.md") - assets = [ - ["revanced", "revanced-cli", config.normal_cli_jar], - ["revanced", "revanced-integrations", config.normal_integrations_apk], - ["revanced", "revanced-patches", config.normal_patches_jar], - ] - if config.build_extended: - assets += [ - ["inotia00", "revanced-cli", config.cli_jar], - ["inotia00", "revanced-integrations", config.integrations_apk], - ["inotia00", "revanced-patches", config.patches_jar], - ] - if ( - "youtube" in config.apps - or "youtube_music" in config.apps - or "microg" in config.apps - ): - if config.build_extended and "microg" in config.apps: - assets += [ - ["inotia00", "mMicroG", "microg.apk"], - ] - else: - assets += [ - ["inotia00", "mMicroG", "microg-output.apk"], - ] - downloader = DownloaderFactory.create_downloader( - app="patches", patcher=patcher, config=config - ) - with ThreadPoolExecutor(7) as executor: - futures = [ - executor.submit( - downloader.download, - version="latest", - app=repo[2], - **{"owner": repo[0], "name": repo[1]}, - ) - for repo in assets - ] - for future in as_completed(futures): - try: - future.result() - except Exception as e: - raise PatcherDownloadFailed(f"An exception occurred: {e}") - logger.info("Downloaded revanced microG ,cli, integrations and patches.") diff --git a/src/parser.py b/src/parser.py index e5694c4..8180847 100644 --- a/src/parser.py +++ b/src/parser.py @@ -6,9 +6,10 @@ from typing import List from loguru import logger +from src.app import APP from src.config import RevancedConfig from src.patches import Patches -from src.utils import possible_archs, slugify +from src.utils import possible_archs class Parser(object): @@ -70,43 +71,29 @@ class Parser(object): # noinspection IncorrectFormatting def patch_app( self, - app: str, - version: str, - is_experimental: bool = False, - output_prefix: str = "-", + app: APP, ) -> None: """Revanced APP Patcher. :param app: Name of the app - :param version: Version of the application - :param is_experimental: Whether to enable experimental support - :param output_prefix: Prefix to add to the output apks file name """ - cli = self.config.normal_cli_jar - patches = self.config.normal_patches_jar - integrations = self.config.normal_integrations_apk - options = self.config.normal_options_json - if self.config.build_extended and app in self.config.extended_apps: - cli = self.config.cli_jar - patches = self.config.patches_jar - integrations = self.config.integrations_apk args = [ "-jar", - cli, + app.resource["cli"], "-a", - app + ".apk", + app.app_name + ".apk", "-b", - patches, + app.resource["patches"], "-m", - integrations, + app.resource["integrations"], "-o", - f"Re-{app}-{slugify(version)}{output_prefix}output.apk", + app.get_output_file_name(), "--keystore", self.config.keystore_name, "--options", - options, + "options.json", ] - if is_experimental: + if app.experiment: logger.debug("Using experimental features") args.append("--experimental") args[1::2] = map(lambda i: self.config.temp_folder.joinpath(i), args[1::2]) @@ -114,11 +101,7 @@ class Parser(object): self.exclude_all_patches() if self._PATCHES: args.extend(self._PATCHES) - if ( - self.config.build_extended - and len(self.config.archs_to_build) > 0 - and app in self.config.rip_libs_apps - ): + if app.app_name in self.config.rip_libs_apps: excluded = set(possible_archs) - set(self.config.archs_to_build) for arch in excluded: args.append("--rip-lib") @@ -126,8 +109,9 @@ class Parser(object): start = perf_counter() logger.debug( - f"Sending request to revanced cli for building {app} revanced with args java {args}" + f"Sending request to revanced cli for building with args java {args}" ) + return process = Popen(["java", *args], stdout=PIPE) output = process.stdout if not output: diff --git a/src/patches.py b/src/patches.py index e168b81..48717ab 100644 --- a/src/patches.py +++ b/src/patches.py @@ -1,13 +1,13 @@ """Revanced Patches.""" import json -import subprocess +import os from typing import Any, Dict, List, Tuple from loguru import logger -from requests import Session +from src.app import APP from src.config import RevancedConfig -from src.utils import AppNotFound, handle_response +from src.utils import AppNotFound, PatchesJsonFailed class Patches(object): @@ -50,59 +50,28 @@ class Patches(object): "ml.docilealligator.infinityforreddit": "infinity", "me.ccrama.redditslide": "slide", "com.onelouder.baconreader": "bacon", + "com.google.android.youtube": "youtube", + "com.google.android.apps.youtube.music": "youtube_music", + "com.mgoogle.android.gms": "microg", } revanced_app_ids = { key: (value, "_" + value) for key, value in _revanced_app_ids.items() } - _revanced_extended_app_ids = { - "com.google.android.youtube": "youtube", - "com.google.android.apps.youtube.music": "youtube_music", - "com.mgoogle.android.gms": "microg", - "com.reddit.frontpage": "reddit", - } - revanced_extended_app_ids = { - key: (value, "_" + value) for key, value in _revanced_extended_app_ids.items() - } - @staticmethod - def support_app() -> Dict[str, str]: - """Return supported apps.""" - return Patches._revanced_app_ids - - @staticmethod - def check_java(dry_run: bool) -> None: - """Check if Java17 is installed.""" - try: - if dry_run: - return - jd = subprocess.check_output( - ["java", "-version"], stderr=subprocess.STDOUT - ).decode("utf-8") - jd = jd[1:-1] - if "Runtime Environment" not in jd: - raise subprocess.CalledProcessError(-1, "java -version") - if "17" not in jd and "20" not in jd: - raise subprocess.CalledProcessError(-1, "java -version") - logger.debug("Cool!! Java is available") - except subprocess.CalledProcessError: - logger.debug("Java>= 17 Must be installed") - exit(-1) + def scrap_patches(self, file_name: str) -> Any: + """Scrap Patches.""" + if os.path.exists(file_name): + with open(file_name) as f: + patches = json.load(f) + return patches + raise PatchesJsonFailed() # noinspection DuplicatedCode - def fetch_patches(self) -> None: + def fetch_patches(self, config: RevancedConfig, app: APP) -> None: """Function to fetch all patches.""" - session = Session() - if self.config.dry_run: - logger.debug("fetching all patches from local file") - with open("patches.json") as f: - patches = json.load(f) - else: - url = "https://raw.githubusercontent.com/revanced/revanced-patches/main/patches.json" - logger.debug(f"fetching all patches from {url}") - response = session.get(url) - handle_response(response) - patches = response.json() - + patches = self.scrap_patches( + f'{config.temp_folder}/{app.resource["patches_json"]}' + ) for app_name in (self.revanced_app_ids[x][1] for x in self.revanced_app_ids): setattr(self, app_name, []) setattr(self, "universal_patch", []) @@ -122,47 +91,11 @@ class Patches(object): p["app"] = compatible_package p["version"] = version[-1] if version else "all" getattr(self, app_name).append(p) - if self.config.dry_run: - extended_patches = patches - else: - if self.config.build_extended: - url = "https://raw.githubusercontent.com/inotia00/revanced-patches/revanced-extended/patches.json" - else: - url = "https://raw.githubusercontent.com/revanced/revanced-patches/main/patches.json" - response = session.get(url) - handle_response(response) - extended_patches = response.json() - for app_name in ( - self.revanced_extended_app_ids[x][1] for x in self.revanced_extended_app_ids - ): - setattr(self, app_name, []) + n_patches = len(getattr(self, f"_{app.app_name}")) + app.no_of_patches = n_patches - for patch in extended_patches: - for compatible_package, version in [ - (x["name"], x["versions"]) for x in patch["compatiblePackages"] - ]: - if compatible_package in self.revanced_extended_app_ids: - app_name = self.revanced_extended_app_ids[compatible_package][1] - p = {x: patch[x] for x in ["name", "description"]} - p["app"] = compatible_package - p["version"] = version[-1] if version else "all" - getattr(self, app_name).append(p) - - for app_name, app_id in self.revanced_extended_app_ids.values(): - n_patches = len(getattr(self, app_id)) - logger.debug(f"Total patches in {app_name} are {n_patches}") - for app_name, app_id in self.revanced_app_ids.values(): - n_patches = len(getattr(self, app_id)) - logger.debug(f"Total patches in {app_name} are {n_patches}") - n_patches = len(getattr(self, "universal_patch")) - logger.debug(f"Total universal patches are {n_patches}") - - def __init__(self, config: RevancedConfig) -> None: - self.config = config - self.check_java(self.config.dry_run) - self.fetch_patches() - if self.config.dry_run: - self.config.apps = list(self._revanced_app_ids.values()) + def __init__(self, config: RevancedConfig, app: APP) -> None: + self.fetch_patches(config, app) def get(self, app: str) -> Tuple[List[Dict[str, str]], str]: """Get all patches for the given app. @@ -170,11 +103,7 @@ class Patches(object): :param app: Name of the application :return: Patches """ - logger.debug("Getting patches for %s" % app) app_names = {value[0]: value[1] for value in self.revanced_app_ids.values()} - app_names.update( - {value[0]: value[1] for value in self.revanced_extended_app_ids.values()} - ) if not (app_name := app_names.get(app)): raise AppNotFound(app) @@ -182,14 +111,13 @@ class Patches(object): version = "latest" try: version = next(i["version"] for i in patches if i["version"] != "all") - logger.debug(f"Recommended Version for patching {app} is {version}") except StopIteration: pass return patches, version # noinspection IncorrectFormatting def include_exclude_patch( - self, app: str, parser: Any, patches: List[Dict[str, str]] + self, app: APP, parser: Any, patches: List[Dict[str, str]] ) -> None: """Include and exclude patches for a given app. @@ -197,34 +125,20 @@ class Patches(object): :param parser: Parser Obj :param patches: All the patches of a given app """ - if self.config.build_extended and app in self.config.extended_apps: - excluded_patches = self.config.env.list( - f"EXCLUDE_PATCH_{app}_EXTENDED".upper(), [] - ) - included_patches = self.config.env.list( - f"INCLUDE_PATCH_{app}_EXTENDED".upper(), [] - ) - else: - excluded_patches = self.config.env.list(f"EXCLUDE_PATCH_{app}".upper(), []) - included_patches = self.config.env.list(f"INCLUDE_PATCH_{app}".upper(), []) for patch in patches: normalized_patch = patch["name"].lower().replace(" ", "-") parser.include( normalized_patch - ) if normalized_patch not in excluded_patches else parser.exclude( + ) if normalized_patch not in app.exclude_request else parser.exclude( normalized_patch ) - for normalized_patch in included_patches: + for normalized_patch in app.include_request: parser.include(normalized_patch) if normalized_patch not in getattr( self, "universal_patch", [] ) else () - excluded = parser.get_excluded_patches() - if excluded: - logger.debug(f"Excluded patches {excluded} for {app}") - else: - logger.debug(f"No excluded patches for {app}") + logger.info(app) - def get_app_configs(self, app: str) -> Tuple[List[Dict[str, str]], str, bool]: + def get_app_configs(self, app: "APP") -> List[Dict[str, str]]: """Get Configurations for a given app. :param app: Name of the application @@ -232,15 +146,15 @@ class Patches(object): experimental """ experiment = False - total_patches, recommended_version = self.get(app=app) - env_version = self.config.env.str(f"{app}_VERSION".upper(), None) - if env_version: - logger.debug(f"Picked {app} version {env_version} from env.") + total_patches, recommended_version = self.get(app=app.app_name) + if app.app_version: + logger.debug(f"Picked {app} version {app.app_version:} from env.") if ( - env_version == "latest" - or env_version > recommended_version - or env_version < recommended_version + app.app_version == "latest" + or app.app_version > recommended_version + or app.app_version < recommended_version ): experiment = True - recommended_version = env_version - return total_patches, recommended_version, experiment + recommended_version = app.app_version + app.set_recommended_version(recommended_version, experiment) + return total_patches diff --git a/src/utils.py b/src/utils.py index 1cb7ad0..950bd6d 100644 --- a/src/utils.py +++ b/src/utils.py @@ -1,5 +1,6 @@ """Utilities.""" import re +import subprocess from typing import Dict from loguru import logger @@ -50,6 +51,12 @@ class PatcherDownloadFailed(Exception): pass +class PatchesJsonFailed(ValueError): + """Patches failed.""" + + pass + + def handle_response(response: Response) -> None: """Handle Get Request Response.""" response_code = response.status_code @@ -76,3 +83,22 @@ def slugify(string: str) -> str: string = string.strip("-") return string + + +def check_java(dry_run: bool) -> None: + """Check if Java17 is installed.""" + try: + if dry_run: + return + jd = subprocess.check_output( + ["java", "-version"], stderr=subprocess.STDOUT + ).decode("utf-8") + jd = jd[1:-1] + if "Runtime Environment" not in jd: + raise subprocess.CalledProcessError(-1, "java -version") + if "17" not in jd and "20" not in jd: + raise subprocess.CalledProcessError(-1, "java -version") + logger.debug("Cool!! Java is available") + except subprocess.CalledProcessError: + logger.debug("Java>= 17 Must be installed") + exit(-1)