Modified: subversion/branches/svn-bisect/subversion/libsvn_wc/status.c URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_wc/status.c?rev=1204374&r1=1204373&r2=1204374&view=diff ============================================================================== --- subversion/branches/svn-bisect/subversion/libsvn_wc/status.c (original) +++ subversion/branches/svn-bisect/subversion/libsvn_wc/status.c Mon Nov 21 07:07:56 2011 @@ -184,6 +184,9 @@ struct dir_baton /* The pool in which this baton itself is allocated. */ apr_pool_t *pool; + /* The repository root relative path to this item in the repository. */ + const char *repos_relpath; + /* out-of-date info corresponding to ood_* fields in svn_wc_status3_t. */ svn_node_kind_t ood_kind; svn_revnum_t ood_changed_rev; @@ -223,6 +226,9 @@ struct file_baton the code that syncs up the adm dir and working copy. */ svn_boolean_t prop_changed; + /* The repository root relative path to this item in the repository. */ + const char *repos_relpath; + /* out-of-date info corresponding to ood_* fields in svn_wc_status3_t. */ svn_node_kind_t ood_kind; svn_revnum_t ood_changed_rev; @@ -266,19 +272,94 @@ read_info(const struct svn_wc__db_info_t happy... (It might be completely unrelated, but...) */ if (mtb->have_base && (mtb->status == svn_wc__db_status_added - || mtb->status == svn_wc__db_status_deleted)) + || mtb->status == svn_wc__db_status_deleted + || mtb->kind == svn_kind_file)) { + svn_boolean_t update_root; + svn_wc__db_lock_t **lock_arg = NULL; + + if (mtb->status == svn_wc__db_status_added + || mtb->status == svn_wc__db_status_deleted) + lock_arg = &mtb->lock; + SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &mtb->lock, NULL, NULL, + lock_arg, NULL, &update_root, db, local_abspath, result_pool, scratch_pool)); + + mtb->file_external = (update_root && mtb->kind == svn_kind_file); + + if (mtb->status == svn_wc__db_status_deleted) + { + const char *moved_to_abspath; + const char *moved_to_op_root_abspath; + + /* NOTE: we can't use op-root-ness as a condition here since a base + * node can be the root of a move and still not be an explicit + * op-root (having a working node with op_depth == pathelements). + * + * Both these (almost identical) situations showcase this: + * svn mv a/b bb + * svn del a + * and + * svn mv a aa + * svn mv aa/b bb + * In both, 'bb' is moved from 'a/b', but 'a/b' has no op_depth>0 + * node at all, as its parent 'a' is locally deleted. */ + + SVN_ERR(svn_wc__db_scan_deletion(NULL, + &moved_to_abspath, + NULL, + &moved_to_op_root_abspath, + db, local_abspath, + scratch_pool, scratch_pool)); + if (moved_to_abspath != NULL + && moved_to_op_root_abspath != NULL + && strcmp(moved_to_abspath, moved_to_op_root_abspath) == 0) + { + mtb->moved_to_abspath = apr_pstrdup(result_pool, + moved_to_abspath); + } + /* ### ^^^ THIS SUCKS. For at least two reasons: + * 1) We scan the node deletion and that's technically not necessary. + * We'd be fine to know if this is an actual root of a move. + * 2) From the elaborately calculated results, we backwards-guess + * whether this is a root. + * It works ok, and this code only gets called when a node is an + * explicit target of a 'status'. But it would be better to do this + * differently. + * We could return moved-to via svn_wc__db_base_get_info() (called + * just above), but as moved-to is only intended to be returned for + * roots of a move, that doesn't fit too well. */ + } + } + + /* ### svn_wc__db_read_info() could easily return the moved-here flag. But + * for now... (The per-dir query for recursive status is far more optimal.) + * Note that this actually scans around to get the full path, for a bool. + * This bool then gets returned, later is evaluated, and if true leads to + * the same paths being scanned again. We'd want to obtain this bool here as + * cheaply as svn_wc__db_read_children_info() does. */ + if (mtb->status == svn_wc__db_status_added) + { + const char *moved_from_abspath = NULL; + svn_wc__db_status_t status; + + SVN_ERR(svn_wc__db_scan_addition(&status, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + &moved_from_abspath, + NULL, + db, local_abspath, + result_pool, scratch_pool)); + mtb->moved_here = (moved_from_abspath != NULL); + mtb->incomplete = (status == svn_wc__db_status_incomplete); } mtb->has_checksum = (checksum != NULL); #ifdef HAVE_SYMLINK - if (mtb->kind == svn_wc__db_kind_file + if (mtb->kind == svn_kind_file && (mtb->had_props || mtb->props_mod)) { apr_hash_t *properties; @@ -404,8 +485,6 @@ assemble_status(svn_wc_status3_t **statu const char *repos_root_url; const char *repos_uuid; const char *moved_from_abspath = NULL; - const char *moved_to_abspath = NULL; - const char *moved_to_op_root_abspath = NULL; svn_filesize_t filesize = (dirent && (dirent->kind == svn_node_file)) ? dirent->filesize : SVN_INVALID_FILESIZE; @@ -426,20 +505,16 @@ assemble_status(svn_wc_status3_t **statu /* A node is switched if it doesn't have the implied repos_relpath */ const char *name = svn_relpath_skip_ancestor(parent_repos_relpath, info->repos_relpath); - switched_p = !name || (strcmp(name, svn_dirent_basename(local_abspath, NULL)) != 0); + switched_p = !name || (strcmp(name, + svn_dirent_basename(local_abspath, NULL)) + != 0); } - /* Examine whether our target is missing or obstructed. - - While we are not completely in single-db mode yet, data about - obstructed or missing nodes might be incomplete here. This is - reported by svn_wc_db_status_obstructed_XXXX. In single-db - mode these obstructions are no longer reported and we have - to detect obstructions by looking at the on disk status in DIRENT. - */ - if (info->kind == svn_wc__db_kind_dir) + /* Examine whether our target is missing or obstructed. To detect + * obstructions, we have to look at the on-disk status in DIRENT. */ + if (info->kind == svn_kind_dir) { - if (info->status == svn_wc__db_status_incomplete) + if (info->status == svn_wc__db_status_incomplete || info->incomplete) { /* Highest precedence. */ node_status = svn_wc_status_incomplete; @@ -500,7 +575,7 @@ assemble_status(svn_wc_status3_t **statu If it was changed, then the subdir is incomplete or missing/obstructed. */ - if (info->kind != svn_wc__db_kind_dir + if (info->kind != svn_kind_dir && node_status == svn_wc_status_normal) { svn_boolean_t text_modified_p = FALSE; @@ -512,8 +587,8 @@ assemble_status(svn_wc_status3_t **statu precedence over M. */ /* If the entry is a file, check for textual modifications */ - if ((info->kind == svn_wc__db_kind_file - || info->kind == svn_wc__db_kind_symlink) + if ((info->kind == svn_kind_file + || info->kind == svn_kind_symlink) #ifdef HAVE_SYMLINK && (info->special == (dirent && dirent->special)) #endif /* HAVE_SYMLINK */ @@ -588,7 +663,7 @@ assemble_status(svn_wc_status3_t **statu { if (!info->op_root) copied = TRUE; /* And keep status normal */ - else if (info->kind == svn_wc__db_kind_file + else if (info->kind == svn_kind_file && !info->have_base && !info->have_more_work) { /* Simple addition or copy, no replacement */ @@ -608,26 +683,18 @@ assemble_status(svn_wc_status3_t **statu else if (schedule == svn_wc_schedule_replace) node_status = svn_wc_status_replaced; } + + /* Get moved-from info (only for potential op-roots of a move). */ + if (info->moved_here && info->op_root) + SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + &moved_from_abspath, + NULL, + db, local_abspath, + result_pool, scratch_pool)); } } - /* Get moved-to info. */ - if (info->status == svn_wc__db_status_deleted) - SVN_ERR(svn_wc__db_scan_deletion(NULL, - &moved_to_abspath, - NULL, - &moved_to_op_root_abspath, - db, local_abspath, - result_pool, scratch_pool)); - - /* Get moved-from info. */ - if (info->status == svn_wc__db_status_added) - SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - &moved_from_abspath, - NULL, - db, local_abspath, - result_pool, scratch_pool)); if (node_status == svn_wc_status_normal) node_status = text_status; @@ -668,14 +735,14 @@ assemble_status(svn_wc_status3_t **statu switch (info->kind) { - case svn_wc__db_kind_dir: + case svn_kind_dir: stat->kind = svn_node_dir; break; - case svn_wc__db_kind_file: - case svn_wc__db_kind_symlink: + case svn_kind_file: + case svn_kind_symlink: stat->kind = svn_node_file; break; - case svn_wc__db_kind_unknown: + case svn_kind_unknown: default: stat->kind = svn_node_unknown; } @@ -722,8 +789,9 @@ assemble_status(svn_wc_status3_t **statu stat->repos_uuid = repos_uuid; stat->moved_from_abspath = moved_from_abspath; - stat->moved_to_abspath = moved_to_abspath; - stat->moved_to_op_root_abspath = moved_to_op_root_abspath; + stat->moved_to_abspath = info->moved_to_abspath; + + stat->file_external = info->file_external; *status = stat; @@ -999,29 +1067,189 @@ send_unversioned_item(const struct walk_ return SVN_NO_ERROR; } -/* Send svn_wc_status3_t * structures for the directory LOCAL_ABSPATH and - for all its entries through STATUS_FUNC/STATUS_BATON, or, if SELECTED - is non-NULL, only for that directory entry. +static svn_error_t * +get_dir_status(const struct walk_status_baton *wb, + const char *local_abspath, + svn_boolean_t skip_this_dir, + const char *parent_repos_root_url, + const char *parent_repos_relpath, + const char *parent_repos_uuid, + const struct svn_wc__db_info_t *dir_info, + const svn_io_dirent2_t *dirent, + const apr_array_header_t *ignore_patterns, + svn_depth_t depth, + svn_boolean_t get_all, + svn_boolean_t no_ignore, + svn_wc_status_func4_t status_func, + void *status_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool); + +/* Send out a status structure according to the information gathered on one + * child node. (Basically this function is the guts of the loop in + * get_dir_status() and of get_child_status().) + * + * Send a status structure of LOCAL_ABSPATH. PARENT_ABSPATH must be the + * dirname of LOCAL_ABSPATH. + * + * INFO should reflect the information on LOCAL_ABSPATH; LOCAL_ABSPATH must + * be an unversioned file or dir, or a versioned file. For versioned + * directories use get_dir_status() instead. + * + * INFO may be NULL for an unversioned node. If such node has a tree conflict, + * UNVERSIONED_TREE_CONFLICTED may be set to TRUE. If INFO is non-NULL, + * UNVERSIONED_TREE_CONFLICTED is ignored. + * + * DIRENT should reflect LOCAL_ABSPATH's dirent information. + * + * DIR_REPOS_* should reflect LOCAL_ABSPATH's parent URL, i.e. LOCAL_ABSPATH's + * URL treated with svn_uri_dirname(). ### TODO verify this (externals) + * + * If *COLLECTED_IGNORE_PATTERNS is NULL and ignore patterns are needed in + * this call, *COLLECTED_IGNORE_PATTERNS will be set to an apr_array_header_t* + * containing all ignore patterns, as returned by collect_ignore_patterns() on + * PARENT_ABSPATH and IGNORE_PATTERNS. If *COLLECTED_IGNORE_PATTERNS is passed + * non-NULL, it is assumed to already hold that result. This speeds up + * repeated calls with the same PARENT_ABSPATH. + * + * *COLLECTED_IGNORE_PATTERNS will be allocated in RESULT_POOL. All other + * allocations are made in SCRATCH_POOL. + * + * The remaining parameters correspond to get_dir_status(). */ +static svn_error_t* +one_child_status(const struct walk_status_baton *wb, + const char *local_abspath, + const char *parent_abspath, + const struct svn_wc__db_info_t *info, + const svn_io_dirent2_t *dirent, + const char *dir_repos_root_url, + const char *dir_repos_relpath, + const char *dir_repos_uuid, + svn_boolean_t unversioned_tree_conflicted, + apr_array_header_t **collected_ignore_patterns, + const apr_array_header_t *ignore_patterns, + svn_depth_t depth, + svn_boolean_t get_all, + svn_boolean_t no_ignore, + svn_wc_status_func4_t status_func, + void *status_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_boolean_t conflicted = info ? info->conflicted + : unversioned_tree_conflicted; + + if (info + && info->status != svn_wc__db_status_not_present + && info->status != svn_wc__db_status_excluded + && info->status != svn_wc__db_status_server_excluded + && !(info->kind == svn_kind_unknown + && info->status == svn_wc__db_status_normal)) + { + if (depth == svn_depth_files + && info->kind == svn_kind_dir) + { + return SVN_NO_ERROR; + } + + SVN_ERR(send_status_structure(wb, local_abspath, + dir_repos_root_url, + dir_repos_relpath, + dir_repos_uuid, + info, dirent, get_all, + status_func, status_baton, + scratch_pool)); + + /* Descend in subdirectories. */ + if (depth == svn_depth_infinity + && info->kind == svn_kind_dir) + { + SVN_ERR(get_dir_status(wb, local_abspath, TRUE, + dir_repos_root_url, dir_repos_relpath, + dir_repos_uuid, info, + dirent, ignore_patterns, + svn_depth_infinity, get_all, + no_ignore, + status_func, status_baton, + cancel_func, cancel_baton, + scratch_pool)); + } + + return SVN_NO_ERROR; + } + + /* If conflicted, fall right through to unversioned. + * With depth_files, show all conflicts, even if their report is only + * about directories. A tree conflict may actually report two different + * kinds, so it's not so easy to define what depth=files means. We could go + * look up the kinds in the conflict ... just show all. */ + if (! conflicted) + { + /* Selected node, but not found */ + if (dirent == NULL) + return SVN_NO_ERROR; - PARENT_ENTRY is the entry for the parent of the directory or NULL - if LOCAL_ABSPATH is a working copy root. + if (depth == svn_depth_files && dirent->kind == svn_node_dir) + return SVN_NO_ERROR; + + if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, scratch_pool), + scratch_pool)) + return SVN_NO_ERROR; + } + + /* The node exists on disk but there is no versioned information about it, + * or it doesn't exist but is a tree conflicted path or should be + * reported not-present. */ + + /* Why pass ignore patterns on a tree conflicted node, even if it should + * always show up in clients' status reports anyway? Because the calling + * client decides whether to ignore, and thus this flag needs to be + * determined. For example, in 'svn status', plain unversioned nodes show + * as '? C', where ignored ones show as 'I C'. */ + + if (ignore_patterns && ! *collected_ignore_patterns) + SVN_ERR(collect_ignore_patterns(collected_ignore_patterns, wb->db, + parent_abspath, ignore_patterns, + result_pool, scratch_pool)); + + SVN_ERR(send_unversioned_item(wb, + local_abspath, + dirent, + conflicted, + *collected_ignore_patterns, + no_ignore, + status_func, status_baton, + scratch_pool)); + + return SVN_NO_ERROR; +} + +/* Send svn_wc_status3_t * structures for the directory LOCAL_ABSPATH and + for all its child nodes (according to DEPTH) through STATUS_FUNC / + STATUS_BATON. If SKIP_THIS_DIR is TRUE, the directory's own status will not be reported. - However, upon recursing, all subdirs *will* be reported, regardless of this + All subdirs reached by recursion will be reported regardless of this parameter's value. - DIRENT is LOCAL_ABSPATH's own dirent and is only needed if it is reported, - so if SKIP_THIS_DIR or SELECTED is not-NULL DIRENT can be left NULL. + PARENT_REPOS_* parameters can be set to refer to LOCAL_ABSPATH's parent's + URL, i.e. the URL the WC reflects at the dirname of LOCAL_ABSPATH, to avoid + retrieving them again. Otherwise they must be NULL. DIR_INFO can be set to the information of LOCAL_ABSPATH, to avoid retrieving - it again. + it again. Otherwise it must be NULL. + + DIRENT is LOCAL_ABSPATH's own dirent and is only needed if it is reported, + so if SKIP_THIS_DIR is TRUE, DIRENT can be left NULL. Other arguments are the same as those passed to svn_wc_get_status_editor5(). */ static svn_error_t * get_dir_status(const struct walk_status_baton *wb, const char *local_abspath, - const char *selected, svn_boolean_t skip_this_dir, const char *parent_repos_root_url, const char *parent_repos_relpath, @@ -1043,7 +1271,7 @@ get_dir_status(const struct walk_status_ const char *dir_repos_relpath; const char *dir_repos_uuid; apr_hash_t *dirents, *nodes, *conflicts, *all_children; - apr_array_header_t *patterns = NULL; + apr_array_header_t *collected_ignore_patterns = NULL; apr_pool_t *iterpool, *subpool = svn_pool_create(scratch_pool); svn_error_t *err; @@ -1076,178 +1304,156 @@ get_dir_status(const struct walk_status_ parent_repos_root_url, parent_repos_uuid, wb->db, local_abspath, subpool, iterpool)); - if (selected == NULL) - { - /* Create a hash containing all children. The source hashes - don't all map the same types, but only the keys of the result - hash are subsequently used. */ - SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, + + /* Create a hash containing all children. The source hashes + don't all map the same types, but only the keys of the result + hash are subsequently used. */ + SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, wb->db, local_abspath, subpool, iterpool)); - all_children = apr_hash_overlay(subpool, nodes, dirents); - if (apr_hash_count(conflicts) > 0) - all_children = apr_hash_overlay(subpool, conflicts, all_children); - } - else - { - const struct svn_wc__db_info_t *info; - const char *selected_abspath = svn_dirent_join(local_abspath, selected, - iterpool); - /* Create a hash containing just selected */ - all_children = apr_hash_make(subpool); - nodes = apr_hash_make(subpool); - conflicts = apr_hash_make(subpool); - - err = read_info(&info, selected_abspath, wb->db, subpool, iterpool); - - if (err) - { - if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND) - return svn_error_trace(err); - svn_error_clear(err); - /* The node is neither a tree conflict nor a versioned node */ - } - else - { - if (!info->conflicted - || info->status != svn_wc__db_status_normal - || info->kind != svn_wc__db_kind_unknown) - { - /* The node is a normal versioned node */ - apr_hash_set(nodes, selected, APR_HASH_KEY_STRING, info); - } - - /* Drop it in the list of possible conflicts */ - if (info->conflicted) - apr_hash_set(conflicts, selected, APR_HASH_KEY_STRING, info); - } - - apr_hash_set(all_children, selected, APR_HASH_KEY_STRING, selected); - } - - if (!selected) - { - /* Handle "this-dir" first. */ - if (! skip_this_dir) - SVN_ERR(send_status_structure(wb, local_abspath, - parent_repos_root_url, - parent_repos_relpath, - parent_repos_uuid, - dir_info, dirent, get_all, - status_func, status_baton, - iterpool)); + all_children = apr_hash_overlay(subpool, nodes, dirents); + if (apr_hash_count(conflicts) > 0) + all_children = apr_hash_overlay(subpool, conflicts, all_children); + + /* Handle "this-dir" first. */ + if (! skip_this_dir) + SVN_ERR(send_status_structure(wb, local_abspath, + parent_repos_root_url, + parent_repos_relpath, + parent_repos_uuid, + dir_info, dirent, get_all, + status_func, status_baton, + iterpool)); - /* If the requested depth is empty, we only need status on this-dir. */ - if (depth == svn_depth_empty) - return SVN_NO_ERROR; - } + /* If the requested depth is empty, we only need status on this-dir. */ + if (depth == svn_depth_empty) + return SVN_NO_ERROR; /* Walk all the children of this directory. */ for (hi = apr_hash_first(subpool, all_children); hi; hi = apr_hash_next(hi)) { const void *key; apr_ssize_t klen; - const char *node_abspath; - svn_io_dirent2_t *dirent_p; - const struct svn_wc__db_info_t *info; + const char *child_abspath; + svn_io_dirent2_t *child_dirent; + const struct svn_wc__db_info_t *child_info; svn_pool_clear(iterpool); apr_hash_this(hi, &key, &klen, NULL); - node_abspath = svn_dirent_join(local_abspath, key, iterpool); - - dirent_p = apr_hash_get(dirents, key, klen); - - info = apr_hash_get(nodes, key, klen); - if (info) - { - if (info->status != svn_wc__db_status_not_present - && info->status != svn_wc__db_status_excluded - && info->status != svn_wc__db_status_server_excluded) - { - if (depth == svn_depth_files - && info->kind == svn_wc__db_kind_dir) - { - continue; - } - - SVN_ERR(send_status_structure(wb, node_abspath, - dir_repos_root_url, - dir_repos_relpath, - dir_repos_uuid, - info, dirent_p, get_all, - status_func, status_baton, - iterpool)); - - /* Descend in subdirectories. */ - if (depth == svn_depth_infinity - && info->kind == svn_wc__db_kind_dir) - { - SVN_ERR(get_dir_status(wb, node_abspath, NULL, TRUE, - dir_repos_root_url, dir_repos_relpath, - dir_repos_uuid, info, - dirent_p, ignore_patterns, - svn_depth_infinity, get_all, - no_ignore, - status_func, status_baton, - cancel_func, cancel_baton, - iterpool)); - } + child_abspath = svn_dirent_join(local_abspath, key, iterpool); - continue; - } - } + child_dirent = apr_hash_get(dirents, key, klen); + child_info = apr_hash_get(nodes, key, klen); - if (apr_hash_get(conflicts, key, klen)) - { - /* Tree conflict */ + SVN_ERR(one_child_status(wb, + child_abspath, + local_abspath, + child_info, + child_dirent, + dir_repos_root_url, + dir_repos_relpath, + dir_repos_uuid, + apr_hash_get(conflicts, key, klen) != NULL, + &collected_ignore_patterns, + ignore_patterns, + depth, + get_all, + no_ignore, + status_func, + status_baton, + cancel_func, + cancel_baton, + subpool, + iterpool)); + } - if (ignore_patterns && ! patterns) - SVN_ERR(collect_ignore_patterns(&patterns, wb->db, local_abspath, - ignore_patterns, subpool, - iterpool)); - - SVN_ERR(send_unversioned_item(wb, - node_abspath, - dirent_p, TRUE, - patterns, - no_ignore, - status_func, - status_baton, - iterpool)); + /* Destroy our subpools. */ + svn_pool_destroy(subpool); - continue; - } + return SVN_NO_ERROR; +} - /* Unversioned node */ - if (dirent_p == NULL) - continue; /* Selected node, but not found */ +/* Send an svn_wc_status3_t * structure for the versioned file, or for the + * unversioned file or directory, LOCAL_ABSPATH, which is not ignored (an + * explicit target). Does not recurse. + * + * INFO should reflect LOCAL_ABSPATH's information, but should be NULL for + * unversioned nodes. An unversioned and tree-conflicted node however should + * pass a non-NULL INFO as returned by read_info() (INFO->CONFLICTED = TRUE). + * + * DIRENT should reflect LOCAL_ABSPATH. + * + * All allocations made in SCRATCH_POOL. + * + * The remaining parameters correspond to get_dir_status(). */ +static svn_error_t * +get_child_status(const struct walk_status_baton *wb, + const char *local_abspath, + const struct svn_wc__db_info_t *info, + const svn_io_dirent2_t *dirent, + const apr_array_header_t *ignore_patterns, + svn_boolean_t get_all, + svn_wc_status_func4_t status_func, + void *status_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) +{ + const char *dir_repos_root_url; + const char *dir_repos_relpath; + const char *dir_repos_uuid; + const struct svn_wc__db_info_t *dir_info; + apr_array_header_t *collected_ignore_patterns = NULL; + const svn_io_dirent2_t *dirent_p; + const char *parent_abspath = svn_dirent_dirname(local_abspath, + scratch_pool); - if (depth == svn_depth_files && dirent_p->kind == svn_node_dir) - continue; + if (cancel_func) + SVN_ERR(cancel_func(cancel_baton)); - if (svn_wc_is_adm_dir(key, iterpool)) - continue; + SVN_ERR(svn_io_stat_dirent(&dirent_p, local_abspath, TRUE, + scratch_pool, scratch_pool)); - if (ignore_patterns && ! patterns) - SVN_ERR(collect_ignore_patterns(&patterns, wb->db, local_abspath, - ignore_patterns, subpool, - iterpool)); + if (dirent_p->kind == svn_node_none) + dirent_p = NULL; - SVN_ERR(send_unversioned_item(wb, - node_abspath, - dirent_p, FALSE, - patterns, - no_ignore || selected, - status_func, status_baton, - iterpool)); - } + SVN_ERR(read_info(&dir_info, parent_abspath, wb->db, + scratch_pool, scratch_pool)); - /* Destroy our subpools. */ - svn_pool_destroy(subpool); + SVN_ERR(get_repos_root_url_relpath(&dir_repos_relpath, &dir_repos_root_url, + &dir_repos_uuid, dir_info, + NULL, NULL, NULL, + wb->db, parent_abspath, + scratch_pool, scratch_pool)); + /* An unversioned node with a tree conflict will see an INFO != NULL here, + * in which case the FALSE passed for UNVERSIONED_TREE_CONFLICTED has no + * effect and INFO->CONFLICTED counts. + * ### Maybe svn_wc__db_read_children_info() and read_info() should be more + * ### alike? */ + SVN_ERR(one_child_status(wb, + local_abspath, + parent_abspath, + info, + dirent_p, + dir_repos_root_url, + dir_repos_relpath, + dir_repos_uuid, + FALSE, /* unversioned_tree_conflicted */ + &collected_ignore_patterns, + ignore_patterns, + svn_depth_empty, + get_all, + TRUE, /* no_ignore. This is an explicit target. */ + status_func, + status_baton, + cancel_func, + cancel_baton, + scratch_pool, + scratch_pool)); return SVN_NO_ERROR; } @@ -1373,6 +1579,27 @@ tweak_statushash(void *baton, { struct dir_baton *b = this_dir_baton; + if (!statstruct->repos_relpath && b->repos_relpath) + { + if (statstruct->repos_node_status == svn_wc_status_deleted) + { + /* When deleting PATH, BATON is for PATH's parent, + so we must construct PATH's real statstruct->url. */ + statstruct->repos_relpath = + svn_relpath_join(b->repos_relpath, + svn_dirent_basename(local_abspath, + NULL), + pool); + } + else + statstruct->repos_relpath = apr_pstrdup(pool, b->repos_relpath); + + statstruct->repos_root_url = + b->edit_baton->anchor_status->repos_root_url; + statstruct->repos_uuid = + b->edit_baton->anchor_status->repos_uuid; + } + /* The last committed date, and author for deleted items isn't available. */ if (statstruct->repos_node_status == svn_wc_status_deleted) @@ -1406,6 +1633,14 @@ tweak_statushash(void *baton, struct file_baton *b = baton; statstruct->ood_changed_rev = b->ood_changed_rev; statstruct->ood_changed_date = b->ood_changed_date; + if (!statstruct->repos_relpath && b->repos_relpath) + { + statstruct->repos_relpath = apr_pstrdup(pool, b->repos_relpath); + statstruct->repos_root_url = + b->edit_baton->anchor_status->repos_root_url; + statstruct->repos_uuid = + b->edit_baton->anchor_status->repos_uuid; + } statstruct->ood_kind = b->ood_kind; if (b->ood_changed_author) statstruct->ood_changed_author = @@ -1428,9 +1663,9 @@ find_dir_repos_relpath(const struct dir_ const svn_wc_status3_t *status = apr_hash_get(pb->statii, db->local_abspath, APR_HASH_KEY_STRING); - /* Note that status->url is NULL in the case of a missing - * directory, which means we need to recurse up another level to - * get a useful URL. */ + /* Note that status->repos_relpath could be NULL in the case of a missing + * directory, which means we need to recurse up another level to get + * a useful relpath. */ if (status) return status->repos_relpath; @@ -1475,6 +1710,7 @@ make_dir_baton(void **dir_baton, d->statii = apr_hash_make(pool); d->ood_changed_rev = SVN_INVALID_REVNUM; d->ood_changed_date = 0; + d->repos_relpath = apr_pstrdup(pool, find_dir_repos_relpath(d, pool)); d->ood_kind = svn_node_dir; d->ood_changed_author = NULL; @@ -1519,7 +1755,7 @@ make_dir_baton(void **dir_baton, const svn_wc_status3_t *this_dir_status; const apr_array_header_t *ignores = eb->ignores; - SVN_ERR(get_dir_status(&eb->wb, local_abspath, NULL, TRUE, + SVN_ERR(get_dir_status(&eb->wb, local_abspath, TRUE, status_in_parent->repos_root_url, NULL /*parent_repos_relpath*/, status_in_parent->repos_uuid, @@ -1568,6 +1804,8 @@ make_file_baton(struct dir_baton *parent f->edit_baton = eb; f->ood_changed_rev = SVN_INVALID_REVNUM; f->ood_changed_date = 0; + f->repos_relpath = svn_relpath_join(find_dir_repos_relpath(pb, pool), + f->name, pool); f->ood_kind = svn_node_file; f->ood_changed_author = NULL; return f; @@ -1702,7 +1940,7 @@ handle_statii(struct edit_baton *eb, || depth == svn_depth_infinity)) { SVN_ERR(get_dir_status(&eb->wb, - local_abspath, NULL, TRUE, + local_abspath, TRUE, dir_repos_root_url, dir_repos_relpath, dir_repos_uuid, NULL, @@ -1765,7 +2003,7 @@ delete_entry(const char *path, struct dir_baton *db = parent_baton; struct edit_baton *eb = db->edit_baton; const char *local_abspath = svn_dirent_join(eb->anchor_abspath, path, pool); - svn_wc__db_kind_t kind; + svn_kind_t kind; /* Note: when something is deleted, it's okay to tweak the statushash immediately. No need to wait until close_file or @@ -1774,7 +2012,7 @@ delete_entry(const char *path, SVN_ERR(svn_wc__db_read_kind(&kind, eb->db, local_abspath, FALSE, pool)); SVN_ERR(tweak_statushash(db, db, TRUE, eb->db, - local_abspath, kind == svn_wc__db_kind_dir, + local_abspath, kind == svn_kind_dir, svn_wc_status_deleted, 0, 0, revision, NULL, pool)); /* Mark the parent dir -- it lost an entry (unless that parent dir @@ -1783,7 +2021,7 @@ delete_entry(const char *path, if (db->parent_baton && (! *eb->target_basename)) SVN_ERR(tweak_statushash(db->parent_baton, db, TRUE,eb->db, db->local_abspath, - kind == svn_wc__db_kind_dir, + kind == svn_kind_dir, svn_wc_status_modified, svn_wc_status_modified, 0, SVN_INVALID_REVNUM, NULL, pool)); @@ -1974,7 +2212,7 @@ close_directory(void *dir_baton, && tgt_status->kind == svn_node_dir) { SVN_ERR(get_dir_status(&eb->wb, - eb->target_abspath, NULL, TRUE, + eb->target_abspath, TRUE, NULL, NULL, NULL, NULL, NULL /* dirent */, eb->ignores, @@ -2218,6 +2456,8 @@ svn_wc_get_status_editor5(const svn_delt svn_delta_editor_t *tree_editor = svn_delta_default_editor(result_pool); void *inner_baton; const svn_delta_editor_t *inner_editor; + svn_delta_shim_callbacks_t *shim_callbacks = + svn_delta_shim_callbacks_default(result_pool); /* Construct an edit baton. */ eb = apr_pcalloc(result_pool, sizeof(*eb)); @@ -2305,6 +2545,10 @@ svn_wc_get_status_editor5(const svn_delt if (set_locks_baton) *set_locks_baton = eb; + SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton, + shim_callbacks, + result_pool, scratch_pool)); + return SVN_NO_ERROR; } @@ -2324,9 +2568,7 @@ svn_wc__internal_walk_status(svn_wc__db_ { struct walk_status_baton wb; const svn_io_dirent2_t *dirent; - const char *anchor_abspath, *target_name; - svn_boolean_t skip_root; - const struct svn_wc__db_info_t *dir_info; + const struct svn_wc__db_info_t *info; svn_error_t *err; wb.db = db; @@ -2348,45 +2590,53 @@ svn_wc__internal_walk_status(svn_wc__db_ ignore_patterns = ignores; } - err = read_info(&dir_info, local_abspath, db, scratch_pool, scratch_pool); + err = read_info(&info, local_abspath, db, scratch_pool, scratch_pool); - if (!err && dir_info->kind == svn_wc__db_kind_dir) - { - anchor_abspath = local_abspath; - target_name = NULL; - skip_root = FALSE; - } - else if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND) - return svn_error_trace(err); - else + if (err) { - svn_error_clear(err); - dir_info = NULL; /* Don't pass information of the child */ - - /* Walk the status of the parent of LOCAL_ABSPATH, but only report - status on its child LOCAL_ABSPATH. */ - anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool); - target_name = svn_dirent_basename(local_abspath, NULL); - skip_root = TRUE; + if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) + { + svn_error_clear(err); + info = NULL; + } + else + return svn_error_trace(err); } SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, TRUE, scratch_pool, scratch_pool)); - SVN_ERR(get_dir_status(&wb, - anchor_abspath, - target_name, - skip_root, - NULL, NULL, NULL, - dir_info, - dirent, - ignore_patterns, - depth, - get_all, - no_ignore, - status_func, status_baton, - cancel_func, cancel_baton, - scratch_pool)); + if (info && info->kind == svn_kind_dir) + { + SVN_ERR(get_dir_status(&wb, + local_abspath, + FALSE /* skip_root */, + NULL, NULL, NULL, + info, + dirent, + ignore_patterns, + depth, + get_all, + no_ignore, + status_func, status_baton, + cancel_func, cancel_baton, + scratch_pool)); + } + else + { + /* It may be a file or an unversioned item. And this is an explicit + * target, so no ignoring. An unversioned item (file or dir) shows a + * status like '?', and can yield a tree conflicted path. */ + SVN_ERR(get_child_status(&wb, + local_abspath, + info, + dirent, + ignore_patterns, + get_all, + status_func, status_baton, + cancel_func, cancel_baton, + scratch_pool)); + } return SVN_NO_ERROR; } @@ -2468,7 +2718,7 @@ internal_status(svn_wc_status3_t **statu apr_pool_t *scratch_pool) { const svn_io_dirent2_t *dirent; - svn_wc__db_kind_t node_kind; + svn_kind_t node_kind; const char *parent_repos_relpath; const char *parent_repos_root_url; const char *parent_repos_uuid; @@ -2492,7 +2742,7 @@ internal_status(svn_wc_status3_t **statu if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) { svn_error_clear(err); - node_kind = svn_wc__db_kind_unknown; + node_kind = svn_kind_unknown; /* Ensure conflicted is always set, but don't hide tree conflicts on 'hidden' nodes. */ conflicted = FALSE; @@ -2505,10 +2755,10 @@ internal_status(svn_wc_status3_t **statu || node_status == svn_wc__db_status_server_excluded || node_status == svn_wc__db_status_excluded) { - node_kind = svn_wc__db_kind_unknown; + node_kind = svn_kind_unknown; } - if (node_kind == svn_wc__db_kind_unknown) + if (node_kind == svn_kind_unknown) return svn_error_trace(assemble_unversioned(status, db, local_abspath, dirent, conflicted, @@ -2624,10 +2874,6 @@ svn_wc_dup_status3(const svn_wc_status3_ new_stat->moved_to_abspath = apr_pstrdup(pool, orig_stat->moved_to_abspath); - if (orig_stat->moved_to_op_root_abspath) - new_stat->moved_to_op_root_abspath - = apr_pstrdup(pool, orig_stat->moved_to_op_root_abspath); - /* Return the new hotness. */ return new_stat; }
Modified: subversion/branches/svn-bisect/subversion/libsvn_wc/translate.c URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_wc/translate.c?rev=1204374&r1=1204373&r2=1204374&view=diff ============================================================================== --- subversion/branches/svn-bisect/subversion/libsvn_wc/translate.c (original) +++ subversion/branches/svn-bisect/subversion/libsvn_wc/translate.c Mon Nov 21 07:07:56 2011 @@ -365,7 +365,7 @@ svn_wc__sync_flags_with_props(svn_boolea apr_pool_t *scratch_pool) { svn_wc__db_status_t status; - svn_wc__db_kind_t kind; + svn_kind_t kind; svn_wc__db_lock_t *lock; apr_hash_t *props = NULL; @@ -387,7 +387,7 @@ svn_wc__sync_flags_with_props(svn_boolea /* We actually only care about the following flags on files, so just early-out for all other types. */ - if (kind != svn_wc__db_kind_file) + if (kind != svn_kind_file) return SVN_NO_ERROR; /* If we get this far, we're going to change *something*, so just set Modified: subversion/branches/svn-bisect/subversion/libsvn_wc/tree_conflicts.c URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_wc/tree_conflicts.c?rev=1204374&r1=1204373&r2=1204374&view=diff ============================================================================== --- subversion/branches/svn-bisect/subversion/libsvn_wc/tree_conflicts.c (original) +++ subversion/branches/svn-bisect/subversion/libsvn_wc/tree_conflicts.c Mon Nov 21 07:07:56 2011 @@ -76,6 +76,9 @@ const svn_token_map_t svn_wc__conflict_r { "added", svn_wc_conflict_reason_added }, { "replaced", svn_wc_conflict_reason_replaced }, { "unversioned", svn_wc_conflict_reason_unversioned }, + { "moved-away", svn_wc_conflict_reason_moved_away }, + { "moved-away-and-edited", svn_wc_conflict_reason_moved_away_and_edited }, + { "moved-here", svn_wc_conflict_reason_moved_here }, { NULL } }; @@ -363,7 +366,7 @@ svn_wc__serialize_conflict(svn_skel_t ** /* Victim path (escaping separator chars). */ victim_basename = svn_dirent_basename(conflict->local_abspath, result_pool); - SVN_ERR_ASSERT(strlen(victim_basename) > 0); + SVN_ERR_ASSERT(victim_basename[0]); svn_skel__prepend(svn_skel__str_atom(victim_basename, result_pool), c_skel); svn_skel__prepend(svn_skel__str_atom("conflict", result_pool), c_skel);
