Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Subversion Wiki" for 
change notification.

The "InheritedProperties" page has been changed by pburba:
http://wiki.apache.org/subversion/InheritedProperties

Comment:
Initial brain dump on simple inherited properties

New page:
= INHERITED PROPERTIES : BACKGROUND =
== What's This? ==
Some ideas on how we might implement simple inherited properties.

== What Are Inherited Properties? ==
Inherited properties are versioned properties that apply not only to the path 
the property is explicitly set on, but also to all of that path's path-wise 
descendants (at the same revision) which do not explicitly have the same 
property set.

== What's Driving This? ==
Desire for some form of inherited properties has existed almost from the dawn 
of Subversion.  This latest effort is in response to a recent proposal 
regarding Server Dictated Configuration (see 
http://wiki.apache.org/subversion/ServerDictatedConfiguration and 
http://svn.haxx.se/dev/archive-2012-01/0032.shtml).  That proposal made use of 
a new mechanism by which server dictated configurations (notably auto-props and 
global-ignores) would be communicated from the server to the client.  In the 
feedback on the proposal several people pointed out that versioned properties 
provide a possible alternative solution (and that the TortoiseSVN project was 
already using pseduo-inheritable properties to address some of the same 
problems -- see 
http://tortoisesvn.net/docs/nightly/TortoiseSVN_en/tsvn-dug-propertypage.html). 
Despite its origins in the server defined configuration work, this wiki 
describes only a generic inheritable properties design (''though my the 
ultimate goal is to use these inheritable properties to implement the server 
dictated configuration feature -- pburba'').

== What This Design Is and What It Isn't ==
This design provides the bare minimum to support the basics of inherited 
properties:

 * A way to identify properties that are inheritable vs. those that are not.
 * A way to set inheritable properties (not really anything to do here, we 
support this today).
 * A way to get a path's inherited properties.

That's it, it's really just a small extension of our existing versioned 
property capabilities.  If your own personal vision of inherited properties 
includes something outside of these three bullets (e.g. merging inherited 
properties), then that is outside of this design's scope (at least initially).

== How Is This Design Different? ==
It's not really.  A lot of the ideas here come from the dev list, #svn-dev, and 
conversations with other devs.  The difference, if there is any, is that this 
design aims to be as simple as possible and steer clear of complications which 
have thwarted inheritable properties in the past. If there is more than one 
reasonable behavior to choose from, it usually goes with the one that is 
simpler to explain/understand/implement/maintain.  ''This means that not 
everyone will be happy, it may not cover every use-case, but I hope it covers 
most of them -- pburba.''

== Inheritable Properties Today ==
Subversion has supported merge-tracking using the svn:mergeinfo property since 
the 1.5 release.  The svn:mergeinfo property is inheritable in some 
merge-sensitive contexts, notably 'svn merge', 'svn log -g', and 'svn 
mergeinfo'. For example, say we have this simple branch structure at r700 in 
our repository:

{{{
projX/
projX/branches/
projX/branches/src/
projX/branches/src/foo.c
projX/branches/inc
projX/branches/inc/bar.h
}}}
And suppose the mergeinfo 'projX/trunk:509-612' is set on 'projX/branches'.  If 
we perform a merge targeting  'projX/branches/src/foo.c', the merge logic 
considers the svn:mergeinfo property on this target path to effectively be 
'projX/trunk/src/foo.c:509-612'. However, unlike a true inheritable property 
however, svn:mergeinfo is not inheritable outside of merge-tracking aware" 
contexts.  For example, the propget and proplist subcommands recognize the 
svn:mergeinfo when it is explicitly set on a path, but does not "see" it on 
those paths' descendants:

{{{
>svn pg svn:mergeinfo -v projX/branches Properties on 'projX/branches':
  svn:mergeinfo
    /projX/trunk:509-612

>svn pg svn:mergeinfo -v branches/projX/src/foo.c

>
}}}
= INHERITED PROPERTIES : DESIGN =
== Differentiating Inheritable Vs. 'Normal' Properties ==
Inheritable properties will be identified by a prefix on the property name.

 1. Custom user properties will use the "svn:inheritable:" prefix.
 1. Reserved Subversion inheritable properties will use the "svn:i:" prefix.

== Inheritance Rules ==
Inheritance will be very similar to the current svn:mergeinfo inheritance 
model.  For a given inheritable property 'svn:i:X':

 1. A path '''''with''''' svn:i:X' explicitly set on it never inherits that 
property (i.e. a path can only inherit a property it doesn't have set on 
itself).''''' '''''
 1. A repository path@REV '''''without''''' the 'svn:i:X' property explicitly 
set on it (we'll refer to this as the 'child' path from here on) may inherit 
the property from the path's nearest path-wise ancestor@REV with the 'svn:i:X' 
property explicitly set on it (we'll refer to this as the 'parent' path).
 1. A '''''working copy''''' child path '''''without''''' the 'svn:i:X' 
property explicitly set on it may inherit the property from the path's nearest 
path-wise ancestor in the working copy.
  * For working copies with no switched subtrees, this inheritance can occur 
from any parent path up to the root of the working copy.
  * If the path is located within a switched subtree then the inheritance can 
occur up to the root of the switched subtree.
  * Unlike svn:mergeinfo and like tsvn:auto-props, inheritance across 
mixed-revision boundaries in the working copy is allowed.
  * If a working copy child path doesn't find a parent with 'svn:i:X' that it 
can inherit from before it reaches the working copy (or switched subtree) root, 
then it may inherit the property from the inherited properties cache (see 
below).
 1. Unlike svn:mergeinfo, the property value a child inherits from a parent 
will not be modified based on the path-difference between the parent and child. 
 The property value on the parent is the value the child will inherit.  There 
are no plans to provide an API which reveals the specific parent path a child 
inherits from.
 1. While setting inheritable properties on a file has no meaning from the 
standpoint of inheritance, the property still applies to the file itself.  Thus 
there will be no prohibitions on setting inheritable properties on files.

'''''### TBD: Externals: Do they work like switched subtrees?'''''

== Inherited Properties Cache ==
A child path that inherits a property from its parent may not have ready access 
to that parent in the working copy (e.g. the root of the working copy is a 
subtree of the parent path).  To ensure that traditionally disconnected 
operations (i.e. those that require no access to the repository, like 'svn 
add') remain disconnected, we will maintain a cache of properties inherited by 
the root of the working copy. Whenever a new working copy is checked out, any 
properties inherited by the root of the working copy will be cached in the 
working copy.  If a subtree within a working copy is switched, a separate cache 
will be created for the root of that subtree.  Whenever an update occurs the 
cache(s) will be refreshed.

'''''### TBD: Specifics for the wcng storage of these caches.'''''

== Authentication ==
In exactly the same way that svn:mergeinfo is handled, generic inheritable 
properties can be inherited by any path the user has read access to, even if 
the user has no access to the parent path the inheritable property is 
explicitly set on.

== Copies and Inherited Properties ==
If a child path which inherits a property is copied, the inherited properties 
are not copied with it.  The new destination path inherits properties from its 
new parents.  This means that depending on the copy destination the new path 
may or may not inherit the same property, and even if it does, it may inherit a 
different value. This puts the onus on users to set their inheritable 
properties as close to the root of the repository tree as makes sense for the 
property in question.  Have a property you want to apply to the whole 
repository?  Set it on the root.  Want it to apply only to a single project?  
Set it on the root of the project. Note that if a path has an inheritable 
property '''''explicitly''''' set on it, the property is copied just like any 
other versioned property.

== Merging Inherited Properties ==
It should be clear from reading this far that no concept of 'merging' inherited 
properties is proposed.  If a path has an inheritable property set on it, then 
that property's value is the complete and full value for that path, end of 
story.  Alternatively, if a path inherits a property, the inherited value is 
the complete and full value.  Explicit and inherited property values will not 
be combined in any way. This means, for example, that if a child path inherits 
"svn:inheritable:someprop=SomeVal" from its parent, and you use 'svn propset' 
to set "svn:inheritable:someprop=NewVal" on the child path, then the latter is 
the new value for the child.  The propset command doesn't care that you 
overrode the path's inherited property with an explicit one. It's easy to 
imagine use-cases where it is useful for a path's explicit and inherited 
properties to be merged, or for the inherited properties of a copy source to be 
merged with the copy destination's new inherited properties.  But these depend 
on the purpose of the particular inherited properties.  There is no way to 
develop a one-size-fits-all approach to merging inheritable properties, so any 
support for this needs to be special cased for the particular property in 
question.

== Subcommand Changes ==
In general inherited properties will be treated like any other versioned 
property, so most subcommands will only notice the paths on which explicit 
properties are set, regardless of whether these are inheritable or not.  For 
example, if we have an unmodified working copy and then make a local change to 
a parent path's explicit inheritable property:

 * 'svn status' won't show any property mods on the parent's children paths.
 * 'svn diff' will only show the property difference on the parent path.

The are a few  exceptions to this business-as-usual behavior. A few subcommands 
require some non-user-visible changes:

 * checkout (co): Populates the inherited properties cache.
 * switch (sw): Creates/clears the inherited properties cache for the root of 
the switched/unswitched subtree.
 * update (up): Updates the inherited properties cache(s).
 * upgrade: Creates an empty inherited properties cache, but doesn't populate 
it since that would require contacting the repository which upgrade shouldn't 
need to do.

Two subcommands, propget (pget, pg) and proplist (plist, pl), will support a 
new option enabling users to find inherited properties on a path: 
'--show-inherited-props'.  When used, any inherited properties for the 
'''''target''''' of the subcommand will be displayed.  At operational depths 
greater than empty however, the inherited mergeinfo subtree targets is not 
shown.  For example: Given this repository structure with the explicit 
properties noted:

{{{
/                  svn:inheritable:foo=bar
branches/          svn:inheritable:baz=qux
branches/src/
branches/src/foo.c
branches/inc
branches/inc/bar.h
trunk/
trunk/src/
trunk/src/foo.c
trunk/inc
trunk/inc/bar.h
}}}
Without the --show-inherited-props option only explicit properties are shown 
(as has always been the case):

{{{
>svn pl -vR ^/branches
Properties on '%ROOT_URL%/branches':
  svn:inheritable:baz
    qux

>svn pg -R svn:inheritable:baz ^/
%ROOT_URL%/branches - qux

>svn pg -v svn:inheritable:baz ^/trunk
Properties on '%ROOT_URL%/branches':
  svn:inheritable:foo
    bar

>svn pg svn:inheritable:baz ^/trunk

>
}}}
With the --show-inherited-props option the inherited properties on the target 
are also shown:

{{{
>svn pl -R --show-inherited-props ^/branches
Properties on '%ROOT_URL%/branches':
  svn:inheritable:baz
  svn:inheritable:foo

>svn pg -v --show-inherited-props svn:inheritable:baz ^/trunk
Properties on '%ROOT_URL%/branches':
  svn:inheritable:foo
    bar
}}}
== API Changes ==
{{{
/**
 * Invoke @a receiver with @a receiver_baton to return the regular properties
 * of @a target, a URL or working copy path.  @a receiver will be called
 * for each path encountered.
 *
 * @a target is a WC path or a URL.
 *
 * If @a revision->kind is #svn_opt_revision_unspecified, then get
 * properties from the working copy, if @a target is a working copy
 * path, or from the repository head if @a target is a URL.  Else get
 * the properties as of @a revision.  The actual node revision
 * selected is determined by the path as it exists in @a peg_revision.
 * If @a peg_revision->kind is #svn_opt_revision_unspecified, then it
 * defaults to #svn_opt_revision_head for URLs or
 * #svn_opt_revision_working for WC targets.  Use the authentication
 * baton cached in @a ctx for authentication if contacting the
 * repository.
 *
 * If @a depth is #svn_depth_empty, list only the properties of
 * @a target itself.  If @a depth is #svn_depth_files, and
 * @a target is a directory, list the properties of @a target
 * and its file entries.  If #svn_depth_immediates, list the properties
 * of its immediate file and directory entries.  If #svn_depth_infinity,
 * list the properties of its file entries and recurse (with
 * #svn_depth_infinity) on directory entries.  #svn_depth_unknown is
 * equivalent to #svn_depth_empty.  All other values produce undefined
 * results.
 *
 * @a changelists is an array of <tt>const char *</tt> changelist
 * names, used as a restrictive filter on items whose properties are
 * listed; that is, don't list properties on any item unless it's a member
 * of one of those changelists.  If @a changelists is empty (or
 * altogether @c NULL), no changelist filtering occurs.
 *
 * If @a get_target_inherited_props is true, then also return any inherited
 * properties when @a receiver is called for @a target.  If @a target is a
 * working copy path, then @a target may inherit properties up to the root
 * of the working copy.  If no inherited properties are found up to the
 * root of the working copy, then check the inherited properties cache.
 * If @a target is a URL, then @a target may inherit properties up to the
 * root of the repository. If @a get_target_inherited_props is false, then
 * no inherited properties are returned to @a receiver.
 *
 * If @a target is not found, return the error #SVN_ERR_ENTRY_NOT_FOUND.
 *
 * @since New in 1.8.
 */
svn_error_t *
svn_client_proplist4(const char *target,
                     const svn_opt_revision_t *peg_revision,
                     const svn_opt_revision_t *revision,
                     svn_depth_t depth,
                     const apr_array_header_t *changelists,
                     svn_boolean_t get_target_inherited_props,
                     svn_proplist_receiver_t receiver,
                     void *receiver_baton,
                     svn_client_ctx_t *ctx,
                     apr_pool_t *pool);
}}}
'''''### TBD: Do we want to rev svn_proplist_receiver_t so it can differentiate 
between explicit and inherited properties?'''''

{{{
/**
 * Set @a *props to a hash table whose keys are absolute paths or URLs
 * of items on which property @a propname is set, and whose values are
 * `#svn_string_t *' representing the property value for @a propname
 * at that path.
 *
 * Allocate @a *props, its keys, and its values in @a pool, use
 * @a scratch_pool for temporary allocations.
 *
 * @a target is a WC absolute path or a URL.
 *
 * Don't store any path, not even @a target, if it does not have a
 * property named @a propname.
 *
 * If @a revision->kind is #svn_opt_revision_unspecified, then: get
 * properties from the working copy if @a target is a working copy
 * path, or from the repository head if @a target is a URL.  Else get
 * the properties as of @a revision.  The actual node revision
 * selected is determined by the path as it exists in @a peg_revision.
 * If @a peg_revision->kind is #svn_opt_revision_unspecified, then
 * it defaults to #svn_opt_revision_head for URLs or
 * #svn_opt_revision_working for WC targets.  Use the authentication
 * baton in @a ctx for authentication if contacting the repository.
 * If @a actual_revnum is not @c NULL, the actual revision number used
 * for the fetch is stored in @a *actual_revnum.
 *
 * If @a depth is #svn_depth_empty, fetch the property from
 * @a target only; if #svn_depth_files, fetch from @a target and its
 * file children (if any); if #svn_depth_immediates, from @a target
 * and all of its immediate children (both files and directories); if
 * #svn_depth_infinity, from @a target and everything beneath it.
 *
 * @a changelists is an array of <tt>const char *</tt> changelist
 * names, used as a restrictive filter on items whose properties are
 * gotten; that is, don't get @a propname on any item unless it's a member
 * of one of those changelists.  If @a changelists is empty (or
 * altogether @c NULL), no changelist filtering occurs.
 *
 * If @a get_target_inherited_prop is true, @a propname is an inheritable
 * property, and @a propname is not explicitly set on @a target, then also
 * include the property value (if any) for @a propname which @a target
 * inherits from its nearest parent.  Regardless of whether @a target has
 * @a propname explicitly set on it or inherits that value, the absolute
 * path or URL key in @a *props still corresponds to @a target.
 * If @a target is a working copy path, then @a target may inherit
 * properties up to the root of the working copy.  If no inherited
 * properties are found up to the root of the working copy, then the
 * the inherited properties cache is checked.  If @a target is a URL,
 * then @a target may inherit properties up to the root of the repository.
 * If @a get_target_inherited_props is false, then no inherited properties
 * are included in @a *props.
 *
 * If error, don't touch @a *props, otherwise @a *props is a hash table
 * even if empty.
 *
 * This function returns SVN_ERR_UNVERSIONED_RESOURCE when it is called on
 * unversioned nodes.
 *
 * @since New in 1.8.
 */
svn_error_t *
svn_client_propget5(apr_hash_t **props,
                    const char *propname,
                    const char *target,  /* abspath or URL */
                    const svn_opt_revision_t *peg_revision,
                    const svn_opt_revision_t *revision,
                    svn_revnum_t *actual_revnum,
                    svn_depth_t depth,
                    const apr_array_header_t *changelists,
                    svn_boolean_t get_target_inherited_prop,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *result_pool,
                    apr_pool_t *scratch_pool);

/**
 * If @a dirents is non @c NULL, set @a *dirents to contain all the entries
 * of directory @a path at @a revision.  The keys of @a dirents will be
 * entry names (<tt>const char *</tt>), and the values dirents
 * (<tt>@c svn_dirent_t *</tt>).  Use @a pool for all allocations.
 *
 * @a dirent_fields controls which portions of the <tt>@c svn_dirent_t</tt>
 * objects are filled in.  To have them completely filled in just pass
 * @c SVN_DIRENT_ALL, otherwise pass the bitwise OR of all the @c SVN_DIRENT_
 * fields you would like to have returned to you.
 *
 * @a path is interpreted relative to the URL in @a session.
 *
 * If @a revision is @c SVN_INVALID_REVNUM (meaning 'head') and
 * @a *fetched_rev is not @c NULL, then this function will set
 * @a *fetched_rev to the actual revision that was retrieved.  (Some
 * callers want to know, and some don't.)
 *
 * If @a props is non @c NULL, set @a *props to contain the properties of
 * the directory.  This means @em all properties: not just ones controlled by
 * the user and stored in the repository fs, but non-tweakable ones
 * generated by the SCM system itself (e.g. 'wcprops', 'entryprops',
 * etc.)  The keys are <tt>const char *</tt>, values are
 * <tt>@c svn_string_t *</tt>.
 *
 * If @a get_inherited_props is true and @a props is non @c NULL, then
 * include any props which @a path inherits in @a *props.
 *
 * @since New in 1.8.
 */
svn_error_t *
svn_ra_get_dir3(svn_ra_session_t *session,
                apr_hash_t **dirents,
                svn_revnum_t *fetched_rev,
                apr_hash_t **props,
                const char *path,
                svn_revnum_t revision,
                apr_uint32_t dirent_fields,
                svn_boolean_t get_inherited_props,
                apr_pool_t *pool);

/**
 * Fetch the contents and properties of file @a path at @a revision.
 * @a revision may be SVN_INVALID_REVNUM, indicating that the HEAD
 * revision should be used.  Interpret @a path relative to the URL in
 * @a session.  Use @a pool for all allocations.
 *
 * If @a revision is @c SVN_INVALID_REVNUM and @a fetched_rev is not
 * @c NULL, then set @a *fetched_rev to the actual revision that was
 * retrieved.
 *
 * If @a stream is non @c NULL, push the contents of the file at @a
 * stream, do not call svn_stream_close() when finished.
 *
 * If @a props is non @c NULL, set @a *props to contain the properties of
 * the file.  This means @em all properties: not just ones controlled by
 * the user and stored in the repository fs, but non-tweakable ones
 * generated by the SCM system itself (e.g. 'wcprops', 'entryprops',
 * etc.)  The keys are <tt>const char *</tt>, values are
 * <tt>@c svn_string_t *</tt>.
 *
 * If @a get_inherited_props is true and @a props is non @c NULL, then
 * include any props which @a path inherits in @a *props.
 *
 * The stream handlers for @a stream may not perform any RA
 * operations using @a session.
 *
 * @since New in 1.8.
 */
svn_error_t *
svn_ra_get_file2(svn_ra_session_t *session,
                 const char *path,
                 svn_revnum_t revision,
                 svn_boolean_t get_inherited_props,
                 svn_stream_t *stream,
                 svn_revnum_t *fetched_rev,
                 apr_hash_t **props,
                 apr_pool_t *pool);

/** Set @a *value to the value of property @a name for @a local_abspath,
 * allocating @a *value in @a result_pool.  If no such prop, set @a *value
 * to @c NULL. @a name may be a regular or wc property; if it is an
 * entry property, return the error #SVN_ERR_BAD_PROP_KIND.  @a wc_ctx
 * is used to access the working copy.
 *
 * If @a get_inherited_prop is true, property @a name is not explicitly
 * set on @a local_abspath, and @a name is an inheritable property, then
 * check if property @a name is inherited from a parent path of @a path.
 * If this is the case, set @a *value to the value held by the nearest
 * parent of @a path.  If no parent is found with property @a name, then
 * check the inherited properties cache.
 *
 * If @a local_abspath is not a versioned path, return
 * #SVN_ERR_WC_PATH_NOT_FOUND
 *
 * @since New in 1.8.
 */
svn_error_t *
svn_wc_prop_get3(const svn_string_t **value,
                 svn_wc_context_t *wc_ctx,
                 const char *local_abspath,
                 const char *name,
                 svn_boolean_t get_inherited_prop,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool);

### TBD: Do we want another output argument to indicate if *VALUE inherited or 
not?

/** Set @a *value_p to the value of the property named @a propname of
 * @a path in @a root.  If the node has no property by that name and
 * @a get_inherited_prop is false, then set @a *value_p to zero.  If
 * the node has no property by that name, @a propname is an inheritable
 * property, and @a get_inherited_prop is true, then set @a *value_p to
 * the value (if any) which @a path inherits from its nearest parent.
 *
 * Allocate the result in @a pool.
 *
 * @since New in 1.8.
 */
svn_error_t *
svn_fs_node_prop2(svn_string_t **value_p,
                  svn_fs_root_t *root,
                  const char *path,
                  const char *propname,
                  svn_boolean_t get_inherited_prop,
                  apr_pool_t *pool);


/** Set @a *table_p to the entire property list of @a path in @a root,
 * as an APR hash table allocated in @a pool.  The resulting table maps
 * property names to pointers to #svn_string_t objects containing the
 * property value.  If @a get_inherited_props is true, then any properties
 * inherited by @a path are also included in @a *table_p.
 *
 * @since New in 1.8.
 */
svn_error_t *
svn_fs_node_proplist2(apr_hash_t **table_p,
                      svn_fs_root_t *root,
                      const char *path,
                      svn_boolean_t get_inherited_props,
                      apr_pool_t *pool);
}}}
== New APIs ==
{{{
/** Return @c TRUE iff @a prop_name represents the name of a inheritable
 * property.
 *
 * @since New in 1.8.
 */
svn_boolean_t
svn_prop_is_inheritable_prop(const char *prop_name);
}}}

Reply via email to