示例#1
0
 def _update_attr_when_hash_equal(self, item_local_path, item):
     t = datetime_to_timestamp(item.modified_time)
     try:
         self.logger.info('Updating timestamp for file "%s" to "%s".', item_local_path,
                          str(item.modified_time))
         os.utime(item_local_path, (t, t))
         self.items_store.update_item(item, ItemRecordStatuses.OK)
     except (IOError, OSError) as e:
         self.logger.error('IO error when updating timestamp for file "%s": %s', item_local_path, e)
         if not self.task_pool.has_pending_task(item_local_path):
             self.logger.info('Update server timestamp for file "%s" instead.', item_local_path)
             self.task_pool.add_task(UpdateMetadataTask(self, rel_parent_path=self.rel_path + '/',
                                                        item_name=item.name, new_mtime=t))
示例#2
0
 def handle(self):
     local_item_tmp_path = self.local_parent_path + get_tmp_filename(self.item_name)
     try:
         with open(local_item_tmp_path, "wb") as f:
             self.drive.download_file(file=f, size=self._item.size, item_id=self._item.id)
         os.rename(local_item_tmp_path, self.local_path)
         t = datetime_to_timestamp(self._item.modified_time)
         os.utime(self.local_path, (t, t))
         os.chown(self.local_path, OS_USER_ID, OS_USER_GID)
         self.items_store.update_item(self._item, ItemRecordStatuses.DOWNLOADED)
     except (IOError, OSError) as e:
         self.logger.error('An IO error occurred when downloading "%s": %s.', self.local_path, e)
     except errors.OneDriveError as e:
         self.logger.error('An API error occurred when downloading "%s": %s.', self.local_path, e)
示例#3
0
 def test_handle(self, mock_request):
     tmp_path = self.parent_task.drive.config.local_root + '/' + get_tmp_filename('test')
     dest_path = self.parent_task.drive.config.local_root + '/test'
     tmp_path2 = self.task.local_parent_path + get_tmp_filename('test')
     ts = datetime_to_timestamp(self.item.modified_time)
     mock_request.get(self.task.drive.drive_uri + self.task.drive.drive_path + '/items/' + self.item.id + '/content',
                      content=b'1', status_code=codes.ok)
     m = mock.mock_open()
     with mock.patch('builtins.open', m, create=True):
         self.task.handle()
     self.assertEqual([(tmp_path, dest_path)], self.calls_hist['os.rename'])
     self.assertEqual([(dest_path, OS_USER_ID, OS_USER_GID)], self.calls_hist['os.chown'])
     self.assertEqual([(dest_path, (ts, ts))], self.calls_hist['os.utime'])
     self.assertEqual(tmp_path, tmp_path2)
     m.assert_called_once_with(tmp_path2, 'wb')
     handle = m()
     handle.write.assert_called_once_with(b'1')
示例#4
0
 def _update_attr_when_hash_equal(self, item_local_path, item):
     t = datetime_to_timestamp(item.modified_time)
     try:
         self.logger.info('Updating timestamp for file "%s" to "%s".',
                          item_local_path, str(item.modified_time))
         os.utime(item_local_path, (t, t))
         self.items_store.update_item(item, ItemRecordStatuses.OK)
     except (IOError, OSError) as e:
         self.logger.error(
             'IO error when updating timestamp for file "%s": %s',
             item_local_path, e)
         if not self.task_pool.has_pending_task(item_local_path):
             self.logger.info(
                 'Update server timestamp for file "%s" instead.',
                 item_local_path)
             self.task_pool.add_task(
                 UpdateMetadataTask(self,
                                    rel_parent_path=self.rel_path + '/',
                                    item_name=item.name,
                                    new_mtime=t))
示例#5
0
 def handle(self):
     local_item_tmp_path = self.local_parent_path + get_tmp_filename(
         self.item_name)
     try:
         with open(local_item_tmp_path, 'wb') as f:
             self.drive.download_file(file=f,
                                      size=self._item.size,
                                      item_id=self._item.id)
         os.rename(local_item_tmp_path, self.local_path)
         t = datetime_to_timestamp(self._item.modified_time)
         os.utime(self.local_path, (t, t))
         os.chown(self.local_path, OS_USER_ID, OS_USER_GID)
         self.items_store.update_item(self._item,
                                      ItemRecordStatuses.DOWNLOADED)
     except (IOError, OSError) as e:
         self.logger.error(
             'An IO error occurred when downloading "%s": %s.',
             self.local_path, e)
     except errors.OneDriveError as e:
         self.logger.error(
             'An API error occurred when downloading "%s": %s.',
             self.local_path, e)
