Hi,

Please see attached patch. Comments most welcome, specially if there
is a better/less intrusive way of implementing <subject>.

Please CC me as I'm not subscribed to the list.

// Erik

[[[
Support printing changed properties in svnlook by passing the "-v" parameter to
the "svnlook changed" command. The changed properties are printed one property
per line with the format: <status> <path>;<prop name>

To support this, the editor created by svn_repos_node_editor has been modified
to record changes to properties (requires the replay to be done with deltas).

* subversion/include/svn_repos.h
  (svn_repos_node_prop_t): New struct to represent a change to a property.
  (svn_repos_node_t): Add pointer to list of changed properties.

* subversion/libsvn_repos/node_tree.c
  (change_node_prop): Add changed properties to the node structure.

* subversion/svnlook/main.c
  (cmd_table subcommand_changed do_changed): New "verbose" option to indicate
   if changed properties should be printed or not.
  (generate_delta_tree): New parameter to make the replay with or without
   deltas.
  (do_dirs_changed do_diff): Add new parameter to generate_delta_tree call.
  (print_changed_tree): Support printing changed properties.
]]]

-- 
Erik Johansson
Home Page: http://ejohansson.se/
PGP Key: http://ejohansson.se/erik.asc
Index: subversion/include/svn_repos.h
===================================================================
--- subversion/include/svn_repos.h	(revision 1043363)
+++ subversion/include/svn_repos.h	(working copy)
@@ -2239,6 +2239,20 @@
  * result of having svn_repos_dir_delta2() drive that editor.
  */
 
+/** A property on a node */
+typedef struct svn_repos_node_prop_t
+{
+  /** How this property entered the node tree: 'A'dd, 'D'elete, 'R'eplace */
+  char action;
+
+  /** The name of the property */
+  const char *name;
+
+  /** Pointer to the next sibling property */
+  struct svn_repos_node_prop_t *sibling;
+
+} svn_repos_node_prop_t;
+
 /** A node in the repository. */
 typedef struct svn_repos_node_t
 {
@@ -2272,6 +2286,9 @@
   /** Pointer to the parent of this node */
   struct svn_repos_node_t *parent;
 
+  /** Pointer to the first modified property */
+  svn_repos_node_prop_t *mod_prop;
+
 } svn_repos_node_t;
 
 
Index: subversion/svnlook/main.c
===================================================================
--- subversion/svnlook/main.c	(revision 1043363)
+++ subversion/svnlook/main.c	(working copy)
@@ -197,8 +197,9 @@
 
   {"changed", subcommand_changed, {0},
    N_("usage: svnlook changed REPOS_PATH\n\n"
-      "Print the paths that were changed.\n"),
-   {'r', 't', svnlook__copy_info} },
+      "Print the paths that were changed.  With -v, also print the names of\n"
+      "changed properties.\n"),
+   {'r', 't', 'v', svnlook__copy_info} },
 
   {"date", subcommand_date, {0},
    N_("usage: svnlook date REPOS_PATH\n\n"
@@ -435,6 +436,7 @@
                     svn_repos_t *repos,
                     svn_fs_root_t *root,
                     svn_revnum_t base_rev,
+                    svn_boolean_t verbose,
                     svn_boolean_t use_copy_history,
                     apr_pool_t *pool)
 {
@@ -452,7 +454,7 @@
                                 base_root, root, pool, edit_pool));
 
   /* Drive our editor. */
-  SVN_ERR(svn_repos_replay2(root, "", SVN_INVALID_REVNUM, FALSE,
+  SVN_ERR(svn_repos_replay2(root, "", SVN_INVALID_REVNUM, verbose,
                             editor, edit_baton, NULL, NULL, edit_pool));
 
   /* Return the tree we just built. */
@@ -550,12 +552,14 @@
 static svn_error_t *
 print_changed_tree(svn_repos_node_t *node,
                    const char *path /* UTF-8! */,
+                   svn_boolean_t verbose,
                    svn_boolean_t copy_info,
                    apr_pool_t *pool)
 {
   const char *full_path;
   char status[4] = "_  ";
   int print_me = 1;
+  svn_repos_node_prop_t *prop;
   apr_pool_t *subpool;
 
   SVN_ERR(check_cancel(NULL));
@@ -600,6 +604,29 @@
                                     : node->copyfrom_path),
                                    (node->kind == svn_node_dir ? "/" : ""),
                                    node->copyfrom_rev));
+
+      if (verbose)
+        {
+          status[0] = '_';
+          status[2] = ' ';
+          for (prop = node->mod_prop; prop != NULL; prop = prop->sibling)
+          {
+            if (prop->action == 'D')
+              status[1] = 'D';
+            else if (prop->action == 'A')
+              status[1] = 'A';
+            else if (prop->action == 'R')
+              status[1] = 'U';
+            else
+              continue;
+
+            SVN_ERR(svn_cmdline_printf(pool, "%s %s%s;%s\n",
+                                       status,
+                                       path,
+                                       node->kind == svn_node_dir ? "/" : "",
+                                       prop->name));
+          }
+        }
     }
 
   /* Return here if the node has no children. */
