[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH]: Change sort order for 'svn diff'

From: Kean Johnston <jkj_at_sco.com>
Date: 2005-11-19 22:27:52 CET

All,

Attached is my first patch for Subversion, so go easy with the
flames :) This is to change the order in which files are shown
by and 'svn diff', such that all files in a directory are shown
first, alphabetically, then all directories, also alphabetically.

I put the function svn_repos_sort_by_type_and_path() in
libsvn_repos, since that is the only consumer of the function.
However, it sorts entries of type svn_fs_dirent_t, so perhaps
a better location would have been libsvn_fs. I am not sure this
is a generically useful function outside of libsvn_repos which
is why it is where it currently is. I originally had the function
as a static inside both delta.c and reporter.c, but thats a bit
wasteful so I make it a visible function.

A similar function was needed in libsvn_wc, but there there is
only a single consumer of it, so I made it static instead of
adding a new API. That version differs from the one in libsvn_repos
only in the data types it sorts on (svn_wc_entry_t).

Please feel free to whack me upside the head with a big SVN
cluestick if this patch is not up to par.

Kean

[[[
Patch by: Kean Johnston <jkj@sco.com>

* subversion/libsvn_repos/delta.c,
  subversion/libsvn_repos/reporter.c:
  (delta_dirs): Sort the hash before processing it, so that diffs arrive
  files first, alphabetically, then directories, alphabetically. Sort using
  the new svn_repos_sort_by_type_and_path() function.

* subversion/libsvn_repos/repos.h:
  Include svn_sorts.h for declaration of svn_sort__item_t, and
  svn_sort__hash().
  (svn_repos_sort_by_type_and_path): Declare new function used for sorting
  diffs so they arrive in a more sensible order.

* subversion/libsvn_repos/repos.c:
  (svn_repos_sort_by_type_and_path): New function to sort an svn_fs_dirent_t
  hash first by type (svn_node_file before svn_node_dir) and then by name,
  using svn_path_compare_paths().

* subversion/libsvn_wc/diff.c:
  Added include of svn_sorts.h for svn_sort__hash.
  (sort_by_type_and_path): New local function for sorting the entries list
  first by file type (svn_node_file before svn_node_dir), and then by the
  standard order imposed by svn_path_compare_paths().
  (directory_elements_diff): Sort the hash before processing it, so that
  diffs arrive files first, alphabetically, then directories, alphabetically.

]]]

Index: subversion/libsvn_repos/delta.c
===================================================================
--- subversion/libsvn_repos/delta.c (revision 17442)
+++ subversion/libsvn_repos/delta.c (working copy)
@@ -928,6 +928,8 @@
   apr_hash_t *s_entries = 0, *t_entries = 0;
   apr_hash_index_t *hi;
   apr_pool_t *subpool;
+ apr_array_header_t *sorted;
+ int i;
 
   assert (target_path);
 
@@ -955,8 +957,14 @@
      still remaining the source entries hash represent entries that no
      longer exist in target. Use editor calls to delete those entries
      from the target tree. */
- for (hi = apr_hash_first (pool, t_entries); hi; hi = apr_hash_next (hi))
+
+ sorted = svn_sort__hash (t_entries, svn_repos_sort_by_type_and_path, pool);
+
+ /* Loop over the dirents in the target. */
+ for (i = 0; i < sorted->nelts; ++i)
     {
+ const svn_sort__item_t *item = &APR_ARRAY_IDX(sorted, i,
+ const svn_sort__item_t);
       const svn_fs_dirent_t *s_entry, *t_entry;
       const void *key;
       void *val;
@@ -970,8 +978,11 @@
       svn_pool_clear (subpool);
 
       /* KEY is the entry name in target, VAL the dirent */
- apr_hash_this (hi, &key, &klen, &val);
- t_entry = val;
+ val = item->value;
+ t_entry = item->value;
+ key = item->key;
+ klen = item->klen;
+
       tgt_kind = t_entry->kind;
       t_fullpath = svn_path_join (target_path, t_entry->name, subpool);
       e_fullpath = svn_path_join (edit_path, t_entry->name, subpool);
Index: subversion/libsvn_repos/reporter.c
===================================================================
--- subversion/libsvn_repos/reporter.c (revision 17442)
+++ subversion/libsvn_repos/reporter.c (working copy)
@@ -693,6 +693,8 @@
   void *val;
   const char *name, *s_fullpath, *t_fullpath, *e_fullpath;
   path_info_t *info;
+ apr_array_header_t *sorted;
+ int i;
 
   /* Compare the property lists. If we're starting empty, pass a NULL
      source path so that we add all the properties.
@@ -776,12 +778,16 @@
         }
     }
 
+ sorted = svn_sort__hash (t_entries, svn_repos_sort_by_type_and_path, pool);
+
   /* Loop over the dirents in the target. */
- for (hi = apr_hash_first (pool, t_entries); hi; hi = apr_hash_next (hi))
+ for (i = 0; i < sorted->nelts; ++i)
     {
+ const svn_sort__item_t *item = &APR_ARRAY_IDX(sorted, i,
+ const svn_sort__item_t);
+
+ t_entry = item->value;
       svn_pool_clear (subpool);
- apr_hash_this (hi, NULL, NULL, &val);
- t_entry = val;
 
       /* Compose the report, editor, and target paths for this entry. */
       e_fullpath = svn_path_join (e_path, t_entry->name, subpool);
Index: subversion/libsvn_repos/repos.c
===================================================================
--- subversion/libsvn_repos/repos.c (revision 17442)
+++ subversion/libsvn_repos/repos.c (working copy)
@@ -2146,3 +2146,24 @@
   *dirent = ent;
   return SVN_NO_ERROR;
 }
+
+
+int
+svn_repos_sort_by_type_and_path (const svn_sort__item_t *item1,
+ const svn_sort__item_t *item2)
+{
+ const svn_fs_dirent_t *entry1;
+ const svn_fs_dirent_t *entry2;
+ const char *astr, *bstr;
+
+ astr = item1->key;
+ bstr = item2->key;
+ entry1 = item1->value;
+ entry2 = item2->value;
+
+ if ((entry1->kind == svn_node_file) && (entry2->kind == svn_node_dir))
+ return -1;
+ else if ((entry2->kind == svn_node_file) && (entry1->kind == svn_node_dir))
+ return 1;
+ return svn_path_compare_paths (astr, bstr);
+}
Index: subversion/libsvn_repos/repos.h
===================================================================
--- subversion/libsvn_repos/repos.h (revision 17442)
+++ subversion/libsvn_repos/repos.h (working copy)
@@ -22,6 +22,7 @@
 #include <apr_hash.h>
 
 #include "svn_fs.h"
+#include "svn_sorts.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -240,6 +241,14 @@
                           apr_pool_t *pool);
 
 
