📄 status.c
字号:
} else { /* File entries are ... just fine! */ SVN_ERR(send_status_structure(path, adm_access, entry, dir_entry, kind, special, get_all, FALSE, eb->repos_locks, eb->repos_root, status_func, status_baton, pool)); } return SVN_NO_ERROR;}/* Send svn_wc_status2_t * structures for the directory ADM_ACCESS and for all its entries through STATUS_FUNC/STATUS_BATON, or, if ENTRY is non-NULL, only for that directory entry. PARENT_ENTRY is the entry for the parent of the directory or NULL if that directory is a working copy root. If SKIP_THIS_DIR is TRUE (and ENTRY is NULL), the directory's own status will not be reported. However, upon recursing, all subdirs *will* be reported, regardless of this parameter's value. Other arguments are the same as those passed to svn_wc_get_status_editor2(). */static svn_error_t *get_dir_status(struct edit_baton *eb, const svn_wc_entry_t *parent_entry, svn_wc_adm_access_t *adm_access, const char *entry, apr_array_header_t *ignores, svn_boolean_t descend, svn_boolean_t get_all, svn_boolean_t no_ignore, svn_boolean_t skip_this_dir, svn_wc_status_func2_t status_func, void *status_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool){ apr_hash_t *entries; apr_hash_index_t *hi; const svn_wc_entry_t *dir_entry; const char *path = svn_wc_adm_access_path(adm_access); apr_hash_t *dirents; apr_array_header_t *patterns = NULL; apr_pool_t *iterpool, *subpool = svn_pool_create(pool); /* See if someone wants to cancel this operation. */ if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); /* Load entries file for the directory into the requested pool. */ SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, subpool)); /* Read PATH's dirents. */ SVN_ERR(svn_io_get_dirents2(&dirents, path, subpool)); /* Get this directory's entry. */ SVN_ERR(svn_wc_entry(&dir_entry, path, adm_access, FALSE, subpool)); /* If "this dir" has "svn:externals" property set on it, store its name and value in traversal_info. Also, we want to track the externals internally so we can report status more accurately. */ { const svn_string_t *prop_val; SVN_ERR(svn_wc_prop_get(&prop_val, SVN_PROP_EXTERNALS, path, adm_access, subpool)); if (prop_val) { apr_array_header_t *ext_items; int i; if (eb->traversal_info) { apr_pool_t *dup_pool = eb->traversal_info->pool; const char *dup_path = apr_pstrdup(dup_pool, path); const char *dup_val = apr_pstrmemdup(dup_pool, prop_val->data, prop_val->len); /* First things first -- we put the externals information into the "global" traversal info structure. */ apr_hash_set(eb->traversal_info->externals_old, dup_path, APR_HASH_KEY_STRING, dup_val); apr_hash_set(eb->traversal_info->externals_new, dup_path, APR_HASH_KEY_STRING, dup_val); } /* Now, parse the thing, and copy the parsed results into our "global" externals hash. */ SVN_ERR(svn_wc_parse_externals_description2(&ext_items, path, prop_val->data, pool)); for (i = 0; ext_items && i < ext_items->nelts; i++) { svn_wc_external_item_t *item; item = APR_ARRAY_IDX(ext_items, i, svn_wc_external_item_t *); apr_hash_set(eb->externals, svn_path_join(path, item->target_dir, pool), APR_HASH_KEY_STRING, item); } } } /* Early out -- our caller only cares about a single ENTRY in this directory. */ if (entry) { const svn_wc_entry_t *entry_entry; svn_io_dirent_t* dirent_p = apr_hash_get(dirents, entry, APR_HASH_KEY_STRING); entry_entry = apr_hash_get(entries, entry, APR_HASH_KEY_STRING); /* If ENTRY is versioned, send its versioned status. */ if (entry_entry) { SVN_ERR(handle_dir_entry(eb, adm_access, entry, dir_entry, entry_entry, dirent_p ? dirent_p->kind : svn_node_none, dirent_p ? dirent_p->special : FALSE, ignores, descend, get_all, no_ignore, status_func, status_baton, cancel_func, cancel_baton, subpool)); } /* Otherwise, if it exists, send its unversioned status. */ else if (dirent_p) { if (ignores && ! patterns) SVN_ERR(collect_ignore_patterns(&patterns, ignores, adm_access, subpool)); SVN_ERR(send_unversioned_item(entry, dirent_p->kind, dirent_p->special, adm_access, patterns, eb->externals, no_ignore, eb->repos_locks, eb->repos_root, status_func, status_baton, subpool)); } /* Regardless, we're done here. Let's go home. */ return SVN_NO_ERROR; } /** If we get here, ENTRY is NULL and we are handling all the directory entries. */ /* Make our iteration pool. */ iterpool = svn_pool_create(subpool); /* Add empty status structures for each of the unversioned things. */ for (hi = apr_hash_first(subpool, dirents); hi; hi = apr_hash_next(hi)) { const void *key; apr_ssize_t klen; void *val; svn_io_dirent_t *dirent_p; apr_hash_this(hi, &key, &klen, &val); /* Skip versioned things, and skip the administrative directory. */ if (apr_hash_get(entries, key, klen) || svn_wc_is_adm_dir(key, subpool)) continue; svn_pool_clear(iterpool); if (ignores && ! patterns) SVN_ERR(collect_ignore_patterns(&patterns, ignores, adm_access, subpool)); /* Make an unversioned status item for KEY, and put it into our return hash. */ dirent_p = val; SVN_ERR(send_unversioned_item(key, dirent_p->kind, dirent_p->special, adm_access, patterns, eb->externals, no_ignore, eb->repos_locks, eb->repos_root, status_func, status_baton, iterpool)); } /* Handle "this-dir" first. */ if (! skip_this_dir) SVN_ERR(send_status_structure(path, adm_access, dir_entry, parent_entry, svn_node_dir, FALSE, get_all, FALSE, eb->repos_locks, eb->repos_root, status_func, status_baton, subpool)); /* Loop over entries hash */ for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi)) { const void *key; void *val; svn_io_dirent_t *dirent_p; /* Get the next entry */ apr_hash_this(hi, &key, NULL, &val); dirent_p = apr_hash_get(dirents, key, APR_HASH_KEY_STRING); /* ### todo: What if the subdir is from another repository? */ /* Skip "this-dir". */ if (strcmp(key, SVN_WC_ENTRY_THIS_DIR) == 0) continue; /* Clear the iteration subpool. */ svn_pool_clear(iterpool); /* Handle this directory entry (possibly recursing). */ SVN_ERR(handle_dir_entry(eb, adm_access, key, dir_entry, val, dirent_p ? dirent_p->kind : svn_node_none, dirent_p ? dirent_p->special : FALSE, ignores, descend, get_all, no_ignore, status_func, status_baton, cancel_func, cancel_baton, iterpool)); } /* Destroy our subpools. */ svn_pool_destroy(subpool); return SVN_NO_ERROR;}/*** Helpers ***//* A faux status callback function for stashing STATUS item in an hash (which is the BATON), keyed on PATH. This implements the svn_wc_status_func2_t interface. */static voidhash_stash(void *baton, const char *path, svn_wc_status2_t *status){ apr_hash_t *stat_hash = baton; apr_pool_t *hash_pool = apr_hash_pool_get(stat_hash); assert(! apr_hash_get(stat_hash, path, APR_HASH_KEY_STRING)); apr_hash_set(stat_hash, apr_pstrdup(hash_pool, path), APR_HASH_KEY_STRING, svn_wc_dup_status2(status, hash_pool));}/* Look up the key PATH in BATON->STATII. IS_DIR_BATON indicates whether baton is a struct *dir_baton or struct *file_baton. If the value doesn't yet exist, and the REPOS_TEXT_STATUS indicates that this is an addition, create a new status struct using the hash's pool. Merge REPOS_TEXT_STATUS and REPOS_PROP_STATUS into the status structure's "network" fields. If a new struct was added, set the repos_lock to REPOS_LOCK. */static svn_error_t *tweak_statushash(void *baton, svn_boolean_t is_dir_baton, svn_wc_adm_access_t *adm_access, const char *path, svn_boolean_t is_dir, enum svn_wc_status_kind repos_text_status, enum svn_wc_status_kind repos_prop_status, svn_lock_t *repos_lock){ svn_wc_status2_t *statstruct; apr_pool_t *pool; apr_hash_t *statushash; if (is_dir_baton) statushash = ((struct dir_baton *) baton)->statii; else statushash = ((struct file_baton *) baton)->dir_baton->statii; pool = apr_hash_pool_get(statushash); /* Is PATH already a hash-key? */ statstruct = apr_hash_get(statushash, path, APR_HASH_KEY_STRING); /* If not, make it so. */ if (! statstruct) { /* 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 reports the state of non-recursive working copies, the repository can send back responses about paths that don't even exist locally. Our best course here is just to ignore those responses. After all, if the client had reported correctly in the first, that path would either be mentioned as an 'add' or not mentioned at all, depending on how we eventually fix the bugs in non-recursivity. See issue #2122 for details. */ if (repos_text_status != svn_wc_status_added) return SVN_NO_ERROR; /* Use the public API to get a statstruct, and put it into the hash. */ SVN_ERR(svn_wc_status2(&statstruct, path, adm_access, pool)); statstruct->repos_lock = repos_lock; apr_hash_set(statushash, apr_pstrdup(pool, path), APR_HASH_KEY_STRING, statstruct); } /* Merge a repos "delete" + "add" into a single "replace". */ if ((repos_text_status == svn_wc_status_added) && (statstruct->repos_text_status == svn_wc_status_deleted)) repos_text_status = svn_wc_status_replaced; /* Tweak the structure's repos fields. */ if (repos_text_status) statstruct->repos_text_status = repos_text_status; if (repos_prop_status) statstruct->repos_prop_status = repos_prop_status; /* Copy out of date info. */ if (is_dir_baton) { struct dir_baton *b = baton; if (b->url) statstruct->url = apr_pstrdup(pool, b->url); statstruct->ood_kind = b->ood_kind; /* The last committed rev, date, and author for deleted items isn't available. */ if (statstruct->repos_text_status != svn_wc_status_deleted) { statstruct->ood_last_cmt_rev = b->ood_last_cmt_rev; statstruct->ood_last_cmt_date = b->ood_last_cmt_date; if (b->ood_last_cmt_author) statstruct->ood_last_cmt_author = apr_pstrdup(pool, b->ood_last_cmt_author); } } else { struct file_baton *b = baton; if (b->url) statstruct->url = apr_pstrdup(pool, b->url); statstruct->ood_last_cmt_rev = b->ood_last_cmt_rev; statstruct->ood_last_cmt_date = b->ood_last_cmt_date; statstruct->ood_kind = b->ood_kind; if (b->ood_last_cmt_author) statstruct->ood_last_cmt_author = apr_pstrdup(pool, b->ood_last_cmt_author); } return SVN_NO_ERROR;}/* Returns the URL for DB, or NULL: */static const char *find_dir_url(const struct dir_baton *db, apr_pool_t *pool){ /* If we have no name, we're the root, return the anchor URL. */ if (! db->name) return db->edit_baton->anchor_status->entry->url; else { const char *url; struct dir_baton *pb = db->parent_baton; svn_wc_status2_t *status = apr_hash_get(pb->statii, db->name, APR_HASH_KEY_STRING); /* Note that status->entry->url is NULL in the case of a missing * directory, which means we need to recurse up another level to * get a useful URL. */ if (status && status->entry && status->entry->url) return status->entry->url; url = find_dir_url(pb, pool); if (url) return svn_path_url_add_component(url, db->name, pool); else return NULL; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -