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;
}