Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h	(revision 1816128)
+++ subversion/include/svn_client.h	(working copy)
@@ -1544,13 +1544,41 @@ svn_client_switch(svn_revnum_t *result_rev,
                   svn_boolean_t recurse,
                   svn_client_ctx_t *ctx,
                   apr_pool_t *pool);
 
 /** @} */
 
+/** Callback for svn_client_layout_list()
+ */
+typedef svn_error_t * (*svn_client_layout_func_t)(
+                            void *layout_baton,
+                            const char *local_abspath,
+                            const char *repos_root_url,
+                            svn_boolean_t not_present,
+                            svn_boolean_t url_changed,
+                            const char *url,
+                            svn_boolean_t revision_changed,
+                            svn_revnum_t revision,
+                            svn_boolean_t depth_changed,
+                            svn_depth_t depth,
+                            apr_pool_t *scratch_pool);
+
 /**
+ * Describe the layout of the working copy below @a local_abspath to
+ * the callback @a layout.
+ */
+SVN_EXPERIMENTAL
+svn_error_t *
+svn_client_layout_list(const char *local_abspath,
+                       svn_client_layout_func_t layout,
+                       void *layout_baton,
+                       svn_client_ctx_t *ctx,
+                       apr_pool_t *scratch_pool);
+
+
+/**
  * @defgroup Add Begin versioning files/directories in a working copy.
  *
  * @{
  */
 
 /**
Index: subversion/libsvn_client/layout.c
===================================================================
--- subversion/libsvn_client/layout.c	(nonexistent)
+++ subversion/libsvn_client/layout.c	(working copy)
@@ -0,0 +1,290 @@
+/*
+* layout.c:  code to list and update the working copy layout
+*
+* ====================================================================
+*    Licensed to the Apache Software Foundation (ASF) under one
+*    or more contributor license agreements.  See the NOTICE file
+*    distributed with this work for additional information
+*    regarding copyright ownership.  The ASF licenses this file
+*    to you under the Apache License, Version 2.0 (the
+*    "License"); you may not use this file except in compliance
+*    with the License.  You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing,
+*    software distributed under the License is distributed on an
+*    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+*    KIND, either express or implied.  See the License for the
+*    specific language governing permissions and limitations
+*    under the License.
+* ====================================================================
+*/
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include "svn_hash.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "svn_wc.h"
+#include "svn_client.h"
+#include "svn_error.h"
+#include "svn_pools.h"
+#include "client.h"
+
+#include "svn_private_config.h"
+#include "private/svn_wc_private.h"
+
+struct layout_item_t
+{
+  const char *local_abspath;
+  const char *url;
+  svn_revnum_t revision;
+  svn_depth_t depth;
+  struct layout_item_t *ancestor;
+  apr_pool_t *pool;
+};
+
+struct client_layout_baton_t
+{
+  const char *root_abspath;
+  svn_wc_context_t *wc_ctx;
+  const char *repos_root_url;
+
+  struct layout_item_t *stack;
+  apr_pool_t *root_pool;
+
+  svn_client_layout_func_t layout;
+  void *layout_baton;
+};
+
+
+static svn_error_t *
+layout_set_path(void *report_baton,
+                const char *path,
+                svn_revnum_t revision,
+                svn_depth_t depth,
+                svn_boolean_t start_empty,
+                const char *lock_token,
+                apr_pool_t *pool)
+{
+  struct client_layout_baton_t *lb = report_baton;
+  const char *local_abspath = svn_dirent_join(lb->root_abspath, path, pool);
+  struct layout_item_t *it;
+  apr_pool_t *item_pool;
+  svn_depth_t expected_depth;
+
+  while (lb->stack
+          && !svn_dirent_is_ancestor(lb->stack->local_abspath, local_abspath))
+    {
+      it = lb->stack;
+      lb->stack = it->ancestor;
+      svn_pool_destroy(it->pool);
+    }
+
+  item_pool = svn_pool_create(lb->stack ? lb->stack->pool
+                                        : lb->root_pool);
+
+  it = apr_pcalloc(item_pool, sizeof(*it));
+  it->pool = item_pool;
+  it->local_abspath = apr_pstrdup(item_pool, local_abspath);
+  it->depth = depth;
+  it->revision = revision;
+  if (lb->stack)
+    {
+      it->url = svn_path_url_add_component2(
+                     lb->stack->url,
+                     svn_dirent_skip_ancestor(lb->stack->local_abspath,
+                                              local_abspath),
+                     item_pool);
+    }
+  else
+    {
+      const char *repos_relpath, *repos_root_url;
+
+      SVN_ERR(svn_wc__node_get_base(NULL, NULL, &repos_relpath,
+                                    &repos_root_url, NULL, NULL,
+                                    lb->wc_ctx, local_abspath,
+                                    FALSE /* ignore_enoent */,
+                                    pool, pool));
+
+      lb->repos_root_url = apr_pstrdup(lb->root_pool, repos_root_url);
+      it->url = svn_path_url_add_component2(repos_root_url, repos_relpath,
+                                            item_pool);
+    }
+  it->ancestor = lb->stack;
+  lb->stack = it;
+
+  if (!it->ancestor)
+    expected_depth = depth;
+  else if (it->ancestor->depth == svn_depth_infinity)
+    expected_depth = svn_depth_infinity;
+  else
+    expected_depth = svn_depth_empty;
+
+  return svn_error_trace(lb->layout(lb->layout_baton,
+                                    it->local_abspath,
+                                    lb->repos_root_url,
+                                    FALSE /* not-present */,
+                                    FALSE /* url changed */,
+                                    it->url,
+                                    it->ancestor
+                                      ? it->ancestor->revision != it->revision
+                                      : FALSE,
+                                    it->revision,
+                                    (depth != expected_depth),
+                                    it->depth,
+                                    pool));
+}
+
+static svn_error_t *
+layout_link_path(void *report_baton,
+                 const char *path,
+                 const char *url,
+                 svn_revnum_t revision,
+                 svn_depth_t depth,
+                 svn_boolean_t start_empty,
+                 const char *lock_token,
+                 apr_pool_t *pool)
+{
+  struct client_layout_baton_t *lb = report_baton;
+  const char *local_abspath = svn_dirent_join(lb->root_abspath, path, pool);
+  struct layout_item_t *it;
+  apr_pool_t *item_pool;
+  svn_depth_t expected_depth;
+
+  SVN_ERR_ASSERT(lb->stack); /* Always below root entry */
+
+  while (!svn_dirent_is_ancestor(lb->stack->local_abspath, local_abspath))
+    {
+      it = lb->stack;
+      lb->stack = it->ancestor;
+      svn_pool_destroy(it->pool);
+    }
+
+  item_pool = svn_pool_create(lb->stack ? lb->stack->pool
+                                        : lb->root_pool);
+
+  it = apr_pcalloc(item_pool, sizeof(*it));
+  it->pool = item_pool;
+  it->local_abspath = apr_pstrdup(item_pool, local_abspath);
+  it->depth = depth;
+  it->revision = revision;
+  it->url = apr_pstrdup(item_pool, url);
+
+  it->ancestor = lb->stack;
+  lb->stack = it;
+
+  if (it->ancestor->depth == svn_depth_infinity)
+    expected_depth = svn_depth_infinity;
+  else
+    expected_depth = svn_depth_empty;
+
+  return svn_error_trace(lb->layout(lb->layout_baton,
+                                    it->local_abspath,
+                                    lb->repos_root_url,
+                                    FALSE /* not-present */,
+                                    TRUE /* url changed */,
+                                    it->url,
+                                    it->ancestor
+                                      ? it->ancestor->revision != it->revision
+                                      : FALSE,
+                                    it->revision,
+                                    (depth != expected_depth),
+                                    it->depth,
+                                    pool));
+}
+
+static svn_error_t *
+layout_delete_path(void *report_baton,
+                   const char *path,
+                   apr_pool_t *pool)
+{
+  struct client_layout_baton_t *lb = report_baton;
+  const char *local_abspath = svn_dirent_join(lb->root_abspath, path, pool);
+  struct layout_item_t *it;
+
+  SVN_ERR_ASSERT(lb->stack); /* Always below root entry */
+
+  while (!svn_dirent_is_ancestor(lb->stack->local_abspath, local_abspath))
+    {
+      it = lb->stack;
+      lb->stack = it->ancestor;
+      svn_pool_destroy(it->pool);
+    }
+
+  return svn_error_trace(lb->layout(lb->layout_baton,
+                                    local_abspath,
+                                    lb->repos_root_url,
+                                    TRUE /* not-present */,
+                                    FALSE /* url changed */,
+                                    NULL /* no-url */,
+                                    FALSE /* revision changed */,
+                                    SVN_INVALID_REVNUM,
+                                    FALSE /* depth changed */,
+                                    svn_depth_unknown,
+                                    pool));
+}
+
+static svn_error_t *
+layout_finish_report(void *report_baton,
+                     apr_pool_t *pool)
+{
+  /*struct client_layout_baton_t *lb = report_baton;*/
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+layout_abort_report(void *report_baton,
+                     apr_pool_t *pool)
+{
+  /*struct client_layout_baton_t *lb = report_baton;*/
+  return SVN_NO_ERROR;
+}
+
+static const svn_ra_reporter3_t layout_reporter =
+{
+  layout_set_path,
+  layout_delete_path,
+  layout_link_path,
+  layout_finish_report,
+  layout_abort_report
+};
+
+svn_error_t *
+svn_client_layout_list(const char *local_abspath,
+                       svn_client_layout_func_t layout,
+                       void *layout_baton,
+                       svn_client_ctx_t *ctx,
+                       apr_pool_t *scratch_pool)
+{
+  struct client_layout_baton_t lb;
+
+  lb.root_abspath = local_abspath;
+  lb.root_pool = scratch_pool;
+  lb.wc_ctx = ctx->wc_ctx;
+  lb.repos_root_url = NULL; /* Filled in later */
+  lb.stack = NULL;
+
+  lb.layout = layout;
+  lb.layout_baton = layout_baton;
+
+  /* Drive the reporter structure, describing the revisions within
+     LOCAL_ABSPATH.  When this calls reporter->finish_report, the
+     reporter will drive the update_editor. */
+  SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx, local_abspath,
+                                  &layout_reporter, &lb,
+                                  FALSE /* restore_files */,
+                                  svn_depth_infinity,
+                                  TRUE /* honor_depth_exclude */,
+                                  FALSE /* depth_compatibility_trick */,
+                                  FALSE /* use_commit_times */,
+                                  ctx->cancel_func, ctx->cancel_baton,
+                                  ctx->notify_func2, ctx->notify_baton2,
+                                  scratch_pool));
+  return SVN_NO_ERROR;
+}

