From 9e8ea219e5f17f18c5be27753f21126c9da73993 Mon Sep 17 00:00:00 2001 From: Muhammad Umer Date: Fri, 17 Nov 2023 15:16:47 +0500 Subject: [PATCH] chore: update process_config.py and releated files --- .gitignore | 1 + OpenEdX.xcodeproj/project.pbxproj | 2 +- OpenEdX/Info.plist | 2 + config.yaml | 5 - config_script/process_config.py | 307 ++++++++++++++++++ default_config/default/config.yaml | 4 - default_config/default/ios.yaml | 1 - .../{default/shared.yaml => dev/config.yaml} | 1 + default_config/dev/file_mappings.yaml | 3 + default_config/prod/config.yaml | 4 + default_config/prod/file_mappings.yaml | 3 + default_config/stage/config.yaml | 4 + default_config/stage/file_mappings.yaml | 3 + process_config.py | 23 +- 14 files changed, 349 insertions(+), 14 deletions(-) delete mode 100644 config.yaml create mode 100644 config_script/process_config.py delete mode 100644 default_config/default/config.yaml delete mode 100644 default_config/default/ios.yaml rename default_config/{default/shared.yaml => dev/config.yaml} (85%) create mode 100644 default_config/dev/file_mappings.yaml create mode 100644 default_config/prod/config.yaml create mode 100644 default_config/prod/file_mappings.yaml create mode 100644 default_config/stage/config.yaml create mode 100644 default_config/stage/file_mappings.yaml diff --git a/.gitignore b/.gitignore index c6c0df98a..c8c1be1a6 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,4 @@ vendor/ venv/ Podfile.lock +config_settings.yaml diff --git a/OpenEdX.xcodeproj/project.pbxproj b/OpenEdX.xcodeproj/project.pbxproj index c51caba45..069226267 100644 --- a/OpenEdX.xcodeproj/project.pbxproj +++ b/OpenEdX.xcodeproj/project.pbxproj @@ -390,7 +390,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "#!/bin/bash\n\nVENV_PATH=\"${SRCROOT}/venv\"\n\nif [ ! -d \"$VENV_PATH\" ]; then\n /usr/bin/python3 -m venv \"$VENV_PATH\"\nfi\n\nsource \"$VENV_PATH/bin/activate\"\n\npip install --upgrade pip\npip install PyYAML\n\npython process_config.py \"$CONFIGURATION\"\n\ndeactivate\n"; + shellScript = "#!/bin/bash\n\nVENV_PATH=\"${SRCROOT}/venv\"\n\nif [ ! -d \"$VENV_PATH\" ]; then\n /usr/bin/python3 -m venv \"$VENV_PATH\"\nfi\n\nsource \"$VENV_PATH/bin/activate\"\n\npip install --upgrade pip\npip install PyYAML\n\nscheme_mapping='{\n \"prod\": [\"ReleaseProd\", \"DebugProd\"],\n \"stage\": [\"ReleaseStage\", \"DebugStage\"],\n \"dev\": [\"ReleaseDev\", \"DebugDev\"]\n}'\n\npython config_script/process_config.py \"$CONFIGURATION\" \"$scheme_mapping\"\n\ndeactivate\n"; }; /* End PBXShellScriptBuildPhase section */ diff --git a/OpenEdX/Info.plist b/OpenEdX/Info.plist index b94522839..9fadbae9c 100644 --- a/OpenEdX/Info.plist +++ b/OpenEdX/Info.plist @@ -4,6 +4,8 @@ Configuration $(CONFIGURATION) + ExampleKey + ExampleValue FirebaseAppDelegateProxyEnabled FirebaseAutomaticScreenReportingEnabled diff --git a/config.yaml b/config.yaml deleted file mode 100644 index c21f3b1cb..000000000 --- a/config.yaml +++ /dev/null @@ -1,5 +0,0 @@ -config_directory: '../config' -config_mapping: - dev: 'prod_test' - prod: 'prod' - stage: 'stage' \ No newline at end of file diff --git a/config_script/process_config.py b/config_script/process_config.py new file mode 100644 index 000000000..5d3f6ad91 --- /dev/null +++ b/config_script/process_config.py @@ -0,0 +1,307 @@ +import plistlib +import os +import yaml +from pathlib import Path +import sys +import json + +class PlistManager: + def __init__(self, config_dir, config_files): + self.config_dir = config_dir + self.config_files = config_files + + def get_config_paths(self): + return [Path(self.config_dir) / config_name for config_name in self.config_files] + + def get_product_name(self): + return os.getenv('PRODUCT_NAME') + + def get_bundle_identifier(self): + return os.getenv('PRODUCT_BUNDLE_IDENTIFIER') + + def get_info_plist_path(self): + return os.getenv('INFOPLIST_PATH') + + def get_wrapper_name(self): + return os.getenv('WRAPPER_NAME') + + def get_built_products_path(self): + return os.getenv('BUILT_PRODUCTS_DIR') + + def get_bundle_config_path(self): + return os.path.join(self.get_built_products_path(), self.get_wrapper_name(), 'config.plist') + + def get_app_info_plist_path(self): + built_products_path = self.get_built_products_path() + info_plist_path = self.get_info_plist_path() + + if built_products_path and info_plist_path: + return os.path.join(built_products_path, info_plist_path) + else: + return None + + def get_firebase_info_plist_path(self): + built_products_path = self.get_built_products_path() + wrapper_name = self.get_wrapper_name() + + if built_products_path and wrapper_name: + return os.path.join(built_products_path, wrapper_name, 'GoogleService-Info.plist') + else: + print("The BUILT_PRODUCTS_DIR or WRAPPER_NAME environment variable is not set.") + return None + + def get_firebase_config_path(self): + built_products_path = self.get_built_products_path() + wrapper_name = self.get_wrapper_name() + + if built_products_path and wrapper_name: + return os.path.join(built_products_path, wrapper_name, 'firebase.plist') + else: + print("The BUILT_PRODUCTS_DIR or WRAPPER_NAME environment variable is not set.") + return None + + def load_config(self): + properties = {} + + for path in self.get_config_paths(): + try: + with open(path, 'r') as file: + dict = yaml.safe_load(file) + if dict is not None: + properties.update(dict) + except FileNotFoundError: + print(f"{path} not found. Skipping.") + + return properties + + def yaml_to_plist(self): + plist_data = {} + + for path in self.get_config_paths(): + try: + with open(path, 'r') as file: + yaml_data = yaml.safe_load(file) + if yaml_data is not None: + plist_data.update(yaml_data) + except FileNotFoundError: + print(f"{path} not found. Skipping.") + except yaml.YAMLError as e: + print(f"Error parsing YAML file {path}: {e}") + + return plist_data + + def write_to_plist_file(self, plist, file_path): + file_name = os.path.basename(file_path) + with open(file_path, 'wb') as plist_file: + plistlib.dump(plist, plist_file) + print(f"File {file_name} has been written to {file_path}") + + def print_info_plist_contents(self, plist_path): + if not plist_path: + print(f"Path is not set. {plist_path}") + try: + with open(plist_path, 'rb') as plist_file: + plist_contents = plistlib.load(plist_file) + print(plist_contents) + except Exception as e: + print(f"Error reading plist file: {e}") + + def get_info_plist_contents(self, plist_path): + if not plist_path: + print(f"Path is not set. {plist_path}") + try: + with open(plist_path, 'rb') as plist_file: + plist_contents = plistlib.load(plist_file) + return plist_contents + except Exception as e: + print(f"Error reading plist file: {e}") + return None + + +class ConfigurationManager: + def __init__(self, plist_manager): + self.plist_manager = plist_manager + + def get_environment_variable(self, variable): + return os.getenv(variable) + + def add_url_scheme(self, scheme, plist): + body = { + 'CFBundleTypeRole': 'Editor', + 'CFBundleURLSchemes': scheme + } + existing = plist.get('CFBundleURLTypes', []) + found = any(scheme in entry.get('CFBundleURLSchemes', []) for entry in existing) + + if not found: + existing.append(body) + plist['CFBundleURLTypes'] = existing + + return plist + + def add_firebase_config(self, config, firebase_info_plist_path): + plist = {} + firebase = config.get('FIREBASE', {}) + + if firebase_info_plist_path and firebase: + plist['BUNDLE_ID'] = self.plist_manager.get_bundle_identifier() + plist['API_KEY'] = firebase.get('API_KEY', '') + plist['CLIENT_ID'] = firebase.get('CLIENT_ID', '') + plist['GOOGLE_APP_ID'] = firebase.get('GOOGLE_APP_ID', '') + plist['GCM_SENDER_ID'] = firebase.get('GCM_SENDER_ID', '') + + project_id = firebase.get('PROJECT_ID', '') + if project_id: + plist['PROJECT_ID'] = project_id + plist['STORAGE_BUCKET'] = project_id + '.appspot.com' + plist['DATABASE_URL'] = 'https://' + project_id + '.firebaseio.com' + + reversed_client_id = firebase.get('REVERSED_CLIENT_ID', '') + if reversed_client_id: + plist['REVERSED_CLIENT_ID'] = reversed_client_id + + self.plist_manager.write_to_plist_file(plist, self.plist_manager.get_firebase_info_plist_path()) + else: + print("Firebase config is empty. Skipping") + + def add_facebook_config(self, config, plist): + facebook = config.get('FACEBOOK', {}) + key = facebook.get('FACEBOOK_APP_ID') + client_token = facebook.get('CLIENT_TOKEN') + + if key and client_token: + plist["FacebookAppID"] = key + plist["FacebookClientToken"] = client_token + plist["FacebookDisplayName"] = self.plist_manager.get_product_name() + scheme = ["fb" + key] + self.add_url_scheme(scheme, plist) + + def add_google_config(self, config, plist): + google = config.get('GOOGLE', {}) + key = google.get('GOOGLE_PLUS_KEY') + + if key: + scheme = ['.'.join(reversed(key.split('.')))] + self.add_url_scheme(scheme, plist) + + def add_microsoft_config(self, config, plist): + microsoft = config.get('MICROSOFT', {}) + key = microsoft.get('APP_ID') + + if key: + bundle_identifier = self.plist_manager.get_bundle_identifier() + scheme = ["msauth." + bundle_identifier] + self.add_url_scheme(scheme, plist) + + def update_info_plist(self, plist_data, plist_path): + if not plist_path: + print("Path is not set.") + sys.exit(1) + + try: + with open(plist_path, 'rb') as plist_file: + plist_contents = plistlib.load(plist_file) + + plist_contents.update(plist_data) + + try: + plistlib.dumps(plist_contents) + except Exception as e: + print(f"Error validating plist contents: {e}") + sys.exit(1) + + self.plist_manager.write_to_plist_file(plist_contents, plist_path) + except FileNotFoundError: + print(f"Plist file not found: {plist_path}") + sys.exit(1) + except Exception as e: + print(f"Error reading or writing plist file: {e}") + sys.exit(1) + +def parse_yaml(file_path): + try: + with open(file_path, 'r') as file: + return yaml.safe_load(file) + except Exception as e: + print(f"Unable to open or read the file '{file_path}': {e}") + return None + +CONFIG_SETTINGS_YAML_FILENAME = 'config_settings.yaml' +DEFAULT_CONFIG_PATH = './default_config/' + CONFIG_SETTINGS_YAML_FILENAME +CONFIG_DIRECTORY_NAME = 'config_directory' + +CONFIG_MAPPINGS = 'config_mapping' +MAPPINGS_FILENAME = 'file_mappings.yaml' + +def get_current_config(configuration, scheme_mappings): + for key, values in scheme_mappings.items(): + if configuration in values: + return key + return None + +def process_plist_files(configuration_manager, plist_manager, config): + firebase_info_plist_path = plist_manager.get_firebase_config_path() + info_plist_path = plist_manager.get_app_info_plist_path() + info_plist_content = plist_manager.get_info_plist_contents(info_plist_path) + + configuration_manager.add_firebase_config(config, firebase_info_plist_path) + configuration_manager.add_facebook_config(config, info_plist_content) + configuration_manager.add_google_config(config, info_plist_content) + configuration_manager.add_microsoft_config(config, info_plist_content) + + configuration_manager.update_info_plist(info_plist_content, info_plist_path) + + bundle_config_path = plist_manager.get_bundle_config_path() + config_plist = plist_manager.yaml_to_plist() + plist_manager.write_to_plist_file(config_plist, bundle_config_path) + +def main(configuration, scheme_mappings): + current_config = get_current_config(configuration, scheme_mappings) + + if current_config is None: + print("Config not found in mappings. Exiting.") + sys.exit(1) + + config_settings = parse_yaml(CONFIG_SETTINGS_YAML_FILENAME) + + if not config_settings: + print("Parsing default config.") + config_settings = parse_yaml(DEFAULT_CONFIG_PATH) + + config_directory = config_settings.get(CONFIG_DIRECTORY_NAME) + config_name = config_settings.get(CONFIG_MAPPINGS, {}).get(current_config) + + if config_directory and config_name: + path = os.path.join(config_directory, config_name) + mappings_path = os.path.join(path, MAPPINGS_FILENAME) + data = parse_yaml(mappings_path) + + if data: + ios_files = data.get('ios', {}).get('files', []) + plist_manager = PlistManager(path, ios_files) + config = plist_manager.load_config() + + if config: + configuration_manager = ConfigurationManager(plist_manager) + process_plist_files(configuration_manager, plist_manager, config) + print(f"Config {configuration} parsed and written successfully.") + else: + print("Unable to parse config files") + sys.exit(1) + + else: + print("Files mappings not found") + sys.exit(1) + + else: + print("Config directory or config name is not provided") + sys.exit(1) + +if __name__ == "__main__": + if len(sys.argv) < 3: + print("Usage: script.py ") + sys.exit(1) + + configuration = sys.argv[1] + scheme_mappings = json.loads(sys.argv[2]) + main(configuration, scheme_mappings) diff --git a/default_config/default/config.yaml b/default_config/default/config.yaml deleted file mode 100644 index 714452183..000000000 --- a/default_config/default/config.yaml +++ /dev/null @@ -1,4 +0,0 @@ -ios: - files: - - shared.yaml - - ios.yaml diff --git a/default_config/default/ios.yaml b/default_config/default/ios.yaml deleted file mode 100644 index 543813eed..000000000 --- a/default_config/default/ios.yaml +++ /dev/null @@ -1 +0,0 @@ -OAUTH_CLIENT_ID: '' diff --git a/default_config/default/shared.yaml b/default_config/dev/config.yaml similarity index 85% rename from default_config/default/shared.yaml rename to default_config/dev/config.yaml index dcf337896..d7e76817e 100644 --- a/default_config/default/shared.yaml +++ b/default_config/dev/config.yaml @@ -1,3 +1,4 @@ API_HOST_URL: 'http://localhost:8000' ENVIRONMENT_DISPLAY_NAME: 'Localhost' FEEDBACK_EMAIL_ADDRESS: 'support@example.com' +OAUTH_CLIENT_ID: '' diff --git a/default_config/dev/file_mappings.yaml b/default_config/dev/file_mappings.yaml new file mode 100644 index 000000000..86d84fa91 --- /dev/null +++ b/default_config/dev/file_mappings.yaml @@ -0,0 +1,3 @@ +ios: + files: + - config.yaml diff --git a/default_config/prod/config.yaml b/default_config/prod/config.yaml new file mode 100644 index 000000000..d7e76817e --- /dev/null +++ b/default_config/prod/config.yaml @@ -0,0 +1,4 @@ +API_HOST_URL: 'http://localhost:8000' +ENVIRONMENT_DISPLAY_NAME: 'Localhost' +FEEDBACK_EMAIL_ADDRESS: 'support@example.com' +OAUTH_CLIENT_ID: '' diff --git a/default_config/prod/file_mappings.yaml b/default_config/prod/file_mappings.yaml new file mode 100644 index 000000000..86d84fa91 --- /dev/null +++ b/default_config/prod/file_mappings.yaml @@ -0,0 +1,3 @@ +ios: + files: + - config.yaml diff --git a/default_config/stage/config.yaml b/default_config/stage/config.yaml new file mode 100644 index 000000000..d7e76817e --- /dev/null +++ b/default_config/stage/config.yaml @@ -0,0 +1,4 @@ +API_HOST_URL: 'http://localhost:8000' +ENVIRONMENT_DISPLAY_NAME: 'Localhost' +FEEDBACK_EMAIL_ADDRESS: 'support@example.com' +OAUTH_CLIENT_ID: '' diff --git a/default_config/stage/file_mappings.yaml b/default_config/stage/file_mappings.yaml new file mode 100644 index 000000000..86d84fa91 --- /dev/null +++ b/default_config/stage/file_mappings.yaml @@ -0,0 +1,3 @@ +ios: + files: + - config.yaml diff --git a/process_config.py b/process_config.py index e3ce6ed4e..e48c43058 100644 --- a/process_config.py +++ b/process_config.py @@ -220,6 +220,19 @@ def get_configuration_name(configuration, config_mapping): return config_mapping.get("prod") else: return None + +def get_configuration_name_two(scheme_mapping, config_mapping): + if scheme_mapping.get('dev'): + return config_mapping.get("dev") + + if configuration in ["dev"]: + return + elif configuration in ["prod"]: + return config_mapping.get("prod") + elif configuration in ["DebugProd", "ReleaseProd"]: + return config_mapping.get("prod") + else: + return None def process_plist_files(configuration_manager, plist_manager, config): firebase_info_plist_path = plist_manager.get_firebase_config_path() @@ -243,7 +256,7 @@ def main(): else: configuration = sys.argv[1] print(f"Running with configuration: {configuration}") - + config_data = parse_yaml('config.yaml') config_directory = config_data.get('config_directory', "") @@ -272,5 +285,9 @@ def main(): process_plist_files(configuration_manager, plist_manager, config) if __name__ == "__main__": - main() - # test() + # main() + path = os.path.join("default_config", "config_settings.yaml") + content = parse_yaml(path) + print(content) + +# check main directory if config_settings.yaml exists else go in default_config and read from there