@@ -132,8 +132,8 @@ def _split_by_type(self, changes: Dict[str, List[dict]]) -> List[Dict[str, List[
132132 1. Blocking: updated/removed and added files that are blocking
133133 2. Non-blocking: added files that are not blocking
134134 """
135- blocking_changes = {"added" : [], "updated" : [], "removed" : [], "renamed" : [] }
136- non_blocking_changes = {"added" : [], "updated" : [], "removed" : [], "renamed" : [] }
135+ blocking_changes = {"added" : [], "updated" : [], "removed" : []}
136+ non_blocking_changes = {"added" : [], "updated" : [], "removed" : []}
137137
138138 for f in changes .get ("added" , []):
139139 if self .is_blocking_file (f ):
@@ -164,18 +164,26 @@ def split(self) -> List[Dict[str, List[dict]]]:
164164 # TODO: apply limits; changes = self._limit_by_file_count(changes)
165165 return changes_list
166166
167- def get_change_batch (self ) -> Tuple [Optional [Dict [str , List [dict ]]], bool ]:
168- """
169- Return the next changes dictionary and flag if there are more changes
170- """
171- changes_list = self .split ()
172- if not changes_list :
173- return None , False
174- return changes_list [0 ], len (changes_list ) > 1
167+ def get_change_batch (mc , project_dir ) -> Tuple [Optional [Dict [str , List [dict ]]], bool ]:
168+ """
169+ Return the next changes dictionary and flag if there are more changes (to be uploaded in the next upload job)
170+ """
171+ changes_list = ChangesHandler (mc , project_dir ).split ()
172+ if not changes_list :
173+ return None , False
174+ non_empty_length = sum (any (v for v in d .values ()) for d in changes_list )
175+ return changes_list [0 ], non_empty_length > 1
175176
176177
177178def push_project_async (mc , directory , change_batch = None ) -> Optional [UploadJob ]:
178- """Starts push of a change of a project and returns pending upload job"""
179+ """
180+ Starts push in background and returns pending upload job.
181+ Pushes all project changes unless change_batch is provided.
182+ When specific change is provided, initial version check is skipped (the pull has just been done).
183+
184+ :param change_batch: A dictionary of changes that was split to blocking and non-blocking.
185+ Pushing only non-blocking changes results in non-exclusive upload which server allows to be concurrent.
186+ """
179187
180188 mp = MerginProject (directory )
181189 if mp .has_unfinished_pull ():
@@ -187,30 +195,32 @@ def push_project_async(mc, directory, change_batch=None) -> Optional[UploadJob]:
187195 mp .log .info ("--- version: " + mc .user_agent_info ())
188196 mp .log .info (f"--- start push { project_path } " )
189197
190- try :
191- project_info = mc .project_info (project_path )
192- except ClientError as err :
193- mp .log .error ("Error getting project info: " + str (err ))
194- mp .log .info ("--- push aborted" )
195- raise
196- server_version = project_info ["version" ] if project_info ["version" ] else "v0"
197-
198- mp .log .info (f"got project info: local version { local_version } / server version { server_version } " )
199-
200- username = mc .username ()
201- # permissions field contains information about update, delete and upload privileges of the user
202- # on a specific project. This is more accurate information than "writernames" field, as it takes
203- # into account namespace privileges. So we have to check only "permissions", namely "upload" once
204- if not mc .has_writing_permissions (project_path ):
205- mp .log .error (f"--- push { project_path } - username { username } does not have write access" )
206- raise ClientError (f"You do not seem to have write access to the project (username '{ username } ')" )
207-
208- if local_version != server_version :
209- mp .log .error (f"--- push { project_path } - not up to date (local { local_version } vs server { server_version } )" )
210- raise ClientError (
211- "There is a new version of the project on the server. Please update your local copy."
212- + f"\n \n Local version: { local_version } \n Server version: { server_version } "
213- )
198+ # if we have specific change to push we don't need version check
199+ if not change_batch :
200+ try :
201+ project_info = mc .project_info (project_path )
202+ except ClientError as err :
203+ mp .log .error ("Error getting project info: " + str (err ))
204+ mp .log .info ("--- push aborted" )
205+ raise
206+ server_version = project_info ["version" ] if project_info ["version" ] else "v0"
207+
208+ mp .log .info (f"got project info: local version { local_version } / server version { server_version } " )
209+
210+ username = mc .username ()
211+ # permissions field contains information about update, delete and upload privileges of the user
212+ # on a specific project. This is more accurate information than "writernames" field, as it takes
213+ # into account namespace privileges. So we have to check only "permissions", namely "upload" once
214+ if not mc .has_writing_permissions (project_path ):
215+ mp .log .error (f"--- push { project_path } - username { username } does not have write access" )
216+ raise ClientError (f"You do not seem to have write access to the project (username '{ username } ')" )
217+
218+ if local_version != server_version :
219+ mp .log .error (f"--- push { project_path } - not up to date (local { local_version } vs server { server_version } )" )
220+ raise ClientError (
221+ "There is a new version of the project on the server. Please update your local copy."
222+ + f"\n \n Local version: { local_version } \n Server version: { server_version } "
223+ )
214224
215225 changes = change_batch or mp .get_push_changes ()
216226 mp .log .debug ("push change:\n " + pprint .pformat (changes ))
@@ -288,16 +298,16 @@ def push_project_async(mc, directory, change_batch=None) -> Optional[UploadJob]:
288298
289299 total_size += file_size
290300
291- job .total_size = total_size
292- job .upload_queue_items = upload_queue_items
301+ job .total_size = total_size
302+ job .upload_queue_items = upload_queue_items
293303
294- mp .log .info (f"will upload { len (upload_queue_items )} items with total size { total_size } " )
304+ mp .log .info (f"will upload { len (upload_queue_items )} items with total size { total_size } " )
295305
296- # start uploads in background
297- job .executor = concurrent .futures .ThreadPoolExecutor (max_workers = 4 )
298- for item in upload_queue_items :
299- future = job .executor .submit (_do_upload , item , job )
300- job .futures .append (future )
306+ # start uploads in background
307+ job .executor = concurrent .futures .ThreadPoolExecutor (max_workers = 4 )
308+ for item in upload_queue_items :
309+ future = job .executor .submit (_do_upload , item , job )
310+ job .futures .append (future )
301311
302312 return job
303313
@@ -435,7 +445,9 @@ def total_upload_size(directory) -> int:
435445 mp = MerginProject (directory )
436446 changes = mp .get_push_changes ()
437447 files = changes .get ("added" , []) + changes .get ("updated" , [])
438- return sum (
448+ size = sum (
439449 f .get ("diff" , {}).get ("size" , f .get ("size" , 0 ))
440450 for f in files
441- )
451+ )
452+ mp .log .info (f"Upload size of all files is { size } " )
453+ return size
0 commit comments