<commit_before>/*
 * log.c:  return log messages
 *
 * ====================================================================
 * Copyright (c) 2000-2008 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */

/* ==================================================================== */




/*** Includes. ***/

#define APR_WANT_STRFUNC
#include <apr_want.h>

#include <apr_strings.h>
#include <apr_pools.h>

#include "client.h"

#include "svn_pools.h"
#include "svn_client.h"
#include "svn_compat.h"
#include "svn_error.h"
#include "svn_path.h"
#include "svn_sorts.h"

#include "svn_private_config.h"
#include "private/svn_wc_private.h"



/*** Getting misc. information ***/

/* A log callback conforming to the svn_log_entry_receiver_t
   interface for obtaining the last revision of a node at a path and
   storing it in *BATON (an svn_revnum_t). */
static svn_error_t *
revnum_receiver(void *baton,
                svn_log_entry_t *log_entry,
                apr_pool_t *pool)
{
  if (SVN_IS_VALID_REVNUM(log_entry->revision))
    *((svn_revnum_t *) baton) = log_entry->revision;

  return SVN_NO_ERROR;
}

svn_error_t *
svn_client__oldest_rev_at_path(svn_revnum_t *oldest_rev,
                               svn_ra_session_t *ra_session,
                               const char *rel_path,
                               svn_revnum_t rev,
                               apr_pool_t *pool)
{
  apr_array_header_t *rel_paths = apr_array_make(pool, 1, sizeof(rel_path));
  apr_array_header_t *revprops = apr_array_make(pool, 0, sizeof(char *));
  *oldest_rev = SVN_INVALID_REVNUM;
  APR_ARRAY_PUSH(rel_paths, const char *) = rel_path;

  /* Trace back in history to find the revision at which this node
     was created (copied or added). */
  return svn_ra_get_log2(ra_session, rel_paths, 1, rev, 1, FALSE, TRUE,
                         FALSE, revprops, revnum_receiver, oldest_rev, pool);
}

/* The baton for use with copyfrom_info_receiver(). */
typedef struct
{
  const char *target_path;
  const char *path;
  svn_revnum_t rev;
  apr_pool_t *pool;
} copyfrom_info_t;

/* A log callback conforming to the svn_log_message_receiver_t
   interface for obtaining the copy source of a node at a path and
   storing it in *BATON (a struct copyfrom_info_t *). */
static svn_error_t *
copyfrom_info_receiver(void *baton,
                       apr_hash_t *changed_paths,
                       svn_revnum_t revision,
                       const char *author,
                       const char *date,
                       const char *message,
                       apr_pool_t *pool)
{
  copyfrom_info_t *copyfrom_info = baton;
  if (copyfrom_info->path)
    /* The copy source has already been found. */
    return SVN_NO_ERROR;

  if (changed_paths)
    {
      int i;
      const char *path;
      svn_log_changed_path_t *changed_path;
      /* Sort paths into depth-first order. */
      apr_array_header_t *sorted_changed_paths =
        svn_sort__hash(changed_paths, svn_sort_compare_items_as_paths, pool);

      for (i = (sorted_changed_paths->nelts -1) ; i >= 0 ; i--)
        {
          svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_changed_paths, i,
                                                  svn_sort__item_t);
          path = item->key;
          changed_path = item->value;

          /* Consider only the path we're interested in. */
          if (changed_path->copyfrom_path &&
              SVN_IS_VALID_REVNUM(changed_path->copyfrom_rev) &&
              svn_path_is_ancestor(path, copyfrom_info->target_path))
            {
              /* Copy source found!  Determine path and note revision. */
              if (strcmp(path, copyfrom_info->target_path) == 0)
                {
                  /* We have the details for a direct copy to
                     copyfrom_info->target_path. */
                  copyfrom_info->path =
                    apr_pstrdup(copyfrom_info->pool,
                                changed_path->copyfrom_path);
                }
              else
                {
                  /* We have a parent of copyfrom_info->target_path. */
                  copyfrom_info->path =
                    apr_pstrcat(copyfrom_info->pool,
                                changed_path->copyfrom_path,
                                copyfrom_info->target_path +
                                strlen(path), NULL);
                }
              copyfrom_info->rev = changed_path->copyfrom_rev;
              break;
            }
        }
    }
  return SVN_NO_ERROR;
}

svn_error_t *
svn_client__get_copy_source(const char *path_or_url,
                            const svn_opt_revision_t *revision,
                            const char **copyfrom_path,
                            svn_revnum_t *copyfrom_rev,
                            svn_client_ctx_t *ctx,
                            apr_pool_t *pool)
{
  svn_error_t *err;
  copyfrom_info_t copyfrom_info = { NULL, NULL, SVN_INVALID_REVNUM, pool };
  apr_array_header_t *targets = apr_array_make(pool, 1, sizeof(path_or_url));
  svn_opt_revision_t oldest_rev;
  apr_pool_t *sesspool = svn_pool_create(pool);
  svn_ra_session_t *ra_session;
  svn_revnum_t at_rev;
  const char *at_url;

  oldest_rev.kind = svn_opt_revision_number;
  oldest_rev.value.number = 1;

  SVN_ERR(svn_client__ra_session_from_path(&ra_session, &at_rev, &at_url,
                                           path_or_url, NULL,
                                           revision, revision,
                                           ctx, sesspool));
  SVN_ERR(svn_client__path_relative_to_root(&copyfrom_info.target_path,
                                            path_or_url, NULL, TRUE,
                                            ra_session, NULL, pool));
  APR_ARRAY_PUSH(targets, const char *) = path_or_url;

  /* Find the copy source.  Trace back in history to find the revision
     at which this node was created (copied or added). 

     ### Reuse ra_session by way of svn_ra_get_log()?
     err = svn_ra_get_log(ra_session, rel_paths, revision, 1, 0, TRUE, TRUE,
                          copyfrom_info_receiver, &copyfrom_info, pool);
  */
  err = svn_client_log3(targets, revision, revision, &oldest_rev, 0,
                        TRUE, TRUE, copyfrom_info_receiver, &copyfrom_info,
                        ctx, pool);

  svn_pool_destroy(sesspool);

  if (err)<commit_msg>Remove the use of a deprecated API.<commit_after>/*
 * log.c:  return log messages
 *
 * ====================================================================
 * Copyright (c) 2000-2008 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */

/* ==================================================================== */




/*** Includes. ***/

#define APR_WANT_STRFUNC
#include <apr_want.h>

#include <apr_strings.h>
#include <apr_pools.h>

#include "client.h"

#include "svn_pools.h"
#include "svn_client.h"
#include "svn_compat.h"
#include "svn_error.h"
#include "svn_path.h"
#include "svn_sorts.h"

#include "svn_private_config.h"
#include "private/svn_wc_private.h"



/*** Getting misc. information ***/

/* A log callback conforming to the svn_log_entry_receiver_t
   interface for obtaining the last revision of a node at a path and
   storing it in *BATON (an svn_revnum_t). */
static svn_error_t *
revnum_receiver(void *baton,
                svn_log_entry_t *log_entry,
                apr_pool_t *pool)
{
  if (SVN_IS_VALID_REVNUM(log_entry->revision))
    *((svn_revnum_t *) baton) = log_entry->revision;

  return SVN_NO_ERROR;
}

svn_error_t *
svn_client__oldest_rev_at_path(svn_revnum_t *oldest_rev,
                               svn_ra_session_t *ra_session,
                               const char *rel_path,
                               svn_revnum_t rev,
                               apr_pool_t *pool)
{
  apr_array_header_t *rel_paths = apr_array_make(pool, 1, sizeof(rel_path));
  apr_array_header_t *revprops = apr_array_make(pool, 0, sizeof(char *));
  *oldest_rev = SVN_INVALID_REVNUM;
  APR_ARRAY_PUSH(rel_paths, const char *) = rel_path;

  /* Trace back in history to find the revision at which this node
     was created (copied or added). */
  return svn_ra_get_log2(ra_session, rel_paths, 1, rev, 1, FALSE, TRUE,
                         FALSE, revprops, revnum_receiver, oldest_rev, pool);
}

/* The baton for use with copyfrom_info_receiver(). */
typedef struct
{
  const char *target_path;
  const char *path;
  svn_revnum_t rev;
  apr_pool_t *pool;
} copyfrom_info_t;

/* A log callback conforming to the svn_log_message_receiver_t
   interface for obtaining the copy source of a node at a path and
   storing it in *BATON (a struct copyfrom_info_t *).
   Implements svn_log_entry_receiver_t. */
static svn_error_t *
copyfrom_info_receiver(void *baton,
                       svn_log_entry_t *log_entry,
                       apr_pool_t *pool)
{
  copyfrom_info_t *copyfrom_info = baton;
  if (copyfrom_info->path)
    /* The copy source has already been found. */
    return SVN_NO_ERROR;

  if (log_entry->changed_paths)
    {
      int i;
      const char *path;
      svn_log_changed_path_t *changed_path;
      /* Sort paths into depth-first order. */
      apr_array_header_t *sorted_changed_paths =
        svn_sort__hash(log_entry->changed_paths,
                       svn_sort_compare_items_as_paths, pool);

      for (i = (sorted_changed_paths->nelts -1) ; i >= 0 ; i--)
        {
          svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_changed_paths, i,
                                                  svn_sort__item_t);
          path = item->key;
          changed_path = item->value;

          /* Consider only the path we're interested in. */
          if (changed_path->copyfrom_path &&
              SVN_IS_VALID_REVNUM(changed_path->copyfrom_rev) &&
              svn_path_is_ancestor(path, copyfrom_info->target_path))
            {
              /* Copy source found!  Determine path and note revision. */
              if (strcmp(path, copyfrom_info->target_path) == 0)
                {
                  /* We have the details for a direct copy to
                     copyfrom_info->target_path. */
                  copyfrom_info->path =
                    apr_pstrdup(copyfrom_info->pool,
                                changed_path->copyfrom_path);
                }
              else
                {
                  /* We have a parent of copyfrom_info->target_path. */
                  copyfrom_info->path =
                    apr_pstrcat(copyfrom_info->pool,
                                changed_path->copyfrom_path,
                                copyfrom_info->target_path +
                                strlen(path), NULL);
                }
              copyfrom_info->rev = changed_path->copyfrom_rev;
              break;
            }
        }
    }
  return SVN_NO_ERROR;
}

