pburba_at_tigris.org writes:
> Log:
> Merge the issue-2843 branch back to trunk.
>
> I wasn't able to use reintegrate, see
> http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=145078. So
> this was done the old-fashioned way, with a 2-URL merge:
> http://svn.collab.net/repos/svn/trunk@34105
> http://svn.collab.net/repos/svn/branches/issue-2843-dev@34105.
>
> Note: This merge added mergeinfo on the subversion directory. This
> mergeinfo originated in r31940 on the issue-2843 branch, but there is no
> obvious reason why it was there. r31940 was a merge of r31359-31939 from
> trunk, but there is no mergeinfo diff between those revs, so where this came
> from is a complete mystery. In that light I removed this mergeinfo prior to
> the commit.
Thanks, Paul. I'm pretty sure if I'd tried to get there on my own, I
would have done something even more hackish.
> Added:
> trunk/subversion/libsvn_wc/crop.c
> - copied unchanged from r34105, branches/issue-2843-dev/subversion/libsvn_wc/crop.c
> Modified:
> trunk/ (props changed)
> trunk/build.conf (props changed)
> trunk/subversion/include/ (props changed)
> trunk/subversion/include/private/svn_auth_private.h (props changed)
> trunk/subversion/include/private/svn_cache.h (props changed)
> trunk/subversion/include/svn_wc.h
> trunk/subversion/libsvn_auth_kwallet/kwallet.cpp (props changed)
> trunk/subversion/libsvn_client/commit_util.c
> trunk/subversion/libsvn_client/copy.c
> trunk/subversion/libsvn_client/diff.c
> trunk/subversion/libsvn_client/merge.c
> trunk/subversion/libsvn_client/ra.c
> trunk/subversion/libsvn_client/status.c
> trunk/subversion/libsvn_client/switch.c
> trunk/subversion/libsvn_client/update.c
> trunk/subversion/libsvn_repos/reporter.c
> trunk/subversion/libsvn_subr/ (props changed)
> trunk/subversion/libsvn_wc/README
> trunk/subversion/libsvn_wc/adm_crawler.c
> trunk/subversion/libsvn_wc/adm_ops.c
> trunk/subversion/libsvn_wc/ambient_depth_filter_editor.c
> trunk/subversion/libsvn_wc/copy.c
> trunk/subversion/libsvn_wc/entries.c
> trunk/subversion/libsvn_wc/lock.c
> trunk/subversion/libsvn_wc/log.c
> trunk/subversion/libsvn_wc/props.c
> trunk/subversion/libsvn_wc/relocate.c
> trunk/subversion/libsvn_wc/update_editor.c
> trunk/subversion/svn/main.c
> trunk/subversion/tests/cmdline/depth_tests.py
> trunk/subversion/tests/cmdline/tree_conflict_tests.txt (props changed)
> trunk/subversion/tests/libsvn_subr/ (props changed)
> trunk/tools/buildbot/slaves/win32-xp-VS2005/ (props changed)
> trunk/tools/server-side/svn_server_log_parse.py (props changed)
> trunk/tools/server-side/test_svn_server_log_parse.py (props changed)
> trunk/www/development.html (props changed)
> trunk/www/issue-tracker.html (props changed)
> trunk/www/tasks.html (props changed)
>
> Merged:
> /branches/issue-2843-dev:r31358-34105
>
> Modified: trunk/subversion/include/svn_wc.h
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/include/svn_wc.h?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/include/svn_wc.h Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/include/svn_wc.h Fri Nov 7 19:14:59 2008 (r34108)
> @@ -2070,11 +2070,12 @@ typedef struct svn_wc_entry_t
> #define SVN_WC_ENTRY_THIS_DIR ""
>
>
> -/** Set @a *entry to an entry for @a path, allocated in the access baton
> - * pool. If @a show_hidden is TRUE, return the entry even if it's in
> - * 'deleted' or 'absent' state. If @a path is not under revision
> - * control, or if entry is hidden, not scheduled for re-addition,
> - * and @a show_hidden is @c FALSE, then set @a *entry to @c NULL.
> +/** Set @a *entry to an entry for @a path, allocated in the access baton pool.
> + * If @a show_hidden is TRUE, return the entry even if it's in 'excluded',
> + * 'deleted' or 'absent' state. Excluded entries are those with their depth
> + * set to @c svn_depth_exclude. If @a path is not under revision control, or
> + * if entry is hidden, not scheduled for re-addition, and @a show_hidden is @c
> + * FALSE, then set @a *entry to @c NULL.
> *
> * @a *entry should not be modified, since doing so modifies the entries
> * cache in @a adm_access without changing the entries file on disk.
> @@ -2109,9 +2110,10 @@ svn_wc_entry(const svn_wc_entry_t **entr
> * baton (that's how the entries caching works). @a pool is used for
> * transient allocations.
> *
> - * Entries that are in a 'deleted' or 'absent' state (and not
> + * Entries that are in a 'excluded', 'deleted' or 'absent' state (and not
> * scheduled for re-addition) are not returned in the hash, unless
> - * @a show_hidden is TRUE.
> + * @a show_hidden is TRUE. Excluded entries are those with their depth set to
> + * @c svn_depth_exclude.
> *
> * @par Important:
> * The @a entries hash is the entries cache in @a adm_access
> @@ -2258,9 +2260,10 @@ typedef struct svn_wc_entry_callbacks_t
> * If @a cancel_func is non-NULL, call it with @a cancel_baton to determine
> * if the client has cancelled the operation.
> *
> - * Like our other entries interfaces, entries that are in a 'deleted'
> - * or 'absent' state (and not scheduled for re-addition) are not
> - * discovered, unless @a show_hidden is TRUE.
> + * Like our other entries interfaces, entries that are in a 'excluded',
> + * 'deleted' or 'absent' state (and not scheduled for re-addition) are not
> + * discovered, unless @a show_hidden is TRUE. Excluded entries are those with
> + * their depth set to @c svn_depth_exclude.
> *
> * When a new directory is entered, @c SVN_WC_ENTRY_THIS_DIR will always
> * be returned first.
> @@ -3618,6 +3621,23 @@ svn_wc_process_committed(const char *pat
> * course. If @a depth is @c svn_depth_unknown, then just use
> * @c svn_depth_infinity, which in practice means depth of @a path.
> *
> + * Iff @a honor_depth_exclude is TRUE, the crawler will report paths
> + * whose ambient depth is @c svn_depth_exclude as being excluded, and
> + * thus prevent the server from pushing update data for those paths;
> + * therefore, don't set this flag if you wish to pull in excluded paths.
> + * Note that @c svn_depth_exclude on the target @a path is never
> + * honored, even if @a honor_depth_exclude is TRUE, because we need to
> + * be able to explicitly pull in a target. For example, if this is
> + * the working copy...
> + *
> + * svn co greek_tree_repos wc_dir
> + * svn up --set-depth exclude wc_dir/A/B/E # now A/B/E is excluded
> + *
> + * ...then 'svn up wc_dir/A/B' would report E as excluded (assuming
> + * @a honor_depth_exclude is TRUE), but 'svn up wc_dir/A/B/E' would
> + * not, because the latter is trying to explicitly pull in E. In
> + * general, we never report the update target as excluded.
> + *
> * Iff @a depth_compatibility_trick is TRUE, then set the @c start_empty
> * flag on @a reporter->set_path() and @a reporter->link_path() calls
> * as necessary to trick a pre-1.5 (i.e., depth-unaware) server into
> @@ -3636,7 +3656,28 @@ svn_wc_process_committed(const char *pat
> * state in it. (Caller should obtain @a traversal_info from
> * svn_wc_init_traversal_info().)
> *
> - * @since New in 1.5.
> + * @since New in 1.6.
> + */
> +svn_error_t *
> +svn_wc_crawl_revisions4(const char *path,
> + svn_wc_adm_access_t *adm_access,
> + const svn_ra_reporter3_t *reporter,
> + void *report_baton,
> + svn_boolean_t restore_files,
> + svn_depth_t depth,
> + svn_boolean_t honor_depth_exclude,
> + svn_boolean_t depth_compatibility_trick,
> + svn_boolean_t use_commit_times,
> + svn_wc_notify_func2_t notify_func,
> + void *notify_baton,
> + svn_wc_traversal_info_t *traversal_info,
> + apr_pool_t *pool);
> +
> +/**
> + * Similar to svn_wc_crawl_revisions4, but with @a honor_depth_exclude always
> + * set to false.
> + *
> + * @deprecated Provided for compatibility with the 1.5 API.
> */
> svn_error_t *
> svn_wc_crawl_revisions3(const char *path,
> @@ -5262,6 +5303,46 @@ svn_wc_set_changelist(const char *path,
> void *notify_baton,
> apr_pool_t *pool);
>
> +/** Crop @a target according to @a depth.
> + *
> + * Remove any item that exceeds the boundary of @a depth (relative to
> + * @a target) from revision control. Leave modified items behind
> + * (unversioned), while removing unmodified ones completely.
> + *
> + * If @a target starts out with a shallower depth than @a depth, do not
> + * upgrade it to @a depth (that would not be cropping); however, do
> + * check children and crop them appropriately according to @a depth.
> + *
> + * Returns immediately with no error if @a target is not a directory,
> + * or if @a depth is not restrictive (e.g., @c svn_depth_infinity).
> + *
> + * @a anchor is an access baton, with a tree lock, for the local path to the
> + * working copy which will be used as the root of this operation. If
> + * @a target is not empty, it represents an entry in the @a anchor path;
> + * otherwise, the @a anchor path is the target. @a target may not be
> + * @c NULL.
> + *
> + * If @a cancel_func is not @c NULL, call it with @a cancel_baton at
> + * various points to determine if the client has cancelled the operation.
> + *
> + * If @a notify_func is not @c NULL, call it with @a notify_baton to
> + * report changes as they are made.
> + *
> + * @note: svn_depth_exclude currently does nothing; passing it results
> + * in immediate success with no side effects.
> + *
> + * @since New in 1.6
> + */
> +svn_error_t *
> +svn_wc_crop_tree(svn_wc_adm_access_t *anchor,
> + const char *target,
> + svn_depth_t depth,
> + svn_wc_notify_func2_t notify_func,
> + void *notify_baton,
> + svn_cancel_func_t cancel_func,
> + void *cancel_baton,
> + apr_pool_t *pool);
> +
> /** @} */
>
> /** Set @a *tree_conflict to a newly allocated @c
>
> Modified: trunk/subversion/libsvn_client/commit_util.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_client/commit_util.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_client/commit_util.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_client/commit_util.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -561,6 +561,11 @@ harvest_committables(apr_hash_t *committ
> continue;
>
> this_entry = val;
> +
> + /* Skip the excluded item. */
> + if (this_entry->depth == svn_depth_exclude)
> + continue;
> +
> name_uri = svn_path_uri_encode(name, loop_pool);
>
> full_path = svn_path_join(path, name, loop_pool);
> @@ -1271,7 +1276,11 @@ do_item_commit(void **dir_baton,
> }
> }
>
> - SVN_ERR(svn_wc_entry(&tmp_entry, item->path, adm_access, TRUE, pool));
> + /* Ensured by harvest_commitables(), item->path will never be an
> + excluded path. However, will it be deleted/absent items? I think
> + committing an modification on a deleted/absent item does not make
> + sense. So it's probably safe to turn off the show_hidden flag here.*/
> + SVN_ERR(svn_wc_entry(&tmp_entry, item->path, adm_access, FALSE, pool));
>
> /* When committing a directory that no longer exists in the
> repository, a "not found" error does not occur immediately
>
> Modified: trunk/subversion/libsvn_client/copy.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_client/copy.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_client/copy.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_client/copy.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -1615,13 +1615,28 @@ repos_to_wc_copy(const apr_array_header_
>
> svn_pool_clear(iterpool);
>
> - SVN_ERR(svn_wc_entry(&ent, pair->dst, adm_access, FALSE, iterpool));
> - if (ent && (ent->kind != svn_node_dir) &&
> - (ent->schedule != svn_wc_schedule_delete))
> - return svn_error_createf
> - (SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
> - _("Entry for '%s' exists (though the working file is missing)"),
> - svn_path_local_style(pair->dst, pool));
> + SVN_ERR(svn_wc_entry(&ent, pair->dst, adm_access, TRUE, iterpool));
> + if (ent)
> + {
> + /* TODO(#2843): Rework the error report. Maybe we can simplify the
> + condition. Currently, the first is about hidden items and the
> + second is for missing items. */
> + if (ent->depth == svn_depth_exclude
> + || ent->absent)
> + {
> + return svn_error_createf
> + (SVN_ERR_ENTRY_EXISTS,
> + NULL, _("'%s' is already under version control"),
> + svn_path_local_style(pair->dst, pool));
> + }
> + else if ((ent->kind != svn_node_dir) &&
> + (ent->schedule != svn_wc_schedule_delete)
> + && ! ent->deleted)
> + return svn_error_createf
> + (SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
> + _("Entry for '%s' exists (though the working file is missing)"),
> + svn_path_local_style(pair->dst, pool));
> + }
> }
>
> /* Decide whether the two repositories are the same or not. */
>
> Modified: trunk/subversion/libsvn_client/diff.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_client/diff.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_client/diff.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_client/diff.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -1352,9 +1352,9 @@ diff_repos_wc(const char *path1,
>
> /* Create a txn mirror of path2; the diff editor will print
> diffs in reverse. :-) */
> - SVN_ERR(svn_wc_crawl_revisions3(path2, dir_access,
> + SVN_ERR(svn_wc_crawl_revisions4(path2, dir_access,
> reporter, report_baton,
> - FALSE, depth, (! server_supports_depth),
> + FALSE, depth, TRUE, (! server_supports_depth),
> FALSE, NULL, NULL, /* notification is N/A */
> NULL, pool));
>
>
> Modified: trunk/subversion/libsvn_client/merge.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_client/merge.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_client/merge.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_client/merge.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -155,7 +155,7 @@ check_scheme_match(svn_wc_adm_access_t *
> const svn_wc_entry_t *ent;
> const char *idx1, *idx2;
>
> - SVN_ERR(svn_wc_entry(&ent, path, adm_access, TRUE, pool));
> + SVN_ERR(svn_wc_entry(&ent, path, adm_access, FALSE, pool));
>
> idx1 = strchr(url, ':');
> idx2 = strchr(ent->url, ':');
> @@ -3917,6 +3917,8 @@ get_mergeinfo_walk_cb(const char *path,
> !svn_path_compare_paths(path, wb->merge_target_path);
> const char *parent_path = svn_path_dirname(path, pool);
>
> + /* TODO(#2843) How to deal with a excluded item on merge? */
> +
> /* We're going to receive dirents twice; we want to ignore the
> first one (where it's a child of a parent dir), and only use
> the second one (where we're looking at THIS_DIR). The exception
>
> Modified: trunk/subversion/libsvn_client/ra.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_client/ra.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_client/ra.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_client/ra.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -416,6 +416,9 @@ svn_client_uuid_from_path(const char **u
> }
> else
> {
> + /* Excluded path will fall into this code branch, since the missed
> + fields in the entry for excluded path is not filled. But it is just
> + ok. */
> return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
> _("'%s' has no URL"),
> svn_path_local_style(path, pool));
>
> Modified: trunk/subversion/libsvn_client/status.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_client/status.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_client/status.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_client/status.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -358,9 +358,9 @@ svn_client_status4(svn_revnum_t *result_
> within PATH. When we call reporter->finish_report,
> EDITOR will be driven to describe differences between our
> working copy and HEAD. */
> - SVN_ERR(svn_wc_crawl_revisions3(path, target_access,
> + SVN_ERR(svn_wc_crawl_revisions4(path, target_access,
> &lock_fetch_reporter, &rb, FALSE,
> - depth, (! server_supports_depth),
> + depth, TRUE, (! server_supports_depth),
> FALSE, NULL, NULL, NULL, pool));
> }
> }
>
> Modified: trunk/subversion/libsvn_client/switch.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_client/switch.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_client/switch.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_client/switch.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -92,6 +92,11 @@ svn_client__switch_internal(svn_revnum_t
> if (depth == svn_depth_unknown)
> depth_is_sticky = FALSE;
>
> + /* Do not support the situation of both exclude and switch a target. */
> + if (depth_is_sticky && depth == svn_depth_exclude)
> + return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
> + _("Can not both exclude and switch a path"));
> +
> /* Get the external diff3, if any. */
> svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS,
> SVN_CONFIG_OPTION_DIFF3_CMD, NULL);
> @@ -166,6 +171,15 @@ svn_client__switch_internal(svn_revnum_t
> "is not the same repository as\n"
> "'%s'"), URL, source_root);
>
> + /* We may need to crop the tree if the depth is sticky */
> + if (depth_is_sticky && depth < svn_depth_infinity)
> + {
> + SVN_ERR(svn_wc_crop_tree(adm_access, target, depth,
> + ctx->notify_func2, ctx->notify_baton2,
> + ctx->cancel_func, ctx->cancel_baton,
> + pool));
> + }
> +
> SVN_ERR(svn_ra_reparent(ra_session, URL, pool));
>
> /* Fetch the switch (update) editor. If REVISION is invalid, that's
> @@ -196,8 +210,9 @@ svn_client__switch_internal(svn_revnum_t
> We pass NULL for traversal_info because this is a switch, not an
> update, and therefore we don't want to handle any externals
> except the ones directly affected by the switch. */
> - err = svn_wc_crawl_revisions3(path, dir_access, reporter, report_baton,
> - TRUE, depth, (! server_supports_depth),
> + err = svn_wc_crawl_revisions4(path, dir_access, reporter, report_baton,
> + TRUE, depth, (! depth_is_sticky),
> + (! server_supports_depth),
> use_commit_times,
> ctx->notify_func2, ctx->notify_baton2,
> NULL, /* no traversal info */
>
> Modified: trunk/subversion/libsvn_client/update.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_client/update.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_client/update.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_client/update.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -127,7 +127,11 @@ svn_client__update_internal(svn_revnum_t
> ### lock the entire tree when we don't actually need to, that's a
> ### performance hit, but (except for access contention) it is not
> ### a correctness problem. */
> - levels_to_lock = SVN_WC__LEVELS_TO_LOCK_FROM_DEPTH(depth);
> +
> + /* We may have to crop the subtree if the depth is sticky, so lock the
> + entire tree in such a situation*/
> + levels_to_lock = depth_is_sticky
> + ? -1 : SVN_WC__LEVELS_TO_LOCK_FROM_DEPTH(depth);
>
> /* Sanity check. Without this, the update is meaningless. */
> SVN_ERR_ASSERT(path);
> @@ -151,6 +155,21 @@ svn_client__update_internal(svn_revnum_t
> _("Entry '%s' has no URL"),
> svn_path_local_style(anchor, pool));
>
> + /* We may need to crop the tree if the depth is sticky */
> + if (depth_is_sticky && depth < svn_depth_infinity)
> + {
> + SVN_ERR(svn_wc_crop_tree(adm_access, target, depth,
> + ctx->notify_func2, ctx->notify_baton2,
> + ctx->cancel_func, ctx->cancel_baton,
> + pool));
> + /* If we are asked to exclude a target, we can just stop now. */
> + if (depth == svn_depth_exclude)
> + {
> + SVN_ERR(svn_wc_adm_close2(adm_access, pool));
> + return SVN_NO_ERROR;
> + }
> + }
> +
> /* Get revnum set to something meaningful, so we can fetch the
> update editor. */
> if (revision->kind == svn_opt_revision_number)
> @@ -232,8 +251,9 @@ svn_client__update_internal(svn_revnum_t
> /* Drive the reporter structure, describing the revisions within
> PATH. When we call reporter->finish_report, the
> update_editor will be driven by svn_repos_dir_delta2. */
> - err = svn_wc_crawl_revisions3(path, dir_access, reporter, report_baton,
> - TRUE, depth, (! server_supports_depth),
> + err = svn_wc_crawl_revisions4(path, dir_access, reporter, report_baton,
> + TRUE, depth, (! depth_is_sticky),
> + (! server_supports_depth),
> use_commit_times,
> ctx->notify_func2, ctx->notify_baton2,
> traversal_info, pool);
>
> Modified: trunk/subversion/libsvn_repos/reporter.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_repos/reporter.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_repos/reporter.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_repos/reporter.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -1017,7 +1017,10 @@ delta_dirs(report_baton_t *b, svn_revnum
>
> /* Don't revisit this name in the target or source entries. */
> apr_hash_set(t_entries, name, APR_HASH_KEY_STRING, NULL);
> - if (s_entries)
> + if (s_entries
> + /* Keep the entry for later process if it is reported as
> + excluded and got deleted in repos. */
> + && (! info || info->depth != svn_depth_exclude || t_entry))
> apr_hash_set(s_entries, name, APR_HASH_KEY_STRING, NULL);
>
> /* pathinfo entries live in their own subpools due to lookahead,
>
> Modified: trunk/subversion/libsvn_wc/README
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/README?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/README Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/README Fri Nov 7 19:14:59 2008 (r34108)
> @@ -503,6 +503,13 @@ depth:
> entries and pulls new entries with depth infinity as well.
> Default is infinite (`').
>
> + Apart from above normal values, there is still a special `exclude',
> + which means the directory is excluded from wc even if the depth of
> + parent directory is infinity or immediates. The directory in
> + question will not physically exist on the disk. In other words, we
> + can only store the `exclude' value in the corresponding entry of
> + the entries file in parent directory.
> +
> tree-conflicts:
> A list of details of the tree conflicts that children are currently
> suffering. This is only allowed on the this_dir entry.
> @@ -519,8 +526,9 @@ file-external:
>
> The only fields allowed in an entry for a directory (other than the
> this_dir entry) are name, absent, deleted, schedule, copied,
> -copyfrom-url, copyfrom-rev and kind. The other fields are only stored
> -in the this_dir entry for the directory in question.
> +copyfrom-url, copyfrom-rev, kind and depth (only when the value says
> +exclude). The other fields are only stored in the this_dir entry for
> +the directory in question.
>
>
> XML-based entries format
>
> Modified: trunk/subversion/libsvn_wc/adm_crawler.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/adm_crawler.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/adm_crawler.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/adm_crawler.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -179,6 +179,7 @@ report_revisions_and_depths(svn_wc_adm_a
> void *notify_baton,
> svn_boolean_t restore_files,
> svn_depth_t depth,
> + svn_boolean_t honor_depth_exclude,
> svn_boolean_t depth_compatibility_trick,
> svn_boolean_t report_everything,
> svn_boolean_t use_commit_times,
> @@ -272,6 +273,39 @@ report_revisions_and_depths(svn_wc_adm_a
> continue;
> }
>
> + if (current_entry->depth == svn_depth_exclude)
> + {
> + if (honor_depth_exclude)
> + {
> + /* Report the excluded path, no matter whether report_everything
> + flag is set. Because the report_everything flag indicates
> + that the server will treate the wc as empty and thus push
> + full content of the files/subdirs. But we want to prevent the
> + server from pushing the full content of this_path at us. */
> +
> + /* The server does not support link_path report on excluded
> + path. We explicitly prohibit this situation in
> + svn_wc_crop_tree(). */
> + SVN_ERR(reporter->set_path(report_baton,
> + this_path,
> + dir_rev,
> + svn_depth_exclude,
> + FALSE,
> + NULL,
> + iterpool));
> + }
> + else
> + {
> + /* We want to pull in the excluded target. So, report it as deleted,
> + and server will respond properly. */
> + if (! report_everything)
> + SVN_ERR(reporter->delete_path(report_baton,
> + this_path, iterpool));
> + }
> +
> + continue;
> + }
> +
> /* Is the entry on disk? Set a flag if not. */
> dirent = apr_hash_get(dirents, key, klen);
> if (! dirent)
> @@ -452,6 +486,7 @@ report_revisions_and_depths(svn_wc_adm_a
> reporter, report_baton,
> notify_func, notify_baton,
> restore_files, depth,
> + honor_depth_exclude,
> depth_compatibility_trick,
> start_empty,
> use_commit_times,
> @@ -472,12 +507,13 @@ report_revisions_and_depths(svn_wc_adm_a
>
>
> svn_error_t *
> -svn_wc_crawl_revisions3(const char *path,
> +svn_wc_crawl_revisions4(const char *path,
> svn_wc_adm_access_t *adm_access,
> const svn_ra_reporter3_t *reporter,
> void *report_baton,
> svn_boolean_t restore_files,
> svn_depth_t depth,
> + svn_boolean_t honor_depth_exclude,
> svn_boolean_t depth_compatibility_trick,
> svn_boolean_t use_commit_times,
> svn_wc_notify_func2_t notify_func,
> @@ -501,6 +537,16 @@ svn_wc_crawl_revisions3(const char *path
> if ((! entry) || ((entry->schedule == svn_wc_schedule_add)
> && (entry->kind == svn_node_dir)))
> {
> + /* Don't check the exclude flag for the target.
> +
> + If we report the target itself as excluded, the server will
> + send us nothing about the target -- but we want to permit
> + targets to be explicitly pulled in. For example, 'svn up A'
> + should always work, even if its parent is svn_depth_empty or
> + svn_depth_files, or even if A was explicitly excluded from a
> + parent at svn_depth_immediates or svn_depth_infinity.
> + Whatever the case, we want A back now. */
> +
> /* There aren't any versioned paths to crawl which are known to
> the repository. */
> SVN_ERR(svn_wc__entry_versioned(&parent_entry,
> @@ -582,6 +628,7 @@ svn_wc_crawl_revisions3(const char *path
> reporter, report_baton,
> notify_func, notify_baton,
> restore_files, depth,
> + honor_depth_exclude,
> depth_compatibility_trick,
> start_empty,
> use_commit_times,
> @@ -673,6 +720,34 @@ svn_wc_crawl_revisions3(const char *path
> return err;
> }
>
> +svn_error_t *
> +svn_wc_crawl_revisions3(const char *path,
> + svn_wc_adm_access_t *adm_access,
> + const svn_ra_reporter3_t *reporter,
> + void *report_baton,
> + svn_boolean_t restore_files,
> + svn_depth_t depth,
> + svn_boolean_t depth_compatibility_trick,
> + svn_boolean_t use_commit_times,
> + svn_wc_notify_func2_t notify_func,
> + void *notify_baton,
> + svn_wc_traversal_info_t *traversal_info,
> + apr_pool_t *pool)
> +{
> + return svn_wc_crawl_revisions4(path,
> + adm_access,
> + reporter, report_baton,
> + restore_files,
> + depth,
> + FALSE,
> + depth_compatibility_trick,
> + use_commit_times,
> + notify_func,
> + notify_baton,
> + traversal_info,
> + pool);
> +}
> +
> /*** Copying stream ***/
>
> /* A copying stream is a bit like the unix tee utility:
>
> Modified: trunk/subversion/libsvn_wc/adm_ops.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/adm_ops.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/adm_ops.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/adm_ops.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -125,10 +125,11 @@ tweak_entries(svn_wc_adm_access_t *dirpa
> excluded = (apr_hash_get(exclude_paths, child_path,
> APR_HASH_KEY_STRING) != NULL);
>
> - /* If a file, or deleted or absent dir, then tweak the entry
> - but don't recurse. */
> + /* If a file, or deleted, excluded or absent dir, then tweak the
> + entry but don't recurse. */
> if ((current_entry->kind == svn_node_file)
> - || (current_entry->deleted || current_entry->absent))
> + || (current_entry->deleted || current_entry->absent
> + || current_entry->depth == svn_depth_exclude))
> {
> if (! excluded)
> SVN_ERR(svn_wc__tweak_entry(entries, name,
> @@ -235,7 +236,9 @@ svn_wc__do_update_cleanup(const char *pa
> return SVN_NO_ERROR;
>
> if (entry->kind == svn_node_file
> - || (entry->kind == svn_node_dir && (entry->deleted || entry->absent)))
> + || (entry->kind == svn_node_dir
> + && (entry->deleted || entry->absent
> + || entry->depth == svn_depth_exclude)))
> {
> const char *parent, *base_name;
> svn_wc_adm_access_t *dir_access;
> @@ -517,6 +520,12 @@ process_committed_internal(int *log_numb
> if (! strcmp(name, SVN_WC_ENTRY_THIS_DIR))
> continue;
>
> + /* We come to this branch since we have committed a copied tree.
> + svn_depth_exclude is possible in this situation. So check and
> + skip */
> + if (current_entry->depth == svn_depth_exclude)
> + continue;
> +
> /* Create child path by telescoping the main path. */
> this_path = svn_path_join(path, name, subpool);
>
> @@ -1172,6 +1181,8 @@ svn_wc_delete3(const char *path,
> /* The deleted state is only available in the entry in parent's
> entries file */
> SVN_ERR(svn_wc_adm_retrieve(&parent_access, adm_access, parent, pool));
> + /* We don't need to check for excluded item, since we won't fall into
> + this code path in that case. */
> SVN_ERR(svn_wc_entries_read(&entries, parent_access, TRUE, pool));
> entry_in_parent = apr_hash_get(entries, base_name, APR_HASH_KEY_STRING);
> was_deleted = entry_in_parent ? entry_in_parent->deleted : FALSE;
> @@ -1359,12 +1370,15 @@ svn_wc_add3(const char *path,
> that is slated for deletion from revision control, or has been
> previously 'deleted', unless, of course, you're specifying an
> addition with -history-; then it's okay for the object to be
> - under version control already; it's not really new. */
> + under version control already; it's not really new.
> + Also, if the target is recorded as excluded from wc, it really
> + exists in repos. Report error on this situation too. */
> if (orig_entry)
> {
> - if ((! copyfrom_url)
> + if (((! copyfrom_url)
> && (orig_entry->schedule != svn_wc_schedule_delete)
> && (! orig_entry->deleted))
> + || (orig_entry->depth == svn_depth_exclude))
> {
> return svn_error_createf
> (SVN_ERR_ENTRY_EXISTS, NULL,
> @@ -2019,6 +2033,8 @@ revert_entry(svn_depth_t *depth,
> "directory; please try again from the "
> "parent directory"));
>
> + /* We don't need to check for excluded item, since we won't fall
> + into this code path in that case. */
> SVN_ERR(svn_wc_entries_read(&entries, parent_access, TRUE, pool));
> parents_entry = apr_hash_get(entries, basey, APR_HASH_KEY_STRING);
> if (parents_entry)
> @@ -2104,6 +2120,8 @@ revert_entry(svn_depth_t *depth,
> svn_wc_entry_t *entry_in_parent;
> apr_hash_t *entries;
>
> + /* The entry to revert will not be an excluded item. Don't
> + bother check for it. */
> SVN_ERR(svn_wc_entries_read(&entries, parent_access, TRUE,
> pool));
> entry_in_parent = apr_hash_get(entries, bname,
> @@ -2517,11 +2535,12 @@ svn_wc_remove_from_revision_control(svn_
> current_entry_name,
> subpool);
>
> - if (svn_wc__adm_missing(adm_access, entrypath))
> + if (svn_wc__adm_missing(adm_access, entrypath)
> + || current_entry->depth == svn_depth_exclude)
> {
> - /* The directory is already missing, so don't try to
> - recurse, just delete the entry in the parent
> - directory. */
> + /* The directory is either missing or excluded,
> + so don't try to recurse, just delete the
> + entry in the parent directory. */
> svn_wc__entry_remove(entries, current_entry_name);
> }
> else
> @@ -2567,6 +2586,7 @@ svn_wc_remove_from_revision_control(svn_
> full_path. We need to remove that entry: */
> if (! is_root)
> {
> + svn_wc_entry_t *dir_entry;
> apr_hash_t *parent_entries;
> svn_wc_adm_access_t *parent_access;
>
> @@ -2576,8 +2596,19 @@ svn_wc_remove_from_revision_control(svn_
> parent_dir, pool));
> SVN_ERR(svn_wc_entries_read(&parent_entries, parent_access, TRUE,
> pool));
> - svn_wc__entry_remove(parent_entries, base_name);
> - SVN_ERR(svn_wc__entries_write(parent_entries, parent_access, pool));
> +
> + /* An exception: When the path is at svn_depth_exclude,
> + the entry in the parent directory should be preserved
> + for bookkeeping purpose. This only happens when the
> + function is called by svn_wc_crop_tree(). */
> + dir_entry = apr_hash_get(parent_entries, base_name,
> + APR_HASH_KEY_STRING);
> + if (dir_entry->depth != svn_depth_exclude)
> + {
> + svn_wc__entry_remove(parent_entries, base_name);
> + SVN_ERR(svn_wc__entries_write(parent_entries, parent_access, pool));
> +
> + }
> }
> }
>
>
> Modified: trunk/subversion/libsvn_wc/ambient_depth_filter_editor.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/ambient_depth_filter_editor.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/ambient_depth_filter_editor.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/ambient_depth_filter_editor.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -132,19 +132,32 @@ make_dir_baton(struct dir_baton **d_p,
> if (path)
> d->path = svn_path_join(d->path, path, pool);
>
> - if (pb
> - && (pb->ambient_depth == svn_depth_empty
> - || pb->ambient_depth == svn_depth_files))
> + /* The svn_depth_unknown means that: 1) pb is the anchor; 2) there
> + is an non-null target, for which we are preparing the baton.
> + This enables explicitly pull in the target. */
> + if (pb && pb->ambient_depth != svn_depth_unknown)
> {
> - /* This is not a depth upgrade, and the parent directory is
> - depth==empty or depth==files. So if the parent doesn't
> - already have an entry for the new dir, then the parent
> - doesn't want the new dir at all, thus we should initialize
> - it with ambiently_excluded=TRUE. */
> const svn_wc_entry_t *entry;
> + svn_boolean_t exclude;
>
> - SVN_ERR(svn_wc_entry(&entry, d->path, eb->adm_access, FALSE, pool));
> - if (! entry)
> + SVN_ERR(svn_wc_entry(&entry, d->path, eb->adm_access, TRUE, pool));
> + if (pb->ambient_depth == svn_depth_empty
> + || pb->ambient_depth == svn_depth_files)
> + {
> + /* This is not a depth upgrade, and the parent directory is
> + depth==empty or depth==files. So if the parent doesn't
> + already have an entry for the new dir, then the parent
> + doesn't want the new dir at all, thus we should initialize
> + it with ambiently_excluded=TRUE. */
> + exclude = (entry == NULL);
> + }
> + else
> + {
> + /* If the parent expect all children by default, only exclude
> + it whenever it is explicitly marked as exclude. */
> + exclude = (entry && (entry->depth == svn_depth_exclude));
> + }
> + if (exclude)
> {
> d->ambiently_excluded = TRUE;
> *d_p = d;
>
> Modified: trunk/subversion/libsvn_wc/copy.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/copy.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/copy.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/copy.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -267,6 +267,10 @@ copy_added_dir_administratively(const ch
> SVN_ERR(svn_wc_entry(&entry, src_fullpath, src_child_dir_access,
> TRUE, subpool));
>
> + /* We do not need to handle excluded items here, since this function
> + only deal with the sources which are not yet in the repos.
> + Exclude flag is by definition not expected in such situation. */
> +
> /* Recurse on directories; add files; ignore the rest. */
> if (this_entry.filetype == APR_DIR)
> {
> @@ -647,6 +651,9 @@ post_copy_cleanup(svn_wc_adm_access_t *a
> kind = entry->kind;
> deleted = entry->deleted;
>
> + if (entry->depth == svn_depth_exclude)
> + continue;
> +
> /* Convert deleted="true" into schedule="delete" for all
> children (and grandchildren, if RECURSE is set) of the path
> represented by ADM_ACCESS. The result of this is that when
> @@ -862,8 +869,8 @@ svn_wc_copy2(const char *src_path,
> {
> svn_wc_adm_access_t *adm_access;
> svn_node_kind_t src_kind;
> - const char *dst_path;
> - const svn_wc_entry_t *dst_entry, *src_entry;
> + const char *dst_path, *target_path;
> + const svn_wc_entry_t *dst_entry, *src_entry, *target_entry;
>
> SVN_ERR(svn_wc_adm_probe_open3(&adm_access, NULL, src_path, FALSE, -1,
> cancel_func, cancel_baton, pool));
> @@ -888,6 +895,21 @@ svn_wc_copy2(const char *src_path,
> _("Cannot copy to '%s' as it is scheduled for deletion"),
> svn_path_local_style(svn_wc_adm_access_path(dst_parent), pool));
>
> + /* TODO(#2843): Rework the erroer report. */
> + /* Check if the copy target is missing or hidden and thus not exist on the
> + disk, before actually doing the file copy. */
> + target_path = svn_path_join(dst_path, dst_basename, pool);
> + SVN_ERR(svn_wc_entry(&target_entry, target_path, dst_parent, TRUE, pool));
> + if (target_entry
> + && ((target_entry->depth == svn_depth_exclude)
> + || target_entry->absent))
> + {
> + return svn_error_createf
> + (SVN_ERR_ENTRY_EXISTS,
> + NULL, _("'%s' is already under version control"),
> + svn_path_local_style(target_path, pool));
> + }
> +
> SVN_ERR(svn_io_check_path(src_path, &src_kind, pool));
>
> if (src_kind == svn_node_file)
>
> Copied: trunk/subversion/libsvn_wc/crop.c (from r34105, branches/issue-2843-dev/subversion/libsvn_wc/crop.c)
> ==============================================================================
> --- /dev/null 00:00:00 1970 (empty, because file is newly added)
> +++ trunk/subversion/libsvn_wc/crop.c Fri Nov 7 19:14:59 2008 (r34108, copy of r34105, branches/issue-2843-dev/subversion/libsvn_wc/crop.c)
> @@ -0,0 +1,320 @@
> +/*
> + * crop.c: Cropping the WC
> + *
> + * ====================================================================
> + * Copyright (c) 2000-2007 CollabNet. All rights reserved.
> + *
> + * This software is licensed as described in the file COPYING, which
> + * you should have received as part of this distribution. The terms
> + * are also available at http://subversion.tigris.org/license-1.html.
> + * If newer versions of this license are posted there, you may use a
> + * newer version instead, at your option.
> + *
> + * This software consists of voluntary contributions made by many
> + * individuals. For exact contribution history, see the revision
> + * history and logs, available at http://subversion.tigris.org/.
> + * ====================================================================
> + */
> +
> +/* ==================================================================== */
> +
> +#include "svn_wc.h"
> +#include "lock.h"
> +#include "svn_pools.h"
> +#include "svn_error.h"
> +#include "svn_client.h"
> +#include "svn_error_codes.h"
> +#include "svn_path.h"
> +#include "entries.h"
> +
> +#include "svn_private_config.h"
> +
> +/* Evaluate EXPR. If it returns an error, return that error, unless
> + the error's code is SVN_ERR_WC_LEFT_LOCAL_MOD, in which case clear
> + the error and do not return. */
> +#define IGNORE_LOCAL_MOD(expr) \
> + do { \
> + svn_error_t *__temp = (expr); \
> + if (__temp) \
> + { \
> + if (__temp->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD) \
> + svn_error_clear(__temp); \
> + else \
> + return __temp; \
> + } \
> + } while (0)
> +
> +/* Helper function that crops the children of the DIR_PATH, under the constraint
> + * of DEPTH. The DIR_PATH itself will never be cropped. The ADM_ACCESS is the
> + * access baton that contains DIR_PATH. And the whole subtree should have been
> + * locked.
> + *
> + * If NOTIFY_FUNC is not null, each file and ROOT of subtree will be reported
> + * upon remove.
> + */
> +static svn_error_t *
> +crop_children(svn_wc_adm_access_t *adm_access,
> + const char *dir_path,
> + svn_depth_t depth,
> + svn_wc_notify_func2_t notify_func,
> + void *notify_baton,
> + svn_cancel_func_t cancel_func,
> + void *cancel_baton,
> + apr_pool_t *pool)
> +{
> + apr_hash_t *entries;
> + apr_hash_index_t *hi;
> + svn_wc_adm_access_t *dir_access;
> + svn_wc_entry_t *dot_entry;
> + apr_pool_t *subpool = svn_pool_create(pool), *iterpool;
> +
> + SVN_ERR(svn_wc_adm_retrieve(&dir_access, adm_access, dir_path, subpool));
> + SVN_ERR(svn_wc_entries_read(&entries, dir_access, TRUE, subpool));
> + dot_entry = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR,
> + APR_HASH_KEY_STRING);
> +
> + /* Update the depth of target first, if needed. */
> + if (dot_entry->depth > depth)
> + {
> + dot_entry->depth = depth;
> + SVN_ERR(svn_wc__entries_write(entries, dir_access, subpool));
> + }
> +
> + /* Looping over current directory's SVN entries: */
> + iterpool = svn_pool_create(subpool);
> +
> + for (hi = apr_hash_first(subpool, entries); hi; hi = apr_hash_next(hi))
> + {
> + const void *key;
> + const char *this_path;
> + void *val;
> + apr_ssize_t klen;
> + svn_wc_entry_t *current_entry;
> + svn_pool_clear(iterpool);
> +
> + /* Get the next entry */
> + apr_hash_this(hi, &key, &klen, &val);
> + if (! strcmp(key, SVN_WC_ENTRY_THIS_DIR))
> + continue;
> +
> + current_entry = val;
> + this_path = svn_path_join(dir_path, current_entry->name, iterpool);
> +
> + if (current_entry->kind == svn_node_file)
> + {
> + /* We currently crop on a directory basis. So don't worry about
> + svn_depth_exclude here. And even we permit excluding a single
> + file in the future, svn_wc_remove_from_revision_control() can
> + also handle it. We only need to skip the notification in that
> + case. */
> + if (depth == svn_depth_empty)
> + IGNORE_LOCAL_MOD
> + (svn_wc_remove_from_revision_control(dir_access,
> + current_entry->name,
> + TRUE, /* destroy */
> + FALSE, /* instant error */
> + cancel_func,
> + cancel_baton,
> + iterpool));
> + else
> + continue;
> +
> + }
> + else if (current_entry->kind == svn_node_dir)
> + {
> + if (current_entry->depth == svn_depth_exclude)
> + {
> + /* Preserve the excluded entry if the parent need it.
> + Anyway, don't report on excluded subdir, since they are
> + logically not exist. */
> + if (depth < svn_depth_immediates)
> + {
> + svn_wc__entry_remove(entries, current_entry->name);
> + SVN_ERR(svn_wc__entries_write(entries, dir_access, iterpool));
> + }
> + continue;
> + }
> + else if (depth < svn_depth_immediates)
> + {
> + svn_wc_adm_access_t *child_access;
> + SVN_ERR(svn_wc_adm_retrieve(&child_access, dir_access,
> + this_path, iterpool));
> +
> + IGNORE_LOCAL_MOD
> + (svn_wc_remove_from_revision_control(child_access,
> + SVN_WC_ENTRY_THIS_DIR,
> + TRUE, /* destroy */
> + FALSE, /* instant error */
> + cancel_func,
> + cancel_baton,
> + iterpool));
> + }
> + else
> + {
> + SVN_ERR(crop_children(dir_access,
> + this_path,
> + svn_depth_empty,
> + notify_func,
> + notify_baton,
> + cancel_func,
> + cancel_baton,
> + iterpool));
> + continue;
> + }
> + }
> + else
> + {
> + return svn_error_createf
> + (SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("Unknown entry kind for '%s'"),
> + svn_path_local_style(this_path, pool));
> + }
> +
> + if (notify_func)
> + {
> + svn_wc_notify_t *notify;
> + notify = svn_wc_create_notify(this_path,
> + svn_wc_notify_delete,
> + iterpool);
> + (*notify_func)(notify_baton, notify, iterpool);
> + }
> + }
> +
> + svn_pool_destroy(subpool);
> +
> + return SVN_NO_ERROR;
> +}
> +
> +svn_error_t *
> +svn_wc_crop_tree(svn_wc_adm_access_t *anchor,
> + const char *target,
> + svn_depth_t depth,
> + svn_wc_notify_func2_t notify_func,
> + void *notify_baton,
> + svn_cancel_func_t cancel_func,
> + void *cancel_baton,
> + apr_pool_t *pool)
> +{
> + const svn_wc_entry_t *entry;
> + const char *full_path;
> + svn_wc_adm_access_t *dir_access;
> +
> + /* Only makes sense when the depth is restrictive. */
> + if (!(depth >= svn_depth_exclude && depth < svn_depth_infinity))
> + return SVN_NO_ERROR;
> +
> + /* Only makes sense to crop a dir target. */
> + full_path = svn_path_join(svn_wc_adm_access_path(anchor), target, pool);
> + SVN_ERR(svn_wc_entry(&entry, full_path, anchor, FALSE, pool));
> + if (!entry || entry->kind != svn_node_dir)
> + return SVN_NO_ERROR;
> +
> + /* Don't bother to crop if the target is scheduled delete. */
> + if (entry->schedule == svn_wc_schedule_delete)
> + return svn_error_createf
> + (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
> + _("Cannot crop '%s': it is going to be removed from repository."
> + " Try commit instead."),
> + svn_path_local_style(full_path, pool));
> +
> + /* Crop the target itself if we are requested to. */
> + if (depth == svn_depth_exclude)
> + {
> + svn_boolean_t switched, entry_in_repos;
> + const svn_wc_entry_t *parent_entry = NULL;
> + svn_wc_adm_access_t *p_access;
> +
> + /* Safeguard on bad target. */
> + if (*full_path == 0)
> + return svn_error_createf
> + (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
> + _("Cannot exclude current directory."));
> +
> + if (svn_dirent_is_root(full_path, strlen(full_path)))
> + return svn_error_createf
> + (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
> + _("Cannot exclude root directory."));
> +
> + /* This simulates the logic of svn_wc_is_wc_root(). */
> + {
> + const char *bname, *pname;
> + svn_error_t *err = NULL;
> + svn_path_split(full_path, &pname, &bname, pool);
> + SVN_ERR(svn_wc__adm_retrieve_internal(&p_access, anchor, pname,
> + pool));
> + if (! p_access)
> + err = svn_wc_adm_probe_open3(&p_access, NULL, pname, FALSE, 0,
> + NULL, NULL, pool);
> +
> + if (! err)
> + err = svn_wc_entry(&parent_entry, pname, p_access, FALSE, pool);
> +
> + if (err)
> + svn_error_clear(err);
> +
> + switched
> + = parent_entry && strcmp(entry->url,
> + svn_path_url_add_component
> + (parent_entry->url, bname, pool));
> +
> + /* The server simply do not accept excluded link_path and thus
> + switched path can not be excluede. Just completely prohibit this
> + situation. */
> + if (switched)
> + return svn_error_createf
> + (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
> + _("Cannot crop '%s': it is a switched path."),
> + svn_path_local_style(full_path, pool));
> + }
> +
> + /* If the target entry is just added without history, it does not exist
> + in the repos (in which case we won't exclude it). */
> + entry_in_repos
> + = ! ((entry->schedule == svn_wc_schedule_add
> + || entry->schedule == svn_wc_schedule_replace)
> + && ! entry->copied);
> +
> + /* Mark the target as excluded, if the parent requires it by
> + default. */
> + if (parent_entry && entry_in_repos
> + && (parent_entry->depth > svn_depth_files))
> + {
> + svn_wc_entry_t *target_entry;
> + apr_hash_t *parent_entries;
> + SVN_ERR(svn_wc_entries_read(&parent_entries, p_access,
> + FALSE, pool));
> +
> + target_entry = apr_hash_get(parent_entries,
> + svn_path_basename(full_path, pool),
> + APR_HASH_KEY_STRING);
> +
> + target_entry->depth = svn_depth_exclude;
> + SVN_ERR(svn_wc__entries_write(parent_entries, anchor, pool));
> + }
> +
> + /* TODO(#2843): Do we need to restore the modified depth if the user
> + cancel this operation? */
> + SVN_ERR(svn_wc_adm_retrieve(&dir_access, anchor, full_path, pool));
> + IGNORE_LOCAL_MOD
> + (svn_wc_remove_from_revision_control(dir_access,
> + SVN_WC_ENTRY_THIS_DIR,
> + TRUE, /* destroy */
> + FALSE, /* instant error */
> + cancel_func,
> + cancel_baton,
> + pool));
> +
> + if (notify_func)
> + {
> + svn_wc_notify_t *notify;
> + notify = svn_wc_create_notify(full_path,
> + svn_wc_notify_delete,
> + pool);
> + (*notify_func)(notify_baton, notify, pool);
> + }
> + return SVN_NO_ERROR;
> + }
> +
> + return crop_children(anchor, full_path, depth,
> + notify_func, notify_baton,
> + cancel_func, cancel_baton, pool);
> +}
>
> Modified: trunk/subversion/libsvn_wc/entries.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/entries.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/entries.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/entries.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -667,9 +667,29 @@ read_entry(svn_wc_entry_t **new_entry,
> const char *result;
> SVN_ERR(read_val(&result, buf, end));
> if (result)
> - entry->depth = svn_depth_from_word(result);
> + {
> + svn_boolean_t invalid;
> + svn_boolean_t is_this_dir;
> +
> + entry->depth = svn_depth_from_word(result);
> +
> + /* Verify the depth value:
> + THIS_DIR should not have an excluded value and SUB_DIR should only
> + have excluded value. Remember that infinity value is not stored and
> + should not show up here. Otherwise, something bad may have
> + happened. However, infinity value itself will always be okay. */
> + is_this_dir = !name;
> + /* '!=': XOR */
> + invalid = is_this_dir != (entry->depth != svn_depth_exclude);
> + if (entry->depth != svn_depth_infinity && invalid)
> + return svn_error_createf
> + (SVN_ERR_ENTRY_ATTRIBUTE_INVALID, NULL,
> + _("Entry '%s' has invalid depth"),
> + (name ? name : SVN_WC_ENTRY_THIS_DIR));
> + }
> else
> entry->depth = svn_depth_infinity;
> +
> }
> MAYBE_DONE;
>
> @@ -1415,8 +1435,12 @@ read_entries(svn_wc_adm_access_t *adm_ac
>
> ++curp;
> ++entryno;
> - if (!entry_is_hidden(entry) || show_hidden)
> - apr_hash_set(entries, entry->name, APR_HASH_KEY_STRING, entry);
> +
> + if ((entry->depth != svn_depth_exclude)
> + || (!entry_is_hidden(entry) || show_hidden))
> + {
> + apr_hash_set(entries, entry->name, APR_HASH_KEY_STRING, entry);
> + }
> }
> }
>
> @@ -1877,7 +1901,9 @@ write_entry(svn_stringbuf_t *buf,
> }
>
> /* Depth. */
> - if (is_subdir || entry->depth == svn_depth_infinity)
> + /* Accept `exclude' for subdir entry. */
> + if ((is_subdir && entry->depth != svn_depth_exclude)
> + || entry->depth == svn_depth_infinity)
> {
> write_val(buf, NULL, 0);
> }
> @@ -3266,7 +3292,7 @@ svn_wc_walk_entries3(const char *path,
> svn_path_local_style(path, pool)),
> walk_baton, pool);
>
> - if (entry->kind == svn_node_file)
> + if (entry->kind == svn_node_file || entry->depth == svn_depth_exclude)
> return walk_callbacks->handle_error
> (path, walk_callbacks->found_entry(path, entry, walk_baton, pool),
> walk_baton, pool);
>
> Modified: trunk/subversion/libsvn_wc/lock.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/lock.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/lock.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/lock.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -698,6 +698,11 @@ do_open(svn_wc_adm_access_t **adm_access
> if (entry->kind != svn_node_dir
> || ! strcmp(entry->name, SVN_WC_ENTRY_THIS_DIR))
> continue;
> +
> + /* Also skip the excluded subdir. */
> + if (entry->depth == svn_depth_exclude)
> + continue;
> +
> entry_path = svn_path_join(path, entry->name, subpool);
>
> /* Don't use the subpool pool here, the lock needs to persist */
> @@ -1595,7 +1600,7 @@ prune_deleted(svn_wc_adm_access_t *adm_a
> if ((entry->deleted
> && (entry->schedule != svn_wc_schedule_add)
> && (entry->schedule != svn_wc_schedule_replace))
> - || entry->absent)
> + || entry->absent || (entry->depth == svn_depth_exclude))
> break;
> }
>
> @@ -1618,7 +1623,8 @@ prune_deleted(svn_wc_adm_access_t *adm_a
>
> apr_hash_this(hi, &key, NULL, &val);
> entry = val;
> - if (((entry->deleted == FALSE) && (entry->absent == FALSE))
> + if (((entry->deleted == FALSE) && (entry->absent == FALSE)
> + && (entry->depth != svn_depth_exclude))
> || (entry->schedule == svn_wc_schedule_add)
> || (entry->schedule == svn_wc_schedule_replace))
> {
>
> Modified: trunk/subversion/libsvn_wc/log.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/log.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/log.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/log.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -1003,7 +1003,8 @@ remove_deleted_entry(void *baton, const
> const svn_wc_entry_t *cur_entry = val;
> svn_wc_adm_access_t *entry_access;
>
> - /* Skip each entry that isn't scheduled for deletion. */
> + /* Skip each entry that isn't scheduled for deletion. This gracefully
> + includes excluded item. */
> if (cur_entry->schedule != svn_wc_schedule_delete)
> return SVN_NO_ERROR;
>
> @@ -1163,7 +1164,7 @@ log_do_committed(struct log_runner *logg
> SVN_ERR(svn_wc_entry(&parentry,
> svn_wc_adm_access_path(loggy->adm_access),
> loggy->adm_access,
> - TRUE, pool));
> + FALSE, pool));
> if (new_rev > parentry->revision)
> {
> /* ...then the parent's revision is now officially a
>
> Modified: trunk/subversion/libsvn_wc/props.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/props.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/props.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/props.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -480,7 +480,10 @@ svn_wc__working_props_committed(const ch
> svn_wc_adm_access_t *mod_access;
>
>
> - SVN_ERR(svn_wc__entry_versioned(&entry, path, adm_access, TRUE, pool));
> + /* The path is ensured not an excluded path. */
> + /* TODO(#2843) It seems that there is no need to
> + reveal hidden entry here? */
> + SVN_ERR(svn_wc__entry_versioned(&entry, path, adm_access, FALSE, pool));
>
> SVN_ERR(svn_wc__prop_path(&working, path, entry->kind,
> svn_wc__props_working, FALSE, pool));
> @@ -831,7 +834,9 @@ svn_wc__loggy_revert_props_create(svn_st
> const char *tmp_rprop;
> svn_node_kind_t kind;
>
> - SVN_ERR(svn_wc__entry_versioned(&entry, path, adm_access, TRUE, pool));
> + /* TODO(#2843) The current caller ensures that PATH will not be an excluded
> + item. But do we really need show_hidden = TRUE here? */
> + SVN_ERR(svn_wc__entry_versioned(&entry, path, adm_access, FALSE, pool));
>
> SVN_ERR(svn_wc__prop_path(&dst_rprop, path,
> entry->kind, svn_wc__props_revert, FALSE, pool));
> @@ -941,7 +946,9 @@ svn_wc__loggy_revert_props_restore(svn_s
> const svn_wc_entry_t *entry;
> const char *revert_file, *base_file;
>
> - SVN_ERR(svn_wc__entry_versioned(&entry, path, adm_access, TRUE, pool));
> + /* TODO(#2843) The current caller ensures that PATH will not be an excluded
> + item. But do we really need show_hidden = TRUE here? */
> + SVN_ERR(svn_wc__entry_versioned(&entry, path, adm_access, FALSE, pool));
>
> SVN_ERR(svn_wc__prop_path(&base_file, path, entry->kind, svn_wc__props_base,
> FALSE, pool));
> @@ -2212,10 +2219,10 @@ svn_wc_prop_list(apr_hash_t **props,
> {
> const svn_wc_entry_t *entry;
>
> - SVN_ERR(svn_wc_entry(&entry, path, adm_access, TRUE, pool));
> + SVN_ERR(svn_wc_entry(&entry, path, adm_access, FALSE, pool));
>
> /* if there is no entry, 'path' is not under version control and
> - therefore has no props */
> + therefore has no props. */
> if (! entry)
> {
> *props = apr_hash_make(pool);
> @@ -2263,7 +2270,7 @@ svn_wc_prop_get(const svn_string_t **val
> enum svn_prop_kind kind = svn_property_kind(NULL, name);
> const svn_wc_entry_t *entry;
>
> - SVN_ERR(svn_wc_entry(&entry, path, adm_access, TRUE, pool));
> + SVN_ERR(svn_wc_entry(&entry, path, adm_access, FALSE, pool));
>
> if (entry == NULL)
> {
> @@ -2817,7 +2824,7 @@ modified_props(svn_boolean_t *modified_p
> if (want_props)
> *which_props = apr_hash_make(pool);
>
> - SVN_ERR(svn_wc_entry(&entry, path, adm_access, TRUE, subpool));
> + SVN_ERR(svn_wc_entry(&entry, path, adm_access, FALSE, subpool));
>
> /* If we have no entry, we can't have any prop mods. */
> if (! entry)
>
> Modified: trunk/subversion/libsvn_wc/relocate.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/relocate.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/relocate.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/relocate.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -128,7 +128,8 @@ svn_wc_relocate3(const char *path,
> if (! entry)
> return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, NULL, NULL);
>
> - if (entry->kind == svn_node_file)
> + if (entry->kind == svn_node_file
> + || entry->depth == svn_depth_exclude)
> return relocate_entry(adm_access, entry, from, to,
> validator, validator_baton, TRUE /* sync */,
> pool);
> @@ -160,7 +161,8 @@ svn_wc_relocate3(const char *path,
>
> if (recurse && (entry->kind == svn_node_dir)
> && (! entry->deleted || (entry->schedule == svn_wc_schedule_add))
> - && ! entry->absent)
> + && ! entry->absent
> + && (entry->depth != svn_depth_exclude))
> {
> svn_wc_adm_access_t *subdir_access;
> const char *subdir = svn_path_join(path, key, subpool);
>
> Modified: trunk/subversion/libsvn_wc/update_editor.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/update_editor.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/libsvn_wc/update_editor.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/libsvn_wc/update_editor.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -549,6 +549,13 @@ make_dir_baton(struct dir_baton **d_p,
> }
>
>
> +/* Forward declaration. */
> +static svn_error_t *
> +do_entry_deletion(struct edit_baton *eb,
> + const char *parent_path,
> + const char *path,
> + int *log_number,
> + apr_pool_t *pool);
>
> /* Helper for maybe_bump_dir_info():
>
> @@ -574,7 +581,41 @@ complete_directory(struct edit_baton *eb
> /* If this is the root directory and there is a target, we can't
> mark this directory complete. */
> if (is_root_dir && *eb->target)
> - return SVN_NO_ERROR;
> + {
> + /* Before we can finish, we may need to clear the exclude flag for
> + target. Also give a chance to the target that is explicitly pulled
> + in. */
> + if (eb->depth_is_sticky || *eb->target)
> + {
> + svn_wc_adm_access_t *target_access;
> + SVN_ERR(svn_wc_adm_retrieve(&adm_access,
> + eb->adm_access, path, pool));
> + SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE, pool));
> + entry = apr_hash_get(entries, eb->target, APR_HASH_KEY_STRING);
> + if (entry && entry->depth == svn_depth_exclude)
> + {
> + char * full_target;
> + /* There is a small chance that the target is gone in the
> + repository. If so, we should get rid of the entry
> + (and thus get rid of the exclude flag) now. */
> + full_target = svn_path_join(eb->anchor, eb->target, pool);
> + SVN_ERR(svn_wc__adm_retrieve_internal
> + (&target_access, eb->adm_access, full_target, pool));
> + if (!target_access && entry->kind == svn_node_dir)
> + {
> + int log_number = 0;
> + SVN_ERR(do_entry_deletion(eb, eb->anchor, eb->target,
> + &log_number, pool));
> + }
> + else
> + {
> + entry->depth = svn_depth_infinity;
> + SVN_ERR(svn_wc__entries_write(entries, adm_access, pool));
> + }
> + }
> + }
> + return SVN_NO_ERROR;
> + }
>
> /* All operations are on the in-memory entries hash. */
> SVN_ERR(svn_wc_adm_retrieve(&adm_access, eb->adm_access, path, pool));
> @@ -642,21 +683,27 @@ complete_directory(struct edit_baton *eb
> {
> const char *child_path = svn_path_join(path, name, subpool);
>
> - if ((svn_wc__adm_missing(adm_access, child_path))
> - && (! current_entry->absent)
> - && (current_entry->schedule != svn_wc_schedule_add))
> + if (current_entry->depth == svn_depth_exclude)
> {
> - svn_wc__entry_remove(entries, name);
> - if (eb->notify_func)
> - {
> - svn_wc_notify_t *notify
> - = svn_wc_create_notify(child_path,
> - svn_wc_notify_update_delete,
> - subpool);
> - notify->kind = current_entry->kind;
> - (* eb->notify_func)(eb->notify_baton, notify, subpool);
> - }
> - }
> + /* Clear the exclude flag if it is pulled in again. */
> + if (eb->depth_is_sticky
> + && eb->requested_depth >= svn_depth_immediates)
> + current_entry->depth = svn_depth_infinity;
> + } else if ((svn_wc__adm_missing(adm_access, child_path))
> + && (! current_entry->absent)
> + && (current_entry->schedule != svn_wc_schedule_add))
> + {
> + svn_wc__entry_remove(entries, name);
> + if (eb->notify_func)
> + {
> + svn_wc_notify_t *notify
> + = svn_wc_create_notify(child_path,
> + svn_wc_notify_update_delete,
> + subpool);
> + notify->kind = current_entry->kind;
> + (* eb->notify_func)(eb->notify_baton, notify, subpool);
> + }
> + }
> }
> }
>
> @@ -1469,7 +1516,20 @@ do_entry_deletion(struct edit_baton *eb,
> SVN_ERR(svn_wc_adm_retrieve(&adm_access, eb->adm_access,
> parent_path, pool));
>
> - SVN_ERR(svn_wc__entry_versioned(&entry, full_path, adm_access, FALSE, pool));
> + SVN_ERR(svn_wc__entry_versioned(&entry, full_path, adm_access, TRUE, pool));
> +
> + /* Receive the remote removal of excluded entry. Do not notify. */
> + if (entry->depth == svn_depth_exclude)
> + {
> + apr_hash_t *entries;
> + const char *base_name = svn_path_basename(full_path, pool);
> + SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE, pool));
> + svn_wc__entry_remove(entries, base_name);
> + SVN_ERR(svn_wc__entries_write(entries, adm_access, pool));
> + if (strcmp(path, eb->target) == 0)
> + eb->target_deleted = TRUE;
> + return SVN_NO_ERROR;
> + }
>
> SVN_ERR(check_tree_conflict(&tree_conflict, eb, log_item, full_path, entry,
> adm_access, svn_wc_conflict_action_delete, pool));
> @@ -3890,41 +3950,25 @@ make_editor(svn_revnum_t *target_revisio
> inner_editor = tree_editor;
> inner_baton = eb;
>
> - /* If our requested depth is sticky, we'll raise an error if asked
> - to make our target more shallow, which is currently unsupported.
> -
> - Otherwise, if our requested depth is *not* sticky, then we need
> - to limit the scope of our operation to the ambient depths present
> - in the working copy already. If a depth was explicitly
> - requested, libsvn_delta/depth_filter_editor.c will ensure that we
> - never see editor calls that extend beyond the scope of the
> - requested depth. But even what we do so might extend beyond the
> - scope of our ambient depth. So we use another filtering editor
> - to avoid modifying the ambient working copy depth when not asked
> - to do so. (This can also be skipped if the server understands
> - consider letting the depth RA capability percolate down to this
> - level.) */
> - if (depth_is_sticky)
> - {
> - const svn_wc_entry_t *target_entry;
> - SVN_ERR(svn_wc_entry(&target_entry, svn_path_join(anchor, target, pool),
> - adm_access, FALSE, pool));
> - if (target_entry && (target_entry->depth > depth))
> - return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
> - _("Shallowing of working copy depths is not "
> - "yet supported"));
> - }
> - else
> - {
> - SVN_ERR(svn_wc__ambient_depth_filter_editor(&inner_editor,
> - &inner_baton,
> - inner_editor,
> - inner_baton,
> - anchor,
> - target,
> - adm_access,
> - pool));
> - }
> + /* We need to limit the scope of our operation to the ambient depths
> + present in the working copy already, but only if the requested
> + depth is not sticky. If a depth was explicitly requested,
> + libsvn_delta/depth_filter_editor.c will ensure that we never see
> + editor calls that extend beyond the scope of the requested depth.
> + But even what we do so might extend beyond the scope of our
> + ambient depth. So we use another filtering editor to avoid
> + modifying the ambient working copy depth when not asked to do so.
> + (This can also be skipped if the server understands depth; consider
> + letting the depth RA capability percolate down to this level.) */
> + if (!depth_is_sticky)
> + SVN_ERR(svn_wc__ambient_depth_filter_editor(&inner_editor,
> + &inner_baton,
> + inner_editor,
> + inner_baton,
> + anchor,
> + target,
> + adm_access,
> + pool));
>
> return svn_delta_get_cancellation_editor(cancel_func,
> cancel_baton,
>
> Modified: trunk/subversion/svn/main.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/svn/main.c?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/svn/main.c Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/svn/main.c Fri Nov 7 19:14:59 2008 (r34108)
> @@ -1317,13 +1317,13 @@ main(int argc, const char *argv[])
> _("Error converting depth "
> "from locale to UTF8")), pool, "svn: ");
> opt_state.set_depth = svn_depth_from_word(utf8_opt_arg);
> - if (opt_state.set_depth == svn_depth_unknown
> - || opt_state.set_depth == svn_depth_exclude)
> + /* svn_depth_exclude is okay for --set-depth. */
> + if (opt_state.set_depth == svn_depth_unknown)
> {
> return svn_cmdline_handle_exit_error
> (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
> _("'%s' is not a valid depth; try "
> - "'empty', 'files', 'immediates', "
> + "'exclude', 'empty', 'files', 'immediates', "
> "or 'infinity'"),
> utf8_opt_arg), pool, "svn: ");
> }
>
> Modified: trunk/subversion/tests/cmdline/depth_tests.py
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/tests/cmdline/depth_tests.py?pathrev=34108&r1=34107&r2=34108
> ==============================================================================
> --- trunk/subversion/tests/cmdline/depth_tests.py Fri Nov 7 15:41:58 2008 (r34107)
> +++ trunk/subversion/tests/cmdline/depth_tests.py Fri Nov 7 19:14:59 2008 (r34108)
> @@ -1450,7 +1450,6 @@ def depthy_update_above_dir_to_be_delete
> #----------------------------------------------------------------------
>
> # Tests for deselection interface (a.k.a folding subtrees).
> -# XFail until issue #2843 is resolved.
> #----------------------------------------------------------------------
> def depth_folding_clean_trees_1(sbox):
> "gradually fold wc from depth=infinity to empty"
> @@ -1474,15 +1473,16 @@ def depth_folding_clean_trees_1(sbox):
> A_path = os.path.join(wc_dir, 'A')
> C_path = os.path.join(A_path, 'C')
> B_path = os.path.join(A_path, 'B')
> + D_path = os.path.join(A_path, 'D')
> E_path = os.path.join(B_path, 'E')
> F_path = os.path.join(B_path, 'F')
> - D_path = os.path.join(A_path, 'D')
> - H_path = os.path.join(A_path, 'H')
> + G_path = os.path.join(D_path, 'G')
> + H_path = os.path.join(D_path, 'H')
>
> # Run 'svn up --set-depth=immediates' to directory A/B/E.
> # This is an infinity=>immediates folding, changes on metadata only
> expected_output = svntest.wc.State(wc_dir, {})
> - expected_status = svntest.actions.get_virginal_state('', 1)
> + expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
> expected_disk = svntest.main.greek_state.copy()
> svntest.actions.run_and_verify_update(wc_dir,
> expected_output,
> @@ -1645,8 +1645,8 @@ def depth_folding_clean_trees_1(sbox):
> expected_status,
> None, None,
> None, None, None, None,
> - '--set-depth', 'files')
> - verify_depth(None, "files")
> + '--set-depth', 'files', wc_dir)
> + verify_depth(None, "files", wc_dir)
>
>
> #------------------------------------------------------------------------------
> @@ -1675,7 +1675,8 @@ def depth_folding_clean_trees_2(sbox):
> verify_depth(None, "immediates", A_path)
>
> # pull in directory D at infinity
> - svntest.actions.run_and_verify_svn(None, None, [], 'up', D_path)
> + svntest.actions.run_and_verify_svn(None, None, [],
> + 'up', '--set-depth', 'infinity', D_path)
>
> # Run 'svn up --set-depth=immediates' to directory A/D.
> # This is an infinity=>immediates folding
> @@ -1699,7 +1700,7 @@ def depth_folding_clean_trees_2(sbox):
> 'A/D/G' : Item(status=' ', wc_rev=1),
> 'A/D/H' : Item(status=' ', wc_rev=1)
> })
> - expected_disk = svntest.wc.State(wc_dir, {
> + expected_disk = svntest.wc.State('', {
> 'iota' : Item(contents="This is the file 'iota'.\n"),
> 'A' : Item(contents=None),
> 'A/mu' : Item(contents="This is the file 'mu'.\n"),
> @@ -1708,7 +1709,7 @@ def depth_folding_clean_trees_2(sbox):
> 'A/D' : Item(contents=None),
> 'A/D/gamma' : Item(contents="This is the file 'gamma'.\n"),
> 'A/D/G' : Item(contents=None),
> - 'A/D/H' : Item(contents=None)
> + 'A/D/H' : Item(contents=None),
> })
> svntest.actions.run_and_verify_update(wc_dir,
> expected_output,
> @@ -1742,20 +1743,14 @@ def depth_folding_clean_trees_2(sbox):
>
> # pull in directory D at infinity
> svntest.actions.run_and_verify_svn(None, None, [],
> - 'up', D_path)
> + 'up', '--set-depth', 'infinity', D_path)
>
> # Run 'svn up --set-depth=immediates' to directory A.
> # This is an mixed(immediates+infinity)=>immediates folding
> expected_output = svntest.wc.State(wc_dir, {
> 'A/D/gamma' : Item(status='D '),
> 'A/D/G' : Item(status='D '),
> - 'A/D/G/pi' : Item(status='D '),
> - 'A/D/G/rho' : Item(status='D '),
> - 'A/D/G/tau' : Item(status='D '),
> 'A/D/H' : Item(status='D '),
> - 'A/D/H/chi' : Item(status='D '),
> - 'A/D/H/psi' : Item(status='D '),
> - 'A/D/H/omega' : Item(status='D ')
> })
> svntest.actions.run_and_verify_update(wc_dir,
> expected_output,
> @@ -1769,7 +1764,7 @@ def depth_folding_clean_trees_2(sbox):
>
> # pull in directory D at files
> svntest.actions.run_and_verify_svn(None, None, [],
> - 'up', '--depth', 'files', D_path)
> + 'up', '--set-depth', 'files', D_path)
>
> # Run 'svn up --set-depth=immediates' to directory A.
> # This is an mixed(immediates+files)=>immediates folding
> @@ -1786,30 +1781,30 @@ def depth_folding_clean_trees_2(sbox):
> verify_depth(None, "immediates", A_path)
> verify_depth(None, "empty", D_path)
>
> - # Run 'svn up --set-depth=empty' to directory A.
> - # This is an immediates=>empty folding, the directory A should be deleted
> - # too since the parent directory is at files/empty
> - expected_output = svntest.wc.State(wc_dir, {
> - 'A' : Item(status='D '),
> - 'A/mu' : Item(status='D '),
> - 'A/D' : Item(status='D '),
> - 'A/C' : Item(status='D '),
> - 'A/B' : Item(status='D ')
> - })
> - expected_status = svntest.wc.State(wc_dir, {
> - '' : Item(status=' ', wc_rev=1),
> - 'iota' : Item(status=' ', wc_rev=1)
> - })
> - expected_disk = svntest.wc.State(wc_dir, {
> - 'iota' : Item(contents="This is the file 'iota'.\n")
> - })
> - svntest.actions.run_and_verify_update(wc_dir,
> - expected_output,
> - expected_disk,
> - expected_status,
> - None, None,
> - None, None, None, None,
> - '--set-depth', 'empty', A_path)
> +# Comment the following out, since cropping out the root of tree is now
> +# handled by svn_depth_exclude and should have a separate test case for all
> +# influenced commands.
> +#
> +# # Run 'svn up --set-depth=empty' to directory A.
> +# # This is an immediates=>empty folding, the directory A should be deleted
> +# # too since the parent directory is at files/empty
> +# expected_output = svntest.wc.State(wc_dir, {
> +# 'A' : Item(status='D '),
> +# })
> +# expected_status = svntest.wc.State(wc_dir, {
> +# '' : Item(status=' ', wc_rev=1),
> +# 'iota' : Item(status=' ', wc_rev=1)
> +# })
> +# expected_disk = svntest.wc.State('', {
> +# 'iota' : Item(contents="This is the file 'iota'.\n")
> +# })
> +# svntest.actions.run_and_verify_update(wc_dir,
> +# expected_output,
> +# expected_disk,
> +# expected_status,
> +# None, None,
> +# None, None, None, None,
> +# '--set-depth', 'empty', A_path)
>
> def depth_fold_expand_clean_trees(sbox):
> "expand target while contracting subtree"
> @@ -1844,13 +1839,7 @@ def depth_fold_expand_clean_trees(sbox):
> 'A/C' : Item(status='A '),
> 'A/D/gamma' : Item(status='D '),
> 'A/D/G' : Item(status='D '),
> - 'A/D/G/pi' : Item(status='D '),
> - 'A/D/G/rho' : Item(status='D '),
> - 'A/D/G/tau' : Item(status='D '),
> 'A/D/H' : Item(status='D '),
> - 'A/D/H/chi' : Item(status='D '),
> - 'A/D/H/psi' : Item(status='D '),
> - 'A/D/H/omega' : Item(status='D ')
> })
> expected_status = svntest.wc.State(wc_dir, {
> '' : Item(status=' ', wc_rev=1),
> @@ -1860,7 +1849,7 @@ def depth_fold_expand_clean_trees(sbox):
> 'A/C' : Item(status=' ', wc_rev=1),
> 'A/D' : Item(status=' ', wc_rev=1)
> })
> - expected_disk = svntest.wc.State(wc_dir, {
> + expected_disk = svntest.wc.State('', {
> 'A' : Item(contents=None),
> 'A/mu' : Item(contents="This is the file 'mu'.\n"),
> 'A/B' : Item(contents=None),
> @@ -1881,25 +1870,16 @@ def depth_fold_expand_clean_trees(sbox):
>
> # Run 'svn up --set-depth=files' to directory A in other_wc. This both
> # removes directory D and expands directory A to files
> - expected_output = svntest.wc.State(wc_dir, {
> + expected_output = svntest.wc.State(other_wc, {
> 'A/mu' : Item(status='A '),
> 'A/D' : Item(status='D '),
> - 'A/D/gamma' : Item(status='D '),
> - 'A/D/G' : Item(status='D '),
> - 'A/D/G/pi' : Item(status='D '),
> - 'A/D/G/rho' : Item(status='D '),
> - 'A/D/G/tau' : Item(status='D '),
> - 'A/D/H' : Item(status='D '),
> - 'A/D/H/chi' : Item(status='D '),
> - 'A/D/H/psi' : Item(status='D '),
> - 'A/D/H/omega' : Item(status='D ')
> })
> - expected_status = svntest.wc.State(wc_dir, {
> + expected_status = svntest.wc.State(other_wc, {
> '' : Item(status=' ', wc_rev=1),
> 'A' : Item(status=' ', wc_rev=1),
> 'A/mu' : Item(status=' ', wc_rev=1),
> })
> - expected_disk = svntest.wc.State(wc_dir, {
> + expected_disk = svntest.wc.State('', {
> 'A' : Item(contents=None),
> 'A/mu' : Item(contents="This is the file 'mu'.\n")
> })
> @@ -1971,20 +1951,15 @@ def fold_tree_with_unversioned_modified_
>
> # Fold the A dir to empty, expect the modified & unversioned ones left
> # unversioned rather than removed, along with paths to those items.
> +
> + # Even though the directory B and D is not deleted because of local
> + # modificatoin or unversioned items, there will be only one notification at
> + # B and D.
> expected_output = svntest.wc.State(wc_dir, {
> - 'A/B/lambda' : Item(status='D '),
> - 'A/B/E' : Item(status='D '),
> - 'A/B/E/alpha' : Item(status='D '),
> - 'A/B/E/beta' : Item(status='D '),
> - 'A/B/F' : Item(status='D '),
> + 'A/B' : Item(status='D '),
> 'A/C' : Item(status='D '),
> - 'A/D/gamma' : Item(status='D '),
> - 'A/D/G/rho' : Item(status='D '),
> - 'A/D/G/tau' : Item(status='D '),
> - 'A/D/H' : Item(status='D '),
> - 'A/D/H/chi' : Item(status='D '),
> - 'A/D/H/psi' : Item(status='D '),
> - 'A/D/H/omega' : Item(status='D ')
> + 'A/D' : Item(status='D '),
> + 'A/mu' : Item(status='D '),
> })
> # unversioned items will be ignored in in the status tree, since the
> # run_and_verify_update() function uses a quiet version of svn status
> @@ -1994,8 +1969,8 @@ def fold_tree_with_unversioned_modified_
> 'iota' : Item(status=' ', wc_rev=1),
> 'A' : Item(status=' ', wc_rev=1)
> })
> - expected_disk = svntest.wc.State(wc_dir, {
> - 'iota' : Item(contents="this is iota\n"),
> + expected_disk = svntest.wc.State('', {
> + 'iota' : Item(contents="This is the file 'iota'.\n"),
> 'A' : Item(contents=None),
> 'A/mu' : Item(contents="mu modified\n"),
> 'A/B' : Item(contents=None),
> @@ -2013,7 +1988,6 @@ def fold_tree_with_unversioned_modified_
> '--set-depth', 'empty', A_path)
> verify_depth(None, "empty", A_path)
>
> -
> def depth_empty_update_on_file(sbox):
> "depth-empty update on a file doesn't break it"
> sbox.build()
> @@ -2052,6 +2026,224 @@ def depth_empty_update_on_file(sbox):
> [], 'info', iota_path)
>
>
> +def excluded_path_update_operation(sbox):
> + """make sure update handle svn_depth_exclude properly"""
> +
> + ign_a, ign_b, ign_c, wc_dir = set_up_depthy_working_copies(sbox,
> + infinity=True)
> + A_path = os.path.join(wc_dir, 'A')
> + B_path = os.path.join(A_path, 'B')
> + L_path = os.path.join(A_path, 'L')
> + E_path = os.path.join(B_path, 'E')
> +
> + # Simply exclude a subtree
> + expected_output = svntest.wc.State(wc_dir, {
> + 'A/B/E' : Item(status='D '),
> + })
> + expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
> + expected_status.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E');
> + expected_disk = svntest.main.greek_state.copy()
> + expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E');
> +
> + svntest.actions.run_and_verify_update(wc_dir,
> + expected_output,
> + expected_disk,
> + expected_status,
> + None, None,
> + None, None, None, None,
> + '--set-depth', 'exclude', E_path)
> + # verify_depth exclude? not implemented yet
> +
> + # crop path B to immediates, this just pull in A/B/E again
> + expected_output = svntest.wc.State(wc_dir, {
> + 'A/B/E' : Item(status='A '),
> + })
> + expected_status.add({
> + 'A/B/E' : Item(status=' ', wc_rev=1)
> + })
> + expected_disk.add({
> + 'A/B/E' : Item(contents=None),
> + })
> + svntest.actions.run_and_verify_update(wc_dir,
> + expected_output,
> + expected_disk,
> + expected_status,
> + None, None,
> + None, None, None, None,
> + '--set-depth', 'immediates', B_path)
> + verify_depth(None, "immediates", B_path)
> +
> + # Exclude A/B/E again
> + svntest.actions.run_and_verify_svn(None, None, [],
> + 'up', '--set-depth', 'exclude', E_path)
> +
> + # Exclude path B totally, in which contains an excluded subtree.
> + expected_output = svntest.wc.State(wc_dir, {
> + 'A/B' : Item(status='D '),
> + })
> + expected_status.remove('A/B/F', 'A/B/E', 'A/B/lambda', 'A/B');
> + expected_disk.remove('A/B/F', 'A/B/E', 'A/B/lambda', 'A/B');
> + svntest.actions.run_and_verify_update(wc_dir,
> + expected_output,
> + expected_disk,
> + expected_status,
> + None, None,
> + None, None, None, None,
> + '--set-depth', 'exclude', B_path)
> +
> + # Explicitly pull in excluded path B.
> + expected_output = svntest.wc.State(wc_dir, {
> + 'A/B' : Item(status='A '),
> + 'A/B/lambda' : Item(status='A '),
> + 'A/B/E' : Item(status='A '),
> + 'A/B/E/alpha' : Item(status='A '),
> + 'A/B/E/beta' : Item(status='A '),
> + 'A/B/F' : Item(status='A '),
> + })
> + expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
> + expected_disk = svntest.main.greek_state.copy()
> + svntest.actions.run_and_verify_update(wc_dir,
> + expected_output,
> + expected_disk,
> + expected_status,
> + None, None,
> + None, None, None, None,
> + B_path)
> +
> +def excluded_path_misc_operation(sbox):
> + """make sure other subcommands handle exclude"""
> +
> + ign_a, ign_b, ign_c, wc_dir = set_up_depthy_working_copies(sbox,
> + infinity=True)
> + A_path = os.path.join(wc_dir, 'A')
> + B_path = os.path.join(A_path, 'B')
> + L_path = os.path.join(A_path, 'L')
> + E_path = os.path.join(B_path, 'E')
> + LE_path = os.path.join(L_path, 'E')
> +
> + # Simply exclude a subtree
> + expected_output = svntest.wc.State(wc_dir, {
> + 'A/B/E' : Item(status='D '),
> + })
> + expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
> + expected_status.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E');
> + expected_disk = svntest.main.greek_state.copy()
> + expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E');
> +
> + svntest.actions.run_and_verify_update(wc_dir,
> + expected_output,
> + expected_disk,
> + expected_status,
> + None, None,
> + None, None, None, None,
> + '--set-depth', 'exclude', E_path)
> +
> + # copy A/B to A/L, excluded entry should be copied too
> + expected_output = ['A '+L_path+'\n']
> + svntest.actions.run_and_verify_svn(None, expected_output, [],
> + 'cp', B_path, L_path)
> + # verify_depth exclude? not implemented yet
> + #verify_depth(None, "empty", LE_path)
> +
> + # revert A/L, with an excluded item in the tree
> + expected_output = ["Reverted '"+L_path+"'\n"]
> + svntest.actions.run_and_verify_svn(None, expected_output, [],
> + 'revert', '--depth=infinity', L_path)
> +
> + # Get rid of A/L.
> + svntest.actions.run_and_verify_svn(None, None, [],
> + 'rm', '--force', L_path)
> +
> + # copy A/B to A/L again, excluded entry should be copied too
> + expected_output = ['A '+L_path+'\n']
> + svntest.actions.run_and_verify_svn(None, expected_output, [],
> + 'cp', B_path, L_path)
> +
> + # commit this copy, with an excluded item.
> + expected_output = svntest.wc.State(wc_dir, { 'A/L' : Item(verb='Adding'), })
> + expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
> + expected_status.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E')
> + expected_status.add({
> + 'A/L' : Item(status=' ', wc_rev=2),
> + 'A/L/lambda' : Item(status=' ', wc_rev=2),
> + 'A/L/F' : Item(status=' ', wc_rev=2),
> + })
> + svntest.actions.run_and_verify_commit(wc_dir,
> + expected_output,
> + expected_status,
> + None,
> + wc_dir)
> +
> + # Relocate wc, with excluded items in it.
> + repo_dir = sbox.repo_dir
> + repo_url = sbox.repo_url
> + other_repo_dir, other_repo_url = sbox.add_repo_path('other')
> + svntest.main.copy_repos(repo_dir, other_repo_dir, 2, 0)
> + svntest.main.safe_rmtree(repo_dir, 1)
> + svntest.actions.run_and_verify_svn(None, None, [], 'switch', '--relocate',
> + repo_url, other_repo_url, wc_dir)
> +
> + # remove the new directory A/L, with an excluded item.
> + # If successed, no error will be thrown
> + svntest.actions.run_and_verify_svn(None, None, [],
> + 'rm', L_path)
> +
> + # revert the delete
> + # If successed, no error will be thrown
> + svntest.actions.run_and_verify_svn(None, None, [],
> + 'revert', '--depth=infinity', L_path)
> +
> +
> +def excluded_receive_remote_removal(sbox):
> + """exclude flag should be cleared upon remote removal"""
> + ign_a, ign_b, ign_c, wc \
> + = set_up_depthy_working_copies(sbox, infinity=True)
> +
> + A_path = os.path.join(wc, 'A')
> + B_path = os.path.join(A_path, 'B')
> + C_path = os.path.join(A_path, 'C')
> +
> + # Exclude path B from wc
> + expected_output = svntest.wc.State(wc, {
> + 'A/B' : Item(status='D '),
> + })
> + expected_disk = svntest.main.greek_state.copy()
> + expected_disk.remove('A/B/lambda', 'A/B/E/alpha', 'A/B/E/beta',
> + 'A/B/E', 'A/B/F', 'A/B')
> + expected_status = svntest.actions.get_virginal_state(wc, 1)
> + expected_status.remove('A/B/lambda', 'A/B/E/alpha', 'A/B/E/beta',
> + 'A/B/E', 'A/B/F', 'A/B')
> + svntest.actions.run_and_verify_update(wc,
> + expected_output,
> + expected_disk,
> + expected_status,
> + None, None,
> + None, None, None, None,
> + "--set-depth", "exclude", B_path)
> +
> + # Remove path B in the repos.
> + svntest.actions.run_and_verify_svn(None, None, [], "delete", "-m",
> + "Delete B.", sbox.repo_url + "/A/B")
> +
> + # Update wc, should receive the removal of excluded path B
> + # and handle it silently.
> + expected_status = svntest.actions.get_virginal_state(wc, 2)
> + expected_status.remove('A/B/lambda', 'A/B/E/alpha', 'A/B/E/beta',
> + 'A/B/E', 'A/B/F', 'A/B')
> + svntest.actions.run_and_verify_update(wc,
> + None,
> + expected_disk,
> + expected_status,
> + None, None,
> + None, None, None, None)
> +
> + # Introduce a new path with the same name B.
> + # This should succeed if the exclude entry is gone with the update,
> + # otherwise a name conflict will rise up.
> + expected_output = ['A '+B_path+'\n']
> + svntest.actions.run_and_verify_svn(None, expected_output, [],
> + 'cp', C_path, B_path)
> +
>
> #----------------------------------------------------------------------
> # list all tests here, starting with None:
> @@ -2081,12 +2273,15 @@ test_list = [ None,
> upgrade_from_above,
> status_in_depthy_wc,
> depthy_update_above_dir_to_be_deleted,
> - XFail(depth_folding_clean_trees_1),
> - XFail(depth_folding_clean_trees_2),
> - XFail(depth_fold_expand_clean_trees),
> + depth_folding_clean_trees_1,
> + depth_folding_clean_trees_2,
> + depth_fold_expand_clean_trees,
> pull_in_tree_with_depth_option,
> - XFail(fold_tree_with_unversioned_modified_items),
> + fold_tree_with_unversioned_modified_items,
> depth_empty_update_on_file,
> + excluded_path_update_operation,
> + excluded_path_misc_operation,
> + excluded_receive_remote_removal,
> ]
>
> if __name__ == "__main__":
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: svn-unsubscribe_at_subversion.tigris.org
> For additional commands, e-mail: svn-help_at_subversion.tigris.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe_at_subversion.tigris.org
For additional commands, e-mail: dev-help_at_subversion.tigris.org
Received on 2008-11-08 04:26:24 CET