diff.c

来自「subversion-1.4.3-1.tar.gz 配置svn的源码」· C语言 代码 · 共 1,827 行 · 第 1/4 页

C
1,827
字号
/* * diff.c -- The diff editor for comparing the working copy against the *           repository. * * ==================================================================== * Copyright (c) 2000-2006 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/. * ==================================================================== *//* * This code uses an svn_delta_editor_t editor driven by * svn_wc_crawl_revisions (like the update command) to retrieve the * differences between the working copy and the requested repository * version. Rather than updating the working copy, this new editor creates * temporary files that contain the pristine repository versions. When the * crawler closes the files the editor calls back to a client layer * function to compare the working copy and the temporary file. There is * only ever one temporary file in existence at any time. * * When the crawler closes a directory, the editor then calls back to the * client layer to compare any remaining files that may have been modified * locally. Added directories do not have corresponding temporary * directories created, as they are not needed. * * ### TODO: Replacements where the node kind changes needs support. It * mostly works when the change is in the repository, but not when it is * in the working copy. * * ### TODO: Do we need to support copyfrom? * */#include <assert.h>#include <apr_hash.h>#include "svn_pools.h"#include "svn_path.h"#include "wc.h"#include "props.h"#include "adm_files.h"#include "svn_private_config.h"/*-------------------------------------------------------------------------*//* A little helper function.   You see, when we ask the server to update us to a certain revision,   we construct the new fulltext, and then run          'diff <repos_fulltext> <working_fulltext>'   which is, of course, actually backwards from the repository's point   of view.  It thinks we want to move from working->repos.   So when the server sends property changes, they're effectively   backwards from what we want.  We don't want working->repos, but   repos->working.  So this little helper "reverses" the value in   BASEPROPS and PROPCHANGES before we pass them off to the   prop_changed() diff-callback.  */static voidreverse_propchanges(apr_hash_t *baseprops,                    apr_array_header_t *propchanges,                    apr_pool_t *pool){  int i;  /* ### todo: research lifetimes for property values below */  for (i = 0; i < propchanges->nelts; i++)    {      svn_prop_t *propchange        = &APR_ARRAY_IDX(propchanges, i, svn_prop_t);            const svn_string_t *original_value =        apr_hash_get(baseprops, propchange->name, APR_HASH_KEY_STRING);           if ((original_value == NULL) && (propchange->value != NULL))         {          /* found an addition.  make it look like a deletion. */          apr_hash_set(baseprops, propchange->name, APR_HASH_KEY_STRING,                       svn_string_dup(propchange->value, pool));          propchange->value = NULL;        }      else if ((original_value != NULL) && (propchange->value == NULL))         {          /* found a deletion.  make it look like an addition. */          propchange->value = svn_string_dup(original_value, pool);          apr_hash_set(baseprops, propchange->name, APR_HASH_KEY_STRING,                       NULL);        }      else if ((original_value != NULL) && (propchange->value != NULL))         {          /* found a change.  just swap the values.  */          const svn_string_t *str = svn_string_dup(propchange->value, pool);          propchange->value = svn_string_dup(original_value, pool);          apr_hash_set(baseprops, propchange->name, APR_HASH_KEY_STRING, str);        }    }}/*-------------------------------------------------------------------------*//* Overall crawler editor baton. */struct edit_baton {  /* ANCHOR/TARGET represent the base of the hierarchy to be compared. */  svn_wc_adm_access_t *anchor;  const char *anchor_path;  const char *target;  /* Target revision */  svn_revnum_t revnum;  /* Was the root opened? */  svn_boolean_t root_opened;  /* The callbacks and callback argument that implement the file comparison     functions */  const svn_wc_diff_callbacks2_t *callbacks;  void *callback_baton;  /* Flags whether to diff recursively or not. If set the diff is     recursive. */  svn_boolean_t recurse;  /* Should this diff ignore node ancestry. */  svn_boolean_t ignore_ancestry;  /* Possibly diff repos against text-bases instead of working files. */  svn_boolean_t use_text_base;  /* Possibly show the diffs backwards. */  svn_boolean_t reverse_order;  /* Empty file used to diff adds / deletes */  const char *empty_file;  apr_pool_t *pool;};/* Directory level baton. */struct dir_baton {  /* Gets set if the directory is added rather than replaced/unchanged. */  svn_boolean_t added;  /* The "correct" path of the directory, but it may not exist in the     working copy. */  const char *path;  /* Identifies those directory elements that get compared while running     the crawler.  These elements should not be compared again when     recursively looking for local modifications.     This hash maps the full path of the entry to an unimportant value     (presence in the hash is the important factor here, not the value     itself).     If the directory's properties have been compared, an item with hash     key of "" (an empty string) will be present in the hash. */  apr_hash_t *compared;  /* The baton for the parent directory, or null if this is the root of the     hierarchy to be compared. */  struct dir_baton *dir_baton;  /* The list of incoming BASE->repos propchanges. */  apr_array_header_t *propchanges;  /* The overall crawler editor baton. */  struct edit_baton *edit_baton;  apr_pool_t *pool;};/* File level baton. */struct file_baton {  /* Gets set if the file is added rather than replaced. */  svn_boolean_t added;  /* PATH is the "correct" path of the file, but it may not exist in the     working copy.  WC_PATH is a path we can use to make temporary files     or open empty files; it doesn't necessarily exist either, but the     directory part of it does. */  const char *path;  const char *wc_path; /* When constructing the requested repository version of the file,    ORIGINAL_FILE is version of the file in the working copy. TEMP_FILE is    the pristine repository file obtained by applying the repository diffs    to ORIGINAL_FILE. */  apr_file_t *original_file;  apr_file_t *temp_file;  const char *temp_file_path;  /* The list of incoming BASE->repos propchanges. */  apr_array_header_t *propchanges;  /* APPLY_HANDLER/APPLY_BATON represent the delta applcation baton. */  svn_txdelta_window_handler_t apply_handler;  void *apply_baton;  /* The overall crawler editor baton. */  struct edit_baton *edit_baton;  apr_pool_t *pool;};/* Used to wrap svn_wc_diff_callbacks_t. */struct callbacks_wrapper_baton {  const svn_wc_diff_callbacks_t *callbacks;  void *baton;};/* Create a new edit baton. TARGET/ANCHOR are working copy paths that * describe the root of the comparison. CALLBACKS/CALLBACK_BATON * define the callbacks to compare files. RECURSE defines whether to * descend into subdirectories.  IGNORE_ANCESTRY defines whether to * utilize node ancestry when calculating diffs.  USE_TEXT_BASE * defines whether to compare against working files or text-bases. * REVERSE_ORDER defines which direction to perform the diff. */static struct edit_baton *make_editor_baton(svn_wc_adm_access_t *anchor,                  const char *target,                  const svn_wc_diff_callbacks2_t *callbacks,                  void *callback_baton,                  svn_boolean_t recurse,                  svn_boolean_t ignore_ancestry,                  svn_boolean_t use_text_base,                  svn_boolean_t reverse_order,                  apr_pool_t *pool){  struct edit_baton *eb = apr_pcalloc(pool, sizeof(*eb));  eb->anchor = anchor;  eb->anchor_path = svn_wc_adm_access_path(anchor);  eb->target = apr_pstrdup(pool, target);  eb->callbacks = callbacks;  eb->callback_baton = callback_baton;  eb->recurse = recurse;  eb->ignore_ancestry = ignore_ancestry;  eb->use_text_base = use_text_base;  eb->reverse_order = reverse_order;  eb->pool = pool;  return eb;}/* Create a new directory baton.  PATH is the directory path, * including anchor_path.  ADDED is set if this directory is being * added rather than replaced.  PARENT_BATON is the baton of the * parent directory, it will be null if this is the root of the * comparison hierarchy.  The directory and its parent may or may not * exist in the working copy.  EDIT_BATON is the overall crawler * editor baton. */static struct dir_baton *make_dir_baton(const char *path,               struct dir_baton *parent_baton,               struct edit_baton *edit_baton,               svn_boolean_t added,               apr_pool_t *pool){  struct dir_baton *dir_baton = apr_pcalloc(pool, sizeof(*dir_baton));  dir_baton->dir_baton = parent_baton;  dir_baton->edit_baton = edit_baton;  dir_baton->added = added;  dir_baton->pool = pool;  dir_baton->propchanges = apr_array_make(pool, 1, sizeof(svn_prop_t));  dir_baton->compared = apr_hash_make(dir_baton->pool);  dir_baton->path = path;  return dir_baton;}/* Create a new file baton.  PATH is the file path, including * anchor_path.  ADDED is set if this file is being added rather than * replaced.  PARENT_BATON is the baton of the parent directory.  The * directory and its parent may or may not exist in the working copy. */static struct file_baton *make_file_baton(const char *path,                svn_boolean_t added,                struct dir_baton *parent_baton,                apr_pool_t *pool){  struct file_baton *file_baton = apr_pcalloc(pool, sizeof(*file_baton));  struct edit_baton *edit_baton = parent_baton->edit_baton;  file_baton->edit_baton = edit_baton;  file_baton->added = added;  file_baton->pool = pool;  file_baton->propchanges  = apr_array_make(pool, 1, sizeof(svn_prop_t));  file_baton->path = path;  /* If the parent directory is added rather than replaced it does not     exist in the working copy.  Determine a working copy path whose     directory part does exist; we can use that to create temporary     files.  It doesn't matter whether the file part exists in the     directory. */  if (parent_baton->added)    {      struct dir_baton *wc_dir_baton = parent_baton;      /* Ascend until a directory is not being added, this will be a         directory that does exist. This must terminate since the root of         the comparison cannot be added. */      while (wc_dir_baton->added)        wc_dir_baton = wc_dir_baton->dir_baton;      file_baton->wc_path = svn_path_join(wc_dir_baton->path, "unimportant",                                          file_baton->pool);    }  else    {      file_baton->wc_path = file_baton->path;    }  return file_baton;}/* Get the empty file associated with the edit baton. This is cached so * that it can be reused, all empty files are the same. */static svn_error_t *get_empty_file(struct edit_baton *b,               const char **empty_file){  /* Create the file if it does not exist */  /* Note that we tried to use /dev/null in r17220, but     that won't work on Windows: it's impossible to stat NUL */  if (!b->empty_file)    {      const char *temp_dir;      SVN_ERR(svn_io_temp_dir(&temp_dir, b->pool));      SVN_ERR(svn_io_open_unique_file2              (NULL, &(b->empty_file),               svn_path_join(temp_dir, "tmp", b->pool),               "", svn_io_file_del_on_pool_cleanup,               b->pool));    }  *empty_file = b->empty_file;  return SVN_NO_ERROR;}/* Return the value of the svn:mime-type property held in PROPS, or NULL   if no such property exists. */static const char *get_prop_mimetype(apr_hash_t *props){  const svn_string_t *mimetype_val;  mimetype_val = apr_hash_get(props,                              SVN_PROP_MIME_TYPE,                              strlen(SVN_PROP_MIME_TYPE));  return (mimetype_val) ? mimetype_val->data : NULL;}/* Set *MIMETYPE to the BASE version of the svn:mime-type property of   file PATH, using ADM_ACCESS, or to NULL if no such property exists.   BASEPROPS is optional: if present, use it to cache the BASE properties   of the file.   Return the property value and property hash allocated in POOL.*/static svn_error_t *get_base_mimetype(const char **mimetype,                  apr_hash_t **baseprops,                  svn_wc_adm_access_t *adm_access,                  const char *path,                  apr_pool_t *pool){  apr_hash_t *props = NULL;  if (baseprops == NULL)    baseprops = &props;  if (*baseprops == NULL)    SVN_ERR(svn_wc_get_prop_diffs(NULL, baseprops, path, adm_access, pool));  *mimetype = get_prop_mimetype(*baseprops);  return SVN_NO_ERROR;}/* Set *MIMETYPE to the WORKING version of the svn:mime-type property   of file PATH, using ADM_ACCESS, or to NULL if no such property exists.   WORKINGPROPS is optional: if present, use it to cache the WORKING   properties of the file.   Return the property value and property hash allocated in POOL.*/static svn_error_t *get_working_mimetype(const char **mimetype,                     apr_hash_t **workingprops,                     svn_wc_adm_access_t *adm_access,                     const char *path,                     apr_pool_t *pool){  apr_hash_t *props = NULL;  if (workingprops == NULL)    workingprops = &props;  if (*workingprops == NULL)    SVN_ERR(svn_wc_prop_list(workingprops, path, adm_access, pool));  *mimetype = get_prop_mimetype(*workingprops);  return SVN_NO_ERROR;}/* Called by directory_elements_diff when a file is to be compared. At this * stage we are dealing with a file that does exist in the working copy. * * DIR_BATON is the parent directory baton, PATH is the path to the file to * be compared. ENTRY is the working copy entry for the file. * * Do all allocation in POOL. * * ### TODO: Need to work on replace if the new filename used to be a * directory. */static svn_error_t *file_diff(struct dir_baton *dir_baton,          const char *path,          const svn_wc_entry_t *entry,          apr_pool_t *pool){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?