@log_calls
  def update(self, scope, srev="tip", force=False, is_checkout=False, mode=None):
    '''
    Update working directory. Checkouts are also implemented here, as if they were updates from an empty manifest.
    mode is only for checkout
    '''
    partial_mode = mode == Mode.PARTIAL
    is_partial_checkout = is_checkout and partial_mode

    # Get manifest for working dir
    cur_rev = self.get_checkout_rev(scope)
    if is_checkout:
      if cur_rev and not force:
        raise InvalidOperation("scope '%s' is already checked out; use update instead" % scope)
      old_mf = Manifest()
    else:
      if mode is not None:
        raise InvalidOperation(mode % "mode option '%s' is used with update")
      old_mf = self.repo.get_manifest(scope, cur_rev) if cur_rev else Manifest()
    # Get new manifest. Doing this first also validates scope and srev.
    new_mf = self.repo.get_manifest(scope, srev)

    # Find out what files we need to update.
    changelist = changelist_for_items(old_mf.items, new_mf.items) if not is_partial_checkout else Changelist()
    log.debug("update from %s to %s, changing %s", old_mf, new_mf, changelist)

    # If in partial tracking mode, keep only FileState.Tracked files
    if partial_mode or self.get_scope_mode(scope) == Mode.PARTIAL:
      for path in changelist.all_paths():
        with self._yield_fingerprint(scope, path) as (fp, local_path):
          if fp is None or fp.state not in FileStateTrackedList:
            if fp is not None:
              fp.invalidate() # we have to invalidate this fingerprint since the remote file might be updated.
            changelist.discard(path)

    # Check for local uncommitted changes. If there is no overlap, the update is safe.
    status_changelist = self.status(scope) if not is_checkout else Changelist()
    overlap_changelist = status_changelist.intersect(changelist)
    log.debug("update changelist:\n%s", changelist.to_summary())
    log.debug("status changelist:\n%s", status_changelist.to_summary())
    if not overlap_changelist.is_empty():
      log.error("local changes conflict with update for scope '%s':", scope)
      log.stream.write(overlap_changelist.to_summary())
      raise InvalidOperation("Zinc does not currently support automatic merges: must revert locally changed files, update, and then manually merge")

    log.info("%s: scope '%s' at revision %s (%s files total)",
             "checkout" if is_checkout else "update", scope, new_mf.rev, len(new_mf.items))
    conflict_str = "no conflicting local changes" if status_changelist.is_empty() else "have %s of non-conflicting local changes" % status_changelist.brief_summary()
    if not changelist.is_empty():
      log.info("updating files: %s (%s)", changelist.brief_summary(), conflict_str)

    # Update and delete files
    new_fingerprints = self._update_local_files(scope, new_mf.items, changelist, delete_all=True)

    # Changes to files are done. Update checkout state. We already have hashes in new_fingerprints.
    self.checkout_state.update_from_changelist(scope, changelist, new_fingerprints)
    self.checkout_state.update_checkout_rev(scope, new_mf.rev)
    if is_partial_checkout:
      self.update_scope_mode(scope, Mode.PARTIAL)
    self._write_checkout_state()

    return new_mf
dataset/ETHPy150Open bloomreach/zinc/zinc.py/WorkingDir.update/swapped operands of `%`