FreeBSD/contrib/subversion/subversion/libsvn_client/blame.c
/* Calculate and record blame information for one revision of the file,
 * by comparing the file content against the previously seen revision.
 *
 * This handler is called once for each interesting revision of the file.
 *
 * Record the blame information for this revision in (file_rev_baton) BATON.
 *
 * Implements svn_file_rev_handler_t.
 */
Calculate and record blame information for one revision of the file,
by comparing the file content against the previously seen revision.

This handler is called once for each interesting revision of the file.

Record the blame information for this revision in (file_rev_baton) BATON.


Calculate and record blame information for one revision of the file by comparing the file content against the previously seen revision . This handler is called once for each interesting revision of the file . Record the blame information for this revision in ( file_rev_baton ) BATON .
static svn_error_t *
file_rev_handler(void *baton, const char *path, svn_revnum_t revnum,
                 apr_hash_t *rev_props,
                 svn_boolean_t merged_revision,
                 svn_txdelta_window_handler_t *content_delta_handler,
                 void **content_delta_baton,
                 apr_array_header_t *prop_diffs,
                 apr_pool_t *pool)
{
  struct file_rev_baton *frb = baton;
  svn_stream_t *last_stream;
  svn_stream_t *cur_stream;
  struct delta_baton *delta_baton;
  apr_pool_t *filepool;
  svn_pool_clear(frb->currpool);
  if (frb->check_mime_type)
    {
      apr_hash_t *props = svn_prop_array_to_hash(prop_diffs, frb->currpool);
      const char *value;
      frb->check_mime_type = FALSE; 
      value = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
      if (value && svn_mime_type_is_binary(value))
        {
          return svn_error_createf(
              SVN_ERR_CLIENT_IS_BINARY_FILE, NULL,
              _("Cannot calculate blame information for binary file '%s'"),
               (svn_path_is_url(frb->target)
                      ? frb->target 
                      : svn_dirent_local_style(frb->target, pool)));
        }
    }
  if (frb->ctx->notify_func2)
    {
      svn_wc_notify_t *notify
            = svn_wc_create_notify_url(
                            svn_path_url_add_component2(frb->repos_root_url,
                                                        path+1, pool),
                            svn_wc_notify_blame_revision, pool);
      notify->path = path;
      notify->kind = svn_node_none;
      notify->content_state = notify->prop_state
        = svn_wc_notify_state_inapplicable;
      notify->lock_state = svn_wc_notify_lock_state_inapplicable;
      notify->revision = revnum;
      notify->rev_props = rev_props;
      frb->ctx->notify_func2(frb->ctx->notify_baton2, notify, pool);
    }
  if (frb->ctx->cancel_func)
    SVN_ERR(frb->ctx->cancel_func(frb->ctx->cancel_baton));
  if (!content_delta_handler
      && (!frb->include_merged_revisions || merged_revision))
    return SVN_NO_ERROR;
  delta_baton = apr_pcalloc(frb->currpool, sizeof(*delta_baton));
  if (frb->last_filename)
    SVN_ERR(svn_stream_open_readonly(&delta_baton->source_stream, frb->last_filename,
                                     frb->currpool, pool));
  else
    delta_baton->source_stream = NULL;
  last_stream = svn_stream_disown(delta_baton->source_stream, pool);
  if (frb->include_merged_revisions && !merged_revision)
    filepool = frb->filepool;
  else
    filepool = frb->currpool;
  SVN_ERR(svn_stream_open_unique(&cur_stream, &delta_baton->filename, NULL,
                                 svn_io_file_del_on_pool_cleanup,
                                 filepool, filepool));
  delta_baton->file_rev_baton = frb;
  delta_baton->is_merged_revision = merged_revision;
  delta_baton->rev = apr_pcalloc(frb->mainpool, sizeof(struct rev));
  if (frb->backwards)
    {
      delta_baton->rev->revision = frb->last_revnum;
      delta_baton->rev->rev_props = frb->last_props;
      if (revnum >= MIN(frb->start_rev, frb->end_rev))
        {
          frb->last_revnum = revnum;
          frb->last_props = svn_prop_hash_dup(rev_props, frb->mainpool);
        }
    }
  else if (merged_revision
           || (revnum >= MIN(frb->start_rev, frb->end_rev)))
    {
      SVN_ERR_ASSERT(revnum <= 1 + MAX(frb->end_rev, frb->start_rev));
      delta_baton->rev->revision = revnum;
      delta_baton->rev->rev_props = svn_prop_hash_dup(rev_props, frb->mainpool);
    }
  else
    {
      SVN_ERR_ASSERT((frb->last_filename == NULL)
                     || frb->include_merged_revisions);
      delta_baton->rev->revision = SVN_INVALID_REVNUM;
    }
  if (frb->include_merged_revisions)
    delta_baton->rev->path = apr_pstrdup(frb->mainpool, path);
  frb->last_rev = delta_baton->rev;
  if (content_delta_handler)
    {
      svn_txdelta_apply(last_stream, cur_stream, NULL, NULL,
                        frb->currpool,
                        &delta_baton->wrapped_handler,
                        &delta_baton->wrapped_baton);
      *content_delta_handler = window_handler;
      *content_delta_baton = delta_baton;
    }
  else
    {
      SVN_ERR(svn_stream_copy3(last_stream, cur_stream, NULL, NULL, pool));
      SVN_ERR(update_blame(delta_baton));
    }
  return SVN_NO_ERROR;
}
static svn_error_t * file_rev_handler ( void * baton , const char * path , svn_revnum_t revnum , apr_hash_t * rev_props , svn_boolean_t merged_revision , svn_txdelta_window_handler_t * content_delta_handler , void * * content_delta_baton , apr_array_header_t * prop_diffs , apr_pool_t * pool ) { struct file_rev_baton * frb = baton ; svn_stream_t * last_stream ; svn_stream_t * cur_stream ; struct delta_baton * delta_baton ; apr_pool_t * filepool ; svn_pool_clear ( frb -> currpool ) ; if ( frb -> check_mime_type ) { apr_hash_t * props = svn_prop_array_to_hash ( prop_diffs , frb -> currpool ) ; const char * value ; frb -> check_mime_type = FALSE ; value = svn_prop_get_value ( props , SVN_PROP_MIME_TYPE ) ; if ( value && svn_mime_type_is_binary ( value ) ) { return svn_error_createf ( SVN_ERR_CLIENT_IS_BINARY_FILE , NULL , _ ( " " ) , ( svn_path_is_url ( frb -> target ) ? frb -> target : svn_dirent_local_style ( frb -> target , pool ) ) ) ; } } if ( frb -> ctx -> notify_func2 ) { svn_wc_notify_t * notify = svn_wc_create_notify_url ( svn_path_url_add_component2 ( frb -> repos_root_url , path + 1 , pool ) , svn_wc_notify_blame_revision , pool ) ; notify -> path = path ; notify -> kind = svn_node_none ; notify -> content_state = notify -> prop_state = svn_wc_notify_state_inapplicable ; notify -> lock_state = svn_wc_notify_lock_state_inapplicable ; notify -> revision = revnum ; notify -> rev_props = rev_props ; frb -> ctx -> notify_func2 ( frb -> ctx -> notify_baton2 , notify , pool ) ; } if ( frb -> ctx -> cancel_func ) SVN_ERR ( frb -> ctx -> cancel_func ( frb -> ctx -> cancel_baton ) ) ; if ( ! content_delta_handler && ( ! frb -> include_merged_revisions || merged_revision ) ) return SVN_NO_ERROR ; delta_baton = apr_pcalloc ( frb -> currpool , sizeof ( * delta_baton ) ) ; if ( frb -> last_filename ) SVN_ERR ( svn_stream_open_readonly ( & delta_baton -> source_stream , frb -> last_filename , frb -> currpool , pool ) ) ; else delta_baton -> source_stream = NULL ; last_stream = svn_stream_disown ( delta_baton -> source_stream , pool ) ; if ( frb -> include_merged_revisions && ! merged_revision ) filepool = frb -> filepool ; else filepool = frb -> currpool ; SVN_ERR ( svn_stream_open_unique ( & cur_stream , & delta_baton -> filename , NULL , svn_io_file_del_on_pool_cleanup , filepool , filepool ) ) ; delta_baton -> file_rev_baton = frb ; delta_baton -> is_merged_revision = merged_revision ; delta_baton -> rev = apr_pcalloc ( frb -> mainpool , sizeof ( struct rev ) ) ; if ( frb -> backwards ) { delta_baton -> rev -> revision = frb -> last_revnum ; delta_baton -> rev -> rev_props = frb -> last_props ; if ( revnum >= MIN ( frb -> start_rev , frb -> end_rev ) ) { frb -> last_revnum = revnum ; frb -> last_props = svn_prop_hash_dup ( rev_props , frb -> mainpool ) ; } } else if ( merged_revision || ( revnum >= MIN ( frb -> start_rev , frb -> end_rev ) ) ) { SVN_ERR_ASSERT ( revnum <= 1 + MAX ( frb -> end_rev , frb -> start_rev ) ) ; delta_baton -> rev -> revision = revnum ; delta_baton -> rev -> rev_props = svn_prop_hash_dup ( rev_props , frb -> mainpool ) ; } else { SVN_ERR_ASSERT ( ( frb -> last_filename == NULL ) || frb -> include_merged_revisions ) ; delta_baton -> rev -> revision = SVN_INVALID_REVNUM ; } if ( frb -> include_merged_revisions ) delta_baton -> rev -> path = apr_pstrdup ( frb -> mainpool , path ) ; frb -> last_rev = delta_baton -> rev ; if ( content_delta_handler ) { svn_txdelta_apply ( last_stream , cur_stream , NULL , NULL , frb -> currpool , & delta_baton -> wrapped_handler , & delta_baton -> wrapped_baton ) ; * content_delta_handler = window_handler ; * content_delta_baton = delta_baton ; } else { SVN_ERR ( svn_stream_copy3 ( last_stream , cur_stream , NULL , NULL , pool ) ) ; SVN_ERR ( update_blame ( delta_baton ) ) ; } return SVN_NO_ERROR ; }
Calculate and record blame information for one revision of the file,
 by comparing the file content against the previously seen revision.
