Example #1
0
 def _generate_compressed_dir_changes(self, dir_changes):
   dir_changes = copy.deepcopy(dir_changes)
   for c in dir_changes.flat_changes():
     if c.cur_info and c.cur_info.tmp_file:
       compressed_tmp_filename = change_entry.generate_tmp_file(self.tmp_dir)
       compressed_tmp_file = os.path.join(self.tmp_dir,
                                          compressed_tmp_filename)
       tmp_file_with_realname = os.path.join(self.tmp_dir,
                                             os.path.basename(c.path))
       # Rename the tmp file so that the archive includes the original
       # filename.
       os.rename(c.cur_info.tmp_file, tmp_file_with_realname)
       compression.compress_file(tmp_file_with_realname, compressed_tmp_file,
                                 password=self.password,
                                 encryption_method=self.encryption_method,
                                 compression_level=self.compression_level)
       # Rename the tmp filename back.
       os.rename(tmp_file_with_realname, c.cur_info.tmp_file)
       tmp_fi = file_info.load_file_info(compressed_tmp_file)
       compressed_file_info = file_info.FileInfo(
           # TODO: check conflict of compressed filename?
           compression.get_compressed_filename(c.cur_info.path),
           c.cur_info.is_dir, c.cur_info.mode, tmp_fi.size,
           c.cur_info.last_modified_time)
       c.cur_info.compressed_file_info = file_info.copy_with_tmp_file(
           compressed_file_info, compressed_tmp_filename, self.tmp_dir)
   return dir_changes
Example #2
0
def _get_file_conflict_state(change, full_path, force_conflict):
  if os.path.isdir(full_path):
    return CONFLICT_NEW
  elif force_conflict:
    return force_conflict
  elif os.path.isfile(full_path):
    fi = file_info.load_file_info(full_path)
    if ((change.old_info and not change.old_info.is_modified(fi)) or
        (change.cur_info and not change.cur_info.is_modified(fi)) or
        (change.conflict_info and not change.conflict_info.is_modified(fi))):
      return CONFLICT_NO_CONFLICT
    else:
      # Keep the dest unchanged, because it may be opened
      return CONFLICT_NEW
  else:
    # No exist
    return CONFLICT_NO_CONFLICT
