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

[PATCH] fix for non-recursive checkouts/updates (issue 695)

From: Henry Baldursson <henry_at_f-prot.com>
Date: 2004-06-13 23:36:43 CEST

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,
I've made a patch against r9980 in an attempt to fix issue 695. This is
the "co -N, up -N not working" issue.

My approach is to add a "ghost entry" to the entries file for each
directory that should exist but doesn't because of the non-recursive
checkout. This ghost entry describes an incomplete directory entry.

For this purpose I added a function to the update_editor.c called
"add_ghost_entry ()" which simply creates a new svn_wc_entry_t variable,
sets it to a proper name and kind, and sets it as "incomplete". Then it
calls svn_wc__entry_modify () with an immediate sync. Then in
libsvn_repos' update_entry () I added a call to this function for the
case of directories in non-recursive updates/checkouts. I also added a
cancel wrapped version of add_ghost_entry () so it can be used widely.

Another thing I tinkered with is locking. I avoid recursive locking on
non-recursive operations, and I avoid locking incomplete directories.
This avoids the "D dir/" when we do a "svn up -N" of a repository that
was previously co'd with -N.

It now works to update a previously non-recursively checked out repos.

One problem I'm having is that my patch appears to work on file://
access, and not http://. I don't have the resources atm to fully test
this, but I would have thought implementing the ghost entry addition in
libsvn_repos would have it work for every protocol since it is a layer
on top of libsvn_fs and all the protocols should use it.

I'd like to thank everyone at #svn (I'm sulkd). Everyone there was very
helpful. And also, I'd like to congratulate you all on subversion, it's
pretty amazing both from a user's and programmer's perspective.

Cheers.

(also available at http://www.moresecurity.org/~henry/svn/sulkd_NR.diff)

Index: subversion/include/svn_delta.h
===================================================================
- --- subversion/include/svn_delta.h (revision 9980)
+++ subversion/include/svn_delta.h (working copy)
@@ -799,6 +799,15 @@
~ svn_error_t *(*abort_edit) (void *edit_baton,
~ apr_pool_t *pool);

+ /** Add an entry for @a path in the directory represented by
+ * @a parent_baton. The @a path will not exist on disc, but
+ * an entry will exist to indicate that it should.
+ */
+ svn_error_t *(*add_ghost_entry) (const char *path,
+ svn_node_kind_t kind,
+ void *parent_baton,
+ apr_pool_t *pool);
+
~ } svn_delta_editor_t;

Index: subversion/libsvn_wc/lock.c
===================================================================
- --- subversion/libsvn_wc/lock.c (revision 9980)
+++ subversion/libsvn_wc/lock.c (working copy)
@@ -431,6 +431,7 @@
~ && (entry->schedule != svn_wc_schedule_add)
~ && (entry->schedule != svn_wc_schedule_replace))
~ || entry->kind != svn_node_dir
+ || entry->incomplete
~ || ! strcmp (entry->name, SVN_WC_ENTRY_THIS_DIR))
~ continue;
~ entry_path = svn_path_join (lock->path, entry->name, subpool);
Index: subversion/libsvn_wc/update_editor.c
===================================================================
- --- subversion/libsvn_wc/update_editor.c (revision 9980)
+++ subversion/libsvn_wc/update_editor.c (working copy)
@@ -1334,7 +1334,40 @@
~ return SVN_NO_ERROR;
~ }

