Author: pburba Date: Mon Mar 26 22:29:55 2012 New Revision: 1305641 URL: http://svn.apache.org/viewvc?rev=1305641&view=rev Log: On the inheritable-props branch: Implement getting inherited props over ra_svn.
* subversion/libsvn_client/prop_commands.c (remote_proplist): Raise an error if we insist on asking a server for inherited props if that server isn't advertising the SVN_RA_CAPABILITY_INHERITED_PROPS capability. * subversion/libsvn_ra_svn/client.c (parse_iproplist): New. (ra_svn_get_file, ra_svn_get_dir): Implement the client-side stuffs for getting inherited props over ra_svn. * subversion/libsvn_ra_svn/protocol (get-file, get-dir): Document the new protocol options. * subversion/svnserve/serve.c (get_props): Support getting inherited props via svn_fs_node_proplist2. (get_file, get_dir): Implement the server-side stuffs for getting inherited props over ra_svn. Modified: subversion/branches/inheritable-props/subversion/libsvn_ra_svn/client.c subversion/branches/inheritable-props/subversion/libsvn_ra_svn/protocol subversion/branches/inheritable-props/subversion/svnserve/serve.c Modified: subversion/branches/inheritable-props/subversion/libsvn_ra_svn/client.c URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_ra_svn/client.c?rev=1305641&r1=1305640&r2=1305641&view=diff ============================================================================== --- subversion/branches/inheritable-props/subversion/libsvn_ra_svn/client.c (original) +++ subversion/branches/inheritable-props/subversion/libsvn_ra_svn/client.c Mon Mar 26 22:29:55 2012 @@ -1009,6 +1009,82 @@ static svn_error_t *ra_svn_commit(svn_ra return SVN_NO_ERROR; } +/* Parse IPROPLIST, an array of svn_ra_svn_item_t structures, as a list of + const char * repos relative paths and properties for those paths, storing + the result as an array of svn_prop_inherited_item_t *items. */ +static svn_error_t * +parse_iproplist(apr_array_header_t **inherited_props, + const apr_array_header_t *iproplist, + svn_ra_session_t *session, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) + +{ + int i; + const char *repos_root_url; + apr_pool_t *iterpool; + + if (iproplist == NULL) + { + /* If the server doesn't have the SVN_RA_CAPABILITY_INHERITED_PROPS + capability we shouldn't be asking for inherited props, but if we + did and the server sent back nothing then we'll want to handle + that. */ + *inherited_props = NULL; + return SVN_NO_ERROR; + } + + SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url, scratch_pool)); + + *inherited_props = apr_array_make( + result_pool, iproplist->nelts, sizeof(svn_prop_inherited_item_t *)); + + iterpool = svn_pool_create(scratch_pool); + + /* Iterate backwards over the array to preserve the depth-first ordering + of the parent paths as we create *INHERITED_PROPS. */ + for (i = iproplist->nelts - 1; i >= 0; i--) + { + apr_array_header_t *iprop_list; + char *parent_rel_path; + apr_hash_t *iprops; + apr_hash_index_t *hi; + svn_prop_inherited_item_t *new_iprop = + apr_palloc(result_pool, sizeof(*new_iprop)); + svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(iproplist, i, + svn_ra_svn_item_t); + if (elt->kind != SVN_RA_SVN_LIST) + return svn_error_create( + SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, + _("Inherited proplist element not a list")); + + svn_pool_clear(iterpool); + + SVN_ERR(svn_ra_svn_parse_tuple(elt->u.list, iterpool, "cl", + &parent_rel_path, &iprop_list)); + SVN_ERR(svn_ra_svn_parse_proplist(iprop_list, iterpool, &iprops)); + new_iprop->path_or_url = svn_path_url_add_component2(repos_root_url, + parent_rel_path, + result_pool); + new_iprop->prop_hash = apr_hash_make(result_pool); + for (hi = apr_hash_first(iterpool, iprops); + hi; + hi = apr_hash_next(hi)) + { + const char *name = svn__apr_hash_index_key(hi); + svn_string_t *value = svn__apr_hash_index_val(hi); + apr_hash_set(new_iprop->prop_hash, + apr_pstrdup(result_pool, name), + APR_HASH_KEY_STRING, + svn_string_dup(value, result_pool)); + } + APR_ARRAY_PUSH(*inherited_props, svn_prop_inherited_item_t *) = + new_iprop; + } + svn_pool_destroy(iterpool); + return SVN_NO_ERROR; +} + static svn_error_t *ra_svn_get_file(svn_ra_session_t *session, const char *path, svn_revnum_t rev, svn_stream_t *stream, svn_revnum_t *fetched_rev, @@ -1019,22 +1095,26 @@ static svn_error_t *ra_svn_get_file(svn_ svn_ra_svn__session_baton_t *sess_baton = session->priv; svn_ra_svn_conn_t *conn = sess_baton->conn; apr_array_header_t *proplist; + apr_array_header_t *iproplist; const char *expected_digest; svn_checksum_t *expected_checksum = NULL; svn_checksum_ctx_t *checksum_ctx; apr_pool_t *iterpool; - SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "get-file", "c(?r)bb", path, - rev, (props != NULL), (stream != NULL))); + SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "get-file", "c(?r)bbb", path, + rev, (props != NULL), (stream != NULL), + (inherited_props != NULL))); SVN_ERR(handle_auth_request(sess_baton, pool)); - SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "(?c)rl", + SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "(?c)rl?l", &expected_digest, - &rev, &proplist)); + &rev, &proplist, &iproplist)); if (fetched_rev) *fetched_rev = rev; if (props) SVN_ERR(svn_ra_svn_parse_proplist(proplist, pool, props)); + if (inherited_props) + SVN_ERR(parse_iproplist(inherited_props, iproplist, session, pool, pool)); /* We're done if the contents weren't wanted. */ if (!stream) @@ -1098,7 +1178,7 @@ static svn_error_t *ra_svn_get_dir(svn_r { svn_ra_svn__session_baton_t *sess_baton = session->priv; svn_ra_svn_conn_t *conn = sess_baton->conn; - apr_array_header_t *proplist, *dirlist; + apr_array_header_t *proplist, *dirlist, *iproplist; int i; SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(c(?r)bb(!", "get-dir", path, @@ -1116,16 +1196,20 @@ static svn_error_t *ra_svn_get_dir(svn_r if (dirent_fields & SVN_DIRENT_LAST_AUTHOR) SVN_ERR(svn_ra_svn_write_word(conn, pool, SVN_RA_SVN_DIRENT_LAST_AUTHOR)); - SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!))")); + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!)b)", + (inherited_props != NULL))); SVN_ERR(handle_auth_request(sess_baton, pool)); - SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "rll", &rev, &proplist, - &dirlist)); + SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "rll?l", &rev, &proplist, + &dirlist, &iproplist)); if (fetched_rev) *fetched_rev = rev; if (props) SVN_ERR(svn_ra_svn_parse_proplist(proplist, pool, props)); + if (inherited_props) + SVN_ERR(parse_iproplist(inherited_props, iproplist, session, pool, + pool)); /* We're done if dirents aren't wanted. */ if (!dirents) Modified: subversion/branches/inheritable-props/subversion/libsvn_ra_svn/protocol URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_ra_svn/protocol?rev=1305641&r1=1305640&r2=1305641&view=diff ============================================================================== --- subversion/branches/inheritable-props/subversion/libsvn_ra_svn/protocol (original) +++ subversion/branches/inheritable-props/subversion/libsvn_ra_svn/protocol Mon Mar 26 22:29:55 2012 @@ -222,6 +222,7 @@ responds. Here are some miscellaneous prototypes used by the command sets: proplist: ( ( name:string value:string ) ... ) + iproplist: ( ( name:string proplist ) ... ) propdelta: ( ( name:string [ value:string ] ) ... ) node-kind: none|file|dir|unknown bool: true|false @@ -293,8 +294,10 @@ second place for auth-request point as n ? ( post-commit-err:string ) ) get-file - params: ( path:string [ rev:number ] want-props:bool want-contents:bool ) - response: ( [ checksum:string ] rev:number props:proplist ) + params: ( path:string [ rev:number ] want-props:bool want-contents:bool + [ want-iprops:bool ] ) + response: ( [ checksum:string ] rev:number props:proplist + [ inherited-props:iproplist ] ) If want-contents is specified, then after sending response, server sends file contents as a series of strings, terminated by the empty string, followed by a second empty command response to indicate @@ -302,8 +305,9 @@ second place for auth-request point as n get-dir params: ( path:string [ rev:number ] want-props:bool want-contents:bool - ? ( field:dirent-field ... ) ) - response: ( rev:number props:proplist ( entry:dirent ... ) )] + ? ( field:dirent-field ... ) [ want-iprops:bool ] ) + response: ( rev:number props:proplist ( entry:dirent ... ) + [ inherited-props:iproplist ] )] dirent: ( name:string kind:node-kind size:number has-props:bool created-rev:number [ created-date:string ] [ last-author:string ] ) Modified: subversion/branches/inheritable-props/subversion/svnserve/serve.c URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/svnserve/serve.c?rev=1305641&r1=1305640&r2=1305641&view=diff ============================================================================== --- subversion/branches/inheritable-props/subversion/svnserve/serve.c (original) +++ subversion/branches/inheritable-props/subversion/svnserve/serve.c Mon Mar 26 22:29:55 2012 @@ -963,15 +963,19 @@ static svn_error_t *write_lock(svn_ra_sv /* ### This really belongs in libsvn_repos. */ /* Get the properties for a path, with hardcoded committed-info values. */ -static svn_error_t *get_props(apr_hash_t **props, svn_fs_root_t *root, - const char *path, apr_pool_t *pool) +static svn_error_t * +get_props(apr_hash_t **props, + apr_array_header_t **iprops, + svn_fs_root_t *root, + const char *path, + apr_pool_t *pool) { svn_string_t *str; svn_revnum_t crev; const char *cdate, *cauthor, *uuid; /* Get the properties. */ - SVN_ERR(svn_fs_node_proplist(props, root, path, pool)); + SVN_ERR(svn_fs_node_proplist2(props, iprops, root, path, pool, pool)); /* Hardcode the values for the committed revision, date, and author. */ SVN_ERR(svn_repos_get_committed_info(&crev, &cdate, &cauthor, root, @@ -1390,16 +1394,20 @@ static svn_error_t *get_file(svn_ra_svn_ svn_fs_root_t *root; svn_stream_t *contents; apr_hash_t *props = NULL; + apr_array_header_t *inherited_props; svn_string_t write_str; char buf[4096]; apr_size_t len; svn_boolean_t want_props, want_contents; + apr_uint64_t wants_inherited_props; svn_checksum_t *checksum; svn_error_t *err, *write_err; + int i; /* Parse arguments. */ - SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c(?r)bb", &path, &rev, - &want_props, &want_contents)); + SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c(?r)bb?B", &path, &rev, + &want_props, &want_contents, + &wants_inherited_props)); full_path = svn_fspath__join(b->fs_path->data, svn_relpath_canonicalize(path, pool), pool); @@ -1420,8 +1428,8 @@ static svn_error_t *get_file(svn_ra_svn_ SVN_CMD_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5, root, full_path, TRUE, pool)); hex_digest = svn_checksum_to_cstring_display(checksum, pool); - if (want_props) - SVN_CMD_ERR(get_props(&props, root, full_path, pool)); + if (want_props || wants_inherited_props) + SVN_CMD_ERR(get_props(&props, &inherited_props, root, full_path, pool)); if (want_contents) SVN_CMD_ERR(svn_fs_file_contents(&contents, root, full_path, pool)); @@ -1429,6 +1437,23 @@ static svn_error_t *get_file(svn_ra_svn_ SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w((?c)r(!", "success", hex_digest, rev)); SVN_ERR(svn_ra_svn_write_proplist(conn, pool, props)); + + if (wants_inherited_props) + { + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!)(?!")); + for (i = 0; i < inherited_props->nelts; i++) + { + svn_prop_inherited_item_t *iprop = + APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *); + + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!(c(!", + iprop->path_or_url)); + SVN_ERR(svn_ra_svn_write_proplist(conn, pool, iprop->prop_hash)); + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!))!", + iprop->path_or_url)); + } + } + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!))")); /* Now send the file's contents. */ @@ -1473,17 +1498,21 @@ static svn_error_t *get_dir(svn_ra_svn_c const char *path, *full_path, *file_path, *cdate; svn_revnum_t rev; apr_hash_t *entries, *props = NULL, *file_props; + apr_array_header_t *inherited_props; apr_hash_index_t *hi; svn_fs_root_t *root; apr_pool_t *subpool; svn_boolean_t want_props, want_contents; + apr_uint64_t wants_inherited_props; apr_uint64_t dirent_fields; apr_array_header_t *dirent_fields_list = NULL; svn_ra_svn_item_t *elt; + int i; - SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c(?r)bb?l", &path, &rev, + SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c(?r)bb?l?B", &path, &rev, &want_props, &want_contents, - &dirent_fields_list)); + &dirent_fields_list, + &wants_inherited_props)); if (! dirent_fields_list) { @@ -1491,8 +1520,6 @@ static svn_error_t *get_dir(svn_ra_svn_c } else { - int i; - dirent_fields = 0; for (i = 0; i < dirent_fields_list->nelts; ++i) @@ -1536,9 +1563,10 @@ static svn_error_t *get_dir(svn_ra_svn_c /* Fetch the root of the appropriate revision. */ SVN_CMD_ERR(svn_fs_revision_root(&root, b->fs, rev, pool)); - /* Fetch the directory properties if requested. */ - if (want_props) - SVN_CMD_ERR(get_props(&props, root, full_path, pool)); + /* Fetch the directory's explicit and/or inherited properties + if requested. */ + if (want_props || wants_inherited_props) + SVN_CMD_ERR(get_props(&props, &inherited_props, root, full_path, pool)); /* Begin response ... */ SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(r(!", "success", rev)); @@ -1612,6 +1640,22 @@ static svn_error_t *get_dir(svn_ra_svn_c svn_pool_destroy(subpool); } + if (wants_inherited_props) + { + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!)(?!")); + for (i = 0; i < inherited_props->nelts; i++) + { + svn_prop_inherited_item_t *iprop = + APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *); + + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!(c(!", + iprop->path_or_url)); + SVN_ERR(svn_ra_svn_write_proplist(conn, pool, iprop->prop_hash)); + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!))!", + iprop->path_or_url)); + } + } + /* Finish response. */ return svn_ra_svn_write_tuple(conn, pool, "!))"); }