You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2011/05/08 17:39:45 UTC
svn commit: r1100758 - in /subversion/trunk/subversion:
libsvn_client/externals.c libsvn_wc/externals.c
Author: rhuijben
Date: Sun May 8 15:39:45 2011
New Revision: 1100758
URL: http://svn.apache.org/viewvc?rev=1100758&view=rev
Log:
Complete the file external editor in libsvn_wc and enable its use in
libsvn_client. This removes the dependency on an existing parent directory
from the updating of file externals.
So this opens the door for moving file externals to their own storage outside
NODES.
* subversion/libsvn_client/externals.c
(switch_file_external): Remove ancestor checks. Start using the file external
editor. Add missing update completed notification.
* subversion/libsvn_wc/externals.c
(): Update includes.
(edit_baton): Add missing variables for callbacks and file closed.
(close_file): Handle property and file merging. Extend notification to make
svn actually show output.
(close_edit): Bump revisions if the file didn't change while updating.
(svn_wc__get_file_external_editor): Fill more baton fields.
Modified:
subversion/trunk/subversion/libsvn_client/externals.c
subversion/trunk/subversion/libsvn_wc/externals.c
Modified: subversion/trunk/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/externals.c?rev=1100758&r1=1100757&r2=1100758&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/externals.c (original)
+++ subversion/trunk/subversion/libsvn_client/externals.c Sun May 8 15:39:45 2011
@@ -434,17 +434,10 @@ switch_file_external(const char *local_a
void *report_baton;
const svn_delta_editor_t *switch_editor;
void *switch_baton;
- const char *anchor_url;
const char *switch_rev_url;
+ const char *repos_uuid;
svn_revnum_t revnum;
- SVN_ERR(svn_wc__node_get_url(&anchor_url, ctx->wc_ctx, dir_abspath,
- subpool, subpool));
- if (! anchor_url)
- return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
- _("Directory '%s' has no URL"),
- svn_dirent_local_style(dir_abspath, subpool));
-
/* Open an RA session to 'source' URL */
SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
&switch_rev_url,
@@ -453,19 +446,23 @@ switch_file_external(const char *local_a
ctx, subpool));
SVN_ERR(svn_ra_reparent(ra_session, url, subpool));
+ SVN_ERR(svn_ra_get_uuid2(ra_session, &repos_uuid, subpool));
- SVN_ERR(svn_wc_get_switch_editor4(&switch_editor, &switch_baton,
- &revnum, ctx->wc_ctx,
- dir_abspath, target,
- switch_rev_url, use_commit_times,
- svn_depth_infinity, FALSE, FALSE, TRUE,
- diff3_cmd, preserved_exts,
- ctx->conflict_func2,
- ctx->conflict_baton2,
- NULL, NULL,
- ctx->cancel_func, ctx->cancel_baton,
- ctx->notify_func2, ctx->notify_baton2,
- subpool, subpool));
+ SVN_ERR(svn_wc__get_file_external_editor(&switch_editor, &switch_baton,
+ &revnum, ctx->wc_ctx,
+ local_abspath,
+ switch_rev_url,
+ repos_root_url,
+ repos_uuid,
+ use_commit_times,
+ diff3_cmd, preserved_exts,
+ ctx->conflict_func2,
+ ctx->conflict_baton2,
+ ctx->cancel_func,
+ ctx->cancel_baton,
+ ctx->notify_func2,
+ ctx->notify_baton2,
+ subpool, subpool));
/* Tell RA to do an update of URL+TARGET to REVISION; if we pass an
invalid revnum, that means RA will use the latest revision. */
@@ -479,6 +476,19 @@ switch_file_external(const char *local_a
ctx->cancel_func, ctx->cancel_baton,
ctx->notify_func2, ctx->notify_baton2,
subpool));
+
+ if (ctx->notify_func2)
+ {
+ svn_wc_notify_t *notify
+ = svn_wc_create_notify(local_abspath, svn_wc_notify_update_completed,
+ subpool);
+ notify->kind = svn_node_none;
+ notify->content_state = notify->prop_state
+ = svn_wc_notify_state_inapplicable;
+ notify->lock_state = svn_wc_notify_lock_state_inapplicable;
+ notify->revision = revnum;
+ (*ctx->notify_func2)(ctx->notify_baton2, notify, subpool);
+ }
}
cleanup:
Modified: subversion/trunk/subversion/libsvn_wc/externals.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/externals.c?rev=1100758&r1=1100757&r2=1100758&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/externals.c (original)
+++ subversion/trunk/subversion/libsvn_wc/externals.c Sun May 8 15:39:45 2011
@@ -31,15 +31,16 @@
#include <apr_tables.h>
#include <apr_general.h>
-#include "svn_types.h"
-#include "svn_string.h"
-#include "svn_pools.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_error.h"
-#include "svn_props.h"
-#include "svn_io.h"
#include "svn_hash.h"
+#include "svn_io.h"
+#include "svn_pools.h"
+#include "svn_props.h"
+#include "svn_string.h"
+#include "svn_time.h"
+#include "svn_types.h"
#include "svn_wc.h"
#include "private/svn_skel.h"
@@ -382,11 +383,15 @@ struct edit_baton
/* Information from the caller */
svn_boolean_t use_commit_times;
+ const apr_array_header_t *ext_patterns;
+ const char *diff3cmd;
const char *url;
const char *repos_root_url;
const char *repos_uuid;
+ svn_wc_conflict_resolver_func2_t conflict_func;
+ void *conflict_baton;
svn_cancel_func_t cancel_func;
void *cancel_baton;
svn_wc_notify_func2_t notify_func;
@@ -405,6 +410,8 @@ struct edit_baton
/* List of incoming propchanges */
apr_array_header_t *propchanges;
+
+ svn_boolean_t file_closed;
};
/* svn_delta_editor_t function for svn_wc__get_file_external_editor */
@@ -572,6 +579,11 @@ close_file(void *file_baton,
apr_pool_t *pool)
{
struct edit_baton *eb = file_baton;
+ svn_wc_notify_state_t prop_state = svn_wc_notify_state_unknown;
+ svn_wc_notify_state_t content_state = svn_wc_notify_state_unknown;
+ svn_boolean_t obstructed = FALSE;
+
+ eb->file_closed = TRUE; /* We bump the revision here */
if (expected_md5_digest)
{
@@ -608,39 +620,228 @@ close_file(void *file_baton,
svn_dirent_local_style(eb->local_abspath, pool));
}
+ /* First move the file in the pristine store; this hands over the cleanup
+ behavior to the pristine store. */
if (eb->new_sha1_checksum)
- SVN_ERR(svn_wc__db_pristine_install(eb->db, eb->new_pristine_abspath,
- eb->new_sha1_checksum,
- eb->new_md5_checksum, pool));
+ {
+ SVN_ERR(svn_wc__db_pristine_install(eb->db, eb->new_pristine_abspath,
+ eb->new_sha1_checksum,
+ eb->new_md5_checksum, pool));
+
+ eb->new_pristine_abspath = NULL;
+ }
/* ### TODO: Merge the changes */
{
- svn_skel_t *work_items;
+ svn_skel_t *all_work_items = NULL;
+ svn_skel_t *work_item;
+ apr_hash_t *base_props = NULL;
+ apr_hash_t *actual_props = NULL;
+ apr_hash_t *new_pristine_props = NULL;
+ apr_hash_t *new_actual_props = NULL;
+ apr_hash_t *new_dav_props = NULL;
+ const svn_checksum_t *new_checksum = NULL;
+ const svn_checksum_t *original_checksum = NULL;
+ svn_revnum_t changed_rev = SVN_INVALID_REVNUM;
+ apr_time_t changed_date = 0;
+ const char *changed_author = NULL;
+ svn_boolean_t added = !SVN_IS_VALID_REVNUM(eb->original_revision);
const char *repos_relpath = svn_uri_is_child(eb->repos_root_url,
eb->url, pool);
- /* ###### COMPLETE HACK: This just overwrites whatever there was.
- ###### Don't enable this code */
-/* SVN_ERR(svn_wc__wq_build_file_install(&work_items, eb->db,
- eb->local_abspath,
- NULL, eb->use_commit_times, TRUE,
- pool, pool));
+ if (! added)
+ {
+ svn_boolean_t had_props;
+
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, NULL, NULL,
+ &changed_rev, &changed_date,
+ &changed_author, NULL,
+ &original_checksum,
+ NULL, NULL, &had_props, NULL, NULL,
+ eb->db, eb->local_abspath,
+ pool, pool));
+
+ new_checksum = original_checksum;
+
+ if (had_props)
+ SVN_ERR(svn_wc__db_base_get_props(&base_props, eb->db,
+ eb->local_abspath,
+ pool, pool));
+
+ SVN_ERR(svn_wc__db_read_props(&actual_props, eb->db, eb->local_abspath,
+ pool, pool));
+ }
+
+ if (!base_props)
+ base_props = apr_hash_make(pool);
+
+ if (!actual_props)
+ actual_props = apr_hash_make(pool);
+
+ if (eb->new_sha1_checksum)
+ new_checksum = eb->new_sha1_checksum;
+
+ {
+ apr_array_header_t *entry_prop_changes;
+ apr_array_header_t *dav_prop_changes;
+ apr_array_header_t *regular_prop_changes;
+ int i;
+
+ SVN_ERR(svn_categorize_props(eb->propchanges, &entry_prop_changes,
+ &dav_prop_changes, ®ular_prop_changes,
+ pool));
+
+ for (i = 0; i < entry_prop_changes->nelts; i++)
+ {
+ const svn_prop_t *prop = &APR_ARRAY_IDX(entry_prop_changes, i,
+ svn_prop_t);
+
+ if (! prop->value)
+ continue; /* authz or something */
+
+ if (! strcmp(prop->name, SVN_PROP_ENTRY_LAST_AUTHOR))
+ changed_author = apr_pstrdup(pool, prop->value->data);
+ else if (! strcmp(prop->name, SVN_PROP_ENTRY_COMMITTED_REV))
+ {
+ apr_int64_t rev;
+ SVN_ERR(svn_cstring_atoi64(&rev, prop->value->data));
+ changed_rev = (svn_revnum_t)rev;
+ }
+ else if (! strcmp(prop->name, SVN_PROP_ENTRY_COMMITTED_DATE))
+ SVN_ERR(svn_time_from_cstring(&changed_date, prop->value->data,
+ pool));
+ }
+
+ if (dav_prop_changes->nelts > 0)
+ new_dav_props = svn_prop_array_to_hash(dav_prop_changes, pool);
+
+ if (regular_prop_changes->nelts > 0)
+ {
+ SVN_ERR(svn_wc__merge_props(&work_item, &prop_state,
+ &new_pristine_props,
+ &new_actual_props,
+ eb->db, eb->local_abspath,
+ svn_wc__db_kind_file,
+ NULL, NULL,
+ NULL /* server_baseprops*/,
+ base_props,
+ actual_props,
+ regular_prop_changes,
+ TRUE /* base_merge */,
+ FALSE /* dry_run */,
+ eb->conflict_func,
+ eb->conflict_baton,
+ eb->cancel_func, eb->cancel_baton,
+ pool, pool));
+
+ if (work_item)
+ all_work_items = svn_wc__wq_merge(all_work_items, work_item,
+ pool);
+ }
+ else
+ {
+ new_pristine_props = base_props;
+ new_actual_props = actual_props;
+ }
+ }
+
+ if (eb->new_sha1_checksum)
+ {
+ svn_node_kind_t disk_kind;
+ svn_boolean_t install_pristine = FALSE;
+ const char *install_from = NULL;
+
+ SVN_ERR(svn_io_check_path(eb->local_abspath, &disk_kind, pool));
+
+ if (disk_kind == svn_node_none)
+ {
+ /* Just install the file */
+ install_pristine = TRUE;
+ content_state = svn_wc_notify_state_changed;
+ }
+ else if (disk_kind != svn_node_file)
+ {
+ /* The node is obstructed; we just change the DB */
+ obstructed = TRUE;
+ content_state = svn_wc_notify_state_unchanged;
+ }
+ else
+ {
+ svn_boolean_t is_mod;
+ SVN_ERR(svn_wc__internal_file_modified_p(&is_mod, NULL, NULL,
+ eb->db, eb->local_abspath,
+ FALSE, FALSE, pool));
+
+ if (!is_mod)
+ {
+ install_pristine = TRUE;
+ content_state = svn_wc_notify_state_changed;
+ }
+ else
+ {
+ enum svn_wc_merge_outcome_t merge_outcome;
+ /* Ok, we have to do some work to merge a local change */
+ SVN_ERR(svn_wc__perform_file_merge(&work_item,
+ &merge_outcome,
+ eb->db,
+ eb->local_abspath,
+ eb->wri_abspath,
+ new_checksum,
+ original_checksum,
+ eb->ext_patterns,
+ eb->original_revision,
+ *eb->target_revision,
+ eb->propchanges,
+ eb->diff3cmd,
+ eb->conflict_func,
+ eb->conflict_baton,
+ eb->cancel_func,
+ eb->cancel_baton,
+ pool, pool));
+
+ all_work_items = svn_wc__wq_merge(all_work_items, work_item,
+ pool);
+
+ if (merge_outcome == svn_wc_merge_conflict)
+ content_state = svn_wc_notify_state_conflicted;
+ else
+ content_state = svn_wc_notify_state_merged;
+ }
+ }
+ if (install_pristine)
+ {
+ SVN_ERR(svn_wc__wq_build_file_install(&work_item, eb->db,
+ eb->local_abspath,
+ install_from,
+ eb->use_commit_times, TRUE,
+ pool, pool));
+
+ all_work_items = svn_wc__wq_merge(all_work_items, work_item, pool);
+ }
+ }
+ else
+ {
+ content_state = svn_wc_notify_state_unchanged;
+ /* ### Retranslate on magic property changes, etc. */
+ }
SVN_ERR(svn_wc__db_base_add_file(eb->db, eb->local_abspath,
repos_relpath,
eb->repos_root_url,
eb->repos_uuid,
*eb->target_revision,
- apr_hash_make(pool),
- 1,
- 1,
- "somebody",
- eb->new_sha1_checksum,
- NULL, NULL,
- FALSE, NULL,
- FALSE, FALSE,
- work_items,
+ new_pristine_props,
+ changed_rev,
+ changed_date,
+ changed_author,
+ new_checksum,
+ new_dav_props,
+ NULL,
+ TRUE, new_actual_props,
+ FALSE /* keep_recorded_info */,
+ FALSE /* insert_base_deleted */,
+ all_work_items,
pool));
{
@@ -655,7 +856,7 @@ close_file(void *file_baton,
}
SVN_ERR(svn_wc__wq_run(eb->db, eb->wri_abspath,
- eb->cancel_func, eb->cancel_baton, pool));*/
+ eb->cancel_func, eb->cancel_baton, pool));
}
if (eb->notify_func)
@@ -664,16 +865,46 @@ close_file(void *file_baton,
svn_wc_notify_t *notify;
if (SVN_IS_VALID_REVNUM(eb->original_revision))
- action = svn_wc_notify_update_update;
+ action = obstructed ? svn_wc_notify_update_shadowed_update
+ : svn_wc_notify_update_update;
else
- action = svn_wc_notify_update_add;
+ action = obstructed ? svn_wc_notify_update_shadowed_add
+ : svn_wc_notify_update_add;
notify = svn_wc_create_notify(eb->local_abspath, action, pool);
- notify->old_revision = eb->original_revision;
+ notify->kind = svn_node_file;
+
notify->revision = *eb->target_revision;
+ notify->prop_state = prop_state;
+ notify->content_state = content_state;
+
+ notify->old_revision = eb->original_revision;
eb->notify_func(eb->notify_baton, notify, pool);
}
+
+
+ return SVN_NO_ERROR;
+}
+
+/* svn_delta_editor_t function for svn_wc__get_file_external_editor */
+static svn_error_t *
+close_edit(void *edit_baton,
+ apr_pool_t *pool)
+{
+ struct edit_baton *eb = edit_baton;
+
+ if (!eb->file_closed)
+ {
+ /* The node wasn't updated, so we just have to bump its revision */
+ SVN_ERR(svn_wc__db_op_bump_revisions_post_update(eb->db,
+ eb->local_abspath,
+ svn_depth_infinity,
+ NULL, NULL, NULL,
+ *eb->target_revision,
+ apr_hash_make(pool),
+ pool));
+ }
return SVN_NO_ERROR;
}
@@ -716,7 +947,11 @@ svn_wc__get_file_external_editor(const s
eb->repos_uuid = apr_pstrdup(edit_pool, repos_uuid);
eb->use_commit_times = use_commit_times;
+ eb->ext_patterns = preserved_exts;
+ eb->diff3cmd = diff3_cmd;
+ eb->conflict_func = conflict_func;
+ eb->conflict_baton = conflict_baton;
eb->cancel_func = cancel_func;
eb->cancel_baton = cancel_baton;
eb->notify_func = notify_func;
@@ -731,6 +966,7 @@ svn_wc__get_file_external_editor(const s
tree_editor->apply_textdelta = apply_textdelta;
tree_editor->change_file_prop = change_file_prop;
tree_editor->close_file = close_file;
+ tree_editor->close_edit = close_edit;
return svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
tree_editor, eb,