cloudinary-cli 1.10.1__tar.gz → 1.10.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cloudinary-cli-1.10.1/cloudinary_cli.egg-info → cloudinary_cli-1.10.2}/PKG-INFO +1 -1
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/modules/sync.py +39 -10
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/utils/api_utils.py +5 -3
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/utils/file_utils.py +2 -0
- cloudinary_cli-1.10.2/cloudinary_cli/version.py +1 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2/cloudinary_cli.egg-info}/PKG-INFO +1 -1
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_modules/test_cli_sync.py +8 -1
- cloudinary-cli-1.10.1/cloudinary_cli/version.py +0 -1
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/LICENSE +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/MANIFEST.in +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/README.md +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/__init__.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/cli.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/cli_group.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/core/__init__.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/core/admin.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/core/config.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/core/overrides.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/core/provisioning.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/core/search.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/core/uploader.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/core/utils.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/defaults.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/modules/__init__.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/modules/make.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/modules/migrate.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/modules/regen_derived.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/modules/upload_dir.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/samples/__init__.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/html/media_library_widget +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/html/product_gallery +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/html/upload_widget +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/html/video_player +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/node/upload +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/python/base +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/python/explicit +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/python/find_all_empty_folders +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/python/upload +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/ruby/upload +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/utils/__init__.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/utils/config_utils.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/utils/json_utils.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/utils/utils.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli.egg-info/SOURCES.txt +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli.egg-info/dependency_links.txt +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli.egg-info/entry_points.txt +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli.egg-info/not-zip-safe +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli.egg-info/requires.txt +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli.egg-info/top_level.txt +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/requirements.txt +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/setup.cfg +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/setup.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/__init__.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/helper_test.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_cli.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_cli_api.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_cli_config.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_cli_samples.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_cli_search_api.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_cli_url.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_cli_utils.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_file_utils.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_modules/__init__.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_modules/test_cli_make.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_modules/test_cli_upload_dir.py +0 -0
- {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/test/test_utils.py +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import os.path
|
|
2
3
|
import re
|
|
3
4
|
from collections import Counter
|
|
4
5
|
from itertools import groupby
|
|
@@ -45,10 +46,6 @@ def sync(local_folder, cloudinary_folder, push, pull, include_hidden, concurrent
|
|
|
45
46
|
if push == pull:
|
|
46
47
|
raise UsageError("Please use either the '--push' OR '--pull' options")
|
|
47
48
|
|
|
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
|
-
|
|
52
49
|
sync_dir = SyncDir(local_folder, cloudinary_folder, include_hidden, concurrent_workers, force, keep_unique,
|
|
53
50
|
deletion_batch_size, folder_mode, optional_parameter, optional_parameter_parsed)
|
|
54
51
|
|
|
@@ -58,7 +55,8 @@ def sync(local_folder, cloudinary_folder, push, pull, include_hidden, concurrent
|
|
|
58
55
|
elif pull:
|
|
59
56
|
result = sync_dir.pull()
|
|
60
57
|
|
|
61
|
-
|
|
58
|
+
if result:
|
|
59
|
+
logger.info("Done!")
|
|
62
60
|
|
|
63
61
|
return result
|
|
64
62
|
|
|
@@ -84,12 +82,32 @@ class SyncDir:
|
|
|
84
82
|
|
|
85
83
|
self.verbose = logger.getEffectiveLevel() < logging.INFO
|
|
86
84
|
|
|
87
|
-
self.local_files =
|
|
88
|
-
|
|
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)")
|
|
89
110
|
|
|
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)")
|
|
93
111
|
self.remote_files = self._normalize_remote_file_names(raw_remote_files, self.local_files)
|
|
94
112
|
self.remote_duplicate_names = duplicate_values(self.remote_files, "normalized_path", "asset_id")
|
|
95
113
|
self._print_duplicate_file_names()
|
|
@@ -137,6 +155,11 @@ class SyncDir:
|
|
|
137
155
|
"""
|
|
138
156
|
Pushes changes from the local folder to the Cloudinary folder.
|
|
139
157
|
"""
|
|
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
|
+
|
|
140
163
|
if not self._handle_unique_remote_files():
|
|
141
164
|
logger.info("Aborting...")
|
|
142
165
|
return False
|
|
@@ -176,6 +199,12 @@ class SyncDir:
|
|
|
176
199
|
"""
|
|
177
200
|
Pulls changes from the Cloudinary folder to the local folder.
|
|
178
201
|
"""
|
|
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
|
+
|
|
179
208
|
download_results = {}
|
|
180
209
|
download_errors = {}
|
|
181
210
|
if not self._handle_unique_local_files():
|
|
@@ -59,21 +59,23 @@ def query_cld_folder(folder, folder_mode):
|
|
|
59
59
|
|
|
60
60
|
return files
|
|
61
61
|
|
|
62
|
+
|
|
62
63
|
def cld_folder_exists(folder):
|
|
63
64
|
folder = folder.strip('/') # omit redundant leading slash and duplicate trailing slashes in query
|
|
64
65
|
|
|
65
66
|
if not folder:
|
|
66
|
-
return True
|
|
67
|
+
return True # root folder
|
|
67
68
|
|
|
68
|
-
res = SearchFolders().expression(f"
|
|
69
|
+
res = SearchFolders().expression(f"path=\"{folder}\"").execute()
|
|
69
70
|
|
|
70
71
|
return res.get("total_count", 0) > 0
|
|
71
72
|
|
|
73
|
+
|
|
72
74
|
def _display_path(asset):
|
|
73
75
|
if asset.get("display_name") is None:
|
|
74
76
|
return ""
|
|
75
77
|
|
|
76
|
-
return "/".join([asset.get("asset_folder", ""), ".".join([asset["display_name"], asset
|
|
78
|
+
return "/".join([asset.get("asset_folder", ""), ".".join(filter(None, [asset["display_name"], asset.get("format", None)]))])
|
|
77
79
|
|
|
78
80
|
|
|
79
81
|
def _relative_display_path(asset, folder):
|
|
@@ -129,6 +129,7 @@ def normalize_file_extension(filename: str) -> str:
|
|
|
129
129
|
|
|
130
130
|
return ".".join([p for p in [filename, extension_alias] if p])
|
|
131
131
|
|
|
132
|
+
|
|
132
133
|
def populate_duplicate_name(filename, index=0):
|
|
133
134
|
"""
|
|
134
135
|
Adds index to the filename in order to avoid duplicates.
|
|
@@ -143,6 +144,7 @@ def populate_duplicate_name(filename, index=0):
|
|
|
143
144
|
|
|
144
145
|
return ".".join([p for p in [filename, extension[1:]] if p])
|
|
145
146
|
|
|
147
|
+
|
|
146
148
|
def posix_rel_path(end, start) -> str:
|
|
147
149
|
"""
|
|
148
150
|
Returns a relative path in posix style on any system.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.10.2"
|
|
@@ -44,6 +44,13 @@ class TestCLISync(unittest.TestCase):
|
|
|
44
44
|
self.assertIn("Synced | 12", result.output)
|
|
45
45
|
self.assertIn("Done!", result.output)
|
|
46
46
|
|
|
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
|
+
|
|
47
54
|
@retry_assertion
|
|
48
55
|
def test_cli_sync_push_twice(self):
|
|
49
56
|
self._upload_sync_files(TEST_FILES_DIR)
|
|
@@ -92,7 +99,7 @@ class TestCLISync(unittest.TestCase):
|
|
|
92
99
|
non_existing_dir = self.CLD_SYNC_DIR + "non_existing"
|
|
93
100
|
result = self.runner.invoke(cli, ['sync', '--pull', self.LOCAL_SYNC_PULL_DIR, non_existing_dir])
|
|
94
101
|
|
|
95
|
-
self.assertIn(f"
|
|
102
|
+
self.assertIn(f"Cannot pull from a non-existent Cloudinary folder '{non_existing_dir}'", result.output)
|
|
96
103
|
self.assertIn("Aborting...", result.output)
|
|
97
104
|
|
|
98
105
|
@retry_assertion
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.10.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/html/media_library_widget
RENAMED
|
File without changes
|
{cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli/templates/html/product_gallery
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cloudinary-cli-1.10.1 → cloudinary_cli-1.10.2}/cloudinary_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|