From a2088d843aff594b1c5c0ecf32d5e7e02378251a Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Fri, 5 Sep 2025 12:49:45 +0200 Subject: [PATCH 01/11] Cleanup after failed cfbs-convert now works also when `cfbs.json` doesn't exist Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfbs/commands.py b/cfbs/commands.py index d2b26eeb..809b210a 100644 --- a/cfbs/commands.py +++ b/cfbs/commands.py @@ -1093,7 +1093,7 @@ def analyze_command( @cfbs_command("convert") def convert_command(non_interactive=False, offline=False): def cfbs_convert_cleanup(): - os.unlink(cfbs_filename()) + rm(cfbs_filename(), missing_ok=True) rm(".git", missing_ok=True) def cfbs_convert_git_commit( From 369206ed33cfab4ddabbba023955de174131236f Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Mon, 8 Sep 2025 13:06:14 +0200 Subject: [PATCH 02/11] Renamed masterfiles download related code file Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/masterfiles/{download_all_versions.py => download.py} | 0 cfbs/masterfiles/generate_release_information.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename cfbs/masterfiles/{download_all_versions.py => download.py} (100%) diff --git a/cfbs/masterfiles/download_all_versions.py b/cfbs/masterfiles/download.py similarity index 100% rename from cfbs/masterfiles/download_all_versions.py rename to cfbs/masterfiles/download.py diff --git a/cfbs/masterfiles/generate_release_information.py b/cfbs/masterfiles/generate_release_information.py index 02b3403e..2e4ea7e2 100644 --- a/cfbs/masterfiles/generate_release_information.py +++ b/cfbs/masterfiles/generate_release_information.py @@ -1,5 +1,5 @@ from cfbs.masterfiles.analyze import version_is_at_least -from cfbs.masterfiles.download_all_versions import download_all_versions +from cfbs.masterfiles.download import download_all_versions from cfbs.masterfiles.generate_vcf_download import generate_vcf_download from cfbs.masterfiles.generate_vcf_git_checkout import generate_vcf_git_checkout from cfbs.masterfiles.check_download_matches_git import check_download_matches_git From 6d6003ba4efb284625256a004646823108f21745 Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Mon, 8 Sep 2025 13:25:22 +0200 Subject: [PATCH 03/11] Decoupled MPF download URLs code Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/masterfiles/download.py | 40 +++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/cfbs/masterfiles/download.py b/cfbs/masterfiles/download.py index 968a8cb2..93e8ed52 100644 --- a/cfbs/masterfiles/download.py +++ b/cfbs/masterfiles/download.py @@ -75,6 +75,28 @@ def get_download_urls_enterprise(min_version=None): return download_urls, reported_checksums +def get_all_download_urls(min_version=None): + download_urls, reported_checksums = get_download_urls_enterprise(min_version) + + # add masterfiles versions which do not appear in Enterprise releases but appear in Community releases + # 3.12.0b1 + version = "3.12.0b1" + if version_is_at_least(version, min_version): + download_url = "https://cfengine-package-repos.s3.amazonaws.com/community_binaries/Community-3.12.0b1/misc/cfengine-masterfiles-3.12.0b1.pkg.tar.gz" + digest = "ede305dae7be3edfac04fc5b7f63b46adb3a5b1612f4755e855ee8e6b8d344d7" + download_urls[version] = download_url + reported_checksums[version] = digest + # 3.10.0b1 + version = "3.10.0b1" + if version_is_at_least(version, min_version): + download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.10.0b1.pkg.tar.gz" + digest = "09291617254705d79dea2531b23dbd0754f09029e90ce0b43b275aa02c1223a3" + download_urls[version] = download_url + reported_checksums[version] = digest + + return download_urls, reported_checksums + + def download_versions_from_urls(download_path, download_urls, reported_checksums): downloaded_versions = [] @@ -107,23 +129,7 @@ def download_versions_from_urls(download_path, download_urls, reported_checksums def download_all_versions(download_path, min_version=None): - download_urls, reported_checksums = get_download_urls_enterprise(min_version) - - # add masterfiles versions which do not appear in Enterprise releases but appear in Community releases - # 3.12.0b1 - version = "3.12.0b1" - if version_is_at_least(version, min_version): - download_url = "https://cfengine-package-repos.s3.amazonaws.com/community_binaries/Community-3.12.0b1/misc/cfengine-masterfiles-3.12.0b1.pkg.tar.gz" - digest = "ede305dae7be3edfac04fc5b7f63b46adb3a5b1612f4755e855ee8e6b8d344d7" - download_urls[version] = download_url - reported_checksums[version] = digest - # 3.10.0b1 - version = "3.10.0b1" - if version_is_at_least(version, min_version): - download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.10.0b1.pkg.tar.gz" - digest = "09291617254705d79dea2531b23dbd0754f09029e90ce0b43b275aa02c1223a3" - download_urls[version] = download_url - reported_checksums[version] = digest + download_urls, reported_checksums = get_all_download_urls(min_version) downloaded_versions = download_versions_from_urls( download_path, download_urls, reported_checksums From a4df834a0fb5e2bfd2e567e60240e157f25dbe50 Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:24:57 +0200 Subject: [PATCH 04/11] Added utility function to display a diff between two files at paths Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/utils.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cfbs/utils.py b/cfbs/utils.py index b79280f3..6ae97b6e 100644 --- a/cfbs/utils.py +++ b/cfbs/utils.py @@ -102,6 +102,15 @@ def sh(cmd: str, directory=None): _sh("%s" % cmd) +def display_diff(path_A, path_B): + """Also displays `stderr`.""" + cmd = "diff -u " + path_A + " " + path_B + # `diff`'s exit code is 1 for success when there's a difference, so don't use `check=True` + cp = subprocess.run(cmd, shell=True) + if cp.returncode not in (0, 1): + raise + + def mkdir(path: str, exist_ok=True): os.makedirs(path, exist_ok=exist_ok) From 5f099e378f71b6bee2830f4a1da72ffdf65d44a0 Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:25:34 +0200 Subject: [PATCH 05/11] Using cfbs-convert non-interactively is now actually enabled Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cfbs/main.py b/cfbs/main.py index 92c225b7..b5b6b82c 100644 --- a/cfbs/main.py +++ b/cfbs/main.py @@ -145,6 +145,7 @@ def _main() -> int: "clean", "update", "input", + "convert", ): raise CFBSUserError( "The option --non-interactive is not for cfbs %s" % (args.command) From a6b08177762f42b49a82b7ea701d3e1b9c1f669d Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:27:26 +0200 Subject: [PATCH 06/11] Added a function to download a single masterfiles version Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/masterfiles/download.py | 84 ++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/cfbs/masterfiles/download.py b/cfbs/masterfiles/download.py index 93e8ed52..82308bb3 100644 --- a/cfbs/masterfiles/download.py +++ b/cfbs/masterfiles/download.py @@ -97,6 +97,81 @@ def get_all_download_urls(min_version=None): return download_urls, reported_checksums +def get_single_download_url(version): + # missing hard-coded (url, checksum)s, taken from above functions + if version == "3.10.0": + download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.10.0.pkg.tar.gz" + reported_checksum = ( + "7b5e237529e11ce4ae295922dad1a681f13b95f3a7d247d39d3f5088f1a1d7d3" + ) + elif version == "3.9.2": + download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.9.2.pkg.tar.gz" + reported_checksum = ( + "ae1a758530d4a4aad5b6812b61fc37ad1b5900b755f88a1ab98da7fd05a9f5cc" + ) + elif version == "3.12.0b1": + download_url = "https://cfengine-package-repos.s3.amazonaws.com/community_binaries/Community-3.12.0b1/misc/cfengine-masterfiles-3.12.0b1.pkg.tar.gz" + reported_checksum = ( + "ede305dae7be3edfac04fc5b7f63b46adb3a5b1612f4755e855ee8e6b8d344d7" + ) + elif version == "3.10.0b1": + download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.10.0b1.pkg.tar.gz" + reported_checksum = ( + "09291617254705d79dea2531b23dbd0754f09029e90ce0b43b275aa02c1223a3" + ) + else: + masterfiles_found = False + + try: + data = get_json(ENTERPRISE_RELEASES_URL) + except CFBSNetworkError: + raise CFBSExitError( + "Downloading CFEngine release data failed - check your Wi-Fi / network settings." + ) + + for release_data in data["releases"]: + release_version = release_data["version"] + + if release_version == version: + release_url = release_data["URL"] + try: + subdata = get_json(release_url) + except CFBSNetworkError: + raise CFBSExitError( + "Downloading CFEngine release data for version %s failed - check your Wi-Fi / network settings." + % version + ) + artifacts_data = subdata["artifacts"] + + if "Additional Assets" not in artifacts_data: + break + + assets_data = artifacts_data["Additional Assets"] + masterfiles_data = None + + for asset in assets_data: + if asset["Title"] == "Masterfiles ready-to-install tarball": + masterfiles_data = asset + + if masterfiles_data is None: + break + + download_url = masterfiles_data["URL"] + reported_checksum = masterfiles_data["SHA256"] + + masterfiles_found = True + break + + if not masterfiles_found: + raise CFBSExitError("Download URL of given MPF version was not found") + + # Pyright doesn't understand that these variables are in fact bound when `masterfiles_found` is `True` + return ( + download_url, # pyright: ignore[reportPossiblyUnboundVariable] + reported_checksum, # pyright: ignore[reportPossiblyUnboundVariable] + ) + + def download_versions_from_urls(download_path, download_urls, reported_checksums): downloaded_versions = [] @@ -136,3 +211,12 @@ def download_all_versions(download_path, min_version=None): ) return downloaded_versions + + +def download_single_version(download_path, version): + download_url, reported_checksum = get_single_download_url(version) + + download_urls = {version: download_url} + reported_checksums = {version: reported_checksum} + + download_versions_from_urls(download_path, download_urls, reported_checksums) From 05844e14e6c1e149a5d01c6f84d9f1c321d5ab8c Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:28:57 +0200 Subject: [PATCH 07/11] Handle errors and cleanup in more places in cfbs-convert Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/commands.py | 63 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/cfbs/commands.py b/cfbs/commands.py index 809b210a..1110677f 100644 --- a/cfbs/commands.py +++ b/cfbs/commands.py @@ -1134,14 +1134,18 @@ def cfbs_convert_git_commit( ) print("Analyzing '" + path_string + "'...") - analyzed_files, _ = analyze_policyset( - path=dir_name, - is_parentpath=False, - reference_version=None, - masterfiles_dir=dir_name, - ignored_path_components=None, - offline=offline, - ) + try: + analyzed_files, _ = analyze_policyset( + path=dir_name, + is_parentpath=False, + reference_version=None, + masterfiles_dir=dir_name, + ignored_path_components=None, + offline=offline, + ) + except: + print("Analyzing the policy set failed, aborting conversion.") + raise current_index = CFBSConfig.get_instance().index default_version = current_index.get_module_object("masterfiles")["version"] @@ -1167,7 +1171,20 @@ def cfbs_convert_git_commit( print("Initializing a new CFBS project...") # since there should be no other files than the masterfiles-name directory, there shouldn't be a .git directory assert not is_git_repo() - r = init_command(masterfiles="no", non_interactive=non_interactive, use_git=True) + try: + r = init_command( + masterfiles="no", non_interactive=non_interactive, use_git=True + ) + except CFBSGitError: + cfbs_convert_cleanup() + print( + "A Git operation failed during initialization of a new CFBS project, aborting conversion." + ) + raise + except: + print("Initializing a new CFBS project failed, aborting conversion.") + cfbs_convert_cleanup() + raise # the cfbs-init should've created a Git repository assert is_git_repo() if r != 0: @@ -1177,19 +1194,33 @@ def cfbs_convert_git_commit( print("Adding masterfiles %s to the project..." % masterfiles_version) masterfiles_to_add = ["masterfiles@%s" % masterfiles_version] - r = add_command(masterfiles_to_add, added_by="cfbs convert") + try: + r = add_command(masterfiles_to_add, added_by="cfbs convert") + except: + print( + "Adding the masterfiles module to the project failed, aborting conversion." + ) + cfbs_convert_cleanup() + raise if r != 0: - print("Adding the masterfiles module failed, aborting conversion.") + print( + "Adding the masterfiles module to the project failed, aborting conversion." + ) cfbs_convert_cleanup() return r print("Adding the policy files...") local_module_to_add = [path_string] - r = add_command( - local_module_to_add, - added_by="cfbs convert", - explicit_build_steps=["copy ./ ./"], - ) + try: + r = add_command( + local_module_to_add, + added_by="cfbs convert", + explicit_build_steps=["copy ./ ./"], + ) + except: + print("Adding the policy files module failed, aborting conversion.") + cfbs_convert_cleanup() + raise if r != 0: print("Adding the policy files module failed, aborting conversion.") cfbs_convert_cleanup() From 74f489aa203118652cabf8ed137bbf5b97f47182 Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:29:42 +0200 Subject: [PATCH 08/11] Implemented Step 3 of cfbs-convert Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/commands.py | 67 ++++++++++++++++++++++++++++++++++++++++++++++-- cfbs/git.py | 2 +- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/cfbs/commands.py b/cfbs/commands.py index 1110677f..93b57948 100644 --- a/cfbs/commands.py +++ b/cfbs/commands.py @@ -60,12 +60,15 @@ def search_command(terms: List[str]): from cfbs.cfbs_json import CFBSJson from cfbs.cfbs_types import CFBSCommandExitCode, CFBSCommandGitResult from cfbs.masterfiles.analyze import most_relevant_version +from cfbs.masterfiles.download import download_single_version from cfbs.updates import ModuleUpdates, update_module from cfbs.utils import ( CFBSNetworkError, CFBSUserError, CFBSValidationError, + cfbs_dir, cfbs_filename, + display_diff, is_cfbs_repo, read_json, CFBSExitError, @@ -1278,7 +1281,7 @@ def cfbs_convert_git_commit( if prompt_user_yesno( non_interactive, "Delete files from other versions? (Recommended)" ): - print("Deleting %s files." % len(files_to_delete)) + print("Deleting %s files..." % len(files_to_delete)) for file_d in files_to_delete: rm(os.path.join(dir_name, file_d)) @@ -1292,7 +1295,67 @@ def cfbs_convert_git_commit( print( "The next conversion step is to handle files which have custom modifications." ) - print("This is not implemented yet.") + if not prompt_user_yesno(non_interactive, "Do you want to continue?"): + raise CFBSExitError("User did not proceed, exiting.") + print("The following files have custom modifications:") + modified_files = analyzed_files.modified + for modified_file in modified_files: + print("-", modified_file) + for i, modified_file in enumerate(modified_files, start=1): + # program failures in the middle of this loop would be very user-unfriendly, + # so we will catch exceptions and continue the conversion when handling errors + print("\nFile", i, "diff -", modified_file + ":") + mpf_dir_path = os.path.join(cfbs_dir(), "masterfiles") + mpf_version_dir_path = os.path.join( + mpf_dir_path, masterfiles_version, "tarball", "masterfiles" + ) + mpf_filepath = os.path.join(mpf_version_dir_path, modified_file) + if not os.path.exists(mpf_version_dir_path): + try: + download_single_version(mpf_dir_path, masterfiles_version) + except Exception as e: + print( + "Downloading original masterfiles failed (%s), continuing conversion - displaying file diffs will fail." + % str(e) + ) + try: + display_diff(mpf_filepath, os.path.join(dir_name, modified_file)) + except: + log.warning( + "Displaying a diff between your file and the default file failed, continuing without displaying a diff..." + ) + if i == 1: + print( + "Above you can see the differences between your file and the default file." + ) + print( + "As much as possible, we recommend getting rid of these custom modifications." + ) + print( + "Usually, the same thing can be achieved by adding a variable to def.json, or through adding your own policy file (inside 'services/')." + ) + prompt_str = "\nChoose an option:\n" + prompt_str += "1) Drop modifications - They are not important, or can be achieved in another way.\n" + prompt_str += "2) Keep modified file - File is kept as is, and can be handled later. Can make future upgrades more complicated.\n" + prompt_str += "3) (Not implemented yet) Keep patch file - " + prompt_str += "File is converted into a patch file (diff) that hopefully will apply to future versions as well.\n" + + response = prompt_user(non_interactive, prompt_str, ["1", "2"], "1") + + if response == "1": + print("Deleting './%s'..." % modified_file) + rm(os.path.join(dir_name, modified_file)) + commit_message = "Deleted './%s'" % modified_file + print("Creating Git commit - %s..." % commit_message) + try: + cfbs_convert_git_commit(commit_message) + except: + log.warning("Git commit failed, continuing without committing...") + if response == "2": + print("Keeping file as is, nothing to do.") + + print("Conversion finished successfully.") + return 0 diff --git a/cfbs/git.py b/cfbs/git.py index 87a9686a..335515bb 100644 --- a/cfbs/git.py +++ b/cfbs/git.py @@ -49,7 +49,7 @@ def ls_remote(remote, branch): def is_git_repo(path=None): - """Is the given path a Git repository?) + """Is the given path a Git repository? :param:`path` defaults to CWD (if `None`) From 1829897dad3f8567274c8c1496e5b77f8963fb67 Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:36:09 +0200 Subject: [PATCH 09/11] Do not display file diffs at all if downloading masterfiles failed Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/commands.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/cfbs/commands.py b/cfbs/commands.py index 93b57948..8fd09e31 100644 --- a/cfbs/commands.py +++ b/cfbs/commands.py @@ -1310,24 +1310,28 @@ def cfbs_convert_git_commit( mpf_dir_path, masterfiles_version, "tarball", "masterfiles" ) mpf_filepath = os.path.join(mpf_version_dir_path, modified_file) + display_diffs = True if not os.path.exists(mpf_version_dir_path): try: download_single_version(mpf_dir_path, masterfiles_version) except Exception as e: print( - "Downloading original masterfiles failed (%s), continuing conversion - displaying file diffs will fail." + "Downloading original masterfiles failed (%s), continuing conversion without displaying file diffs." % str(e) ) - try: - display_diff(mpf_filepath, os.path.join(dir_name, modified_file)) - except: - log.warning( - "Displaying a diff between your file and the default file failed, continuing without displaying a diff..." - ) + display_diffs = False + if display_diffs: + try: + display_diff(mpf_filepath, os.path.join(dir_name, modified_file)) + except: + log.warning( + "Displaying a diff between your file and the default file failed, continuing without displaying a diff..." + ) if i == 1: - print( - "Above you can see the differences between your file and the default file." - ) + if display_diffs: + print( + "Above you can see the differences between your file and the default file." + ) print( "As much as possible, we recommend getting rid of these custom modifications." ) From 810312b59499ff1d678f4c62c79e5505207e3501 Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Tue, 9 Sep 2025 20:25:05 +0200 Subject: [PATCH 10/11] Reduced repetition of hardcoded version, URL and checksum strings Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/masterfiles/download.py | 160 ++++++++++++++++------------------- 1 file changed, 74 insertions(+), 86 deletions(-) diff --git a/cfbs/masterfiles/download.py b/cfbs/masterfiles/download.py index 82308bb3..6ae2e3f4 100644 --- a/cfbs/masterfiles/download.py +++ b/cfbs/masterfiles/download.py @@ -7,6 +7,33 @@ ENTERPRISE_RELEASES_URL = "https://cfengine.com/release-data/enterprise/releases.json" +COMMUNITY_ONLY_VERSIONS = ["3.12.0b1", "3.10.0b1"] +"""Masterfiles versions which do not appear in Enterprise releases but appear in Community releases.""" + +MISSING_DATA_VERSIONS = ["3.10.0", "3.9.2"] +"""Rationale for each version: +* 3.10.0:\\ + For some reason, the `"Masterfiles ready-to-install tarball"` is a .tar.gz tarball, rather than a .pkg.tar.gz tarball. + However, an unlisted analoguous URL for the .pkg.tar.gz tarball does exist. +* 3.9.2:\\ + No masterfiles are listed in the release data, but an unlisted analoguous URL does exist.""" + +HARDCODED_VERSIONS = COMMUNITY_ONLY_VERSIONS + MISSING_DATA_VERSIONS + +HARDCODED_URLS = { + "3.12.0b1": "https://cfengine-package-repos.s3.amazonaws.com/community_binaries/Community-3.12.0b1/misc/cfengine-masterfiles-3.12.0b1.pkg.tar.gz", + "3.10.0b1": "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.10.0b1.pkg.tar.gz", + "3.10.0": "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.10.0.pkg.tar.gz", + "3.9.2": "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.9.2.pkg.tar.gz", +} +HARDCODED_CHECKSUMS = { + "3.12.0b1": "ede305dae7be3edfac04fc5b7f63b46adb3a5b1612f4755e855ee8e6b8d344d7", + "3.10.0b1": "09291617254705d79dea2531b23dbd0754f09029e90ce0b43b275aa02c1223a3", + "3.10.0": "7b5e237529e11ce4ae295922dad1a681f13b95f3a7d247d39d3f5088f1a1d7d3", + "3.9.2": "ae1a758530d4a4aad5b6812b61fc37ad1b5900b755f88a1ab98da7fd05a9f5cc", +} + + def get_download_urls_enterprise(min_version=None): download_urls = {} reported_checksums = {} @@ -26,20 +53,9 @@ def get_download_urls_enterprise(min_version=None): if not version_is_at_least(version, min_version): continue - if version == "3.10.0": - # for 3.10.0, for some reason, the "Masterfiles ready-to-install tarball" is a .tar.gz tarball, rather than a .pkg.tar.gz tarball - # download the .pkg.tar.gz tarball from an unlisted analoguous URL instead - download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.10.0.pkg.tar.gz" - digest = "7b5e237529e11ce4ae295922dad1a681f13b95f3a7d247d39d3f5088f1a1d7d3" - download_urls[version] = download_url - reported_checksums[version] = digest - continue - if version == "3.9.2": - # for 3.9.2, no masterfiles are listed, but an unlisted analoguous URL exists - download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.9.2.pkg.tar.gz" - digest = "ae1a758530d4a4aad5b6812b61fc37ad1b5900b755f88a1ab98da7fd05a9f5cc" - download_urls[version] = download_url - reported_checksums[version] = digest + if version in MISSING_DATA_VERSIONS: + download_urls[version] = HARDCODED_URLS[version] + reported_checksums[version] = HARDCODED_CHECKSUMS[version] continue release_url = release_data["URL"] @@ -78,92 +94,64 @@ def get_download_urls_enterprise(min_version=None): def get_all_download_urls(min_version=None): download_urls, reported_checksums = get_download_urls_enterprise(min_version) - # add masterfiles versions which do not appear in Enterprise releases but appear in Community releases - # 3.12.0b1 - version = "3.12.0b1" - if version_is_at_least(version, min_version): - download_url = "https://cfengine-package-repos.s3.amazonaws.com/community_binaries/Community-3.12.0b1/misc/cfengine-masterfiles-3.12.0b1.pkg.tar.gz" - digest = "ede305dae7be3edfac04fc5b7f63b46adb3a5b1612f4755e855ee8e6b8d344d7" - download_urls[version] = download_url - reported_checksums[version] = digest - # 3.10.0b1 - version = "3.10.0b1" - if version_is_at_least(version, min_version): - download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.10.0b1.pkg.tar.gz" - digest = "09291617254705d79dea2531b23dbd0754f09029e90ce0b43b275aa02c1223a3" - download_urls[version] = download_url - reported_checksums[version] = digest + for version in COMMUNITY_ONLY_VERSIONS: + if version_is_at_least(version, min_version): + download_urls[version] = HARDCODED_URLS[version] + reported_checksums[version] = HARDCODED_CHECKSUMS[version] return download_urls, reported_checksums def get_single_download_url(version): - # missing hard-coded (url, checksum)s, taken from above functions - if version == "3.10.0": - download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.10.0.pkg.tar.gz" - reported_checksum = ( - "7b5e237529e11ce4ae295922dad1a681f13b95f3a7d247d39d3f5088f1a1d7d3" - ) - elif version == "3.9.2": - download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.9.2.pkg.tar.gz" - reported_checksum = ( - "ae1a758530d4a4aad5b6812b61fc37ad1b5900b755f88a1ab98da7fd05a9f5cc" - ) - elif version == "3.12.0b1": - download_url = "https://cfengine-package-repos.s3.amazonaws.com/community_binaries/Community-3.12.0b1/misc/cfengine-masterfiles-3.12.0b1.pkg.tar.gz" - reported_checksum = ( - "ede305dae7be3edfac04fc5b7f63b46adb3a5b1612f4755e855ee8e6b8d344d7" - ) - elif version == "3.10.0b1": - download_url = "https://cfengine-package-repos.s3.amazonaws.com/tarballs/cfengine-masterfiles-3.10.0b1.pkg.tar.gz" - reported_checksum = ( - "09291617254705d79dea2531b23dbd0754f09029e90ce0b43b275aa02c1223a3" - ) - else: - masterfiles_found = False - - try: - data = get_json(ENTERPRISE_RELEASES_URL) - except CFBSNetworkError: - raise CFBSExitError( - "Downloading CFEngine release data failed - check your Wi-Fi / network settings." - ) + if version in HARDCODED_VERSIONS: + download_url = HARDCODED_URLS[version] + reported_checksum = HARDCODED_CHECKSUMS[version] + return (download_url, reported_checksum) - for release_data in data["releases"]: - release_version = release_data["version"] + masterfiles_found = False - if release_version == version: - release_url = release_data["URL"] - try: - subdata = get_json(release_url) - except CFBSNetworkError: - raise CFBSExitError( - "Downloading CFEngine release data for version %s failed - check your Wi-Fi / network settings." - % version - ) - artifacts_data = subdata["artifacts"] + try: + data = get_json(ENTERPRISE_RELEASES_URL) + except CFBSNetworkError: + raise CFBSExitError( + "Downloading CFEngine release data failed - check your Wi-Fi / network settings." + ) - if "Additional Assets" not in artifacts_data: - break + for release_data in data["releases"]: + release_version = release_data["version"] + + if release_version == version: + release_url = release_data["URL"] + try: + subdata = get_json(release_url) + except CFBSNetworkError: + raise CFBSExitError( + "Downloading CFEngine release data for version %s failed - check your Wi-Fi / network settings." + % version + ) + artifacts_data = subdata["artifacts"] + + if "Additional Assets" not in artifacts_data: + break - assets_data = artifacts_data["Additional Assets"] - masterfiles_data = None + assets_data = artifacts_data["Additional Assets"] + masterfiles_data = None - for asset in assets_data: - if asset["Title"] == "Masterfiles ready-to-install tarball": - masterfiles_data = asset + for asset in assets_data: + if asset["Title"] == "Masterfiles ready-to-install tarball": + masterfiles_data = asset - if masterfiles_data is None: - break + if masterfiles_data is None: + break - download_url = masterfiles_data["URL"] - reported_checksum = masterfiles_data["SHA256"] + download_url = masterfiles_data["URL"] + reported_checksum = masterfiles_data["SHA256"] - masterfiles_found = True - break + masterfiles_found = True + break - if not masterfiles_found: - raise CFBSExitError("Download URL of given MPF version was not found") + if not masterfiles_found: + raise CFBSExitError("Download URL of given MPF version was not found") # Pyright doesn't understand that these variables are in fact bound when `masterfiles_found` is `True` return ( From 945b64334269ec28cbcb6d82028dc6b4455f32cd Mon Sep 17 00:00:00 2001 From: jakub-nt <175944085+jakub-nt@users.noreply.github.com> Date: Tue, 9 Sep 2025 20:36:28 +0200 Subject: [PATCH 11/11] Simplified logic in masterfiles download code Signed-off-by: jakub-nt <175944085+jakub-nt@users.noreply.github.com> --- cfbs/masterfiles/download.py | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/cfbs/masterfiles/download.py b/cfbs/masterfiles/download.py index 6ae2e3f4..43685887 100644 --- a/cfbs/masterfiles/download.py +++ b/cfbs/masterfiles/download.py @@ -72,10 +72,8 @@ def get_download_urls_enterprise(min_version=None): # happens for 3.9.0b1, 3.8.0b1, 3.6.1, 3.6.0 continue - assets_data = artifacts_data["Additional Assets"] masterfiles_data = None - - for asset in assets_data: + for asset in artifacts_data["Additional Assets"]: if asset["Title"] == "Masterfiles ready-to-install tarball": masterfiles_data = asset @@ -108,8 +106,6 @@ def get_single_download_url(version): reported_checksum = HARDCODED_CHECKSUMS[version] return (download_url, reported_checksum) - masterfiles_found = False - try: data = get_json(ENTERPRISE_RELEASES_URL) except CFBSNetworkError: @@ -134,30 +130,14 @@ def get_single_download_url(version): if "Additional Assets" not in artifacts_data: break - assets_data = artifacts_data["Additional Assets"] - masterfiles_data = None - - for asset in assets_data: + for asset in artifacts_data["Additional Assets"]: if asset["Title"] == "Masterfiles ready-to-install tarball": - masterfiles_data = asset - - if masterfiles_data is None: - break - - download_url = masterfiles_data["URL"] - reported_checksum = masterfiles_data["SHA256"] + download_url = asset["URL"] + reported_checksum = asset["SHA256"] - masterfiles_found = True - break + return (download_url, reported_checksum) - if not masterfiles_found: - raise CFBSExitError("Download URL of given MPF version was not found") - - # Pyright doesn't understand that these variables are in fact bound when `masterfiles_found` is `True` - return ( - download_url, # pyright: ignore[reportPossiblyUnboundVariable] - reported_checksum, # pyright: ignore[reportPossiblyUnboundVariable] - ) + raise CFBSExitError("Download URL of given MPF version was not found") def download_versions_from_urls(download_path, download_urls, reported_checksums):