Calculate and record blame information for one revision of the file by comparing the file content against the previously seen revision .
/* Clear the current pool. */ /* Only check first */ /* If there were no content changes and no (potential) merges, we couldn't
     care less about this revision now.  Note that we checked the mime type
     above, so things work if the user just changes the mime type in a commit.
     Also note that we don't switch the pools in this case.  This is important,
     since the tempfile will be removed by the pool and we need the tempfile
     from the last revision with content changes. */ /* Create delta baton. */ /* Prepare the text delta window handler. */ /* Means empty stream below. */ /* Wrap the window handler with our own. */ /* Create the rev structure. */ /* Use from last round...
         SVN_INVALID_REVNUM on first, which is exactly
         what we want */ /* Store for next delta */ /* Else: Not needed on last rev */ /* 1+ for the "youngest to oldest" blame */ /* Set values from revision props. */ /* We shouldn't get more than one revision outside the
         specified range (unless we alsoe receive merged revisions) */ /* The file existed before start_rev; generate no blame info for
         lines from this revision (or before). 

         This revision specifies the state as it was at the start revision */ /* Keep last revision for postprocessing after all changes */ /* Handle all delta - even if it is empty.
     We must do the latter to "merge" blame info from other branches. */ /* Proper delta - get window handler for applying delta.
         svn_ra_get_file_revs2 will drive the delta editor. */ /* Apply an empty delta, i.e. simply copy the old contents.
         We can't simply use the existing file due to the pool rotation logic.
         Trigger the blame update magic. */