Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/status.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/status.c?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/status.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/status.c Wed Mar 4 15:56:18 2015 @@ -53,6 +53,26 @@ #include "private/svn_editor.h" +/* The file internal variant of svn_wc_status3_t, with slightly more + data. + + Instead of directly creating svn_wc_status3_t instances, we really + create instances of this struct with slightly more data for processing + by the status walker and status editor. + + svn_wc_status3_dup() allocates space for this struct, but doesn't + copy the actual data. The remaining fields are copied by hash_stash(), + which is where the status editor stashes information for producing + later. */ +typedef struct svn_wc__internal_status_t +{ + svn_wc_status3_t s; /* First member; same pointer*/ + + svn_boolean_t has_descendants; + + /* Make sure to update hash_stash() when adding values here */ +} svn_wc__internal_status_t; + /*** Baton used for walking the local status */ struct walk_status_baton @@ -126,7 +146,7 @@ struct edit_baton const apr_array_header_t *ignores; /* Status item for the path represented by the anchor of the edit. */ - svn_wc_status3_t *anchor_status; + svn_wc__internal_status_t *anchor_status; /* Was open_root() called for this edit drive? */ svn_boolean_t root_opened; @@ -288,7 +308,7 @@ get_repos_root_url_relpath(const char ** } static svn_error_t * -internal_status(svn_wc_status3_t **status, +internal_status(svn_wc__internal_status_t **status, svn_wc__db_t *db, const char *local_abspath, svn_boolean_t check_working_copy, @@ -315,7 +335,7 @@ internal_status(svn_wc_status3_t **statu The status struct's repos_lock field will be set to REPOS_LOCK. */ static svn_error_t * -assemble_status(svn_wc_status3_t **status, +assemble_status(svn_wc__internal_status_t **status, svn_wc__db_t *db, const char *local_abspath, const char *parent_repos_root_url, @@ -330,6 +350,7 @@ assemble_status(svn_wc_status3_t **statu apr_pool_t *result_pool, apr_pool_t *scratch_pool) { + svn_wc__internal_status_t *inner_stat; svn_wc_status3_t *stat; svn_boolean_t switched_p = FALSE; svn_boolean_t copied = FALSE; @@ -582,7 +603,9 @@ assemble_status(svn_wc_status3_t **statu /* 6. Build and return a status structure. */ - stat = apr_pcalloc(result_pool, sizeof(**status)); + inner_stat = apr_pcalloc(result_pool, sizeof(*inner_stat)); + stat = &inner_stat->s; + inner_stat->has_descendants = info->has_descendants; switch (info->kind) { @@ -598,6 +621,7 @@ assemble_status(svn_wc_status3_t **statu stat->kind = svn_node_unknown; } stat->depth = info->depth; + if (dirent) { stat->filesize = (dirent->kind == svn_node_file) @@ -670,7 +694,7 @@ assemble_status(svn_wc_status3_t **statu stat->file_external = info->file_external; - *status = stat; + *status = inner_stat; return SVN_NO_ERROR; } @@ -684,7 +708,7 @@ assemble_status(svn_wc_status3_t **statu node_status to svn_wc_status_unversioned. */ static svn_error_t * -assemble_unversioned(svn_wc_status3_t **status, +assemble_unversioned(svn_wc__internal_status_t **status, svn_wc__db_t *db, const char *local_abspath, const svn_io_dirent2_t *dirent, @@ -693,10 +717,12 @@ assemble_unversioned(svn_wc_status3_t ** apr_pool_t *result_pool, apr_pool_t *scratch_pool) { + svn_wc__internal_status_t *inner_status; svn_wc_status3_t *stat; /* return a fairly blank structure. */ - stat = apr_pcalloc(result_pool, sizeof(*stat)); + inner_status = apr_pcalloc(result_pool, sizeof(*inner_status)); + stat = &inner_status->s; /*stat->versioned = FALSE;*/ stat->kind = svn_node_unknown; /* not versioned */ @@ -751,7 +777,7 @@ assemble_unversioned(svn_wc_status3_t ** stat->conflicted = tree_conflicted; stat->changelist = NULL; - *status = stat; + *status = inner_status; return SVN_NO_ERROR; } @@ -772,7 +798,7 @@ send_status_structure(const struct walk_ void *status_baton, apr_pool_t *scratch_pool) { - svn_wc_status3_t *statstruct; + svn_wc__internal_status_t *statstruct; const svn_lock_t *repos_lock = NULL; /* Check for a repository lock. */ @@ -806,7 +832,8 @@ send_status_structure(const struct walk_ if (statstruct && status_func) return svn_error_trace((*status_func)(status_baton, local_abspath, - statstruct, scratch_pool)); + &statstruct->s, + scratch_pool)); return SVN_NO_ERROR; } @@ -962,7 +989,7 @@ send_unversioned_item(const struct walk_ { svn_boolean_t is_ignored; svn_boolean_t is_external; - svn_wc_status3_t *status; + svn_wc__internal_status_t *status; const char *base_name = svn_dirent_basename(local_abspath, NULL); is_ignored = svn_wc_match_ignore_list(base_name, patterns, scratch_pool); @@ -974,12 +1001,12 @@ send_unversioned_item(const struct walk_ is_external = is_external_path(wb->externals, local_abspath, scratch_pool); if (is_external) - status->node_status = svn_wc_status_external; + status->s.node_status = svn_wc_status_external; /* We can have a tree conflict on an unversioned path, i.e. an incoming * delete on a locally deleted path during an update. Don't ever ignore * those! */ - if (status->conflicted) + if (status->s.conflicted) is_ignored = FALSE; /* If we aren't ignoring it, or if it's an externals path, pass this @@ -988,7 +1015,7 @@ send_unversioned_item(const struct walk_ || !is_ignored || is_external) return svn_error_trace((*status_func)(status_baton, local_abspath, - status, scratch_pool)); + &status->s, scratch_pool)); return SVN_NO_ERROR; } @@ -1091,7 +1118,7 @@ one_child_status(const struct walk_statu /* Descend in subdirectories. */ if (depth == svn_depth_infinity - && info->kind == svn_node_dir) + && info->has_descendants /* is dir, or was dir and tc descendants */) { SVN_ERR(get_dir_status(wb, local_abspath, TRUE, dir_repos_root_url, dir_repos_relpath, @@ -1451,9 +1478,15 @@ hash_stash(void *baton, { apr_hash_t *stat_hash = baton; apr_pool_t *hash_pool = apr_hash_pool_get(stat_hash); + void *new_status = svn_wc_dup_status3(status, hash_pool); + const svn_wc__internal_status_t *old_status = (const void*)status; + + /* Copy the internal/private data. */ + svn_wc__internal_status_t *is = new_status; + is->has_descendants = old_status->has_descendants; + assert(! svn_hash_gets(stat_hash, path)); - svn_hash_sets(stat_hash, apr_pstrdup(hash_pool, path), - svn_wc_dup_status3(status, hash_pool)); + svn_hash_sets(stat_hash, apr_pstrdup(hash_pool, path), new_status); return SVN_NO_ERROR; } @@ -1518,6 +1551,7 @@ tweak_statushash(void *baton, /* If not, make it so. */ if (! statstruct) { + svn_wc__internal_status_t *i_stat; /* If this item isn't being added, then we're most likely dealing with a non-recursive (or at least partially non-recursive) working copy. Due to bugs in how the client @@ -1533,8 +1567,9 @@ tweak_statushash(void *baton, return SVN_NO_ERROR; /* Use the public API to get a statstruct, and put it into the hash. */ - SVN_ERR(internal_status(&statstruct, db, local_abspath, + SVN_ERR(internal_status(&i_stat, db, local_abspath, check_working_copy, pool, scratch_pool)); + statstruct = &i_stat->s; statstruct->repos_lock = repos_lock; svn_hash_sets(statushash, apr_pstrdup(pool, local_abspath), statstruct); } @@ -1573,9 +1608,9 @@ tweak_statushash(void *baton, statstruct->repos_relpath = apr_pstrdup(pool, b->repos_relpath); statstruct->repos_root_url = - b->edit_baton->anchor_status->repos_root_url; + b->edit_baton->anchor_status->s.repos_root_url; statstruct->repos_uuid = - b->edit_baton->anchor_status->repos_uuid; + b->edit_baton->anchor_status->s.repos_uuid; } /* The last committed date, and author for deleted items @@ -1615,9 +1650,9 @@ tweak_statushash(void *baton, { statstruct->repos_relpath = apr_pstrdup(pool, b->repos_relpath); statstruct->repos_root_url = - b->edit_baton->anchor_status->repos_root_url; + b->edit_baton->anchor_status->s.repos_root_url; statstruct->repos_uuid = - b->edit_baton->anchor_status->repos_uuid; + b->edit_baton->anchor_status->s.repos_uuid; } statstruct->ood_kind = b->ood_kind; if (b->ood_changed_author) @@ -1633,7 +1668,7 @@ find_dir_repos_relpath(const struct dir_ { /* If we have no name, we're the root, return the anchor URL. */ if (! db->name) - return db->edit_baton->anchor_status->repos_relpath; + return db->edit_baton->anchor_status->s.repos_relpath; else { const char *repos_relpath; @@ -1665,7 +1700,7 @@ make_dir_baton(void **dir_baton, struct edit_baton *eb = edit_baton; struct dir_baton *d; const char *local_abspath; - const svn_wc_status3_t *status_in_parent; + const svn_wc__internal_status_t *status_in_parent; apr_pool_t *dir_pool; if (parent_baton) @@ -1724,8 +1759,7 @@ make_dir_baton(void **dir_baton, status_in_parent = eb->anchor_status; if (status_in_parent - && status_in_parent->versioned - && (status_in_parent->kind == svn_node_dir) + && (status_in_parent->has_descendants) && (! d->excluded) && (d->depth == svn_depth_unknown || d->depth == svn_depth_infinity @@ -1737,9 +1771,9 @@ make_dir_baton(void **dir_baton, const apr_array_header_t *ignores = eb->ignores; SVN_ERR(get_dir_status(&eb->wb, local_abspath, TRUE, - status_in_parent->repos_root_url, + status_in_parent->s.repos_root_url, NULL /*parent_repos_relpath*/, - status_in_parent->repos_uuid, + status_in_parent->s.repos_uuid, NULL, NULL /* dirent */, ignores, d->depth == svn_depth_files @@ -1754,7 +1788,7 @@ make_dir_baton(void **dir_baton, this_dir_status = svn_hash_gets(d->statii, d->local_abspath); if (this_dir_status && this_dir_status->versioned && (d->depth == svn_depth_unknown - || d->depth > status_in_parent->depth)) + || d->depth > status_in_parent->s.depth)) { d->depth = this_dir_status->depth; } @@ -1800,10 +1834,11 @@ make_file_baton(struct dir_baton *parent * This implementation should match the filter in assemble_status() */ static svn_boolean_t -is_sendable_status(const svn_wc_status3_t *status, +is_sendable_status(const svn_wc__internal_status_t *i_status, svn_boolean_t no_ignore, svn_boolean_t get_all) { + const svn_wc_status3_t *status = &i_status->s; /* If the repository status was touched at all, it's interesting. */ if (status->repos_node_status != svn_wc_status_none) return TRUE; @@ -1829,8 +1864,8 @@ is_sendable_status(const svn_wc_status3_ return TRUE; /* If the text, property or tree state is interesting, send it. */ - if ((status->node_status != svn_wc_status_none - && (status->node_status != svn_wc_status_normal))) + if ((status->node_status != svn_wc_status_none) + && (status->node_status != svn_wc_status_normal)) return TRUE; /* If it's switched, send it. */ @@ -1913,14 +1948,14 @@ handle_statii(struct edit_baton *eb, for (hi = apr_hash_first(pool, statii); hi; hi = apr_hash_next(hi)) { const char *local_abspath = apr_hash_this_key(hi); - svn_wc_status3_t *status = apr_hash_this_val(hi); + svn_wc__internal_status_t *status = apr_hash_this_val(hi); /* Clear the subpool. */ svn_pool_clear(iterpool); /* Now, handle the status. We don't recurse for svn_depth_immediates because we already have the subdirectories' statii. */ - if (status->versioned && status->kind == svn_node_dir + if (status->has_descendants && (depth == svn_depth_unknown || depth == svn_depth_infinity)) { @@ -1936,9 +1971,9 @@ handle_statii(struct edit_baton *eb, iterpool)); } if (dir_was_deleted) - status->repos_node_status = svn_wc_status_deleted; + status->s.repos_node_status = svn_wc_status_deleted; if (is_sendable_status(status, eb->no_ignore, eb->get_all)) - SVN_ERR((eb->status_func)(eb->status_baton, local_abspath, status, + SVN_ERR((eb->status_func)(eb->status_baton, local_abspath, &status->s, iterpool)); } @@ -2138,17 +2173,17 @@ close_directory(void *dir_baton, /* We're editing the root dir of the WC. As its repos status info isn't otherwise set, set it directly to trigger invocation of the status callback below. */ - eb->anchor_status->repos_node_status = repos_node_status; - eb->anchor_status->repos_prop_status = repos_prop_status; - eb->anchor_status->repos_text_status = repos_text_status; + eb->anchor_status->s.repos_node_status = repos_node_status; + eb->anchor_status->s.repos_prop_status = repos_prop_status; + eb->anchor_status->s.repos_text_status = repos_text_status; /* If the root dir is out of date set the ood info directly too. */ - if (db->ood_changed_rev != eb->anchor_status->revision) + if (db->ood_changed_rev != eb->anchor_status->s.revision) { - eb->anchor_status->ood_changed_rev = db->ood_changed_rev; - eb->anchor_status->ood_changed_date = db->ood_changed_date; - eb->anchor_status->ood_kind = db->ood_kind; - eb->anchor_status->ood_changed_author = + eb->anchor_status->s.ood_changed_rev = db->ood_changed_rev; + eb->anchor_status->s.ood_changed_date = db->ood_changed_date; + eb->anchor_status->s.ood_kind = db->ood_kind; + eb->anchor_status->s.ood_changed_author = apr_pstrdup(pool, db->ood_changed_author); } } @@ -2159,25 +2194,25 @@ close_directory(void *dir_baton, if (pb && ! db->excluded) { svn_boolean_t was_deleted = FALSE; - const svn_wc_status3_t *dir_status; + svn_wc__internal_status_t *dir_status; /* See if the directory was deleted or replaced. */ dir_status = svn_hash_gets(pb->statii, db->local_abspath); if (dir_status && - ((dir_status->repos_node_status == svn_wc_status_deleted) - || (dir_status->repos_node_status == svn_wc_status_replaced))) + ((dir_status->s.repos_node_status == svn_wc_status_deleted) + || (dir_status->s.repos_node_status == svn_wc_status_replaced))) was_deleted = TRUE; /* Now do the status reporting. */ SVN_ERR(handle_statii(eb, - dir_status ? dir_status->repos_root_url : NULL, - dir_status ? dir_status->repos_relpath : NULL, - dir_status ? dir_status->repos_uuid : NULL, + dir_status ? dir_status->s.repos_root_url : NULL, + dir_status ? dir_status->s.repos_relpath : NULL, + dir_status ? dir_status->s.repos_uuid : NULL, db->statii, was_deleted, db->depth, scratch_pool)); if (dir_status && is_sendable_status(dir_status, eb->no_ignore, eb->get_all)) SVN_ERR((eb->status_func)(eb->status_baton, db->local_abspath, - dir_status, scratch_pool)); + &dir_status->s, scratch_pool)); svn_hash_sets(pb->statii, db->local_abspath, NULL); } else if (! pb) @@ -2186,13 +2221,12 @@ close_directory(void *dir_baton, target, we should only report the target. */ if (*eb->target_basename) { - const svn_wc_status3_t *tgt_status; + const svn_wc__internal_status_t *tgt_status; tgt_status = svn_hash_gets(db->statii, eb->target_abspath); if (tgt_status) { - if (tgt_status->versioned - && tgt_status->kind == svn_node_dir) + if (tgt_status->has_descendants) { SVN_ERR(get_dir_status(&eb->wb, eb->target_abspath, TRUE, @@ -2207,7 +2241,7 @@ close_directory(void *dir_baton, } if (is_sendable_status(tgt_status, eb->no_ignore, eb->get_all)) SVN_ERR((eb->status_func)(eb->status_baton, eb->target_abspath, - tgt_status, scratch_pool)); + &tgt_status->s, scratch_pool)); } } else @@ -2216,15 +2250,15 @@ close_directory(void *dir_baton, Note that our directory couldn't have been deleted, because it is the root of the edit drive. */ SVN_ERR(handle_statii(eb, - eb->anchor_status->repos_root_url, - eb->anchor_status->repos_relpath, - eb->anchor_status->repos_uuid, + eb->anchor_status->s.repos_root_url, + eb->anchor_status->s.repos_relpath, + eb->anchor_status->s.repos_uuid, db->statii, FALSE, eb->default_depth, scratch_pool)); if (is_sendable_status(eb->anchor_status, eb->no_ignore, eb->get_all)) SVN_ERR((eb->status_func)(eb->status_baton, db->local_abspath, - eb->anchor_status, scratch_pool)); + &eb->anchor_status->s, scratch_pool)); eb->anchor_status = NULL; } } @@ -2645,7 +2679,7 @@ svn_wc__internal_walk_status(svn_wc__db_ } if (info - && info->kind == svn_node_dir + && info->has_descendants /* is dir, or was dir and has tc descendants */ && info->status != svn_wc__db_status_not_present && info->status != svn_wc__db_status_excluded && info->status != svn_wc__db_status_server_excluded) @@ -2765,7 +2799,7 @@ svn_wc_get_default_ignores(apr_array_hea /* */ static svn_error_t * -internal_status(svn_wc_status3_t **status, +internal_status(svn_wc__internal_status_t **status, svn_wc__db_t *db, const char *local_abspath, svn_boolean_t check_working_copy, @@ -2872,17 +2906,21 @@ svn_wc_status3(svn_wc_status3_t **status apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - return svn_error_trace( - internal_status(status, wc_ctx->db, local_abspath, - TRUE /* check_working_copy */, - result_pool, scratch_pool)); + svn_wc__internal_status_t *stat; + SVN_ERR(internal_status(&stat, wc_ctx->db, local_abspath, + TRUE /* check_working_copy */, + result_pool, scratch_pool)); + *status = &stat->s; + return SVN_NO_ERROR; } svn_wc_status3_t * svn_wc_dup_status3(const svn_wc_status3_t *orig_stat, apr_pool_t *pool) { - svn_wc_status3_t *new_stat = apr_palloc(pool, sizeof(*new_stat)); + /* Allocate slightly more room */ + svn_wc__internal_status_t *new_istat = apr_palloc(pool, sizeof(*new_istat)); + svn_wc_status3_t *new_stat = &new_istat->s; /* Shallow copy all members. */ *new_stat = *orig_stat;
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/update_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/update_editor.c?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/update_editor.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/update_editor.c Wed Mar 4 15:56:18 2015 @@ -1937,7 +1937,12 @@ add_directory(const char *path, } else if (status == svn_wc__db_status_normal) { - if (wc_kind == svn_node_dir) + svn_boolean_t root; + + SVN_ERR(svn_wc__db_is_wcroot(&root, eb->db, db->local_abspath, + scratch_pool)); + + if (root) { /* !! We found the root of a working copy obstructing the wc !! @@ -1949,9 +1954,16 @@ add_directory(const char *path, resolved. Note that svn_wc__db_base_add_not_present_node() explicitly adds the node into the parent's node database. */ - svn_hash_sets(pb->not_present_nodes, apr_pstrdup(pb->pool, db->name), + svn_hash_sets(pb->not_present_nodes, + apr_pstrdup(pb->pool, db->name), svn_node_kind_to_word(svn_node_dir)); } + else if (wc_kind == svn_node_dir) + { + /* We have an editor violation. Github sometimes does this + in its subversion compatibility code, when changing the + depth of a working copy, or on updates from incomplete */ + } else { /* We found a file external occupating the place we need in BASE. @@ -3108,18 +3120,32 @@ add_file(const char *path, } else if (status == svn_wc__db_status_normal) { - if (wc_kind == svn_node_dir) + svn_boolean_t root; + + SVN_ERR(svn_wc__db_is_wcroot(&root, eb->db, fb->local_abspath, + scratch_pool)); + + if (root) { /* !! We found the root of a working copy obstructing the wc !! If the directory would be part of our own working copy then - we wouldn't have been called as an add_file(). + we wouldn't have been called as an add_directory(). The only thing we can do is add a not-present node, to allow a future update to bring in the new files when the problem is - resolved. */ - svn_hash_sets(pb->not_present_nodes, apr_pstrdup(pb->pool, fb->name), - svn_node_kind_to_word(svn_node_file)); + resolved. Note that svn_wc__db_base_add_not_present_node() + explicitly adds the node into the parent's node database. */ + + svn_hash_sets(pb->not_present_nodes, + apr_pstrdup(pb->pool, fb->name), + svn_node_kind_to_word(svn_node_dir)); + } + else if (wc_kind == svn_node_dir) + { + /* We have an editor violation. Github sometimes does this + in its subversion compatibility code, when changing the + depth of a working copy, or on updates from incomplete */ } else { Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/upgrade.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/upgrade.c?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/upgrade.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/upgrade.c Wed Mar 4 15:56:18 2015 @@ -2366,40 +2366,6 @@ is_old_wcroot(const char *local_abspath, svn_dirent_local_style(parent_abspath, scratch_pool)); } -/* Data for upgrade_working_copy_txn(). */ -typedef struct upgrade_working_copy_baton_t -{ - svn_wc__db_t *db; - const char *dir_abspath; - svn_wc_upgrade_get_repos_info_t repos_info_func; - void *repos_info_baton; - apr_hash_t *repos_cache; - const struct upgrade_data_t *data; - svn_cancel_func_t cancel_func; - void *cancel_baton; - svn_wc_notify_func2_t notify_func; - void *notify_baton; - apr_pool_t *result_pool; -} upgrade_working_copy_baton_t; - - -/* Helper for svn_wc_upgrade. Implements svn_sqlite__transaction_callback_t */ -static svn_error_t * -upgrade_working_copy_txn(void *baton, - svn_sqlite__db_t *sdb, - apr_pool_t *scratch_pool) -{ - upgrade_working_copy_baton_t *b = baton; - - /* Upgrade the pre-wcng into a wcng in a temporary location. */ - return(upgrade_working_copy(NULL, b->db, b->dir_abspath, - b->repos_info_func, b->repos_info_baton, - b->repos_cache, b->data, - b->cancel_func, b->cancel_baton, - b->notify_func, b->notify_baton, - b->result_pool, scratch_pool)); -} - svn_error_t * svn_wc_upgrade(svn_wc_context_t *wc_ctx, const char *local_abspath, @@ -2419,7 +2385,6 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx, svn_wc_entry_t *this_dir; apr_hash_t *entries; const char *root_adm_abspath; - upgrade_working_copy_baton_t cb_baton; svn_error_t *err; int result_format; svn_boolean_t bumped_format; @@ -2517,22 +2482,14 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx, SVN_ERR(svn_wc__db_wclock_obtain(db, data.root_abspath, 0, FALSE, scratch_pool)); - cb_baton.db = db; - cb_baton.dir_abspath = local_abspath; - cb_baton.repos_info_func = repos_info_func; - cb_baton.repos_info_baton = repos_info_baton; - cb_baton.repos_cache = repos_cache; - cb_baton.data = &data; - cb_baton.cancel_func = cancel_func; - cb_baton.cancel_baton = cancel_baton; - cb_baton.notify_func = notify_func; - cb_baton.notify_baton = notify_baton; - cb_baton.result_pool = scratch_pool; - - SVN_ERR(svn_sqlite__with_lock(data.sdb, - upgrade_working_copy_txn, - &cb_baton, - scratch_pool)); + SVN_SQLITE__WITH_LOCK( + upgrade_working_copy(NULL, db, local_abspath, + repos_info_func, repos_info_baton, + repos_cache, &data, + cancel_func, cancel_baton, + notify_func, notify_baton, + scratch_pool, scratch_pool), + data.sdb); /* A workqueue item to move the pristine dir into place */ pristine_from = svn_wc__adm_child(data.root_abspath, PRISTINE_STORAGE_RELPATH, Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc-queries.sql URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc-queries.sql?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc-queries.sql (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc-queries.sql Wed Mar 4 15:56:18 2015 @@ -46,7 +46,7 @@ SELECT op_depth, nodes.repos_id, nodes.r lock_token, lock_owner, lock_comment, lock_date FROM nodes LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id - AND nodes.repos_path = lock.repos_relpath + AND nodes.repos_path = lock.repos_relpath AND nodes.op_depth=0 WHERE wc_id = ?1 AND local_relpath = ?2 ORDER BY op_depth DESC @@ -134,7 +134,7 @@ SELECT op_depth, nodes.repos_id, nodes.r lock_comment, lock_date, local_relpath, moved_here, moved_to, file_external FROM nodes LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id - AND nodes.repos_path = lock.repos_relpath AND op_depth = 0 + AND nodes.repos_path = lock.repos_relpath AND nodes.op_depth = 0 WHERE wc_id = ?1 AND parent_relpath = ?2 ORDER BY local_relpath DESC, op_depth DESC @@ -148,7 +148,7 @@ SELECT op_depth, nodes.repos_id, nodes.r lock_comment, lock_date, local_relpath, moved_here, moved_to, file_external FROM nodes LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id - AND nodes.repos_path = lock.repos_relpath AND op_depth = 0 + AND nodes.repos_path = lock.repos_relpath WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0 ORDER BY local_relpath DESC @@ -249,7 +249,8 @@ WHERE wc_id = ?1 AND IS_STRICT_DESCENDAN -- STMT_DELETE_BASE_RECURSIVE DELETE FROM nodes -WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2) +WHERE wc_id = ?1 AND (local_relpath = ?2 + OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) AND op_depth = 0 -- STMT_DELETE_WORKING_OP_DEPTH @@ -954,6 +955,14 @@ SELECT local_dir_relpath FROM wc_lock WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_dir_relpath, ?2) +-- STMT_FIND_CONFLICT_DESCENDANT +SELECT 1 FROM actual_node +WHERE wc_id = ?1 + AND local_relpath > (?2 || '/') + AND local_relpath < (?2 || '0') /* '0' = ascii('/') +1 */ + AND conflict_data IS NOT NULL +LIMIT 1 + -- STMT_DELETE_WC_LOCK_ORPHAN DELETE FROM wc_lock WHERE wc_id = ?1 AND local_dir_relpath = ?2 Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.c?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.c Wed Mar 4 15:56:18 2015 @@ -2125,11 +2125,13 @@ db_base_remove(svn_wc__db_wcroot_t *wcro int op_depth; svn_node_kind_t wrk_kind; svn_boolean_t no_delete_wc = FALSE; + svn_boolean_t file_external; SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, &revision, &repos_relpath, &repos_id, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + &file_external, wcroot, local_relpath, scratch_pool, scratch_pool)); @@ -2360,35 +2362,69 @@ db_base_remove(svn_wc__db_wcroot_t *wcro SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); SVN_ERR(svn_sqlite__step_done(stmt)); - /* Step 5: handle the BASE node itself */ - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_DELETE_BASE_NODE)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); - SVN_ERR(svn_sqlite__step_done(stmt)); - SVN_ERR(db_retract_parent_delete(wcroot, local_relpath, 0, scratch_pool)); if (mark_not_present || mark_excluded) { struct insert_base_baton_t ibb; - blank_ibb(&ibb); + svn_boolean_t no_marker = FALSE; - ibb.repos_id = repos_id; - ibb.status = mark_excluded ? svn_wc__db_status_excluded - : svn_wc__db_status_not_present; - ibb.kind = kind; - ibb.repos_relpath = repos_relpath; - ibb.revision = SVN_IS_VALID_REVNUM(marker_revision) - ? marker_revision - : revision; - - /* Depending upon KIND, any of these might get used. */ - ibb.children = NULL; - ibb.depth = svn_depth_unknown; - ibb.checksum = NULL; - ibb.target = NULL; + if (file_external) + { + const char *parent_local_relpath; + const char *name; + svn_error_t *err; - SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool)); + /* For file externals we only want to place a not present marker + if there is a BASE parent */ + + svn_relpath_split(&parent_local_relpath, &name, local_relpath, + scratch_pool); + + err = svn_wc__db_base_get_info_internal(NULL, NULL, NULL, + &repos_relpath, &repos_id, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + wcroot, parent_local_relpath, + scratch_pool, scratch_pool); + + if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND) + return svn_error_trace(err); + else if (err) + { + svn_error_clear(err); + no_marker = TRUE; + } + else + { + /* Replace the repos_relpath with something more expected than + the unrelated old file external repository relpath, which + one day may come from a different repository */ + repos_relpath = svn_relpath_join(repos_relpath, name, scratch_pool); + } + } + + if (!no_marker) + { + blank_ibb(&ibb); + + ibb.repos_id = repos_id; + ibb.status = mark_excluded ? svn_wc__db_status_excluded + : svn_wc__db_status_not_present; + ibb.kind = kind; + ibb.repos_relpath = repos_relpath; + ibb.revision = SVN_IS_VALID_REVNUM(marker_revision) + ? marker_revision + : revision; + + /* Depending upon KIND, any of these might get used. */ + ibb.children = NULL; + ibb.depth = svn_depth_unknown; + ibb.checksum = NULL; + ibb.target = NULL; + + SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool)); + } } SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool)); @@ -3007,6 +3043,11 @@ svn_wc__db_depth_get_info(svn_wc__db_sta return svn_error_compose_create(err, svn_sqlite__reset(stmt)); } +/* A callback which supplies WCROOTs and LOCAL_RELPATHs. */ +typedef svn_error_t *(*svn_wc__db_txn_callback_t)(void *baton, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_pool_t *scratch_pool); /* Baton for passing args to with_triggers(). */ struct with_triggers_baton_t { @@ -3083,8 +3124,13 @@ with_finalization(svn_wc__db_wcroot_t *w svn_error_t *err1; svn_error_t *err2; - err1 = svn_wc__db_with_txn(wcroot, local_relpath, txn_cb, txn_baton, - scratch_pool); + err1 = svn_sqlite__begin_savepoint(wcroot->sdb); + if (!err1) + { + err1 = txn_cb(txn_baton, wcroot, local_relpath, scratch_pool); + + err1 = svn_sqlite__finish_savepoint(wcroot->sdb, err1); + } if (err1 == NULL && notify_func != NULL) { @@ -3470,11 +3516,18 @@ db_external_remove(const svn_skel_t *wor apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; + int affected_rows; SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_DELETE_EXTERNAL)); SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); - SVN_ERR(svn_sqlite__step_done(stmt)); + SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); + + if (!affected_rows) + return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, + _("The node '%s' is not an external."), + path_for_error_message(wcroot, local_relpath, + scratch_pool)); SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool)); @@ -3957,14 +4010,14 @@ get_moved_to(const char **moved_to_relpa /* The body of svn_wc__db_scan_deletion(). */ static svn_error_t * -scan_deletion_txn(const char **base_del_relpath, - const char **moved_to_relpath, - const char **work_del_relpath, - const char **moved_to_op_root_relpath, - svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +scan_deletion(const char **base_del_relpath, + const char **moved_to_relpath, + const char **work_del_relpath, + const char **moved_to_op_root_relpath, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { const char *current_relpath = local_relpath; svn_sqlite__stmt_t *stmt; @@ -4109,6 +4162,25 @@ scan_deletion_txn(const char **base_del_ } svn_error_t * +svn_wc__db_scan_deletion_internal( + const char **base_del_relpath, + const char **moved_to_relpath, + const char **work_del_relpath, + const char **moved_to_op_root_relpath, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_error_trace( + scan_deletion(base_del_relpath, moved_to_relpath, work_del_relpath, + moved_to_op_root_relpath, + wcroot, local_relpath, + result_pool, scratch_pool)); +} + + +svn_error_t * svn_wc__db_scan_deletion(const char **base_del_abspath, const char **moved_to_abspath, const char **work_del_abspath, @@ -4130,9 +4202,9 @@ svn_wc__db_scan_deletion(const char **ba VERIFY_USABLE_WCROOT(wcroot); SVN_WC__DB_WITH_TXN( - scan_deletion_txn(&base_del_relpath, &moved_to_relpath, - &work_del_relpath, &moved_to_op_root_relpath, - wcroot, local_relpath, result_pool, scratch_pool), + scan_deletion(&base_del_relpath, &moved_to_relpath, + &work_del_relpath, &moved_to_op_root_relpath, + wcroot, local_relpath, result_pool, scratch_pool), wcroot); if (base_del_abspath) @@ -4230,10 +4302,10 @@ get_info_for_copy(apr_int64_t *copyfrom_ { const char *base_del_relpath, *work_del_relpath; - SVN_ERR(scan_deletion_txn(&base_del_relpath, NULL, - &work_del_relpath, - NULL, src_wcroot, local_relpath, - scratch_pool, scratch_pool)); + SVN_ERR(scan_deletion(&base_del_relpath, NULL, + &work_del_relpath, + NULL, src_wcroot, local_relpath, + scratch_pool, scratch_pool)); if (work_del_relpath) { const char *op_root_relpath; @@ -8990,10 +9062,8 @@ read_info(svn_wc__db_status_t *status, err = svn_error_compose_create(err, svn_sqlite__reset(stmt_act)); if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND) - err = svn_error_quick_wrap(err, - apr_psprintf(scratch_pool, - _("Error reading node '%s'"), - local_relpath)); + err = svn_error_quick_wrapf(err, _("Error reading node '%s'"), + local_relpath); SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt_info))); @@ -9113,6 +9183,27 @@ is_wclocked(svn_boolean_t *locked, const char *dir_relpath, apr_pool_t *scratch_pool); +/* Helper for read_children_info and single variant */ +static svn_error_t * +find_conflict_descendants(svn_boolean_t *conflict_exists, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_pool_t *scratch_pool) +{ + svn_sqlite__stmt_t *stmt; + + /* Only used on files, so certainly not wcroot*/ + assert(local_relpath[0] != '\0'); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_FIND_CONFLICT_DESCENDANT)); + + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step(conflict_exists, stmt)); + + return svn_error_trace(svn_sqlite__reset(stmt)); +} + /* What we really want to store about a node. This relies on the offset of svn_wc__db_info_t being zero. */ struct read_children_info_item_t @@ -9120,6 +9211,7 @@ struct read_children_info_item_t struct svn_wc__db_info_t info; int op_depth; int nr_layers; + svn_boolean_t was_dir; }; /* Implementation of svn_wc__db_read_children_info */ @@ -9169,7 +9261,7 @@ read_children_info(svn_wc__db_wcroot_t * op_depth = svn_sqlite__column_int(stmt, 0); /* Do we have new or better information? */ - if (new_child || op_depth > child_item->op_depth) + if (new_child) { struct svn_wc__db_info_t *child = &child_item->info; child_item->op_depth = op_depth; @@ -9250,6 +9342,8 @@ read_children_info(svn_wc__db_wcroot_t * child->depth = svn_depth_unknown; else { + child->has_descendants = TRUE; + child_item->was_dir = TRUE; child->depth = svn_sqlite__column_token_null(stmt, 11, depth_map, svn_depth_unknown); if (new_child) @@ -9292,6 +9386,17 @@ read_children_info(svn_wc__db_wcroot_t * if (new_child) svn_hash_sets(nodes, apr_pstrdup(result_pool, name), child); } + else if (!child_item->was_dir + && svn_sqlite__column_token(stmt, 4, kind_map) == svn_node_dir) + { + child_item->was_dir = TRUE; + + err = find_conflict_descendants(&child_item->info.has_descendants, + wcroot, child_relpath, + scratch_pool); + if (err) + SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt))); + } if (op_depth == 0) { @@ -9600,6 +9705,12 @@ read_single_info(const struct svn_wc__db if (!base_tree_only && mtb->kind == svn_node_dir) SVN_ERR(is_wclocked(&mtb->locked, wcroot, local_relpath, scratch_pool)); + if (mtb->kind == svn_node_dir) + mtb->has_descendants = TRUE; + else + SVN_ERR(find_conflict_descendants(&mtb->has_descendants, + wcroot, local_relpath, scratch_pool)); + *info = mtb; return SVN_NO_ERROR; @@ -9965,12 +10076,12 @@ db_read_repos_info(svn_revnum_t *revisio const char *base_del_relpath; const char *work_del_relpath; - SVN_ERR(scan_deletion_txn(&base_del_relpath, NULL, - &work_del_relpath, - NULL, wcroot, - local_relpath, - scratch_pool, - scratch_pool)); + SVN_ERR(scan_deletion(&base_del_relpath, NULL, + &work_del_relpath, + NULL, wcroot, + local_relpath, + scratch_pool, + scratch_pool)); if (work_del_relpath) { @@ -11197,11 +11308,11 @@ relocate_txn(svn_wc__db_wcroot_t *wcroot { const char *work_del_relpath; - SVN_ERR(scan_deletion_txn(NULL, NULL, - &work_del_relpath, NULL, - wcroot, local_dir_relpath, - scratch_pool, - scratch_pool)); + SVN_ERR(scan_deletion(NULL, NULL, + &work_del_relpath, NULL, + wcroot, local_dir_relpath, + scratch_pool, + scratch_pool)); if (work_del_relpath) { /* Deleted within a copy/move */ @@ -11289,59 +11400,86 @@ svn_wc__db_global_relocate(svn_wc__db_t } -/* Set *REPOS_ID and *REPOS_RELPATH to the BASE repository location of +/* Helper for commit_node() + Set *REPOS_ID and *REPOS_RELPATH to the BASE repository location of (WCROOT, LOCAL_RELPATH), directly if its BASE row exists or implied from its parent's BASE row if not. In the latter case, error if the parent BASE row does not exist. */ static svn_error_t * -determine_repos_info(apr_int64_t *repos_id, - const char **repos_relpath, - svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +determine_commit_repos_info(apr_int64_t *repos_id, + const char **repos_relpath, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; - const char *repos_parent_relpath; - const char *local_parent_relpath, *name; - - /* ### is it faster to fetch fewer columns? */ + int op_depth; /* Prefer the current node's repository information. */ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_SELECT_BASE_NODE)); + STMT_SELECT_NODE_INFO)); SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); - if (have_row) + if (!have_row) + return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, + svn_sqlite__reset(stmt), + _("The node '%s' was not found."), + path_for_error_message(wcroot, local_relpath, + scratch_pool)); + + op_depth = svn_sqlite__column_int(stmt, 0); + + if (op_depth > 0) { - SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 0)); - SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 1)); + svn_wc__db_status_t presence = svn_sqlite__column_token(stmt, 3, + presence_map); - *repos_id = svn_sqlite__column_int64(stmt, 0); - *repos_relpath = svn_sqlite__column_text(stmt, 1, result_pool); + if (presence == svn_wc__db_status_base_deleted) + { + SVN_ERR(svn_sqlite__step_row(stmt)); /* There must be a row */ + op_depth = svn_sqlite__column_int(stmt, 0); + } + else + { + const char *parent_repos_relpath; + const char *parent_relpath; + const char *name; - return svn_error_trace(svn_sqlite__reset(stmt)); + SVN_ERR(svn_sqlite__reset(stmt)); + + /* The repository relative path of an add/copy is based on its + ancestor, not on the shadowed base layer. + + As this function is only used from the commit processing we know + the parent directory has only a BASE row, so we can just obtain + the information directly by recursing (once!) */ + + svn_relpath_split(&parent_relpath, &name, local_relpath, + scratch_pool); + + SVN_ERR(determine_commit_repos_info(repos_id, &parent_repos_relpath, + wcroot, parent_relpath, + scratch_pool, scratch_pool)); + + *repos_relpath = svn_relpath_join(parent_repos_relpath, name, + result_pool); + return SVN_NO_ERROR; + } } - SVN_ERR(svn_sqlite__reset(stmt)); - /* This was a child node within this wcroot. We want to look at the - BASE node of the directory. */ - svn_relpath_split(&local_parent_relpath, &name, local_relpath, scratch_pool); + SVN_ERR_ASSERT(op_depth == 0); /* And that row must be BASE */ - /* The REPOS_ID will be the same (### until we support mixed-repos) */ - SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL, - &repos_parent_relpath, repos_id, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - wcroot, local_parent_relpath, - scratch_pool, scratch_pool)); + SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 1)); + SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 2)); - *repos_relpath = svn_relpath_join(repos_parent_relpath, name, result_pool); + *repos_id = svn_sqlite__column_int64(stmt, 1); + *repos_relpath = svn_sqlite__column_text(stmt, 2, result_pool); - return SVN_NO_ERROR; + return svn_error_trace(svn_sqlite__reset(stmt)); } static svn_error_t * @@ -11548,9 +11686,9 @@ commit_node(svn_wc__db_wcroot_t *wcroot, For existing nodes, we should retain the (potentially-switched) repository information. */ - SVN_ERR(determine_repos_info(&repos_id, &repos_relpath, - wcroot, local_relpath, - scratch_pool, scratch_pool)); + SVN_ERR(determine_commit_repos_info(&repos_id, &repos_relpath, + wcroot, local_relpath, + scratch_pool, scratch_pool)); /* ### is it better to select only the data needed? */ SVN_ERR(svn_sqlite__get_statement(&stmt_info, wcroot->sdb, @@ -12747,6 +12885,27 @@ scan_addition(svn_wc__db_status_t *statu } svn_error_t * +svn_wc__db_scan_addition_internal( + svn_wc__db_status_t *status, + const char **op_root_relpath_p, + const char **repos_relpath, + apr_int64_t *repos_id, + const char **original_repos_relpath, + apr_int64_t *original_repos_id, + svn_revnum_t *original_revision, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_error_trace( + scan_addition(status, op_root_relpath_p, repos_relpath, repos_id, + original_repos_relpath, original_repos_id, + original_revision, NULL, NULL, NULL, + wcroot, local_relpath, result_pool, scratch_pool)); +} + +svn_error_t * svn_wc__db_scan_addition(svn_wc__db_status_t *status, const char **op_root_abspath, const char **repos_relpath, Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.h URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.h?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.h (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.h Wed Mar 4 15:56:18 2015 @@ -20,7 +20,7 @@ * ==================================================================== * @endcopyright * - * @file svn_wc_db.h + * @file wc_db.h * @brief The Subversion Working Copy Library - Metadata/Base-Text Support * * Requires: @@ -2019,6 +2019,7 @@ struct svn_wc__db_info_t { svn_boolean_t moved_here; /* Only on op-roots. */ svn_boolean_t file_external; + svn_boolean_t has_descendants; /* Is dir, or has tc descendants */ }; /* Return in *NODES a hash mapping name->struct svn_wc__db_info_t for Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_private.h URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_private.h?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_private.h (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_private.h Wed Mar 4 15:56:18 2015 @@ -313,6 +313,32 @@ svn_wc__db_depth_get_info(svn_wc__db_sta apr_pool_t *result_pool, apr_pool_t *scratch_pool); +svn_error_t * +svn_wc__db_scan_addition_internal( + svn_wc__db_status_t *status, + const char **op_root_relpath_p, + const char **repos_relpath, + apr_int64_t *repos_id, + const char **original_repos_relpath, + apr_int64_t *original_repos_id, + svn_revnum_t *original_revision, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +svn_error_t * +svn_wc__db_scan_deletion_internal( + const char **base_del_relpath, + const char **moved_to_relpath, + const char **work_del_relpath, + const char **moved_to_op_root_relpath, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + /* Look up REPOS_ID in WCROOT->SDB and set *REPOS_ROOT_URL and/or *REPOS_UUID to its root URL and UUID respectively. If REPOS_ID is INVALID_REPOS_ID, use NULL for both URL and UUID. Either or both output parameters may be @@ -345,23 +371,6 @@ svn_wc__db_mark_conflict_internal(svn_wc /* Transaction handling */ -/* A callback which supplies WCROOTs and LOCAL_RELPATHs. */ -typedef svn_error_t *(*svn_wc__db_txn_callback_t)(void *baton, - svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - apr_pool_t *scratch_pool); - - -/* Run CB_FUNC in a SQLite transaction with CB_BATON, using WCROOT and - LOCAL_RELPATH. If callbacks require additional information, they may - provide it using CB_BATON. */ -svn_error_t * -svn_wc__db_with_txn(svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - svn_wc__db_txn_callback_t cb_func, - void *cb_baton, - apr_pool_t *scratch_pool); - /* Evaluate the expression EXPR within a transaction. * * Begin a transaction in WCROOT's DB; evaluate the expression EXPR, which would Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_update_move.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_update_move.c?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_update_move.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_update_move.c Wed Mar 4 15:56:18 2015 @@ -400,7 +400,7 @@ create_tree_conflict(svn_skel_t **confli if (conflict_operation != svn_wc_operation_update && conflict_operation != svn_wc_operation_switch) - return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + return svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL, _("'%s' already in conflict"), path_for_error_message(wcroot, local_relpath, scratch_pool)); @@ -424,7 +424,7 @@ create_tree_conflict(svn_skel_t **confli && strcmp(move_src_op_root_relpath, svn_dirent_skip_ancestor(wcroot->abspath, existing_abspath)))) - return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL, + return svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL, _("'%s' already in conflict"), path_for_error_message(wcroot, local_relpath, @@ -2487,7 +2487,7 @@ static svn_error_t * break_moved_away(svn_wc__db_wcroot_t *wcroot, svn_wc__db_t *db, const char *local_relpath, - int src_op_depth, + int parent_src_op_depth, apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; @@ -2501,7 +2501,7 @@ break_moved_away(svn_wc__db_wcroot_t *wc SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_MOVED_DESCENDANTS_SRC)); SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, - src_op_depth)); + parent_src_op_depth)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); iterpool = svn_pool_create(scratch_pool); Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_util.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_util.c?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_util.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_util.c Wed Mar 4 15:56:18 2015 @@ -152,63 +152,3 @@ svn_wc__db_util_open_db(svn_sqlite__db_t return SVN_NO_ERROR; } - -/* Some helpful transaction helpers. - - Instead of directly using SQLite transactions, these wrappers - relieve the consumer from the need to wrap the wcroot and - local_relpath, which are almost always used within the transaction. - - This also means if we later want to implement some wc_db-specific txn - handling, we have a convenient place to do it. - */ - -/* A callback which supplies WCROOTs and LOCAL_RELPATHs. */ -typedef svn_error_t *(*db_txn_callback_t)(void *baton, - svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - apr_pool_t *scratch_pool); - -/* Baton for use with run_txn() and with_db_txn(). */ -struct txn_baton_t -{ - svn_wc__db_wcroot_t *wcroot; - const char *local_relpath; - - db_txn_callback_t cb_func; - void *cb_baton; -}; - - -/* Unwrap the sqlite transaction into a wc_db txn. - Implements svn_sqlite__transaction_callback_t. */ -static svn_error_t * -run_txn(void *baton, svn_sqlite__db_t *db, apr_pool_t *scratch_pool) -{ - struct txn_baton_t *tb = baton; - - return svn_error_trace( - tb->cb_func(tb->cb_baton, tb->wcroot, tb->local_relpath, scratch_pool)); -} - - -/* Run CB_FUNC in a SQLite transaction with CB_BATON, using WCROOT and - LOCAL_RELPATH. If callbacks require additional information, they may - provide it using CB_BATON. */ -svn_error_t * -svn_wc__db_with_txn(svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - svn_wc__db_txn_callback_t cb_func, - void *cb_baton, - apr_pool_t *scratch_pool) -{ - struct txn_baton_t tb; - - tb.wcroot = wcroot; - tb.local_relpath = local_relpath; - tb.cb_func = cb_func; - tb.cb_baton = cb_baton; - - return svn_error_trace( - svn_sqlite__with_lock(wcroot->sdb, run_txn, &tb, scratch_pool)); -} Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_wcroot.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_wcroot.c?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_wcroot.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_wcroot.c Wed Mar 4 15:56:18 2015 @@ -702,11 +702,9 @@ try_symlink_as_dir: if (err) { if (err->apr_err == SVN_ERR_WC_CORRUPT) - return svn_error_quick_wrap( - err, apr_psprintf(scratch_pool, - _("Missing a row in WCROOT for '%s'."), - svn_dirent_local_style(original_abspath, - scratch_pool))); + return svn_error_quick_wrapf( + err, _("Missing a row in WCROOT for '%s'."), + svn_dirent_local_style(original_abspath, scratch_pool)); return svn_error_trace(err); } Modified: subversion/branches/reuse-ra-session/subversion/svn/cl.h URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/cl.h?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/cl.h (original) +++ subversion/branches/reuse-ra-session/subversion/svn/cl.h Wed Mar 4 15:56:18 2015 @@ -167,7 +167,6 @@ typedef struct svn_cl__opt_state_t svn_boolean_t version; /* print version information */ svn_boolean_t verbose; /* be verbose */ svn_boolean_t update; /* contact the server for the full story */ - svn_boolean_t strict; /* do strictly what was requested */ svn_stringbuf_t *filedata; /* contents of file used as option data (not converted to UTF-8) */ const char *encoding; /* the locale/encoding of 'message' and of @@ -249,6 +248,7 @@ typedef struct svn_cl__opt_state_t svn_boolean_t no_newline; /* do not output the trailing newline */ svn_boolean_t show_passwords; /* show cached passwords */ svn_boolean_t pin_externals; /* pin externals to last-changed revisions */ + const char *show_item; /* print only the given item */ } svn_cl__opt_state_t; @@ -855,6 +855,48 @@ svn_cl__deprecated_merge_reintegrate(con svn_client_ctx_t *ctx, apr_pool_t *pool); + +/* Forward declaration of the similarity check context. */ +typedef struct svn_cl__simcheck_context_t svn_cl__simcheck_context_t; + +/* Token definition for the similarity check. */ +typedef struct svn_cl__simcheck_t +{ + /* The token we're checking for similarity. */ + svn_string_t token; + + /* User data associated with this token. */ + const void *data; + + /* + * The following fields are populated by svn_cl__similarity_check. + */ + + /* Similarity score [0..SVN_STRING__SIM_RANGE_MAX] */ + apr_size_t score; + + /* Number of characters of difference from the key. */ + apr_size_t diff; + + /* Similarity check context (private) */ + svn_cl__simcheck_context_t *context; +} svn_cl__simcheck_t; + +/* Find the entries in TOKENS that are most similar to KEY. + * TOKEN_COUNT is the number of entries in the (mutable) TOKENS array. + * Use SCRATCH_POOL for temporary allocations. + * + * On return, the TOKENS array will be sorted according to similarity + * to KEY, in descending order. The return value will be zero if the + * first token is an exact match; otherwise, it will be one more than + * the number of tokens that are at least two-thirds similar to KEY. + */ +apr_size_t +svn_cl__similarity_check(const char *key, + svn_cl__simcheck_t **tokens, + apr_size_t token_count, + apr_pool_t *scratch_pool); + #ifdef __cplusplus } #endif /* __cplusplus */ Modified: subversion/branches/reuse-ra-session/subversion/svn/info-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/info-cmd.c?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/info-cmd.c (original) +++ subversion/branches/reuse-ra-session/subversion/svn/info-cmd.c Wed Mar 4 15:56:18 2015 @@ -76,6 +76,168 @@ schedule_str(svn_wc_schedule_t schedule) } } +/* Return a relative URL from information in INFO using POOL for + temporary allocation. */ +static const char* +relative_url(const svn_client_info2_t *info, apr_pool_t *pool) +{ + return apr_pstrcat(pool, "^/", + svn_path_uri_encode( + svn_uri_skip_ancestor(info->repos_root_URL, + info->URL, pool), + pool), SVN_VA_NULL); +} + + +/* The kinds of items for print_info_item(). */ +typedef enum +{ + /* Entry kind */ + info_item_kind, + + /* Repository location. */ + info_item_url, + info_item_relative_url, + info_item_repos_root_url, + info_item_repos_uuid, + + /* Working copy revision or repository HEAD revision */ + info_item_revision, + + /* Commit details. */ + info_item_last_changed_rev, + info_item_last_changed_date, + info_item_last_changed_author, + + /* Working copy information */ + info_item_wc_root +} info_item_t; + +/* Mapping between option keywords and info_item_t. */ +typedef struct info_item_map_t +{ + const svn_string_t keyword; + const info_item_t print_what; +} info_item_map_t; + +#define MAKE_STRING(x) { x, sizeof(x) - 1 } +static const info_item_map_t info_item_map[] = + { + { MAKE_STRING("kind"), info_item_kind }, + { MAKE_STRING("url"), info_item_url }, + { MAKE_STRING("relative-url"), info_item_relative_url }, + { MAKE_STRING("repos-root-url"), info_item_repos_root_url }, + { MAKE_STRING("repos-uuid"), info_item_repos_uuid }, + { MAKE_STRING("revision"), info_item_revision }, + { MAKE_STRING("last-changed-revision"), + info_item_last_changed_rev }, + { MAKE_STRING("last-changed-date"), info_item_last_changed_date }, + { MAKE_STRING("last-changed-author"), info_item_last_changed_author }, + { MAKE_STRING("wc-root"), info_item_wc_root } + }; +#undef MAKE_STRING + +static const apr_size_t info_item_map_len = + (sizeof(info_item_map) / sizeof(info_item_map[0])); + + +/* The baton type used by the info receiver functions. */ +typedef struct print_info_baton_t +{ + /* The path prefix that output paths should be normalized to. */ + const char *path_prefix; + + /* + * The following fields are used by print_info_item(). + */ + + /* Which item to print. */ + info_item_t print_what; + + /* Do we expect to show info for multiple targets? */ + svn_boolean_t multiple_targets; + + /* TRUE iff the current is a local path. */ + svn_boolean_t target_is_path; + + /* Did we already print a line of output? */ + svn_boolean_t start_new_line; +} print_info_baton_t; + + +/* Find the appropriate info_item_t for KEYWORD and initialize + * RECEIVER_BATON for print_info_item(). Use SCRATCH_POOL for + * temporary allocation. + */ +static svn_error_t * +find_print_what(const char *keyword, + print_info_baton_t *receiver_baton, + apr_pool_t *scratch_pool) +{ + svn_cl__simcheck_t **keywords = apr_palloc( + scratch_pool, info_item_map_len * sizeof(svn_cl__simcheck_t*)); + svn_cl__simcheck_t *kwbuf = apr_palloc( + scratch_pool, info_item_map_len * sizeof(svn_cl__simcheck_t)); + apr_size_t i; + + for (i = 0; i < info_item_map_len; ++i) + { + keywords[i] = &kwbuf[i]; + kwbuf[i].token.data = info_item_map[i].keyword.data; + kwbuf[i].token.len = info_item_map[i].keyword.len; + kwbuf[i].data = &info_item_map[i]; + } + + switch (svn_cl__similarity_check(keyword, keywords, + info_item_map_len, scratch_pool)) + { + const info_item_map_t *kw0; + const info_item_map_t *kw1; + const info_item_map_t *kw2; + + case 0: /* Exact match. */ + kw0 = keywords[0]->data; + receiver_baton->print_what = kw0->print_what; + return SVN_NO_ERROR; + + case 1: + /* The best alternative isn't good enough */ + return svn_error_createf( + SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("'%s' is not a valid value for --show-item"), + keyword); + + case 2: + /* There is only one good candidate */ + kw0 = keywords[0]->data; + return svn_error_createf( + SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("'%s' is not a valid value for --show-item;" + " did you mean '%s'?"), + keyword, kw0->keyword.data); + + case 3: + /* Suggest a list of the most likely candidates */ + kw0 = keywords[0]->data; + kw1 = keywords[1]->data; + return svn_error_createf( + SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("'%s' is not a valid value for --show-item;" + " did you mean '%s' or '%s'?"), + keyword, kw0->keyword.data, kw1->keyword.data); + + default: + /* Never suggest more than three candidates */ + kw0 = keywords[0]->data; + kw1 = keywords[1]->data; + kw2 = keywords[2]->data; + return svn_error_createf( + SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("'%s' is not a valid value for --show-item;" + " did you mean '%s', '%s' or '%s'?"), + keyword, kw0->keyword.data, kw1->keyword.data, kw2->keyword.data); + } +} /* A callback of type svn_client_info_receiver2_t. Prints svn info in xml mode to standard out */ @@ -87,7 +249,7 @@ print_info_xml(void *baton, { svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool); const char *rev_str; - const char *path_prefix = baton; + print_info_baton_t *const receiver_baton = baton; if (SVN_IS_VALID_REVNUM(info->rev)) rev_str = apr_psprintf(pool, "%ld", info->rev); @@ -97,7 +259,7 @@ print_info_xml(void *baton, /* "<entry ...>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry", "path", svn_cl__local_style_skip_ancestor( - path_prefix, target, pool), + receiver_baton->path_prefix, target, pool), "kind", svn_cl__node_kind_str_xml(info->kind), "revision", rev_str, SVN_VA_NULL); @@ -109,13 +271,7 @@ print_info_xml(void *baton, { /* "<relative-url> xx </relative-url>" */ svn_cl__xml_tagged_cdata(&sb, pool, "relative-url", - apr_pstrcat(pool, "^/", - svn_path_uri_encode( - svn_uri_skip_ancestor( - info->repos_root_URL, - info->URL, pool), - pool), - SVN_VA_NULL)); + relative_url(info, pool)); } if (info->repos_root_URL || info->repos_UUID) @@ -263,11 +419,11 @@ print_info(void *baton, const svn_client_info2_t *info, apr_pool_t *pool) { - const char *path_prefix = baton; + print_info_baton_t *const receiver_baton = baton; SVN_ERR(svn_cmdline_printf(pool, _("Path: %s\n"), svn_cl__local_style_skip_ancestor( - path_prefix, target, pool))); + receiver_baton->path_prefix, target, pool))); /* ### remove this someday: it's only here for cmdline output compatibility with svn 1.1 and older. */ @@ -285,11 +441,8 @@ print_info(void *baton, SVN_ERR(svn_cmdline_printf(pool, _("URL: %s\n"), info->URL)); if (info->URL && info->repos_root_URL) - SVN_ERR(svn_cmdline_printf(pool, _("Relative URL: ^/%s\n"), - svn_path_uri_encode( - svn_uri_skip_ancestor(info->repos_root_URL, - info->URL, pool), - pool))); + SVN_ERR(svn_cmdline_printf(pool, _("Relative URL: %s\n"), + relative_url(info, pool))); if (info->repos_root_URL) SVN_ERR(svn_cmdline_printf(pool, _("Repository Root: %s\n"), @@ -391,14 +544,14 @@ print_info(void *baton, if (info->wc_info->moved_from_abspath) SVN_ERR(svn_cmdline_printf(pool, _("Moved From: %s\n"), svn_cl__local_style_skip_ancestor( - path_prefix, + receiver_baton->path_prefix, info->wc_info->moved_from_abspath, pool))); if (info->wc_info->moved_to_abspath) SVN_ERR(svn_cmdline_printf(pool, _("Moved To: %s\n"), svn_cl__local_style_skip_ancestor( - path_prefix, + receiver_baton->path_prefix, info->wc_info->moved_to_abspath, pool))); } @@ -446,21 +599,24 @@ print_info(void *baton, SVN_ERR(svn_cmdline_printf(pool, _("Conflict Previous Base File: %s\n"), svn_cl__local_style_skip_ancestor( - path_prefix, conflict->base_abspath, + receiver_baton->path_prefix, + conflict->base_abspath, pool))); if (conflict->my_abspath) SVN_ERR(svn_cmdline_printf(pool, _("Conflict Previous Working File: %s\n"), svn_cl__local_style_skip_ancestor( - path_prefix, conflict->my_abspath, + receiver_baton->path_prefix, + conflict->my_abspath, pool))); if (conflict->their_abspath) SVN_ERR(svn_cmdline_printf(pool, _("Conflict Current Base File: %s\n"), svn_cl__local_style_skip_ancestor( - path_prefix, conflict->their_abspath, + receiver_baton->path_prefix, + conflict->their_abspath, pool))); break; @@ -469,7 +625,7 @@ print_info(void *baton, SVN_ERR(svn_cmdline_printf(pool, _("Conflict Properties File: %s\n"), svn_cl__local_style_skip_ancestor( - path_prefix, + receiver_baton->path_prefix, conflict->prop_reject_abspath, pool))); printed_prop_conflict_file = TRUE; @@ -577,6 +733,123 @@ print_info(void *baton, } +/* Helper for print_info_item(): Print the value TEXT for TARGET_PATH, + either of which may be NULL. Use POOL for temporary allocation. */ +static svn_error_t * +print_info_item_string(const char *text, const char *target_path, + apr_pool_t *pool) +{ + if (text) + { + if (target_path) + SVN_ERR(svn_cmdline_printf(pool, "%-10s %s", text, target_path)); + else + SVN_ERR(svn_cmdline_fputs(text, stdout, pool)); + } + else if (target_path) + SVN_ERR(svn_cmdline_printf(pool, "%-10s %s", "", target_path)); + + return SVN_NO_ERROR; +} + +/* Helper for print_info_item(): Print the revision number REV, which + may be SVN_INVALID_REVNUM, for TARGET_PATH, which may be NULL. Use + POOL for temporary allocation. */ +static svn_error_t * +print_info_item_revision(svn_revnum_t rev, const char *target_path, + apr_pool_t *pool) +{ + if (SVN_IS_VALID_REVNUM(rev)) + { + if (target_path) + SVN_ERR(svn_cmdline_printf(pool, "%-10ld %s", rev, target_path)); + else + SVN_ERR(svn_cmdline_printf(pool, "%-10ld", rev)); + } + else if (target_path) + SVN_ERR(svn_cmdline_printf(pool, "%-10s %s", "", target_path)); + + return SVN_NO_ERROR; +} + +/* A callback of type svn_client_info_receiver2_t. */ +static svn_error_t * +print_info_item(void *baton, + const char *target, + const svn_client_info2_t *info, + apr_pool_t *pool) +{ + print_info_baton_t *const receiver_baton = baton; + const char *const target_path = + (!receiver_baton->multiple_targets ? NULL + : (!receiver_baton->target_is_path ? info->URL + : svn_cl__local_style_skip_ancestor( + receiver_baton->path_prefix, target, pool))); + + if (receiver_baton->start_new_line) + SVN_ERR(svn_cmdline_fputs("\n", stdout, pool)); + + switch (receiver_baton->print_what) + { + case info_item_kind: + SVN_ERR(print_info_item_string(svn_node_kind_to_word(info->kind), + target_path, pool)); + break; + + case info_item_url: + SVN_ERR(print_info_item_string(info->URL, target_path, pool)); + break; + + case info_item_relative_url: + SVN_ERR(print_info_item_string(relative_url(info, pool), + target_path, pool)); + break; + + case info_item_repos_root_url: + SVN_ERR(print_info_item_string(info->repos_root_URL, target_path, pool)); + break; + + case info_item_repos_uuid: + SVN_ERR(print_info_item_string(info->repos_UUID, target_path, pool)); + break; + + case info_item_revision: + SVN_ERR(print_info_item_revision(info->rev, target_path, pool)); + break; + + case info_item_last_changed_rev: + SVN_ERR(print_info_item_revision(info->last_changed_rev, + target_path, pool)); + break; + + case info_item_last_changed_date: + SVN_ERR(print_info_item_string( + (!info->last_changed_date ? NULL + : svn_time_to_cstring(info->last_changed_date, pool)), + target_path, pool)); + break; + + case info_item_last_changed_author: + SVN_ERR(print_info_item_string(info->last_changed_author, + target_path, pool)); + break; + + case info_item_wc_root: + SVN_ERR(print_info_item_string( + (info->wc_info && info->wc_info->wcroot_abspath + ? info->wc_info->wcroot_abspath : NULL), + target_path, pool)); + break; + + default: + SVN_ERR_MALFUNCTION(); + } + + receiver_baton->start_new_line = TRUE; + return SVN_NO_ERROR; +} + + /* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__info(apr_getopt_t *os, @@ -592,7 +865,7 @@ svn_cl__info(apr_getopt_t *os, svn_boolean_t seen_nonexistent_target = FALSE; svn_opt_revision_t peg_revision; svn_client_info_receiver2_t receiver; - const char *path_prefix; + print_info_baton_t receiver_baton = { 0 }; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, @@ -605,26 +878,59 @@ svn_cl__info(apr_getopt_t *os, { receiver = print_info_xml; + if (opt_state->show_item) + return svn_error_create( + SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--show-item is not valid in --xml mode")); + if (opt_state->no_newline) + return svn_error_create( + SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--no-newline is not valid in --xml mode")); + /* If output is not incremental, output the XML header and wrap everything in a top-level element. This makes the output in its entirety a well-formed XML document. */ if (! opt_state->incremental) SVN_ERR(svn_cl__xml_print_header("info", pool)); } + else if (opt_state->show_item) + { + receiver = print_info_item; + + if (opt_state->incremental) + return svn_error_create( + SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--incremental is only valid in --xml mode")); + + receiver_baton.multiple_targets = (opt_state->depth > svn_depth_empty + || targets->nelts > 1); + if (receiver_baton.multiple_targets && opt_state->no_newline) + return svn_error_create( + SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--no-newline is only available for single-target," + " non-recursive info operations")); + + SVN_ERR(find_print_what(opt_state->show_item, &receiver_baton, pool)); + receiver_baton.start_new_line = FALSE; + } else { receiver = print_info; if (opt_state->incremental) - return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, - _("'incremental' option only valid in XML " - "mode")); + return svn_error_create( + SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--incremental is only valid in --xml mode")); + if (opt_state->no_newline) + return svn_error_create( + SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--no-newline' is only valid with --show-item")); } if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_empty; - SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", pool)); + SVN_ERR(svn_dirent_get_absolute(&receiver_baton.path_prefix, "", pool)); for (i = 0; i < targets->nelts; i++) { @@ -642,10 +948,12 @@ svn_cl__info(apr_getopt_t *os, { if (peg_revision.kind == svn_opt_revision_unspecified) peg_revision.kind = svn_opt_revision_head; + receiver_baton.target_is_path = FALSE; } else { SVN_ERR(svn_dirent_get_absolute(&truepath, truepath, subpool)); + receiver_baton.target_is_path = TRUE; } err = svn_client_info4(truepath, @@ -655,7 +963,7 @@ svn_cl__info(apr_getopt_t *os, TRUE /* fetch_actual_only */, opt_state->include_externals, opt_state->changelists, - receiver, (void *) path_prefix, + receiver, &receiver_baton, ctx, subpool); if (err) @@ -682,6 +990,9 @@ svn_cl__info(apr_getopt_t *os, if (opt_state->xml && (! opt_state->incremental)) SVN_ERR(svn_cl__xml_print_footer("info", pool)); + else if (opt_state->show_item && !opt_state->no_newline + && receiver_baton.start_new_line) + SVN_ERR(svn_cmdline_fputs("\n", stdout, pool)); if (seen_nonexistent_target) return svn_error_create( Modified: subversion/branches/reuse-ra-session/subversion/svn/propget-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/propget-cmd.c?rev=1664059&r1=1664058&r2=1664059&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/propget-cmd.c (original) +++ subversion/branches/reuse-ra-session/subversion/svn/propget-cmd.c Wed Mar 4 15:56:18 2015 @@ -322,11 +322,11 @@ svn_cl__propget(apr_getopt_t *os, svn_stream_t *out; svn_boolean_t warned = FALSE; - if (opt_state->verbose && (opt_state->revprop || opt_state->strict + if (opt_state->verbose && (opt_state->revprop || opt_state->no_newline || opt_state->xml)) return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL, _("--verbose cannot be used with --revprop or " - "--strict or --xml")); + "--no-newline or --xml")); /* PNAME is first argument (and PNAME_UTF8 will be a UTF-8 version thereof) */ @@ -411,7 +411,7 @@ svn_cl__propget(apr_getopt_t *os, SVN_ERR(stream_write(out, printable_val->data, printable_val->len)); - if (! opt_state->strict) + if (! opt_state->no_newline) SVN_ERR(stream_write(out, APR_EOL_STR, strlen(APR_EOL_STR))); } } @@ -427,16 +427,16 @@ svn_cl__propget(apr_getopt_t *os, if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_empty; - /* Strict mode only makes sense for a single target. So make + /* No-newline mode only makes sense for a single target. So make sure we have only a single target, and that we're not being asked to recurse on that target. */ - if (opt_state->strict + if (opt_state->no_newline && ((targets->nelts > 1) || (opt_state->depth != svn_depth_empty) || (opt_state->show_inherited_props))) return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, - _("Strict output of property values only available for single-" - "target, non-recursive propget operations")); + _("--no-newline is only available for single-target," + " non-recursive propget operations")); for (i = 0; i < targets->nelts; i++) { @@ -472,15 +472,15 @@ svn_cl__propget(apr_getopt_t *os, /* Any time there is more than one thing to print, or where the path associated with a printed thing is not obvious, we'll print filenames. That is, unless we've been told - not to do so with the --strict option. */ + not to do so with the --no-newline option. */ print_filenames = ((opt_state->depth > svn_depth_empty || targets->nelts > 1 || apr_hash_count(props) > 1 || opt_state->verbose || opt_state->show_inherited_props) - && (! opt_state->strict)); - omit_newline = opt_state->strict; - like_proplist = opt_state->verbose && !opt_state->strict; + && (! opt_state->no_newline)); + omit_newline = opt_state->no_newline; + like_proplist = opt_state->verbose && !opt_state->no_newline; /* If there are no properties, and exactly one node was queried, then warn. */
