From 4fecabe4d0d6d99f73a0dd3d6cd3800ce01d9527 Mon Sep 17 00:00:00 2001 From: Constantine Nathanson <35217733+const-cloudinary@users.noreply.github.com> Date: Mon, 24 Feb 2025 14:33:05 +0200 Subject: [PATCH] Add support for `status` option in `sync` command --- cloudinary_cli/modules/sync.py | 10 ++++++---- cloudinary_cli/utils/api_utils.py | 12 ++++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cloudinary_cli/modules/sync.py b/cloudinary_cli/modules/sync.py index d6e7859..d0acb65 100644 --- a/cloudinary_cli/modules/sync.py +++ b/cloudinary_cli/modules/sync.py @@ -38,17 +38,19 @@ help="Specify the batch size for deleting remote assets.") @option("-fm", "--folder-mode", type=Choice(['fixed', 'dynamic'], case_sensitive=False), help="Specify folder mode explicitly. By default uses cloud mode configured in your cloud.", hidden=True) +@option("-st", "--status", type=Choice(['all', 'active', 'pending'], case_sensitive=False), + help="Specify asset status. Server default: active.", default=None) @option("-o", "--optional_parameter", multiple=True, nargs=2, help="Pass optional parameters as raw strings.") @option("-O", "--optional_parameter_parsed", multiple=True, nargs=2, help="Pass optional parameters as interpreted strings.") @option("--dry-run", is_flag=True, help="Simulate the sync operation without making any changes.") def sync(local_folder, cloudinary_folder, push, pull, include_hidden, concurrent_workers, force, keep_unique, - deletion_batch_size, folder_mode, optional_parameter, optional_parameter_parsed, dry_run): + deletion_batch_size, folder_mode, status, optional_parameter, optional_parameter_parsed, dry_run): if push == pull: raise UsageError("Please use either the '--push' OR '--pull' options") sync_dir = SyncDir(local_folder, cloudinary_folder, include_hidden, concurrent_workers, force, keep_unique, - deletion_batch_size, folder_mode, optional_parameter, optional_parameter_parsed, dry_run) + deletion_batch_size, folder_mode, status, optional_parameter, optional_parameter_parsed, dry_run) result = True if push: result = sync_dir.push() @@ -63,7 +65,7 @@ def sync(local_folder, cloudinary_folder, push, pull, include_hidden, concurrent class SyncDir: def __init__(self, local_dir, remote_dir, include_hidden, concurrent_workers, force, keep_deleted, - deletion_batch_size, folder_mode, optional_parameter, optional_parameter_parsed, dry_run): + deletion_batch_size, folder_mode, status, optional_parameter, optional_parameter_parsed, dry_run): self.local_dir = local_dir self.remote_dir = remote_dir.strip('/') self.user_friendly_remote_dir = self.remote_dir if self.remote_dir else '/' @@ -100,7 +102,7 @@ def __init__(self, local_dir, remote_dir, include_hidden, concurrent_workers, fo logger.info(f"Cloudinary folder '{self.user_friendly_remote_dir}' does not exist " f"({self.folder_mode} folder mode).") else: - raw_remote_files = query_cld_folder(self.remote_dir, self.folder_mode) + raw_remote_files = query_cld_folder(self.remote_dir, self.folder_mode, status) if len(raw_remote_files): logger.info( f"Found {len(raw_remote_files)} items in Cloudinary folder '{self.user_friendly_remote_dir}' " diff --git a/cloudinary_cli/utils/api_utils.py b/cloudinary_cli/utils/api_utils.py index 38a1ae3..e21043f 100644 --- a/cloudinary_cli/utils/api_utils.py +++ b/cloudinary_cli/utils/api_utils.py @@ -21,18 +21,22 @@ _cursor_fields = {"resource": "derived_next_cursor"} -def query_cld_folder(folder, folder_mode): +def query_cld_folder(folder, folder_mode, status=None): files = {} folder = folder.strip('/') # omit redundant leading slash and duplicate trailing slashes in query folder_key = "asset_folder" if folder_mode == "dynamic" else "folder" folder_query = f"{folder}/*" if folder else "*" + status_value = "(active OR pending)" if status == "all" else status + status_query = f" AND status:{status_value}" if status_value else "" - expression = Search().expression(f"{folder_key}:\"{folder_query}\"").with_field("image_analysis").max_results(500) + search = Search().expression(f"{folder_key}:\"{folder_query}\"{status_query}").with_field("image_analysis").max_results(500) + + logger.debug(f"Search expression: {search.to_json()}") next_cursor = True while next_cursor: - res = expression.execute() + res = search.execute() for asset in res['resources']: rel_path = _relative_path(asset, folder) @@ -58,7 +62,7 @@ def query_cld_folder(folder, folder_mode): } # use := when switch to python 3.8 next_cursor = res.get('next_cursor') - expression.next_cursor(next_cursor) + search.next_cursor(next_cursor) return files