Property changes on: subversion/libsvn_client/layout.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: subversion/svn/svn.c
===================================================================
--- subversion/svn/svn.c	(revision 1816128)
+++ subversion/svn/svn.c	(working copy)
@@ -1858,17 +1858,18 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table
      "    svn switch ^/branches/1.x-release\n"
      "    svn switch --relocate http:// svn://\n"
      "    svn switch --relocate http://www.example.com/repo/project \\\n"
      "                          svn://svn.example.com/repo/project\n"),
     { 'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd,
       opt_ignore_externals, opt_ignore_ancestry, opt_force, opt_accept,
-      opt_relocate },
+      opt_relocate, opt_list},
     {{opt_ignore_ancestry,
      N_("allow switching to a node with no common ancestor")},
      {opt_force,
       N_("handle unversioned obstructions as changes")},
+     { opt_list, N_("list working copy layout")},
      {opt_relocate,N_("deprecated; use 'svn relocate'")}}
   },
 
   { "unlock", svn_cl__unlock, {0}, N_
     ("Unlock working copy paths or URLs.\n"
      "usage: unlock TARGET...\n"
Index: subversion/svn/switch-cmd.c
===================================================================
--- subversion/svn/switch-cmd.c	(revision 1816128)
+++ subversion/svn/switch-cmd.c	(working copy)
@@ -83,13 +83,138 @@ rewrite_urls(const apr_array_header_t *targets,
     }
 
   svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
 }
 
+struct layout_list_baton_t
+{
+  svn_boolean_t checkout;
+  const char *target;
+  const char *target_abspath;
+};
 
+/* Implements svn_client_layout_func_t */
+static svn_error_t *
+layout_func(void *layout_baton,
+            const char *local_abspath,
+            const char *repos_root_url,
+            svn_boolean_t not_present,
+            svn_boolean_t url_changed,
+            const char *url,
+            svn_boolean_t revision_changed,
+            svn_revnum_t revision,
+            svn_boolean_t depth_changed,
+            svn_depth_t depth,
+            apr_pool_t *scratch_pool)
+{
+  struct layout_list_baton_t *llb = layout_baton;
+  const char *relpath = svn_dirent_skip_ancestor(llb->target_abspath, local_abspath);
+
+  if (llb->checkout)
+    {
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 "svn checkout %s@%lu %s",
+                                 url, revision, llb->target));
+      if (depth != svn_depth_infinity)
+        SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                   " --depth %s", svn_depth_to_word(depth)));
+      llb->checkout = FALSE;
+    }
+  else if (depth == svn_depth_exclude)
+    {
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 "svn update --set-depth exclude %s",
+                                 svn_dirent_join(llb->target, relpath,
+                                                 scratch_pool)));
+    }
+  else if (not_present)
+    {
+      /* Easiest way to create a not present node: update to r0 */
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 "svn update -r 0 %s",
+                                 svn_dirent_join(llb->target, relpath,
+                                                 scratch_pool)));
+    }
+  else if (!url_changed && revision_changed)
+    {
+      /* Easiest way to create a not present node: update to r0 */
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 "svn update -r %lu %s",
+                                 revision,
+                                 svn_dirent_join(llb->target, relpath,
+                                                 scratch_pool)));
+
+      if (depth_changed)
+        SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                   " --set-depth %s",
+                                   svn_depth_to_word(depth)));
+    }
+  else if (url_changed)
+    {
+      /* Easiest way to create a not present node: update to r0 */
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 "svn switch ^/%s@%lu %s",
+                                 svn_uri_skip_ancestor(repos_root_url,
+                                                       url, scratch_pool),
+                                 revision,
+                                 svn_dirent_join(llb->target, relpath,
+                                                 scratch_pool)));
+      if (depth_changed)
+        SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                   " --set-depth %s",
+                                   svn_depth_to_word(depth)));
+    }
+  else if (depth_changed)
+    {
+        SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                   "svn update --set-depth %s %s",
+                                   svn_depth_to_word(depth),
+                                   svn_dirent_join(llb->target, relpath,
+                                                   scratch_pool)));
+    }
+  else
+    return SVN_NO_ERROR;
+
+  SVN_ERR(svn_cmdline_printf(scratch_pool, "\n"));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cl_layout_list(apr_array_header_t *targets,
+               void *baton,
+               svn_client_ctx_t *ctx,
+               apr_pool_t *scratch_pool)
+{
+  const char *list_path, *list_abspath;
+  struct layout_list_baton_t llb;
+
+  /* Add "." if user passed 0 arguments */
+  svn_opt_push_implicit_dot_target(targets, scratch_pool);
+
+  if (targets->nelts > 1)
+    return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
+
+  list_path = APR_ARRAY_IDX(targets, 0, const char *);
+
+  SVN_ERR(svn_cl__check_target_is_local_path(list_path));
+
+  SVN_ERR(svn_dirent_get_absolute(&list_abspath, list_path,
+                                  scratch_pool));
+
+  llb.checkout = TRUE;
+  llb.target = list_path;
+  llb.target_abspath = list_abspath;
+
+  return svn_error_trace(svn_client_layout_list(list_abspath,
+                                                layout_func, &llb,
+                                                ctx, scratch_pool));
+}
+
+
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
 svn_cl__switch(apr_getopt_t *os,
                void *baton,
                apr_pool_t *scratch_pool)
 {
@@ -116,12 +241,14 @@ svn_cl__switch(apr_getopt_t *os,
                                                       scratch_pool));
 
   /* handle only-rewrite case specially */
   if (opt_state->relocate)
     return rewrite_urls(targets, opt_state->ignore_externals,
                         ctx, scratch_pool);
+  else if (opt_state->list)
+    return svn_error_trace(cl_layout_list(targets, baton, ctx, scratch_pool));
 
   if (targets->nelts < 1)
     return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
   if (targets->nelts > 2)
     return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
 