Example #3
0
  def _generate_original_dir_changes(self, dir_changes,
                                     parent_dir_changes=None,
                                     parent_invalid_archive_dc_working=None,
                                     parent_invalid_archive_dc_cloud=None):
    invalid_archive_dc_working = change_entry.DirChanges(
        dir_changes.base_dir(),
        change_entry.CONTENT_STATUS_MODIFIED,
        parent_dir_changes=parent_invalid_archive_dc_working)
    invalid_archive_dc_cloud = change_entry.DirChanges(
        dir_changes.base_dir(),
        change_entry.CONTENT_STATUS_MODIFIED,
        parent_dir_changes=parent_invalid_archive_dc_cloud)
    new_dir_changes = change_entry.DirChanges(
        dir_changes.base_dir(), dir_changes.dir_status(),
        parent_dir_changes=parent_dir_changes)
    for c in dir_changes.changes():
      path = compression.get_original_filename(c.path)
      old_info = None
      if c.old_info and c.old_info.original_file_info:
        old_info = copy.deepcopy(c.old_info.original_file_info)
        old_info.compressed_file_info = copy.deepcopy(c.old_info)
        old_info.compressed_file_info.original_file_info = None
      else:
        old_info = copy.deepcopy(c.old_info)

      cur_info = None
      if c.cur_info:
        if c.cur_info.is_dir:
          cur_info = c.cur_info
        elif c.cur_info.tmp_file:
          original_tmp_filename = change_entry.generate_tmp_file(self.tmp_dir)
          original_tmp_file = os.path.join(self.tmp_dir,
                                           original_tmp_filename)
          if not compression.is_compressed_filename(c.cur_info.path):
            invalid_archive_dc_working.add_change(change_entry.ChangeEntry(
                path, c.cur_info, c.old_info, c.content_status,
                parent_dir_changes=invalid_archive_dc_working))
            invalid_archive_dc_cloud.add_change(change_entry.ChangeEntry(
                path, None, c.cur_info,
                # Remove the file directly because we move it to working dir
                change_entry.CONTENT_STATUS_DELETED,
                parent_dir_changes=invalid_archive_dc_cloud))
            continue
          try:
            compression.decompress_file(c.cur_info.tmp_file, original_tmp_file,
                                        self.tmp_dir, password=self.password)
          except compression.CompressionInvalidArchive:
            invalid_archive_dc_working.add_change(change_entry.ChangeEntry(
                # Not using path because it is not a valid archive
                c.path, c.cur_info, c.old_info, c.content_status,
                parent_dir_changes=invalid_archive_dc_working))
            invalid_archive_dc_cloud.add_change(change_entry.ChangeEntry(
                # Not using path because it is not a valid archive
                c.path, None, c.cur_info,
                # Remove the file directly because we move it to working dir
                change_entry.CONTENT_STATUS_DELETED,
                parent_dir_changes=invalid_archive_dc_cloud))
            continue

          tmp_fi = file_info.load_file_info(original_tmp_file)
          compressed_file_info = copy.deepcopy(c.cur_info)
          compressed_file_info.compressed_file_info = None
          compressed_file_info.original_file_info = None
          cur_info = file_info.FileInfo(
              # TODO: check conflict of original filename?
              compression.get_original_filename(c.cur_info.path),
              c.cur_info.is_dir, c.cur_info.mode, tmp_fi.size,
              c.cur_info.last_modified_time,
              compressed_file_info=compressed_file_info)
          cur_info = file_info.copy_with_tmp_file(
              cur_info, original_tmp_filename, self.tmp_dir)
        else:
          cur_info = old_info

      sub_dir_changes = None
      sub_invalid_archive_dc_working = None
      if c.dir_changes:
        result = self._generate_original_dir_changes(
                c.dir_changes,
                parent_dir_changes=new_dir_changes,
                parent_invalid_archive_dc_working=invalid_archive_dc_working)
        sub_dir_changes = result[0]
        sub_invalid_archive_dc_working = result[1]
        sub_invalid_archive_dc_cloud = result[2]
        if sub_invalid_archive_dc_working:
          invalid_archive_dc_working.add_change(change_entry.ChangeEntry(
              path, cur_info, old_info, c.content_status,
              dir_changes=sub_invalid_archive_dc_working,
              parent_dir_changes=invalid_archive_dc_working))
        if sub_invalid_archive_dc_cloud:
          invalid_archive_dc_cloud.add_change(change_entry.ChangeEntry(
              path, cur_info, old_info, c.content_status,
              dir_changes=sub_invalid_archive_dc_cloud,
              parent_dir_changes=invalid_archive_dc_cloud))
      new_dir_changes.add_change(change_entry.ChangeEntry(
          path, cur_info, old_info, c.content_status,
          dir_changes=sub_dir_changes,
          parent_dir_changes=new_dir_changes))

    if not invalid_archive_dc_working.changes():
      invalid_archive_dc_working = None
    if not invalid_archive_dc_cloud.changes():
      invalid_archive_dc_cloud = None
    return new_dir_changes, invalid_archive_dc_working, invalid_archive_dc_cloud
