[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [PATCH] Make sparse-directories checkouts/updates work with old servers

From: Karl Fogel <kfogel_at_red-bean.com>
Date: 2007-03-25 00:08:52 CET

Vlad Georgescu <vgeorgescu@gmail.com> writes:
> This patch makes checkouts and updates at svn_depth_empty and
> svn_depth_immediates work with servers that do not understand the new
> reporter changes, by making the update editor ignore edits on paths below
> the edit depth.
>
> With this patch, I can successfully run the depth tests against a 1.4
> svnserve. As this is my first attempt at sparse-directories related work,
> I'm posting the patch here for review.

Thanks! I'll take a look as soon as I can (I've been busy with
http://pastebin.ca/408580, that's all.) But hopefully others can
review this patch too; a lot of people here understand the
sparse-directories changes now, which is good.

-Karl

> [[[
> Make updates and checkouts at 'empty' or 'immediates' depth work with old
> servers.
>
> * subversion/include/svn_types.h
> (svn_depth_t): Remove comment about svn_depth_exclude being potentially
> unnecessary.
>
> * subversion/libsvn_ra_svn/client.c
> (ra_svn_update): Don't use the SVN_DEPTH_TO_RECURSE macro, because we
> don't want svn_depth_immediates mapped to FALSE in this case. Use a
> custom check instead.
>
> * subversion/libsvn_wc/update_editor.c
> (dir_baton): New member 'depth'.
> (file_baton.skipped): Update comment to reflect new usage.
> (prep_directory): Remove 'depth' parameter, it is stored in the dir_baton
> now. Use db->depth instead of depth when creating the administrative area.
> (open_root): Initialize the returned dir_baton's depth to the default
> depth of the edit.
> (delete_entry): For svn_depth_empty and svn_depth_files, ignore deletions
> of children that haven't been explicitly brought in.
> (add_directory): If the directory is the target of the edit, set its
> depth to that of the edit. Otherwise, initialize the returned dir_baton's
> depth based on the depth of the parent. Remove the old depth calculation
> code, and update the call to prep_directory.
> (open_directory): If the directory is the target of the edit, set its
> depth to that of the edit. Otherwise, initialize the returned dir_baton's
> depth based on the depth of the parent. If the entry exists on disk, allow
> its depth to override svn_depth_infinity.
> (change_dir_prop, close_directory): Don't do anything if the directory is
> at svn_depth_exclude.
> (absent_file_or_dir): Don't do anything if the parent is empty or excluded,
> or if it is at svn_depth_files and the absent entry is a directory.
> (add_or_open_file): If parent is at svn_depth_empty or svn_depth_exclude,
> skip this file.
> ]]]
>
> --
> Vlad
>
>
>
> Index: subversion/include/svn_types.h
> ===================================================================
> --- subversion/include/svn_types.h (revision 24077)
> +++ subversion/include/svn_types.h (working copy)
> @@ -212,8 +212,7 @@
> ### TODO(sd): This depth may turn out to be unnecessary. ### */
> svn_depth_unknown = -2,
>
> - /* Exclude (remove, whatever) directory D.
> - ### TODO(sd): This depth may turn out to be unnecessary. ### */
> + /* Exclude (remove, whatever) directory D. */
> svn_depth_exclude = -1,
>
> /* Just the named directory D, no entries. Updates will not pull in
> Index: subversion/libsvn_ra_svn/client.c
> ===================================================================
> --- subversion/libsvn_ra_svn/client.c (revision 24077)
> +++ subversion/libsvn_ra_svn/client.c (working copy)
> @@ -1079,8 +1079,14 @@
> {
> svn_ra_svn__session_baton_t *sess_baton = session->priv;
> svn_ra_svn_conn_t *conn = sess_baton->conn;
> - svn_boolean_t recurse = SVN_DEPTH_TO_RECURSE(depth);
> + svn_boolean_t recurse;
>
> + /* Old servers know "recursive" but not "depth"; help them DTRT. */
> + if (depth == svn_depth_empty || depth == svn_depth_files)
> + recurse = FALSE;
> + else
> + recurse = TRUE;
> +
> /* Tell the server we want to start an update. */
> SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "update", "(?r)cbw", rev, target,
> recurse, svn_depth_to_word(depth)));
> Index: subversion/libsvn_wc/update_editor.c
> ===================================================================
> --- subversion/libsvn_wc/update_editor.c (revision 24077)
> +++ subversion/libsvn_wc/update_editor.c (working copy)
> @@ -138,6 +138,9 @@
> /* The global edit baton. */
> struct edit_baton *edit_baton;
>
> + /* The depth of the directory in this edit. */
> + svn_depth_t depth;
> +
> /* Baton for this directory's parent, or NULL if this is the root
> directory. */
> struct dir_baton *parent_baton;
> @@ -567,7 +570,9 @@
> /* Set if this file is new. */
> svn_boolean_t added;
>
> - /* Set if this file is skipped because it was in conflict. */
> + /* Set if this file is skipped because it was in conflict, or because
> + it was a child of a directory at svn_depth_empty or
> + svn_depth_exclude. */
> svn_boolean_t skipped;
>
> /* Set if an unversioned file of the same name already existed in
> @@ -701,7 +706,6 @@
>
>
> /* Prepare directory for dir_baton DB for updating or checking out.
> - * Give it depth DEPTH.
> *
> * If the path already exists, but is not a working copy for
> * ANCESTOR_URL and ANCESTOR_REVISION, then an error will be returned.
> @@ -710,7 +714,6 @@
> prep_directory(struct dir_baton *db,
> const char *ancestor_url,
> svn_revnum_t ancestor_revision,
> - svn_depth_t depth,
> apr_pool_t *pool)
> {
> const char *repos;
> @@ -730,7 +733,7 @@
> or by checking that it is so already. */
> SVN_ERR(svn_wc_ensure_adm3(db->path, NULL,
> ancestor_url, repos,
> - ancestor_revision, depth, pool));
> + ancestor_revision, db->depth, pool));
>
> if (! db->edit_baton->adm_access
> || strcmp(svn_wc_adm_access_path(db->edit_baton->adm_access),
> @@ -898,6 +901,7 @@
> eb->root_opened = TRUE;
>
> *dir_baton = d = make_dir_baton(NULL, eb, NULL, FALSE, pool);
> + d->depth = eb->depth;
> if (! *eb->target)
> {
> /* For an update with a NULL target, this is equivalent to open_dir(): */
> @@ -1108,6 +1112,24 @@
> apr_pool_t *pool)
> {
> struct dir_baton *pb = parent_baton;
> +
> + if (pb->depth == svn_depth_exclude)
> + return SVN_NO_ERROR;
> +
> + /* For svn_depth_empty and svn_depth_files, ignore deletions of entries
> + that haven't been explicitly brought in. */
> + else if (pb->depth == svn_depth_empty || pb->depth == svn_depth_files)
> + {
> + svn_wc_adm_access_t *adm_access;
> + svn_wc_entry_t *entry;
> + const char *full_path = svn_path_join(pb->edit_baton->anchor, path, pool);
> +
> + SVN_ERR(svn_wc_entry(&entry, full_path,
> + pb->edit_baton->adm_access, FALSE, pool));
> + if (! entry)
> + return SVN_NO_ERROR;
> + }
> +
> return do_entry_deletion(pb->edit_baton, pb->path, path, &pb->log_number,
> pool);
> }
> @@ -1135,6 +1157,26 @@
> || ((! copyfrom_path) && (SVN_IS_VALID_REVNUM(copyfrom_revision))))
> abort();
>
> + *child_baton = db;
> +
> + /* If we have a non-empty target and the parent of the newly added
> + directory is the root of the edit, then the new directory *is* the
> + target and we should set its depth accordingly. */
> + if (*eb->target && ! pb->parent_baton)
> + db->depth = eb->depth;
> + else if (pb->depth == svn_depth_empty
> + || pb->depth == svn_depth_exclude
> + || pb->depth == svn_depth_files)
> + {
> + db->depth = svn_depth_exclude;
> + db->bump_info->skipped = TRUE;
> + return SVN_NO_ERROR;
> + }
> + else if (pb->depth == svn_depth_immediates)
> + db->depth = svn_depth_empty;
> + else
> + db->depth = svn_depth_infinity;
> +
> SVN_ERR(svn_io_check_path(db->path, &kind, db->pool));
>
> /* The path can exist, but it must be a directory... */
> @@ -1287,23 +1329,10 @@
> }
> }
>
> - {
> - svn_depth_t depth = svn_depth_infinity;
> + SVN_ERR(prep_directory(db, db->new_URL,
> + *(eb->target_revision),
> + db->pool));
>
> - if (eb->depth == svn_depth_empty
> - || eb->depth == svn_depth_files
> - || eb->depth == svn_depth_immediates)
> - depth = svn_depth_empty;
> -
> - SVN_ERR(prep_directory(db,
> - db->new_URL,
> - *(eb->target_revision),
> - depth,
> - db->pool));
> - }
> -
> - *child_baton = db;
> -
> /* If this add was obstructed by dir scheduled for addition without
> history let close_file() handle the notification because there
> might be properties to deal with. */
> @@ -1350,6 +1379,26 @@
>
> /* Skip this directory if it has property conflicts. */
> SVN_ERR(svn_wc_entry(&entry, db->path, eb->adm_access, FALSE, pool));
> +
> + /* If we have a non-empty target and the parent of the newly added
> + directory is the root of the edit, then the new directory *is* the
> + target and we should set its depth accordingly. */
> + if (*eb->target && ! pb->parent_baton)
> + db->depth = eb->depth;
> + else if (pb->depth == svn_depth_empty
> + || pb->depth == svn_depth_files
> + || pb->depth == svn_depth_exclude)
> + {
> + db->depth = svn_depth_exclude;
> + db->bump_info->skipped = TRUE;
> + return SVN_NO_ERROR;
> + }
> + else if (pb->depth == svn_depth_immediates)
> + db->depth = svn_depth_empty;
> + else if (entry)
> + /* Allow the entry's actual depth to override svn_depth_infinity. */
> + db->depth = entry->depth;
> +
> if (entry)
> {
> /* Text conflicts can't happen for a directory, but we need to supply
> @@ -1411,7 +1460,7 @@
> svn_prop_t *propchange;
> struct dir_baton *db = dir_baton;
>
> - if (db->bump_info->skipped)
> + if (db->bump_info->skipped || db->depth == svn_depth_exclude)
> return SVN_NO_ERROR;
>
> propchange = apr_array_push(db->propchanges);
> @@ -1451,6 +1500,12 @@
> apr_array_header_t *entry_props, *wc_props, *regular_props;
> svn_wc_adm_access_t *adm_access;
>
> + if (db->depth == svn_depth_exclude)
> + {
> + SVN_ERR(maybe_bump_dir_info(db->edit_baton, db->bump_info, db->pool));
> + return SVN_NO_ERROR;
> + }
> +
> SVN_ERR(svn_categorize_props(db->propchanges, &entry_props, &wc_props,
> &regular_props, pool));
>
> @@ -1578,6 +1633,11 @@
> const svn_wc_entry_t *ent;
> svn_wc_entry_t tmp_entry;
>
> + if (pb->depth == svn_depth_empty
> + || pb->depth == svn_depth_exclude
> + || (kind == svn_node_dir && pb->depth == svn_depth_files))
> + return SVN_NO_ERROR;
> +
> /* Extra check: an item by this name may not exist, but there may
> still be one scheduled for addition. That's a genuine
> tree-conflict. */
> @@ -1663,8 +1723,14 @@
> conflict in the entry and proceed. Similarly if it has changed
> kind. see issuezilla task #398. */
>
> - fb = make_file_baton(pb, path, adding, pool);
> + *file_baton = fb = make_file_baton(pb, path, adding, pool);
>
> + if (pb->depth == svn_depth_empty || pb->depth == svn_depth_exclude)
> + {
> + fb->skipped = TRUE;
> + return SVN_NO_ERROR;
> + }
> +
> /* It is interesting to note: everything below is just validation. We
> aren't actually doing any "work" or fetching any persistent data. */
>
> @@ -1773,7 +1839,6 @@
>
> svn_pool_destroy(subpool);
>
> - *file_baton = fb;
> return SVN_NO_ERROR;
> }
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
> For additional commands, e-mail: dev-help@subversion.tigris.org

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sun Mar 25 00:29:04 2007

This is an archived mail posted to the Subversion Dev mailing list.