+static svn_error_t *
+add_ghost_entry (const char *path,
+ svn_node_kind_t kind,
+ void *parent_baton,
+ apr_pool_t *pool)
+{
+ const char *name = svn_path_basename (path, pool);
+ struct dir_baton *pb = parent_baton;
+ struct edit_baton *eb = pb->edit_baton;
+ svn_wc_adm_access_t *adm_access;
+ apr_hash_t *entries;
+ svn_wc_entry_t entry;

+ /* We need path here */
+ assert(path);
+
+ entry.kind = kind;
+ entry.incomplete = TRUE;
+ entry.absent = FALSE;
+ entry.deleted = FALSE;
+
+ SVN_ERR (svn_wc_adm_retrieve (&adm_access, eb->adm_access,
+ pb->path, pool));
+ SVN_ERR (svn_wc__entry_modify (adm_access, name, &entry,
+ (SVN_WC__ENTRY_MODIFY_KIND |
+ SVN_WC__ENTRY_MODIFY_DELETED |
+ SVN_WC__ENTRY_MODIFY_INCOMPLETE |
+ SVN_WC__ENTRY_MODIFY_ABSENT),
+ TRUE /* immediate write */, pool));
+
+ return SVN_NO_ERROR;
+}
+
+
~ /* Common code for 'absent_file' and 'absent_directory'. */
~ static svn_error_t *
~ absent_file_or_dir (const char *path,
@@ -2502,6 +2535,7 @@
~ tree_editor->close_file = close_file;
~ tree_editor->absent_file = absent_file;
~ tree_editor->close_edit = close_edit;
+ tree_editor->add_ghost_entry = add_ghost_entry;

~ SVN_ERR (svn_delta_get_cancellation_editor (cancel_func,
~ cancel_baton,
Index: subversion/libsvn_client/update.c
===================================================================
- --- subversion/libsvn_client/update.c (revision 9980)
+++ subversion/libsvn_client/update.c (working copy)
@@ -75,8 +75,9 @@

~ /* Use PATH to get the update's anchor and targets and get a write
lock */
~ SVN_ERR (svn_wc_get_actual_target (path, &anchor, &target, pool));
- - SVN_ERR (svn_wc_adm_open2 (&adm_access, NULL, anchor, TRUE, -1,
- - pool));
+ /* Lock the stuff under anchor we need */
+ SVN_ERR (svn_wc_adm_open2 (&adm_access, NULL, anchor, TRUE,
+ (recurse ? -1 : 1), pool));

~ /* Get full URL from the ANCHOR. */
~ SVN_ERR (svn_wc_entry (&entry, anchor, adm_access, FALSE, pool));
Index: subversion/libsvn_repos/reporter.c
===================================================================
- --- subversion/libsvn_repos/reporter.c (revision 9980)
+++ subversion/libsvn_repos/reporter.c (working copy)
@@ -624,7 +624,10 @@

~ if (!recurse && ((s_entry && s_entry->kind == svn_node_dir)
~ || (t_entry && t_entry->kind == svn_node_dir)))
+ {
+ SVN_ERR (b->editor->add_ghost_entry (e_path, svn_node_dir,
dir_baton, pool));
~ return skip_path_info (b, e_path);
+ }

~ /* If the source and target both exist and are of the same kind,
~ then find out whether they're related. If they're exactly the
Index: subversion/libsvn_delta/cancel.c
===================================================================
- --- subversion/libsvn_delta/cancel.c (revision 9980)
+++ subversion/libsvn_delta/cancel.c (working copy)
@@ -337,6 +337,24 @@
~ return SVN_NO_ERROR;
~ }

+static svn_error_t *
+add_ghost_entry (const char *path,
+ svn_node_kind_t kind,
+ void *parent_baton,
+ apr_pool_t *pool)
+{
+ struct dir_baton *pb = parent_baton;
+ struct edit_baton *eb = pb->edit_baton;
+
+ SVN_ERR (eb->cancel_func (eb->cancel_baton));
+
+ SVN_ERR (eb->wrapped_editor->add_ghost_entry (path, kind,
+ pb->wrapped_dir_baton,
+ pool));
+
+ return SVN_NO_ERROR;
+}
+
~ svn_error_t *
~ svn_delta_get_cancellation_editor (svn_cancel_func_t cancel_func,
~ void *cancel_baton,
@@ -366,6 +384,7 @@
~ tree_editor->close_file = close_file;
~ tree_editor->absent_file = absent_file;
~ tree_editor->close_edit = close_edit;
+ tree_editor->add_ghost_entry = add_ghost_entry;

~ eb->wrapped_editor = wrapped_editor;
~ eb->wrapped_edit_baton = wrapped_edit_baton;
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFAzMjqmKhgit64+foRAlZDAKDRHSV/G1eTetpUozBz4wAhDVGUMQCdESLf
uVIh9ata2BFJ2r15YxDfuEE=
=s4N2
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sun Jun 13 23:37:30 2004

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

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.