Store property conflicts in the WC in the same way that we store text conflicts - with separate old/theirs/mine files and API access to them - for better automation support. Index: subversion/include/svn_wc.h =================================================================== --- subversion/include/svn_wc.h (revision 31940) +++ subversion/include/svn_wc.h (working copy) @@ -3752,6 +3752,35 @@ svn_wc_prop_list(apr_hash_t **props, svn_wc_adm_access_t *adm_access, apr_pool_t *pool); +/* A type to specify which of the versions held in the WC. Types 'pristine' + * and 'working' are always meaningful (though they may be in the + * "nonexistent" state), whereas types 'conflict_*' are only valid when the WC + * item is in a state of conflict. */ +typedef enum svn_wc_rev_kind_t +{ + svn_wc_rev_kind_pristine, /* the 'pristine' or 'base' version */ + svn_wc_rev_kind_working, /* the version that can be locally edited */ + svn_wc_rev_kind_conflict_old, /* the incoming change's 'old' or 'left' side */ + svn_wc_rev_kind_conflict_new, /* the incoming change's 'new' or 'right' side */ + svn_wc_rev_kind_conflict_mine /* what was 'working' before the conflict */ +} svn_wc_rev_kind_t; + +/** Set @a *props to a hash table mapping char * names onto + * svn_string_t * values for all the regular properties of + * @a path. Allocate the table, names, and values in @a pool. If + * the node has no properties, or does not exist in the working copy, + * then an empty hash is returned. @a adm_access is an access baton + * set that contains @a path. + * @a rev_kind specified whether to access the pristine or working or + * one of the conflict artifact versions of this WC item. + */ +svn_error_t * +svn_wc_prop_list2(apr_hash_t **props, + const char *path, + svn_wc_rev_kind_t rev_kind, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + /** Set @a *value to the value of property @a name for @a path, allocating * @a *value in @a pool. If no such prop, set @a *value to @c NULL. Index: subversion/libsvn_client/client.h =================================================================== --- subversion/libsvn_client/client.h (revision 31940) +++ subversion/libsvn_client/client.h (working copy) @@ -333,7 +333,7 @@ svn_error_t * svn_client__get_prop_from_wc(apr_hash_t *props, const char *propname, const char *target, - svn_boolean_t pristine, + svn_wc_rev_kind_t wc_rev_kind, const svn_wc_entry_t *entry, svn_wc_adm_access_t *adm_access, svn_depth_t depth, @@ -1062,15 +1062,21 @@ svn_client__ensure_revprop_table(apr_has apr_pool_t *pool); -/** Return TRUE iff revision kind is dependent on the working copy. - * Otherwise, return FALSE. - */ -#define SVN_CLIENT__REVKIND_NEEDS_WC(kind) \ - (((kind) == svn_opt_revision_base || \ - (kind) == svn_opt_revision_previous || \ - (kind) == svn_opt_revision_working || \ - (kind) == svn_opt_revision_committed) \ - ? TRUE : FALSE) +/** Return true iff *REVISION is of a kind that is dependent on the working + * copy. The result is unspecified if REVISION->kind is 'unspecified'. */ +#define SVN_CLIENT__REVKIND_NEEDS_WC(revision) \ + ((revision)->kind == svn_opt_revision_base || \ + (revision)->kind == svn_opt_revision_previous || \ + (revision)->kind == svn_opt_revision_working || \ + (revision)->kind == svn_opt_revision_committed) + +/* Return true iff *REVISION is of a kind that the WC can supply without + * reference to the repository. + * The result is unspecified if REVISION->kind is 'unspecified'. */ +#define SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision) \ + ((revision)->kind == svn_opt_revision_base || \ + (revision)->kind == svn_opt_revision_working || \ + (revision)->kind == svn_opt_revision_committed) #ifdef __cplusplus Index: subversion/libsvn_client/copy.c =================================================================== --- subversion/libsvn_client/copy.c (revision 31940) +++ subversion/libsvn_client/copy.c (working copy) @@ -1732,7 +1732,7 @@ setup_copy(svn_commit_info_t **commit_in ((svn_client_copy_source_t **) (sources->elts))[i]; if (svn_path_is_url(source->path) - && (SVN_CLIENT__REVKIND_NEEDS_WC(source->peg_revision->kind))) + && (SVN_CLIENT__REVKIND_NEEDS_WC(source->peg_revision))) return svn_error_create (SVN_ERR_CLIENT_BAD_REVISION, NULL, _("Revision type requires a working copy path, not a URL")); Index: subversion/libsvn_client/log.c =================================================================== --- subversion/libsvn_client/log.c (revision 31940) +++ subversion/libsvn_client/log.c (working copy) @@ -326,9 +326,9 @@ svn_client_log4(const apr_array_header_t /* Use the passed URL, if there is one. */ if (svn_path_is_url(url_or_path)) { - if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind) || - SVN_CLIENT__REVKIND_NEEDS_WC(start->kind) || - SVN_CLIENT__REVKIND_NEEDS_WC(end->kind)) + if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision) || + SVN_CLIENT__REVKIND_NEEDS_WC(start) || + SVN_CLIENT__REVKIND_NEEDS_WC(end)) return svn_error_create (SVN_ERR_CLIENT_BAD_REVISION, NULL, @@ -433,7 +433,7 @@ svn_client_log4(const apr_array_header_t /* If this is a revision type that requires access to the working copy, * we use our initial target path to figure out where to root the RA * session, otherwise we use our URL. */ - if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind)) + if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision)) SVN_ERR(svn_path_condense_targets(&ra_target, NULL, targets, TRUE, pool)); else ra_target = url_or_path; Index: subversion/libsvn_client/mergeinfo.c =================================================================== --- subversion/libsvn_client/mergeinfo.c (revision 31940) +++ subversion/libsvn_client/mergeinfo.c (working copy) @@ -58,7 +58,10 @@ svn_client__parse_mergeinfo(svn_mergeinf ### DannyB thinks that later we'll need behavior more like ### svn_client__get_prop_from_wc(). */ SVN_ERR(svn_client__get_prop_from_wc(props, SVN_PROP_MERGEINFO, - wcpath, pristine, entry, adm_access, + wcpath, pristine + ? svn_wc_rev_kind_pristine + : svn_wc_rev_kind_working, + entry, adm_access, svn_depth_empty, NULL, ctx, pool)); propval = apr_hash_get(props, wcpath, APR_HASH_KEY_STRING); if (propval) @@ -370,7 +373,9 @@ svn_client__get_wc_or_repos_mergeinfo(sv assume the mergeinfo to be NULL. */ SVN_ERR(svn_client__get_prop_from_wc(props, SVN_PROP_MERGEINFO, - target_wcpath, TRUE, entry, + target_wcpath, + svn_wc_rev_kind_pristine, + entry, adm_access, svn_depth_empty, NULL, ctx, pool)); if (apr_hash_get(props, target_wcpath, APR_HASH_KEY_STRING) == NULL) Index: subversion/libsvn_client/prop_commands.c =================================================================== --- subversion/libsvn_client/prop_commands.c (revision 31940) +++ subversion/libsvn_client/prop_commands.c (working copy) @@ -24,6 +24,7 @@ #define APR_WANT_STRFUNC #include +#include #include "svn_error.h" #include "svn_client.h" @@ -552,8 +553,27 @@ svn_client_revprop_set(const char *propn } -/* Set *PROPS to the pristine (base) properties at PATH, if PRISTINE - * is true, or else the working value if PRISTINE is false. +/* ### (Assumes *REVISION is of a kind that the WC can supply. No error handling.) */ +static svn_wc_rev_kind_t +wc_rev_kind_from_rev(const svn_opt_revision_t *revision) +{ + switch (revision->kind) + { + case svn_opt_revision_committed: + case svn_opt_revision_base: + return svn_wc_rev_kind_pristine; + + case svn_opt_revision_working: + return svn_wc_rev_kind_working; + + default: + return svn_wc_rev_kind_conflict_new; /* ### not really, just for testing */ + } +} + +/* Set *PROPS to the pristine/working/conflicted version of the properties + * at PATH, according to the value of WC_REV_KIND. If PATH has no such version, + * then set *PROPS to null. * * The keys of *PROPS will be 'const char *' property names, and the * values 'const svn_string_t *' property values. Allocate *PROPS @@ -562,43 +582,32 @@ svn_client_revprop_set(const char *propn static svn_error_t * pristine_or_working_props(apr_hash_t **props, const char *path, + svn_wc_rev_kind_t wc_rev_kind, svn_wc_adm_access_t *adm_access, - svn_boolean_t pristine, apr_pool_t *pool) { - if (pristine) - SVN_ERR(svn_wc_get_prop_diffs(NULL, props, path, adm_access, pool)); - else - SVN_ERR(svn_wc_prop_list(props, path, adm_access, pool)); - - return SVN_NO_ERROR; + return svn_wc_prop_list2(props, path, wc_rev_kind, adm_access, pool); } -/* Set *PROPVAL to the pristine (base) value of property PROPNAME at - * PATH, if PRISTINE is true, or else the working value if PRISTINE is - * false. Allocate *PROPVAL in POOL. +/* Set *PROPVAL to the pristine/working/conflicted value of property PROPNAME + * at PATH, according to the value of WC_REV_KIND. If PATH does not exist at the + * revision kind WC_REV_KIND then set *PROPVAL to null. + * Allocate *PROPVAL in POOL. */ static svn_error_t * pristine_or_working_propval(const svn_string_t **propval, const char *propname, const char *path, svn_wc_adm_access_t *adm_access, - svn_boolean_t pristine, + svn_wc_rev_kind_t wc_rev_kind, apr_pool_t *pool) { - if (pristine) - { - apr_hash_t *pristine_props; + apr_hash_t *props; - SVN_ERR(svn_wc_get_prop_diffs(NULL, &pristine_props, path, adm_access, + SVN_ERR(pristine_or_working_props(&props, path, wc_rev_kind, adm_access, pool)); - *propval = apr_hash_get(pristine_props, propname, APR_HASH_KEY_STRING); - } - else /* get the working revision */ - { - SVN_ERR(svn_wc_prop_get(propval, propname, path, adm_access, pool)); - } + *propval = apr_hash_get(props, propname, APR_HASH_KEY_STRING); return SVN_NO_ERROR; } @@ -608,7 +617,7 @@ pristine_or_working_propval(const svn_st struct propget_walk_baton { const char *propname; /* The name of the property to get. */ - svn_boolean_t pristine; /* Select base rather than working props. */ + svn_wc_rev_kind_t wc_rev_kind; /* Select base rather than working props. */ svn_wc_adm_access_t *base_access; /* Access for the tree being walked. */ apr_hash_t *changelist_hash; /* Keys are changelists to filter on. */ apr_hash_t *props; /* Out: mapping of (path:propval). */ @@ -619,7 +628,7 @@ struct propget_walk_baton * For the path given by PATH and ENTRY, * populate wb->PROPS with the values of property wb->PROPNAME, * where "wb" is the WALK_BATON of type "struct propget_walk_baton *". - * If wb->PRISTINE is true, use the base value, else use the working value. + * Get the pristine/working/conflict values, according to wb->WC_REV_KIND. * * The keys of wb->PROPS will be 'const char *' paths, rooted at the * path svn_wc_adm_access_path(ADM_ACCESS), and the values are @@ -641,17 +650,19 @@ propget_walk_cb(const char *path, && (strcmp(entry->name, SVN_WC_ENTRY_THIS_DIR) != 0)) return SVN_NO_ERROR; +#if 0 /* Ignore the entry if it does not exist at the time of interest. */ if (entry->schedule == (wb->pristine ? svn_wc_schedule_add : svn_wc_schedule_delete)) return SVN_NO_ERROR; +#endif /* If our entry doesn't pass changelist filtering, get outta here. */ if (! SVN_WC__CL_MATCH(wb->changelist_hash, entry)) return SVN_NO_ERROR; SVN_ERR(pristine_or_working_propval(&propval, wb->propname, path, - wb->base_access, wb->pristine, + wb->base_access, wb->wc_rev_kind, pool)); if (propval) @@ -811,7 +822,7 @@ svn_error_t * svn_client__get_prop_from_wc(apr_hash_t *props, const char *propname, const char *target, - svn_boolean_t pristine, + svn_wc_rev_kind_t wc_rev_kind, const svn_wc_entry_t *entry, svn_wc_adm_access_t *adm_access, svn_depth_t depth, @@ -836,7 +847,7 @@ svn_client__get_prop_from_wc(apr_hash_t depth = svn_depth_infinity; wb.propname = propname; - wb.pristine = pristine; + wb.wc_rev_kind = wc_rev_kind; wb.base_access = adm_access; wb.changelist_hash = changelist_hash; wb.props = props; @@ -857,7 +868,18 @@ svn_client__get_prop_from_wc(apr_hash_t return SVN_NO_ERROR; } -/* Note: this implementation is very similar to svn_client_proplist. */ +/* Return REVISION unless its kind is 'unspecified' in which case return + * a pointer to a statically allocated revision structure of kind 'base'. */ +static const svn_opt_revision_t * +rev_default_to_base(const svn_opt_revision_t *revision) +{ + static svn_opt_revision_t base_revision = { svn_opt_revision_base, { 0 } }; + + return ((revision->kind == svn_opt_revision_unspecified) + ? &base_revision : revision); +} + +/* Note: this implementation is very similar to svn_client_proplist3(). */ svn_error_t * svn_client_propget3(apr_hash_t **props, const char *propname, @@ -877,18 +899,12 @@ svn_client_propget3(apr_hash_t **props, *props = apr_hash_make(pool); if (! svn_path_is_url(path_or_url) - && (peg_revision->kind == svn_opt_revision_base - || peg_revision->kind == svn_opt_revision_working - || peg_revision->kind == svn_opt_revision_committed - || peg_revision->kind == svn_opt_revision_unspecified) - && (revision->kind == svn_opt_revision_base - || revision->kind == svn_opt_revision_working - || revision->kind == svn_opt_revision_committed - || revision->kind == svn_opt_revision_unspecified)) + && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(rev_default_to_base(peg_revision)) + && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(rev_default_to_base(revision))) { + svn_wc_rev_kind_t wc_rev_kind = wc_rev_kind_from_rev(revision); svn_wc_adm_access_t *adm_access; const svn_wc_entry_t *node; - svn_boolean_t pristine; int adm_lock_level = SVN_WC__LEVELS_TO_LOCK_FROM_DEPTH(depth); SVN_ERR(svn_wc_adm_probe_open3(&adm_access, NULL, path_or_url, @@ -901,12 +917,8 @@ svn_client_propget3(apr_hash_t **props, SVN_ERR(svn_client__get_revision_number (&revnum, NULL, NULL, revision, path_or_url, pool)); - /* If FALSE, we must want the working revision. */ - pristine = (revision->kind == svn_opt_revision_committed - || revision->kind == svn_opt_revision_base); - SVN_ERR(svn_client__get_prop_from_wc(*props, propname, path_or_url, - pristine, node, adm_access, + wc_rev_kind, node, adm_access, depth, changelists, ctx, pool)); SVN_ERR(svn_wc_adm_close(adm_access)); @@ -1157,7 +1169,7 @@ remote_proplist(const char *target_prefi /* A baton for proplist_walk_cb. */ struct proplist_walk_baton { - svn_boolean_t pristine; /* Select base rather than working props. */ + svn_wc_rev_kind_t wc_rev_kind; /* Select base rather than working props. */ svn_wc_adm_access_t *base_access; /* Access for the tree being walked. */ apr_hash_t *changelist_hash; /* Keys are changelists to filter on. */ svn_proplist_receiver_t receiver; /* Proplist receiver to call. */ @@ -1169,7 +1181,7 @@ struct proplist_walk_baton * For the path given by PATH and ENTRY, * populate wb->PROPS with a svn_client_proplist_item_t for each path, * where "wb" is the WALK_BATON of type "struct proplist_walk_baton *". - * If wb->PRISTINE is true, use the base values, else use the working values. + * Get the pristine/working/conflict values, according to wb->WC_REV_KIND. */ static svn_error_t * proplist_walk_cb(const char *path, @@ -1187,10 +1199,12 @@ proplist_walk_cb(const char *path, && (strcmp(entry->name, SVN_WC_ENTRY_THIS_DIR) != 0)) return SVN_NO_ERROR; +#if 0 /* Ignore the entry if it does not exist at the time of interest. */ if (entry->schedule == (wb->pristine ? svn_wc_schedule_add : svn_wc_schedule_delete)) return SVN_NO_ERROR; +#endif /* If our entry doesn't pass changelist filtering, get outta here. */ if (! SVN_WC__CL_MATCH(wb->changelist_hash, entry)) @@ -1198,8 +1212,8 @@ proplist_walk_cb(const char *path, path = apr_pstrdup(pool, path); - SVN_ERR(pristine_or_working_props(&hash, path, wb->base_access, - wb->pristine, pool)); + SVN_ERR(pristine_or_working_props(&hash, path, wb->wc_rev_kind, + wb->base_access, pool)); SVN_ERR(call_receiver(path, hash, wb->receiver, wb->receiver_baton, pool)); @@ -1207,6 +1221,7 @@ proplist_walk_cb(const char *path, } +/* Note: this implementation is very similar to svn_client_propget3(). */ svn_error_t * svn_client_proplist3(const char *path_or_url, const svn_opt_revision_t *peg_revision, @@ -1225,16 +1240,10 @@ svn_client_proplist3(const char *path_or depth = svn_depth_empty; if (! svn_path_is_url(path_or_url) - && (peg_revision->kind == svn_opt_revision_base - || peg_revision->kind == svn_opt_revision_working - || peg_revision->kind == svn_opt_revision_committed - || peg_revision->kind == svn_opt_revision_unspecified) - && (revision->kind == svn_opt_revision_base - || revision->kind == svn_opt_revision_working - || revision->kind == svn_opt_revision_committed - || revision->kind == svn_opt_revision_unspecified)) + && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(rev_default_to_base(peg_revision)) + && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(rev_default_to_base(revision))) { - svn_boolean_t pristine; + svn_wc_rev_kind_t wc_rev_kind = wc_rev_kind_from_rev(revision); int levels_to_lock = SVN_WC__LEVELS_TO_LOCK_FROM_DEPTH(depth); const svn_wc_entry_t *entry; apr_hash_t *changelist_hash = NULL; @@ -1246,16 +1255,6 @@ svn_client_proplist3(const char *path_or SVN_ERR(svn_wc__entry_versioned(&entry, path_or_url, adm_access, FALSE, pool)); - if ((revision->kind == svn_opt_revision_committed) - || (revision->kind == svn_opt_revision_base)) - { - pristine = TRUE; - } - else /* must be the working revision */ - { - pristine = FALSE; - } - if (changelists && changelists->nelts) SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelists, pool)); @@ -1268,7 +1267,7 @@ svn_client_proplist3(const char *path_or struct proplist_walk_baton wb; wb.base_access = adm_access; - wb.pristine = pristine; + wb.wc_rev_kind = wc_rev_kind; wb.changelist_hash = changelist_hash; wb.receiver = receiver; wb.receiver_baton = receiver_baton; @@ -1282,8 +1281,8 @@ svn_client_proplist3(const char *path_or { apr_hash_t *hash; - SVN_ERR(pristine_or_working_props(&hash, path_or_url, adm_access, - pristine, pool)); + SVN_ERR(pristine_or_working_props(&hash, path_or_url, wc_rev_kind, + adm_access, pool)); SVN_ERR(call_receiver(path_or_url, hash, receiver, receiver_baton, pool)); @@ -1345,7 +1344,6 @@ proplist_receiver_cb(void *baton, return SVN_NO_ERROR; } -/* Note: this implementation is very similar to svn_client_propget. */ svn_error_t * svn_client_proplist2(apr_array_header_t **props, const char *target, Index: subversion/libsvn_wc/adm_files.c =================================================================== --- subversion/libsvn_wc/adm_files.c (revision 31940) +++ subversion/libsvn_wc/adm_files.c (working copy) @@ -410,10 +410,13 @@ svn_wc__prop_path(const char **prop_path if (node_kind == svn_node_dir) /* It's a working copy dir */ { static const char * names[] = { - SVN_WC__ADM_DIR_PROP_BASE, /* prop_path_kind_base */ - SVN_WC__ADM_DIR_PROP_REVERT, /* prop_path_kind_revert */ - SVN_WC__ADM_DIR_WCPROPS, /* prop_path_kind_wcprop */ - SVN_WC__ADM_DIR_PROPS /* prop_path_kind_working */ + SVN_WC__ADM_DIR_PROP_BASE, /* svn_wc__props_base */ + SVN_WC__ADM_DIR_PROP_REVERT, /* svn_wc__props_revert */ + SVN_WC__ADM_DIR_WCPROPS, /* svn_wc__props_wcprop */ + SVN_WC__ADM_DIR_PROPS, /* svn_wc__props_working */ + SVN_WC__ADM_DIR_PROP_CNFL_OLD, /* svn_wc__props_conflict_old */ + SVN_WC__ADM_DIR_PROP_CNFL_NEW, /* svn_wc__props_conflict_new */ + SVN_WC__ADM_DIR_PROP_CNFL_MINE /* svn_wc__props_conflict_mine */ }; *prop_path = extend_with_adm_name @@ -427,17 +430,23 @@ svn_wc__prop_path(const char **prop_path else /* It's a file */ { static const char * extensions[] = { - SVN_WC__BASE_EXT, /* prop_path_kind_base */ - SVN_WC__REVERT_EXT, /* prop_path_kind_revert */ - SVN_WC__WORK_EXT, /* prop_path_kind_wcprop */ - SVN_WC__WORK_EXT /* prop_path_kind_working */ + SVN_WC__BASE_EXT, /* svn_wc__props_base */ + SVN_WC__REVERT_EXT, /* svn_wc__props_revert */ + SVN_WC__WORK_EXT, /* svn_wc__props_wcprop */ + SVN_WC__WORK_EXT, /* svn_wc__props_working */ + SVN_WC__CNFL_OLD_EXT, /* svn_wc__props_conflict_old */ + SVN_WC__CNFL_NEW_EXT, /* svn_wc__props_conflict_new */ + SVN_WC__CNFL_MINE_EXT /* svn_wc__props_conflict_mine */ }; static const char * dirs[] = { - SVN_WC__ADM_PROP_BASE, /* prop_path_kind_base */ - SVN_WC__ADM_PROP_BASE, /* prop_path_kind_revert */ - SVN_WC__ADM_WCPROPS, /* prop_path_kind_wcprop */ - SVN_WC__ADM_PROPS /* prop_path_kind_working */ + SVN_WC__ADM_PROP_BASE, /* svn_wc__props_base */ + SVN_WC__ADM_PROP_BASE, /* svn_wc__props_revert */ + SVN_WC__ADM_WCPROPS, /* svn_wc__props_wcprop */ + SVN_WC__ADM_PROPS, /* svn_wc__props_working */ + SVN_WC__ADM_PROP_CNFL_OLD, /* svn_wc__props_conflict_old */ + SVN_WC__ADM_PROP_CNFL_NEW, /* svn_wc__props_conflict_new */ + SVN_WC__ADM_PROP_CNFL_MINE /* svn_wc__props_conflict_mine */ }; const char *base_name; Index: subversion/libsvn_wc/props.c =================================================================== --- subversion/libsvn_wc/props.c (revision 31940) +++ subversion/libsvn_wc/props.c (working copy) @@ -198,7 +198,7 @@ append_prop_conflict(apr_file_t *fp, } -/* Look up the entry NAME within ADM_ACCESS and see if it has a `current' +/* Look up the entry for PATH within ADM_ACCESS and see if it has a `current' reject file describing a state of conflict. Set *REJECT_FILE to the name of that file, or to NULL if no such file exists. */ static svn_error_t * @@ -253,12 +253,15 @@ build_present_props(apr_hash_t *props, a /*** Loading regular properties. ***/ svn_error_t * -svn_wc__load_props(apr_hash_t **base_props_p, - apr_hash_t **props_p, - apr_hash_t **revert_props_p, - svn_wc_adm_access_t *adm_access, - const char *path, - apr_pool_t *pool) +svn_wc__load_props2(apr_hash_t **base_props_p, + apr_hash_t **props_p, + apr_hash_t **revert_props_p, + apr_hash_t **conflict_old_props_p, + apr_hash_t **conflict_new_props_p, + apr_hash_t **conflict_mine_props_p, + svn_wc_adm_access_t *adm_access, + const char *path, + apr_pool_t *pool) { svn_node_kind_t kind; svn_boolean_t has_propcaching = @@ -330,9 +333,52 @@ svn_wc__load_props(apr_hash_t **base_pro } } + if (conflict_old_props_p) + { + const char *prop_file_path; + + *conflict_old_props_p = apr_hash_make(pool); + SVN_ERR(svn_wc__prop_path(&prop_file_path, path, kind, + svn_wc__props_conflict_old, FALSE, pool)); + SVN_ERR(load_prop_file(prop_file_path, *conflict_old_props_p, pool)); + } + + if (conflict_new_props_p) + { + const char *prop_file_path; + + *conflict_new_props_p = apr_hash_make(pool); + SVN_ERR(svn_wc__prop_path(&prop_file_path, path, kind, + svn_wc__props_conflict_new, FALSE, pool)); + SVN_ERR(load_prop_file(prop_file_path, *conflict_new_props_p, pool)); + } + + if (conflict_mine_props_p) + { + const char *prop_file_path; + + *conflict_mine_props_p = apr_hash_make(pool); + SVN_ERR(svn_wc__prop_path(&prop_file_path, path, kind, + svn_wc__props_conflict_mine, FALSE, pool)); + SVN_ERR(load_prop_file(prop_file_path, *conflict_mine_props_p, pool)); + } + return SVN_NO_ERROR; } +svn_error_t * +svn_wc__load_props(apr_hash_t **base_props_p, + apr_hash_t **props_p, + apr_hash_t **revert_props_p, + svn_wc_adm_access_t *adm_access, + const char *path, + apr_pool_t *pool) +{ + return svn_wc__load_props2(base_props_p, props_p, revert_props_p, + NULL, NULL, NULL, + adm_access, path, pool); +} + /*---------------------------------------------------------------------*/ @@ -1188,10 +1234,15 @@ set_prop_merge_state(svn_wc_notify_state /* Helper function for the three apply_* functions below, used when - * merging properties together. + * merging properties together. Either resolve the conflict (using the + * resolver callback function) into WORKING_PROPS or set + * *CONFLICT_REMAINS to true. + * + * ### TODO: If a conflict remains, record the four input values in the + * WC to help with later resolution. * * Given property PROPNAME on PATH, and four possible property values, - * generate four tmpfiles and pass them to CONFLICT_FUNC callback. + * generate four (not corresponding) tmpfiles and pass them to CONFLICT_FUNC callback. * This gives the client an opportunity to interactively resolve the * property conflict. (ADM_ACCESS provides the ability to examine * PATH's entries.) @@ -1205,7 +1256,9 @@ set_prop_merge_state(svn_wc_notify_state * 'choose_postpone', then set *CONFLICT_REMAINS to true and return. * * If the callback responds with a choice of 'base', 'theirs', 'mine', - * or 'merged', then install the proper value into WORKING_PROPS and + * or 'merged', then install the proper value (OLD_VAL, NEW_VAL, + * WORKING_VAL, or the merged value provided by the callback, respectively; + * note two different meanings of "base") into WORKING_PROPS and * set *CONFLICT_REMAINS to false. * */ @@ -1312,7 +1365,7 @@ maybe_generate_propconflict(svn_boolean_ HOWEVER: we can still pass one of the two base values as 'base_file' to the callback anyway. It's still useful to present the working and new values to the user to - compare. */ + compare. ### AARGH! Vague wooly spec. */ if (working_val && svn_string_compare(base_val, working_val)) the_val = old_val; @@ -1387,13 +1440,7 @@ maybe_generate_propconflict(svn_boolean_ /* Invoke the interactive conflict callback. */ SVN_ERR(conflict_func(&result, cdesc, conflict_baton, pool)); - if (result == NULL) - { - *conflict_remains = TRUE; - return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, - NULL, _("Conflict callback violated API:" - " returned no results.")); - } + assert(result); switch (result->choice) { @@ -1428,26 +1475,19 @@ maybe_generate_propconflict(svn_boolean_ } case svn_wc_conflict_choose_merged: { - if (!cdesc->merged_file && !result->merged_file) - return svn_error_create - (SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, - NULL, _("Conflict callback violated API:" - " returned no merged file.")); - else - { - svn_stringbuf_t *merged_stringbuf; - svn_string_t *merged_string; + svn_stringbuf_t *merged_stringbuf; + svn_string_t *merged_string; - SVN_ERR(svn_stringbuf_from_file2(&merged_stringbuf, - result->merged_file ? - result->merged_file : - cdesc->merged_file, - pool)); - merged_string = svn_string_create_from_buf(merged_stringbuf, pool); - apr_hash_set(working_props, propname, - APR_HASH_KEY_STRING, merged_string); - *conflict_remains = FALSE; - } + assert(cdesc->merged_file || result->merged_file); + SVN_ERR(svn_stringbuf_from_file2(&merged_stringbuf, + result->merged_file ? + result->merged_file : + cdesc->merged_file, + pool)); + merged_string = svn_string_create_from_buf(merged_stringbuf, pool); + apr_hash_set(working_props, propname, + APR_HASH_KEY_STRING, merged_string); + *conflict_remains = FALSE; break; } } @@ -2202,10 +2242,11 @@ svn_wc__wcprop_set(const char *name, svn_error_t * -svn_wc_prop_list(apr_hash_t **props, - const char *path, - svn_wc_adm_access_t *adm_access, - apr_pool_t *pool) +svn_wc_prop_list2(apr_hash_t **props, + const char *path, + svn_wc_rev_kind_t rev_kind, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool) { const svn_wc_entry_t *entry; @@ -2225,7 +2266,42 @@ svn_wc_prop_list(apr_hash_t **props, SVN_ERR(svn_wc_adm_retrieve(&adm_access, adm_access, svn_path_dirname(path, pool), pool)); - return svn_wc__load_props(NULL, props, NULL, adm_access, path, pool); + switch (rev_kind) + { + case svn_wc_rev_kind_pristine: + SVN_ERR(svn_wc__load_props2(props, NULL, NULL, NULL, NULL, NULL, + adm_access, path, pool)); + break; + case svn_wc_rev_kind_working: + SVN_ERR(svn_wc__load_props2(NULL, props, NULL, NULL, NULL, NULL, + adm_access, path, pool)); + break; + case svn_wc_rev_kind_conflict_old: + SVN_ERR(svn_wc__load_props2(NULL, NULL, NULL, props, NULL, NULL, + adm_access, path, pool)); + break; + case svn_wc_rev_kind_conflict_new: + SVN_ERR(svn_wc__load_props2(NULL, NULL, NULL, NULL, props, NULL, + adm_access, path, pool)); + break; + case svn_wc_rev_kind_conflict_mine: + SVN_ERR(svn_wc__load_props2(NULL, NULL, NULL, NULL, NULL, props, + adm_access, path, pool)); + break; + default: + assert(0); + } + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc_prop_list(apr_hash_t **props, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool) +{ + return svn_wc_prop_list2(props, path, svn_wc_rev_kind_working, adm_access, + pool); } /* Determine if PROPNAME is contained in the list of space separated Index: subversion/libsvn_wc/props.h =================================================================== --- subversion/libsvn_wc/props.h (revision 31940) +++ subversion/libsvn_wc/props.h (working copy) @@ -35,7 +35,10 @@ typedef enum svn_wc__props_kind_t svn_wc__props_base = 0, svn_wc__props_revert, svn_wc__props_wcprop, - svn_wc__props_working + svn_wc__props_working, + svn_wc__props_conflict_old, + svn_wc__props_conflict_new, + svn_wc__props_conflict_mine } svn_wc__props_kind_t; @@ -215,6 +218,21 @@ svn_wc__load_props(apr_hash_t **base_pro const char *path, apr_pool_t *pool); +/* Load the base, working and revert props for PATH in ADM_ACCESS returning + them in *BASE_PROPS_P, *PROPS_P and *REVERT_PROPS_P respectively. + Any of BASE_PROPS, PROPS and REVERT_PROPS may be null. + Do all allocations in POOL. */ +svn_error_t * +svn_wc__load_props2(apr_hash_t **base_props_p, + apr_hash_t **props_p, + apr_hash_t **revert_props_p, + apr_hash_t **conflict_old_props_p, + apr_hash_t **conflict_new_props_p, + apr_hash_t **conflict_mine_props_p, + svn_wc_adm_access_t *adm_access, + const char *path, + apr_pool_t *pool); + #ifdef __cplusplus } #endif /* __cplusplus */ Index: subversion/libsvn_wc/wc.h =================================================================== --- subversion/libsvn_wc/wc.h (revision 31940) +++ subversion/libsvn_wc/wc.h (working copy) @@ -36,8 +36,10 @@ extern "C" { #define SVN_WC__PROP_REJ_EXT ".prej" #define SVN_WC__BASE_EXT ".svn-base" /* for text and prop bases */ #define SVN_WC__WORK_EXT ".svn-work" /* for working propfiles */ -#define SVN_WC__REVERT_EXT ".svn-revert" /* for reverting a replaced - file */ +#define SVN_WC__REVERT_EXT ".svn-revert" /* for reverting a replaced file */ +#define SVN_WC__CNFL_OLD_EXT ".old" +#define SVN_WC__CNFL_NEW_EXT ".new" +#define SVN_WC__CNFL_MINE_EXT ".mine" @@ -140,11 +142,17 @@ struct svn_wc_traversal_info_t #define SVN_WC__ADM_TEXT_BASE "text-base" #define SVN_WC__ADM_PROPS "props" #define SVN_WC__ADM_PROP_BASE "prop-base" +#define SVN_WC__ADM_WCPROPS "wcprops" +#define SVN_WC__ADM_PROP_CNFL_OLD "prop-cnfl-old" +#define SVN_WC__ADM_PROP_CNFL_NEW "prop-cnfl-new" +#define SVN_WC__ADM_PROP_CNFL_MINE "prop-cnfl-mine" #define SVN_WC__ADM_DIR_PROPS "dir-props" #define SVN_WC__ADM_DIR_PROP_BASE "dir-prop-base" #define SVN_WC__ADM_DIR_PROP_REVERT "dir-prop-revert" -#define SVN_WC__ADM_WCPROPS "wcprops" #define SVN_WC__ADM_DIR_WCPROPS "dir-wcprops" +#define SVN_WC__ADM_DIR_PROP_CNFL_OLD "dir-prop-cnfl-old" +#define SVN_WC__ADM_DIR_PROP_CNFL_NEW "dir-prop-cnfl-new" +#define SVN_WC__ADM_DIR_PROP_CNFL_MINE "dir-prop-cnfl-mine" #define SVN_WC__ADM_ALL_WCPROPS "all-wcprops" #define SVN_WC__ADM_LOG "log" #define SVN_WC__ADM_KILLME "KILLME"