Skip to content

Commit 84b4ed1

Browse files
Fix folder existence error in sync command
1 parent 5be226a commit 84b4ed1

File tree

4 files changed

+54
-14
lines changed

4 files changed

+54
-14
lines changed

cloudinary_cli/modules/sync.py

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
import os.path
23
import re
34
from collections import Counter
45
from itertools import groupby
@@ -45,10 +46,6 @@ def sync(local_folder, cloudinary_folder, push, pull, include_hidden, concurrent
4546
if push == pull:
4647
raise UsageError("Please use either the '--push' OR '--pull' options")
4748

48-
if pull and not cld_folder_exists(cloudinary_folder):
49-
logger.error(f"Cloudinary folder '{cloudinary_folder}' does not exist. Aborting...")
50-
return False
51-
5249
sync_dir = SyncDir(local_folder, cloudinary_folder, include_hidden, concurrent_workers, force, keep_unique,
5350
deletion_batch_size, folder_mode, optional_parameter, optional_parameter_parsed)
5451

@@ -58,7 +55,8 @@ def sync(local_folder, cloudinary_folder, push, pull, include_hidden, concurrent
5855
elif pull:
5956
result = sync_dir.pull()
6057

61-
logger.info("Done!")
58+
if result:
59+
logger.info("Done!")
6260

6361
return result
6462

@@ -84,12 +82,32 @@ def __init__(self, local_dir, remote_dir, include_hidden, concurrent_workers, fo
8482

8583
self.verbose = logger.getEffectiveLevel() < logging.INFO
8684

87-
self.local_files = walk_dir(path.abspath(self.local_dir), include_hidden)
88-
logger.info(f"Found {len(self.local_files)} items in local folder '{local_dir}'")
85+
self.local_files = {}
86+
self.local_folder_exists = os.path.isdir(path.abspath(self.local_dir))
87+
if not self.local_folder_exists:
88+
logger.info(f"Local folder '{self.local_dir}' does not exist.")
89+
else:
90+
self.local_files = walk_dir(path.abspath(self.local_dir), include_hidden)
91+
if len(self.local_files):
92+
logger.info(f"Found {len(self.local_files)} items in local folder '{self.local_dir}'")
93+
else:
94+
logger.info(f"Local folder '{self.local_dir}' is empty.")
95+
96+
raw_remote_files = {}
97+
self.cld_folder_exists = cld_folder_exists(self.remote_dir)
98+
if not self.cld_folder_exists:
99+
logger.info(f"Cloudinary folder '{self.user_friendly_remote_dir}' does not exist "
100+
f"({self.folder_mode} folder mode).")
101+
else:
102+
raw_remote_files = query_cld_folder(self.remote_dir, self.folder_mode)
103+
if len(raw_remote_files):
104+
logger.info(
105+
f"Found {len(raw_remote_files)} items in Cloudinary folder '{self.user_friendly_remote_dir}' "
106+
f"({self.folder_mode} folder mode).")
107+
else:
108+
logger.info(f"Cloudinary folder '{self.user_friendly_remote_dir}' is empty. "
109+
f"({self.folder_mode} folder mode)")
89110

90-
raw_remote_files = query_cld_folder(self.remote_dir, self.folder_mode)
91-
logger.info(f"Found {len(raw_remote_files)} items in Cloudinary folder '{self.user_friendly_remote_dir}' "
92-
f"({self.folder_mode} folder mode)")
93111
self.remote_files = self._normalize_remote_file_names(raw_remote_files, self.local_files)
94112
self.remote_duplicate_names = duplicate_values(self.remote_files, "normalized_path", "asset_id")
95113
self._print_duplicate_file_names()
@@ -137,6 +155,11 @@ def push(self):
137155
"""
138156
Pushes changes from the local folder to the Cloudinary folder.
139157
"""
158+
159+
if not self.local_folder_exists:
160+
logger.error(f"Cannot push a non-existent local folder '{self.local_dir}'. Aborting...")
161+
return False
162+
140163
if not self._handle_unique_remote_files():
141164
logger.info("Aborting...")
142165
return False
@@ -176,6 +199,12 @@ def pull(self):
176199
"""
177200
Pulls changes from the Cloudinary folder to the local folder.
178201
"""
202+
203+
if not self.cld_folder_exists:
204+
logger.error(f"Cannot pull from a non-existent Cloudinary folder '{self.user_friendly_remote_dir}' "
205+
f"({self.folder_mode} folder mode). Aborting...")
206+
return False
207+
179208
download_results = {}
180209
download_errors = {}
181210
if not self._handle_unique_local_files():

cloudinary_cli/utils/api_utils.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,23 @@ def query_cld_folder(folder, folder_mode):
5959

6060
return files
6161

62+
6263
def cld_folder_exists(folder):
6364
folder = folder.strip('/') # omit redundant leading slash and duplicate trailing slashes in query
6465

6566
if not folder:
66-
return True # root folder
67+
return True # root folder
6768

68-
res = SearchFolders().expression(f"name=\"{folder}\"").execute()
69+
res = SearchFolders().expression(f"path=\"{folder}\"").execute()
6970

7071
return res.get("total_count", 0) > 0
7172

73+
7274
def _display_path(asset):
7375
if asset.get("display_name") is None:
7476
return ""
7577

76-
return "/".join([asset.get("asset_folder", ""), ".".join([asset["display_name"], asset["format"]])])
78+
return "/".join([asset.get("asset_folder", ""), ".".join(filter(None, [asset["display_name"], asset.get("format", None)]))])
7779

7880

7981
def _relative_display_path(asset, folder):

cloudinary_cli/utils/file_utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ def normalize_file_extension(filename: str) -> str:
129129

130130
return ".".join([p for p in [filename, extension_alias] if p])
131131

132+
132133
def populate_duplicate_name(filename, index=0):
133134
"""
134135
Adds index to the filename in order to avoid duplicates.
@@ -143,6 +144,7 @@ def populate_duplicate_name(filename, index=0):
143144

144145
return ".".join([p for p in [filename, extension[1:]] if p])
145146

147+
146148
def posix_rel_path(end, start) -> str:
147149
"""
148150
Returns a relative path in posix style on any system.

test/test_modules/test_cli_sync.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ def test_cli_sync_push(self):
4444
self.assertIn("Synced | 12", result.output)
4545
self.assertIn("Done!", result.output)
4646

47+
def test_cli_sync_push_non_existing_folder(self):
48+
non_existing_dir = self.LOCAL_SYNC_PULL_DIR + "non_existing"
49+
result = self.runner.invoke(cli, ['sync', '--push', non_existing_dir, self.CLD_SYNC_DIR])
50+
51+
self.assertIn(f"Cannot push a non-existent local folder '{non_existing_dir}'", result.output)
52+
self.assertIn("Aborting...", result.output)
53+
4754
@retry_assertion
4855
def test_cli_sync_push_twice(self):
4956
self._upload_sync_files(TEST_FILES_DIR)
@@ -92,7 +99,7 @@ def test_cli_sync_pull_non_existing_folder(self):
9299
non_existing_dir = self.CLD_SYNC_DIR + "non_existing"
93100
result = self.runner.invoke(cli, ['sync', '--pull', self.LOCAL_SYNC_PULL_DIR, non_existing_dir])
94101

95-
self.assertIn(f"error: Cloudinary folder '{non_existing_dir}' does not exist.", result.output)
102+
self.assertIn(f"Cannot pull from a non-existent Cloudinary folder '{non_existing_dir}'", result.output)
96103
self.assertIn("Aborting...", result.output)
97104

98105
@retry_assertion

0 commit comments

Comments
 (0)