Example #4
0
def apply_dir_changes_to_dir(dest_dir, dir_changes, force_conflict=None,
                             verbose=False):
  for c in dir_changes.changes():
    full_path = os.path.realpath(os.path.join(dest_dir, c.path))
    if c.content_status == CONTENT_STATUS_TO_FILE:
      if not os.path.exists(full_path):
        if verbose:
          print 'Create file %s' % full_path
        c.cur_info.copy_tmp(full_path)
      elif os.path.isdir(full_path):
        apply_dir_changes_to_dir(dest_dir, c.dir_changes,
                                 force_conflict=force_conflict,
                                 verbose=verbose)
        if os.listdir(full_path):
          # Conflict, the directory still exists
          if verbose:
            print 'Create conflict file %s' % _get_conflict_copy_path(full_path)
          c.cur_info.copy_tmp(_get_conflict_copy_path(full_path))
        else:
          if verbose:
            print 'Delete dir %s' % full_path
            print 'Create file %s' % full_path
          os.rmdir(full_path)
          c.cur_info.copy_tmp(full_path)
      else:
        # full_path is a file
        if c.cur_info.is_modified(file_info.load_file_info(full_path)):
          # Conflict, the existing file is changed
          if verbose:
            print 'Create conflict file %s' % _get_conflict_copy_path(full_path)
          c.cur_info.copy_tmp(_get_conflict_copy_path(full_path))

    elif c.content_status == CONTENT_STATUS_TO_DIR:
      if not os.path.exists(full_path):
        if verbose:
          print 'Create dir %s' % full_path
        os.mkdir(full_path)
        apply_dir_changes_to_dir(dest_dir, c.dir_changes,
                                 force_conflict=force_conflict,
                                 verbose=verbose)
      elif os.path.isdir(full_path):
        apply_dir_changes_to_dir(dest_dir, c.dir_changes,
                                 force_conflict=force_conflict,
                                 verbose=verbose)
      else:
        # full_path is still a file
        if c.old_info.is_modified(file_info.load_file_info(full_path)):
          if verbose:
            print 'Move to conflict file %s' % _get_conflict_copy_path(
                full_path)
          # Conflict, the existing file is changed
          os.rename(full_path, _get_conflict_copy_path(full_path))
        else:
          if verbose:
            print 'Delete file %s' % full_path
          os.remove(full_path)
        if verbose:
          print 'Create dir %s' % full_path
        os.mkdir(full_path)
        apply_dir_changes_to_dir(dest_dir, c.dir_changes,
                                 force_conflict=force_conflict,
                                 verbose=verbose)

    elif ((not c.cur_info or not c.cur_info.is_dir)
        and (not c.old_info or not c.old_info.is_dir)):
      # File change
      if c.content_status in [CONTENT_STATUS_NEW,
                              CONTENT_STATUS_MODIFIED]:
        conflict_state = _get_file_conflict_state(c, full_path, force_conflict)
        if conflict_state == CONFLICT_NO_CONFLICT:
          if verbose:
            if c.content_status == CONTENT_STATUS_NEW:
              print 'Create file %s' % full_path
            else:
              print 'Update file %s' % full_path
          c.cur_info.copy_tmp(full_path)
        elif conflict_state == CONFLICT_NEW:
          if verbose:
            print 'Create conflict file %s' % _get_conflict_copy_path(full_path)
          c.cur_info.copy_tmp(_get_conflict_copy_path(full_path))
        elif conflict_state == CONFLICT_DEST:
          if verbose:
            print 'Move to conflict file %s' % _get_conflict_copy_path(full_path)
            print 'Create file %s' % full_path
          shutil.move(full_path, _get_conflict_copy_path(full_path))
          c.cur_info.copy_tmp(full_path)
      elif c.content_status == CONTENT_STATUS_DELETED:
        conflict_state = _get_file_conflict_state(c, full_path, force_conflict)
        if conflict_state == CONFLICT_NO_CONFLICT:
          if os.path.exists(full_path):
            if verbose:
              print 'Delete file %s' % full_path
            os.remove(full_path)

    else:
      # Dir change
      if c.content_status in [CONTENT_STATUS_NEW,
                              CONTENT_STATUS_MODIFIED]:
        conflict_state = _get_dir_conflict_state(c, full_path)
        if conflict_state == CONFLICT_NO_CONFLICT:
          if not os.path.exists(full_path):
            if verbose:
              print 'Create dir %s' % full_path
            os.mkdir(full_path)
        elif conflict_state == CONFLICT_DEST:
          if verbose:
            print 'Move to conflict file %s' % _get_conflict_copy_path(full_path)
            print 'Create dir %s' % full_path
          shutil.move(full_path, _get_conflict_copy_path(full_path))
          os.mkdir(full_path)
        apply_dir_changes_to_dir(dest_dir, c.dir_changes,
                                 force_conflict=force_conflict,
                                 verbose=verbose)
      elif c.content_status == CONTENT_STATUS_DELETED:
        conflict_state = _get_dir_conflict_state(c, full_path)
        if conflict_state == CONFLICT_NO_CONFLICT:
          apply_dir_changes_to_dir(dest_dir, c.dir_changes,
                                   force_conflict=force_conflict,
                                   verbose=verbose)
          if os.path.isdir(full_path) and not os.listdir(full_path):
            if verbose:
              print 'Delete dir %s' % full_path
            os.rmdir(full_path)
      else:
        # No change
        apply_dir_changes_to_dir(dest_dir, c.dir_changes,
                                 force_conflict=force_conflict,
                                 verbose=verbose)