📄 commit.c
字号:
/* Recursively import PATH to a repository using EDITOR and * EDIT_BATON. PATH can be a file or directory. * * NEW_ENTRIES is an ordered array of path components that must be * created in the repository (where the ordering direction is * parent-to-child). If PATH is a directory, NEW_ENTRIES may be empty * -- the result is an import which creates as many new entries in the * top repository target directory as there are importable entries in * the top of PATH; but if NEW_ENTRIES is not empty, its last item is * the name of a new subdirectory in the repository to hold the * import. If PATH is a file, NEW_ENTRIES may not be empty, and its * last item is the name used for the file in the repository. If * NEW_ENTRIES contains more than one item, all but the last item are * the names of intermediate directories that are created before the * real import begins. NEW_ENTRIES may NOT be NULL. * * EXCLUDES is a hash whose keys are absolute paths to exclude from * the import (values are unused). * * If NO_IGNORE is FALSE, don't import files or directories that match * ignore patterns. * * If CTX->NOTIFY_FUNC is non-null, invoke it with CTX->NOTIFY_BATON for * each imported path, passing actions svn_wc_notify_commit_added. * * Use POOL for any temporary allocation. * * Note: the repository directory receiving the import was specified * when the editor was fetched. (I.e, when EDITOR->open_root() is * called, it returns a directory baton for that directory, which is * not necessarily the root.) */static svn_error_t *import(const char *path, apr_array_header_t *new_entries, const svn_delta_editor_t *editor, void *edit_baton, svn_boolean_t nonrecursive, apr_hash_t *excludes, svn_boolean_t no_ignore, svn_client_ctx_t *ctx, apr_pool_t *pool){ void *root_baton; svn_node_kind_t kind; apr_array_header_t *ignores; apr_array_header_t *batons = NULL; const char *edit_path = ""; import_ctx_t *import_ctx = apr_pcalloc(pool, sizeof(*import_ctx)); /* Get a root dir baton. We pass an invalid revnum to open_root to mean "base this on the youngest revision". Should we have an SVN_YOUNGEST_REVNUM defined for these purposes? */ SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, pool, &root_baton)); /* Import a file or a directory tree. */ SVN_ERR(svn_io_check_path(path, &kind, pool)); /* Make the intermediate directory components necessary for properly rooting our import source tree. */ if (new_entries->nelts) { int i; batons = apr_array_make(pool, new_entries->nelts, sizeof(void *)); for (i = 0; i < new_entries->nelts; i++) { const char *component = APR_ARRAY_IDX(new_entries, i, const char *); edit_path = svn_path_join(edit_path, component, pool); /* If this is the last path component, and we're importing a file, then this component is the name of the file, not an intermediate directory. */ if ((i == new_entries->nelts - 1) && (kind == svn_node_file)) break; *((void **) apr_array_push(batons)) = root_baton; SVN_ERR(editor->add_directory(edit_path, root_baton, NULL, SVN_INVALID_REVNUM, pool, &root_baton)); /* Remember that the repository was modified */ import_ctx->repos_changed = TRUE; } } else if (kind == svn_node_file) { return svn_error_create (SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("New entry name required when importing a file")); } /* Note that there is no need to check whether PATH's basename is the same name that we reserve for our administrative subdirectories. It would be strange -- though not illegal -- to import the contents of a directory of that name, because the directory's own name is not part of those contents. Of course, if something underneath it also has our reserved name, then we'll error. */ if (kind == svn_node_file) { svn_boolean_t ignores_match = FALSE; if (!no_ignore) { SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool)); ignores_match = svn_cstring_match_glob_list(path, ignores); } if (!ignores_match) SVN_ERR(import_file(editor, root_baton, path, edit_path, import_ctx, ctx, pool)); } else if (kind == svn_node_dir) { SVN_ERR(import_dir(editor, root_baton, path, edit_path, nonrecursive, excludes, no_ignore, import_ctx, ctx, pool)); } else if (kind == svn_node_none) { return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("'%s' does not exist"), svn_path_local_style(path, pool)); } /* Close up shop; it's time to go home. */ SVN_ERR(editor->close_directory(root_baton, pool)); if (batons && batons->nelts) { void **baton; while ((baton = (void **) apr_array_pop(batons))) { SVN_ERR(editor->close_directory(*baton, pool)); } } if (import_ctx->repos_changed) SVN_ERR(editor->close_edit(edit_baton, pool)); else SVN_ERR(editor->abort_edit(edit_baton, pool)); return SVN_NO_ERROR;}static svn_error_t *get_ra_editor(svn_ra_session_t **ra_session, svn_revnum_t *latest_rev, const svn_delta_editor_t **editor, void **edit_baton, svn_client_ctx_t *ctx, const char *base_url, const char *base_dir, svn_wc_adm_access_t *base_access, const char *log_msg, apr_array_header_t *commit_items, svn_commit_info_t **commit_info_p, svn_boolean_t is_commit, apr_hash_t *lock_tokens, svn_boolean_t keep_locks, apr_pool_t *pool){ void *commit_baton; /* Open an RA session to URL. */ SVN_ERR(svn_client__open_ra_session_internal(ra_session, base_url, base_dir, base_access, commit_items, is_commit, !is_commit, ctx, pool)); /* If this is an import (aka, not a commit), we need to verify that our repository URL exists. */ if (! is_commit) { svn_node_kind_t kind; SVN_ERR(svn_ra_check_path(*ra_session, "", SVN_INVALID_REVNUM, &kind, pool)); if (kind == svn_node_none) return svn_error_createf(SVN_ERR_FS_NO_SUCH_ENTRY, NULL, _("Path '%s' does not exist"), base_url); } /* Fetch the latest revision if requested. */ if (latest_rev) SVN_ERR(svn_ra_get_latest_revnum(*ra_session, latest_rev, pool)); /* Fetch RA commit editor. */ SVN_ERR(svn_client__commit_get_baton(&commit_baton, commit_info_p, pool)); return svn_ra_get_commit_editor2(*ra_session, editor, edit_baton, log_msg, svn_client__commit_callback, commit_baton, lock_tokens, keep_locks, pool);}/*** Public Interfaces. ***/svn_error_t *svn_client_import2(svn_commit_info_t **commit_info_p, const char *path, const char *url, svn_boolean_t nonrecursive, svn_boolean_t no_ignore, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_error_t *err = SVN_NO_ERROR; const char *log_msg = ""; const svn_delta_editor_t *editor; void *edit_baton; svn_ra_session_t *ra_session; apr_hash_t *excludes = apr_hash_make(pool); svn_node_kind_t kind; const char *base_dir = path; apr_array_header_t *new_entries = apr_array_make(pool, 4, sizeof(const char *)); const char *temp; const char *dir; apr_pool_t *subpool; /* Create a new commit item and add it to the array. */ if (ctx->log_msg_func || ctx->log_msg_func2) { /* If there's a log message gatherer, create a temporary commit item array solely to help generate the log message. The array is not used for the import itself. */ svn_client_commit_item2_t *item; const char *tmp_file; apr_array_header_t *commit_items = apr_array_make(pool, 1, sizeof(item)); item = apr_pcalloc(pool, sizeof(*item)); item->path = apr_pstrdup(pool, path); item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD; APR_ARRAY_PUSH(commit_items, svn_client_commit_item2_t *) = item; SVN_ERR(svn_client__get_log_msg(&log_msg, &tmp_file, commit_items, ctx, pool)); if (! log_msg) return SVN_NO_ERROR; if (tmp_file) { const char *abs_path; SVN_ERR(svn_path_get_absolute(&abs_path, tmp_file, pool)); apr_hash_set(excludes, abs_path, APR_HASH_KEY_STRING, (void *)1); } } SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind == svn_node_file) svn_path_split(path, &base_dir, NULL, pool); /* Figure out all the path components we need to create just to have a place to stick our imported tree. */ subpool = svn_pool_create(pool); do { svn_pool_clear(subpool); /* See if the user is interested in cancelling this operation. */ if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); if (err) { /* If get_ra_editor below failed we either tried to open an invalid url, or else some other kind of error. In case the url was bad we back up a directory and try again. */ if (err->apr_err != SVN_ERR_FS_NO_SUCH_ENTRY) return err; else svn_error_clear(err); svn_path_split(url, &temp, &dir, pool); *((const char **) apr_array_push(new_entries)) = svn_path_uri_decode(dir, pool); url = temp; } } while ((err = get_ra_editor(&ra_session, NULL, &editor, &edit_baton, ctx, url, base_dir, NULL, log_msg, NULL, commit_info_p, FALSE, NULL, TRUE, subpool))); /* Reverse the order of the components we added to our NEW_ENTRIES array. */ if (new_entries->nelts) { int i, j; const char *component; for (i = 0; i < (new_entries->nelts / 2); i++) { j = new_entries->nelts - i - 1; component = APR_ARRAY_IDX(new_entries, i, const char *); APR_ARRAY_IDX(new_entries, i, const char *) = APR_ARRAY_IDX(new_entries, j, const char *); APR_ARRAY_IDX(new_entries, j, const char *) = component; } } /* An empty NEW_ENTRIES list the first call to get_ra_editor() above succeeded. That means that URL corresponds to an already existing filesystem entity. */ if (kind == svn_node_file && (! new_entries->nelts)) return svn_error_createf (SVN_ERR_ENTRY_EXISTS, NULL, _("Path '%s' already exists"), url); /* The repository doesn't know about the reserved administrative directory. */ if (new_entries->nelts /* What's this, what's this? This assignment is here because we use the value to construct the error message just below. It may not be asethetically pleasing, but it's less ugly than calling APR_ARRAY_IDX twice. */ && svn_wc_is_adm_dir(temp = APR_ARRAY_IDX(new_entries, new_entries->nelts - 1, const char *), pool)) return svn_error_createf (SVN_ERR_CL_ADM_DIR_RESERVED, NULL, _("'%s' is a reserved name and cannot be imported"), /* ### Is svn_path_local_style() really necessary for this? */ svn_path_local_style(temp, pool)); /* If an error occurred during the commit, abort the edit and return the error. We don't even care if the abort itself fails. */ if ((err = import(path, new_entries, editor, edit_baton, nonrecursive, excludes, no_ignore, ctx, subpool))) { svn_error_clear(editor->abort_edit(edit_baton, subpool)); return err; } /* Transfer *COMMIT_INFO from the subpool to the callers pool */ if (*commit_info_p) { svn_commit_info_t *tmp_commit_info; tmp_commit_info = svn_create_commit_info(pool); *tmp_commit_info = **commit_info_p; if (tmp_commit_info->date) tmp_commit_info->date = apr_pstrdup(pool, tmp_commit_info->date); if (tmp_commit_info->author) tmp_commit_info->author = apr_pstrdup(pool, tmp_commit_info->author); if (tmp_commit_info->post_commit_err) tmp_commit_info->post_commit_err = apr_pstrdup(pool, tmp_commit_info->post_commit_err); *commit_info_p = tmp_commit_info; } svn_pool_destroy(subpool); return SVN_NO_ERROR;}svn_error_t *svn_client_import(svn_client_commit_info_t **commit_info_p, const char *path, const char *url, svn_boolean_t nonrecursive, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_commit_info_t *commit_info = NULL; svn_error_t *err; err = svn_client_import2(&commit_info, path, url, nonrecursive, FALSE, ctx, pool); /* These structs have the same layout for the common fields. */ *commit_info_p = (svn_client_commit_info_t *) commit_info; return err;}static svn_error_t *remove_tmpfiles(apr_hash_t *tempfiles, apr_pool_t *pool){ apr_hash_index_t *hi; apr_pool_t *subpool; /* Split if there's nothing to be done. */ if (! tempfiles) return SVN_NO_ERROR; /* Make a subpool. */ subpool = svn_pool_create(pool); /* Clean up any tempfiles. */ for (hi = apr_hash_first(pool, tempfiles); hi; hi = apr_hash_next(hi)) { const void *key; void *val; svn_error_t *err; svn_pool_clear(subpool); apr_hash_this(hi, &key, NULL, &val); err = svn_io_remove_file((const char *)key, subpool); if (err) { if (! APR_STATUS_IS_ENOENT(err->apr_err)) return err; else svn_error_clear(err);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -