From 2d8bbbe2dd18696e83adfbadaff8be79da01f74b Mon Sep 17 00:00:00 2001 From: lokijuhy Date: Thu, 22 Jul 2021 17:49:17 +0200 Subject: [PATCH 1/7] add ability to edit and delete config entries --- code_sync/code_sync.py | 104 ++++++++++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 21 deletions(-) diff --git a/code_sync/code_sync.py b/code_sync/code_sync.py index e5ffb17..ecab8e6 100644 --- a/code_sync/code_sync.py +++ b/code_sync/code_sync.py @@ -91,6 +91,30 @@ def create_config_if_not_exists() -> None: init_config() +def save_config(config: Dict, mode='a') -> None: + if mode not in ['a', 'w']: + raise ValueError(f"Config must be edited in mode 'a' or 'w', received '{mode}'") + + create_config_if_not_exists() + config_file_path = get_config_file_path() + with open(config_file_path.__str__(), mode) as f: + yaml.dump(config, f, default_flow_style=False, indent=4) + + +def get_project_config() -> Dict: + local_dir = input('Path to code_sync on this local machine: ') + target = input('Destination machine: ') + remote_dir = input('Path on the destination machine to sync: ') + port = int(input('Port number to use (default 22): ') or "22") + project_details = { + 'local_dir': local_dir, + 'target': target, + 'remote_dir': remote_dir, + 'port': port, + } + return project_details + + def register_project(project: str) -> None: """ Register a project to the code_sync config. @@ -110,26 +134,13 @@ def register_project(project: str) -> None: raise ValueError(f"Project '{project}' is already registered") print(f"Registering new project '{project}'") - local_dir = input('Path to code_sync on this local machine: ') - target = input('Destination machine: ') - remote_dir = input('Path on the destination machine to sync: ') - port = int(input('Port number to use (default 22): ') or "22") - - config_entry_data = { - project: { - 'local_dir': local_dir, - 'target': target, - 'remote_dir': remote_dir, - 'port': port, + project_config = get_project_config() - } + project_config_entry = { + project: project_config } - create_config_if_not_exists() - config_file_path = get_config_file_path() - with open(config_file_path.__str__(), 'a') as f: - yaml.dump(config_entry_data, f, default_flow_style=False, indent=4) - + save_config(project_config_entry) print(f"Successfully registered project '{project}'") return @@ -140,10 +151,57 @@ def list_projects() -> None: config = load_config() if len(config) == 0: print('No projects registered') - else: - formatted_keys = ', '.join(list(config.keys())) - print(formatted_keys) - return + return + + formatted_keys = ', '.join(list(config.keys())) + print(formatted_keys) + + +def edit_projects() -> None: + """Edit and delete the config entries of the registered projects.""" + create_config_if_not_exists() + original_config = load_config() + if len(original_config) == 0: + print('No projects registered') + return + + config = original_config.copy() + print("Options: (e)dit, (d)elete, (n)ext, (s)ave and exit, (q)uit and don't save ") + for project in original_config: + response = input(f"Project '{project} > ") + possible_responses = { + 'd': delete_project_from_config, + 'delete': delete_project_from_config, + 'e': edit_project_config, + 'edit': edit_project_config, + } + if response in ['n', 'next']: + continue + elif response in ['s', 'save']: + break + elif response in ['q', 'quit']: + print('Quitting without saving.') + return + elif response in possible_responses: + modify_func = possible_responses[response] + config = modify_func(project, config) + else: + print('Invalid input') + + save_config(config, mode='w') + print('Saved edited code-sync config.') + + +def delete_project_from_config(project: str, config: Dict) -> Dict: + config.pop(project) + return config + + +def edit_project_config(project: str, config: Dict) -> Dict: + print(f"Enter details for project '{project}'") + project_config = get_project_config() + config[project] = project_config + return config def identify_code_sync_parameters(args) -> Dict: @@ -181,6 +239,8 @@ def main(): parser.add_argument('project', nargs='?', default=None) parser.add_argument('--register', help='Register a new project to code_sync', required=False) parser.add_argument('--list', action='store_true', help='List all registered projects', required=False) + parser.add_argument('--edit', action='store_true', help='Edit and delete the config entries of the registered' + ' projects.', required=False) parser.add_argument('--local_dir', help='The local code directory you want to sync', required=False) parser.add_argument('--remote_dir', help='The remote directory you want to sync', required=False) parser.add_argument('--target', help='Specify which remote machine to connect to', required=False) @@ -192,6 +252,8 @@ def main(): register_project(args.register) elif args.list: list_projects() + elif args.edit: + edit_projects() else: params = identify_code_sync_parameters(args) code_sync(local_dir=params['local_dir'], remote_dir=params['remote_dir'], target=params['target'], From 43b4ca2f86ce75815c341276476d61c96d21231e Mon Sep 17 00:00:00 2001 From: lokijuhy Date: Thu, 22 Jul 2021 19:02:49 +0200 Subject: [PATCH 2/7] version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4726ac0..0047bb8 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages setup(name='code_sync', - version='0.2.0', + version='0.3.0', description='', url='https://github.com/uzh-dqbm-cmi/code-sync', packages=find_packages(), From f587bdefbe2ec97839631634a839ae020e28a818 Mon Sep 17 00:00:00 2001 From: lokijuhy Date: Tue, 27 Jul 2021 16:17:09 +0200 Subject: [PATCH 3/7] docstrings --- code_sync/code_sync.py | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/code_sync/code_sync.py b/code_sync/code_sync.py index ecab8e6..90cabd2 100644 --- a/code_sync/code_sync.py +++ b/code_sync/code_sync.py @@ -92,6 +92,16 @@ def create_config_if_not_exists() -> None: def save_config(config: Dict, mode='a') -> None: + """ + Save the code-sync config to file. + + Args: + config: The code-sync config dictionary. + mode: File mode. May be either 'a' for append or 'w' for write. + + Returns: None + + """ if mode not in ['a', 'w']: raise ValueError(f"Config must be edited in mode 'a' or 'w', received '{mode}'") @@ -101,7 +111,13 @@ def save_config(config: Dict, mode='a') -> None: yaml.dump(config, f, default_flow_style=False, indent=4) -def get_project_config() -> Dict: +def get_project_config_from_user() -> Dict: + """ + Ask the user for the information for the project config. + + Returns: A dictionary with the config for the project, including local_dir, target, remote_dir, and port. + + """ local_dir = input('Path to code_sync on this local machine: ') target = input('Destination machine: ') remote_dir = input('Path on the destination machine to sync: ') @@ -134,7 +150,7 @@ def register_project(project: str) -> None: raise ValueError(f"Project '{project}' is already registered") print(f"Registering new project '{project}'") - project_config = get_project_config() + project_config = get_project_config_from_user() project_config_entry = { project: project_config @@ -193,13 +209,24 @@ def edit_projects() -> None: def delete_project_from_config(project: str, config: Dict) -> Dict: + """Delete a project entry from the config dictionary.""" config.pop(project) return config def edit_project_config(project: str, config: Dict) -> Dict: + """ + Edit the project config entry for a project that already exists in the code-sync config. + + Args: + project: The project name (key in the code-sync config). + config: The global code-sync config. + + Returns: + + """ print(f"Enter details for project '{project}'") - project_config = get_project_config() + project_config = get_project_config_from_user() config[project] = project_config return config From 4b1d61eed86634364edf7af63c2cf60e525a33cb Mon Sep 17 00:00:00 2001 From: lokijuhy Date: Tue, 27 Jul 2021 16:18:30 +0200 Subject: [PATCH 4/7] add edit info to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index dfb7f6b..2ee5d94 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ This command will use the configuration you set for the project when you registe #### Run code_sync with specific parameters code_sync --local_dir --remote_dir --target --port 2222\n +#### Edit or delete a registered project + code_sync --edit ### Notes **Starting** From f62ce7f67d0cde7784b5df52cadb193522532047 Mon Sep 17 00:00:00 2001 From: lokijuhy Date: Tue, 27 Jul 2021 16:21:15 +0200 Subject: [PATCH 5/7] clean up user input --- code_sync/code_sync.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code_sync/code_sync.py b/code_sync/code_sync.py index 90cabd2..3a76b27 100644 --- a/code_sync/code_sync.py +++ b/code_sync/code_sync.py @@ -119,7 +119,7 @@ def get_project_config_from_user() -> Dict: """ local_dir = input('Path to code_sync on this local machine: ') - target = input('Destination machine: ') + target = input('Destination machine (name of ssh config entry): ') remote_dir = input('Path on the destination machine to sync: ') port = int(input('Port number to use (default 22): ') or "22") project_details = { @@ -184,7 +184,7 @@ def edit_projects() -> None: config = original_config.copy() print("Options: (e)dit, (d)elete, (n)ext, (s)ave and exit, (q)uit and don't save ") for project in original_config: - response = input(f"Project '{project} > ") + response = input(f"Project '{project}' > ") possible_responses = { 'd': delete_project_from_config, 'delete': delete_project_from_config, From 530b87f593b451efa942fd84226970c79933c846 Mon Sep 17 00:00:00 2001 From: lokijuhy Date: Wed, 1 Sep 2021 15:13:08 +0200 Subject: [PATCH 6/7] changed cli for specific edit and delete commands --- code_sync/code_sync.py | 55 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/code_sync/code_sync.py b/code_sync/code_sync.py index 3a76b27..bfe39a6 100644 --- a/code_sync/code_sync.py +++ b/code_sync/code_sync.py @@ -173,39 +173,38 @@ def list_projects() -> None: print(formatted_keys) -def edit_projects() -> None: - """Edit and delete the config entries of the registered projects.""" +def delete_project(project_name: str) -> None: + """Delete the config entry of the registered project.""" create_config_if_not_exists() original_config = load_config() if len(original_config) == 0: print('No projects registered') return + elif project_name not in original_config: + raise ValueError(f"Project '{project_name}' does not exist") config = original_config.copy() - print("Options: (e)dit, (d)elete, (n)ext, (s)ave and exit, (q)uit and don't save ") - for project in original_config: - response = input(f"Project '{project}' > ") - possible_responses = { - 'd': delete_project_from_config, - 'delete': delete_project_from_config, - 'e': edit_project_config, - 'edit': edit_project_config, - } - if response in ['n', 'next']: - continue - elif response in ['s', 'save']: - break - elif response in ['q', 'quit']: - print('Quitting without saving.') - return - elif response in possible_responses: - modify_func = possible_responses[response] - config = modify_func(project, config) - else: - print('Invalid input') + config = delete_project_from_config(project_name, config) save_config(config, mode='w') - print('Saved edited code-sync config.') + print(f'Deleted {project_name} from code-sync config.') + + +def edit_project(project_name: str) -> None: + """Edit the config entry of the registered project.""" + create_config_if_not_exists() + original_config = load_config() + if len(original_config) == 0: + print('No projects registered') + return + elif project_name not in original_config: + raise ValueError(f"Project '{project_name}' does not exist") + + config = original_config.copy() + config = edit_project_config(project_name, config) + + save_config(config, mode='w') + print(f'Updated code-sync config for project {project_name}.') def delete_project_from_config(project: str, config: Dict) -> Dict: @@ -266,8 +265,8 @@ def main(): parser.add_argument('project', nargs='?', default=None) parser.add_argument('--register', help='Register a new project to code_sync', required=False) parser.add_argument('--list', action='store_true', help='List all registered projects', required=False) - parser.add_argument('--edit', action='store_true', help='Edit and delete the config entries of the registered' - ' projects.', required=False) + parser.add_argument('--edit', help='Edit the config for a registered project.', required=False) + parser.add_argument('--delete', help='Delete the config for a registered project.', required=False) parser.add_argument('--local_dir', help='The local code directory you want to sync', required=False) parser.add_argument('--remote_dir', help='The remote directory you want to sync', required=False) parser.add_argument('--target', help='Specify which remote machine to connect to', required=False) @@ -280,7 +279,9 @@ def main(): elif args.list: list_projects() elif args.edit: - edit_projects() + edit_project(args.edit) + elif args.delete: + delete_project(args.delete) else: params = identify_code_sync_parameters(args) code_sync(local_dir=params['local_dir'], remote_dir=params['remote_dir'], target=params['target'], From 9d4abc51ffd96e9b21394f9d797ac088c086ec4d Mon Sep 17 00:00:00 2001 From: lokijuhy Date: Wed, 1 Sep 2021 15:33:31 +0200 Subject: [PATCH 7/7] update readme with new edit cli --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ee5d94..a9591f9 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,8 @@ This command will use the configuration you set for the project when you registe code_sync --local_dir --remote_dir --target --port 2222\n #### Edit or delete a registered project - code_sync --edit + code_sync --edit + code_sync --delete ### Notes **Starting**