示例#6
0
 def _analyze_remote_item(self, remote_item, all_local_items):
     """
     Analyze what to do with a remote item. Assume that this item passes ignore list.
     This function is the core algorithm and probably the ugliest code I've written so far.
     :param onedrived.api.items.OneDriveItem remote_item: The remote item object.
     :param [str] all_local_items: All remaining untouched local items.
     """
     item_local_path = self.local_path + '/' + remote_item.name
     q = self.items_store.get_items_by_id(parent_path=self.remote_path, item_name=remote_item.name)
     exists = os.path.exists(item_local_path)
     has_record = len(q) > 0
     if not has_record and not exists:
         # There is no record in database. The item is not present. Probably a new file.
         self._create_download_task(item_local_path, remote_item)
     elif has_record and not exists:
         # There is record but the file is gone.
         item_id, item_record = _unpack_first_item(q)
         if item_id == remote_item.id and remote_item.c_tag == item_record.c_tag \
                 and remote_item.e_tag == item_record.e_tag:
             # Same record. The file is probably deleted when daemon is off.
             self._create_delete_item_task(item_local_path, remote_item)
         else:
             # The record differs. For safety we download it.
             self.logger.info('Cannot determine actions for "%s". Non-existent and records differ.', item_local_path)
             self._create_download_task(item_local_path, remote_item)
     else:
         # The entry exists locally.
         # First solve possible type conflict.
         is_dir = os.path.isdir(item_local_path)
         if is_dir != remote_item.is_folder:
             self.logger.info('Type conflict on path "%s". One side is file and the other is dir.', item_local_path)
             self._move_existing_and_download(item_local_path, remote_item, all_local_items, q)
         elif is_dir:
             # Both sides are directories. Just update the record and sync if needed.
             if has_record:
                 item_id, item_record = _unpack_first_item(q)
                 has_record = item_id == remote_item.id
             if not has_record:
                 self.logger.info('Fix database record for directory "%s".', item_local_path)
                 self.items_store.update_item(remote_item, ItemRecordStatuses.OK)
             else:
                 self.logger.debug('Directory "%s" has intact record.', item_local_path)
         else:
             # Both sides are files. Examine file attributes.
             file_size, file_mtime = stat_file(item_local_path)
             if file_size == remote_item.size \
                     and compare_timestamps(file_mtime, datetime_to_timestamp(remote_item.modified_time)) == 0:
                 # Same file name. Same size. Same mtime. Guess they are the same for laziness.
                 # Just update the record.
                 need_update = not has_record
                 if has_record:
                     item_id, item_record = _unpack_first_item(q)
                     need_update = item_record.c_tag != remote_item.c_tag or item_record.e_tag != remote_item.e_tag
                 if need_update:
                     self.logger.info('Fix database record for file "%s" based on file size and mtime.',
                                      item_local_path)
                     self.items_store.update_item(remote_item, ItemRecordStatuses.OK)
                 else:
                     self.logger.debug('File "%s" seems fine.', item_local_path)
             else:
                 if has_record:
                     item_id, item_record = _unpack_first_item(q)
                     if item_id == remote_item.id and item_record.c_tag == remote_item.c_tag \
                             or item_record.e_tag == remote_item.e_tag:
                         # The remote item did not change since last update, but LOCAL file changed since then.
                         self.logger.info('File "%s" changed locally since last sync. Upload.', item_local_path)
                         self._create_upload_task(local_item_name=remote_item.name, is_dir=False)
                     elif file_size == item_record.size and compare_timestamps(
                             file_mtime, datetime_to_timestamp(item_record.modified_time)) == 0:
                         # The local item did not change since last update, but REMOTE file changed since then.
                         self.logger.info('File "%s" changed remotely since last sync. Download.', item_local_path)
                         self._create_download_task(item_local_path, remote_item)
                     else:
                         # Three ends mismatch. Keep both.
                         self.logger.info('Cannot determine file "%s". All information differ. Keep both.',
                                          item_local_path)
                         self._move_existing_and_download(item_local_path, remote_item, all_local_items, q)
                 else:
                     # Examine file hash.
                     if _have_equal_hash(item_local_path, remote_item):
                         # Same hash means that they are the same file. Update local timestamp and database record.
                         self._update_attr_when_hash_equal(item_local_path, remote_item)
                     else:
                         self.logger.info('Cannot determine file "%s". Rename and keep both.', item_local_path)
                         self._move_existing_and_download(item_local_path, remote_item, all_local_items, q)
示例#7
0
 def test_convert(self):
     self.assertEqual(self.d, dateparser.str_to_datetime(self.s))
     self.assertEqual(self.s, dateparser.datetime_to_str(self.d))
     self.assertEqual(self.t, dateparser.datetime_to_timestamp(self.d))
