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