svn_error_t *
svn_client__get_copy_source(const char *path_or_url,
                            const svn_opt_revision_t *revision,
                            const char **copyfrom_path,
                            svn_revnum_t *copyfrom_rev,
                            svn_client_ctx_t *ctx,
                            apr_pool_t *pool)
{
  svn_error_t *err;
  copyfrom_info_t copyfrom_info = { NULL, NULL, SVN_INVALID_REVNUM, pool };
  apr_array_header_t *targets = apr_array_make(pool, 1, sizeof(path_or_url));
  svn_opt_revision_t oldest_rev;
  apr_pool_t *sesspool = svn_pool_create(pool);
  svn_ra_session_t *ra_session;
  svn_revnum_t at_rev;
  const char *at_url;

  oldest_rev.kind = svn_opt_revision_number;
  oldest_rev.value.number = 1;

  SVN_ERR(svn_client__ra_session_from_path(&ra_session, &at_rev, &at_url,
                                           path_or_url, NULL,
                                           revision, revision,
                                           ctx, sesspool));
  SVN_ERR(svn_client__path_relative_to_root(&copyfrom_info.target_path,
                                            path_or_url, NULL, TRUE,
                                            ra_session, NULL, pool));
  APR_ARRAY_PUSH(targets, const char *) = path_or_url;

  /* Find the copy source.  Trace back in history to find the revision
     at which this node was created (copied or added). 

     ### Reuse ra_session by way of svn_ra_get_log()?
     err = svn_ra_get_log(ra_session, rel_paths, revision, 1, 0, TRUE, TRUE,
                          copyfrom_info_receiver, &copyfrom_info, pool);
  */
  err = svn_client_log4(targets, revision, revision, &oldest_rev, 0,
                        TRUE, TRUE, FALSE, apr_array_make(pool, 0,
                                                          sizeof(const char *)),
                        copyfrom_info_receiver, &copyfrom_info, ctx, pool);

  svn_pool_destroy(sesspool);

  if (err)
{'fraction_non_alphanumeric': 0.11049011177987962, 'fraction_numerical': 0.0033677271424476926, 'mean_word_length': 2.1167932112550245, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5192457', 'n_tokens_mistral': 4386, 'n_tokens_neox': 4253, 'n_words': 995}