示例#8
0
 def _analyze_remote_item(self, remote_item, all_local_items):
     """
     Analyze what to do with a remote item. Assume that this item passes ignore list.
     This function is the core algorithm and probably the ugliest code I've written so far.
     :param onedrived.api.items.OneDriveItem remote_item: The remote item object.
     :param [str] all_local_items: All remaining untouched local items.
     """
     item_local_path = self.local_path + '/' + remote_item.name
     q = self.items_store.get_items_by_id(parent_path=self.remote_path,
                                          item_name=remote_item.name)
     exists = os.path.exists(item_local_path)
     has_record = len(q) > 0
     if not has_record and not exists:
         # There is no record in database. The item is not present. Probably a new file.
         self._create_download_task(item_local_path, remote_item)
     elif has_record and not exists:
         # There is record but the file is gone.
         item_id, item_record = _unpack_first_item(q)
         if item_id == remote_item.id and remote_item.c_tag == item_record.c_tag \
                 and remote_item.e_tag == item_record.e_tag:
             # Same record. The file is probably deleted when daemon is off.
             self._create_delete_item_task(item_local_path, remote_item)
         else:
             # The record differs. For safety we download it.
             self.logger.info(
                 'Cannot determine actions for "%s". Non-existent and records differ.',
                 item_local_path)
             self._create_download_task(item_local_path, remote_item)
     else:
         # The entry exists locally.
         # First solve possible type conflict.
         is_dir = os.path.isdir(item_local_path)
         if is_dir != remote_item.is_folder:
             self.logger.info(
                 'Type conflict on path "%s". One side is file and the other is dir.',
                 item_local_path)
             self._move_existing_and_download(item_local_path, remote_item,
                                              all_local_items, q)
         elif is_dir:
             # Both sides are directories. Just update the record and sync if needed.
             if has_record:
                 item_id, item_record = _unpack_first_item(q)
                 has_record = item_id == remote_item.id
             if not has_record:
                 self.logger.info('Fix database record for directory "%s".',
                                  item_local_path)
                 self.items_store.update_item(remote_item,
                                              ItemRecordStatuses.OK)
             else:
                 self.logger.debug('Directory "%s" has intact record.',
                                   item_local_path)
         else:
             # Both sides are files. Examine file attributes.
             file_size, file_mtime = stat_file(item_local_path)
             if file_size == remote_item.size \
                     and compare_timestamps(file_mtime, datetime_to_timestamp(remote_item.modified_time)) == 0:
                 # Same file name. Same size. Same mtime. Guess they are the same for laziness.
                 # Just update the record.
                 need_update = not has_record
                 if has_record:
                     item_id, item_record = _unpack_first_item(q)
                     need_update = item_record.c_tag != remote_item.c_tag or item_record.e_tag != remote_item.e_tag
                 if need_update:
                     self.logger.info(
                         'Fix database record for file "%s" based on file size and mtime.',
                         item_local_path)
                     self.items_store.update_item(remote_item,
                                                  ItemRecordStatuses.OK)
                 else:
                     self.logger.debug('File "%s" seems fine.',
                                       item_local_path)
             else:
                 if has_record:
                     item_id, item_record = _unpack_first_item(q)
                     if item_id == remote_item.id and item_record.c_tag == remote_item.c_tag \
                             or item_record.e_tag == remote_item.e_tag:
                         # The remote item did not change since last update, but LOCAL file changed since then.
                         self.logger.info(
                             'File "%s" changed locally since last sync. Upload.',
                             item_local_path)
                         self._create_upload_task(
                             local_item_name=remote_item.name, is_dir=False)
                     elif file_size == item_record.size and compare_timestamps(
                             file_mtime,
                             datetime_to_timestamp(
                                 item_record.modified_time)) == 0:
                         # The local item did not change since last update, but REMOTE file changed since then.
                         self.logger.info(
                             'File "%s" changed remotely since last sync. Download.',
                             item_local_path)
                         self._create_download_task(item_local_path,
                                                    remote_item)
                     else:
                         # Three ends mismatch. Keep both.
                         self.logger.info(
                             'Cannot determine file "%s". All information differ. Keep both.',
                             item_local_path)
                         self._move_existing_and_download(
                             item_local_path, remote_item, all_local_items,
                             q)
                 else:
                     # Examine file hash.
                     if _have_equal_hash(item_local_path, remote_item):
                         # Same hash means that they are the same file. Update local timestamp and database record.
                         self._update_attr_when_hash_equal(
                             item_local_path, remote_item)
                     else:
                         self.logger.info(
                             'Cannot determine file "%s". Rename and keep both.',
                             item_local_path)
                         self._move_existing_and_download(
                             item_local_path, remote_item, all_local_items,
                             q)