+/* Sort an svn_fs_direct_t hash first by file type (such that nodes of type
+ svn_node_file appear before svn_node_dir nodes), and then alphabetically
+ as defined by svn_path_compare_paths.
+
+ This function is intended as a callback for svn_sort__hash(). */
+int
+svn_repos_sort_by_type_and_path (const svn_sort__item_t *item1,
+ const svn_sort__item_t *item2);
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
Index: subversion/libsvn_wc/diff.c
===================================================================
--- subversion/libsvn_wc/diff.c (revision 17442)
+++ subversion/libsvn_wc/diff.c (working copy)
@@ -50,6 +50,7 @@
 
 #include "svn_pools.h"
 #include "svn_path.h"
+#include "svn_sorts.h"
 
 #include "wc.h"
 #include "props.h"
@@ -621,6 +622,38 @@
   return SVN_NO_ERROR;
 }
 
+
+/*
+ * This function is called to sort the directory entries. The idea is to
+ * have all of the files diffed first, in alphabetical order, then all
+ * of the directories, in alphabetical order. So this modified version of
+ * svn_sort_compare_items_as_paths will check the entry type, and always
+ * return -1 if a file and a directory are being compared, a normal return
+ * or -1, 0 or 1 if the entry types match.
+ */
+static int
+sort_by_type_and_path (const svn_sort__item_t *a,
+ const svn_sort__item_t *b)
+{
+ const svn_wc_entry_t *entry1;
+ const svn_wc_entry_t *entry2;
+ const char *astr, *bstr;
+
+ astr = a->key;
+ bstr = b->key;
+ entry1 = a->value;
+ entry2 = b->value;
+ assert(astr[a->klen] == '\0');
+ assert(bstr[b->klen] == '\0');
+
+ if ((entry1->kind == svn_node_file) && (entry2->kind == svn_node_dir))
+ return -1;
+ else if ((entry2->kind == svn_node_file) && (entry1->kind == svn_node_dir))
+ return 1;
+ return svn_path_compare_paths (astr, bstr);
+}
+
+
 /* Called when the directory is closed to compare any elements that have
  * not yet been compared. This identifies local, working copy only
  * changes. At this stage we are dealing with files/directories that do
@@ -634,10 +667,11 @@
                          svn_boolean_t added)
 {
   apr_hash_t *entries;
- apr_hash_index_t *hi;
   svn_boolean_t in_anchor_not_target;
   apr_pool_t *subpool;
   svn_wc_adm_access_t *adm_access;
+ apr_array_header_t *sorted;
+ int i;
 
   /* This directory should have been unchanged or replaced, not added,
      since an added directory can only contain added files and these will
@@ -691,9 +725,12 @@
 
   subpool = svn_pool_create (dir_baton->pool);
 
- for (hi = apr_hash_first (dir_baton->pool, entries); hi;
- hi = apr_hash_next (hi))
+ sorted = svn_sort__hash (entries, sort_by_type_and_path, dir_baton->pool);
+
+ for (i = 0; i < sorted->nelts; ++i)
     {
+ const svn_sort__item_t *item = &APR_ARRAY_IDX(sorted, i,
+ const svn_sort__item_t);
       const void *key;
       void *val;
       const svn_wc_entry_t *entry;
@@ -702,9 +739,9 @@
 
       svn_pool_clear (subpool);
 
- apr_hash_this (hi, &key, NULL, &val);
- name = key;
- entry = val;
+ name = item->key;
+ key = item->key;
+ entry = item->value;
       
       /* Skip entry for the directory itself. */
       if (strcmp (key, SVN_WC_ENTRY_THIS_DIR) == 0)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sat Nov 19 22:28:40 2005

This is an archived mail posted to the Subversion Dev mailing list.