@@ -610,13 +637,13 @@
   /* Recursively handle the node's children. */
   subpool = svn_pool_create(pool);
   full_path = svn_dirent_join(path, node->name, subpool);
-  SVN_ERR(print_changed_tree(node, full_path, copy_info, subpool));
+  SVN_ERR(print_changed_tree(node, full_path, verbose, copy_info, subpool));
   while (node->sibling)
     {
       svn_pool_clear(subpool);
       node = node->sibling;
       full_path = svn_dirent_join(path, node->name, subpool);
-      SVN_ERR(print_changed_tree(node, full_path, copy_info, subpool));
+      SVN_ERR(print_changed_tree(node, full_path, verbose, copy_info, subpool));
     }
   svn_pool_destroy(subpool);
 
@@ -1375,7 +1402,7 @@
        c->txn_name);
 
   SVN_ERR(generate_delta_tree(&tree, c->repos, root, base_rev_id,
-                              TRUE, pool));
+                              FALSE, TRUE, pool));
   if (tree)
     SVN_ERR(print_dirs_changed_tree(tree, "", pool));
 
@@ -1462,7 +1489,7 @@
 /* Print a list of all paths modified in a format compatible with `svn
    update'. */
 static svn_error_t *
-do_changed(svnlook_ctxt_t *c, apr_pool_t *pool)
+do_changed(svnlook_ctxt_t *c, svn_boolean_t verbose, apr_pool_t *pool)
 {
   svn_fs_root_t *root;
   svn_revnum_t base_rev_id;
@@ -1481,9 +1508,9 @@
        c->txn_name);
 
   SVN_ERR(generate_delta_tree(&tree, c->repos, root, base_rev_id,
-                              TRUE, pool));
+                              verbose, TRUE, pool));
   if (tree)
-    SVN_ERR(print_changed_tree(tree, "", c->copy_info, pool));
+    SVN_ERR(print_changed_tree(tree, "", verbose, c->copy_info, pool));
 
   return SVN_NO_ERROR;
 }
@@ -1510,7 +1537,7 @@
        c->txn_name);
 
   SVN_ERR(generate_delta_tree(&tree, c->repos, root, base_rev_id,
-                              TRUE, pool));
+                              FALSE, TRUE, pool));
   if (tree)
     {
       const char *tmpdir;
@@ -1917,7 +1944,7 @@
   svnlook_ctxt_t *c;
 
   SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
-  SVN_ERR(do_changed(c, pool));
+  SVN_ERR(do_changed(c, opt_state->verbose, pool));
   return SVN_NO_ERROR;
 }
 
Index: subversion/libsvn_repos/node_tree.c
===================================================================
--- subversion/libsvn_repos/node_tree.c	(revision 1043363)
+++ subversion/libsvn_repos/node_tree.c	(working copy)
@@ -378,7 +378,48 @@
                  apr_pool_t *pool)
 {
   struct node_baton *nb = node_baton;
+  struct edit_baton *eb = nb->edit_baton;
+  svn_repos_node_prop_t *prop;
+  const char *base_path;
+  svn_revnum_t base_rev;
+  svn_fs_root_t *base_root;
+  svn_string_t *old_value;
+
   nb->node->prop_mod = TRUE;
+
+  /* Ignore dummy prop change callbacks (empty name) that happen if the replay
+     is done without deltas. */
+  if (name[0] != '\0')
+    {
+      prop = apr_pcalloc(eb->node_pool, sizeof(*prop));
+      prop->name = apr_pstrdup(eb->node_pool, name);
+
+      if (value == NULL)
+        prop->action = 'D';
+      else
+        {
+          /* Get the original filesystem path and base root for the current
+             node so that we can fetch the old property value. */
+          find_real_base_location(&base_path, &base_rev, nb->node, pool);
+          if (! SVN_IS_VALID_REVNUM(base_rev))
+            base_root = eb->base_root;
+          else
+            SVN_ERR(svn_fs_revision_root(&base_root, eb->fs, base_rev, pool));
+
+          /* Fetch old property value */
+          SVN_ERR(svn_fs_node_prop(&old_value, base_root, base_path,
+                                   name, pool));
+          if (old_value == NULL)
+            prop->action = 'A';
+          else
+            prop->action = 'R';
+        }
+
+      /* Insert first in list */
+      prop->sibling = nb->node->mod_prop;
+      nb->node->mod_prop = prop;
+    }
+
   return SVN_NO_ERROR;
 }
 

Reply via email to