📄 commit.c
字号:
/* * commit.c: wrappers around wc commit functionality. * * ==================================================================== * Copyright (c) 2000-2006 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== *//* ==================================================================== *//*** Includes. ***/#include <string.h>#include <assert.h>#include <apr_strings.h>#include <apr_hash.h>#include <apr_md5.h>#include "svn_wc.h"#include "svn_ra.h"#include "svn_delta.h"#include "svn_subst.h"#include "svn_client.h"#include "svn_string.h"#include "svn_pools.h"#include "svn_error.h"#include "svn_path.h"#include "svn_io.h"#include "svn_md5.h"#include "svn_time.h"#include "svn_sorts.h"#include "svn_props.h"#include "client.h"#include "svn_private_config.h"/* Import context baton. ### TODO: Add the following items to this baton: /` import editor/baton. `/ const svn_delta_editor_t *editor; void *edit_baton; /` Client context baton `/ svn_client_ctx_t `ctx; /` Paths (keys) excluded from the import (values ignored) `/ apr_hash_t *excludes;*/typedef struct import_ctx_t{ /* Whether any changes were made to the repository */ svn_boolean_t repos_changed; } import_ctx_t;/* Apply PATH's contents (as a delta against the empty string) to FILE_BATON in EDITOR. Use POOL for any temporary allocation. PROPERTIES is the set of node properties set on this file. Fill DIGEST with the md5 checksum of the sent file; DIGEST must be at least APR_MD5_DIGESTSIZE bytes long. */static svn_error_t *send_file_contents(const char *path, void *file_baton, const svn_delta_editor_t *editor, apr_hash_t *properties, unsigned char *digest, apr_pool_t *pool){ const char *tmpfile_path = NULL; svn_stream_t *contents; svn_txdelta_window_handler_t handler; void *handler_baton; apr_file_t *f; const svn_string_t *eol_style_val = NULL, *keywords_val = NULL; svn_boolean_t special = FALSE; svn_subst_eol_style_t eol_style; const char *eol; apr_hash_t *keywords; /* If there are properties, look for EOL-style and keywords ones. */ if (properties) { eol_style_val = apr_hash_get(properties, SVN_PROP_EOL_STYLE, sizeof(SVN_PROP_EOL_STYLE) - 1); keywords_val = apr_hash_get(properties, SVN_PROP_KEYWORDS, sizeof(SVN_PROP_KEYWORDS) - 1); if (apr_hash_get(properties, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING)) special = TRUE; } /* Get an editor func that wants to consume the delta stream. */ SVN_ERR(editor->apply_textdelta(file_baton, NULL, pool, &handler, &handler_baton)); if (eol_style_val) svn_subst_eol_style_from_value(&eol_style, &eol, eol_style_val->data); else { eol = NULL; eol_style = svn_subst_eol_style_none; } if (keywords_val) SVN_ERR(svn_subst_build_keywords2(&keywords, keywords_val->data, APR_STRINGIFY(SVN_INVALID_REVNUM), "", 0, "", pool)); else keywords = NULL; /* If we have EOL styles or keywords to de-translate, do it. */ if (svn_subst_translation_required(eol_style, eol, keywords, special, TRUE)) { const char *temp_dir; /* Now create a new tempfile, and open a stream to it. */ SVN_ERR(svn_io_temp_dir(&temp_dir, pool)); SVN_ERR(svn_io_open_unique_file2 (NULL, &tmpfile_path, svn_path_join(temp_dir, "svn-import", pool), ".tmp", svn_io_file_del_on_pool_cleanup, pool)); SVN_ERR(svn_subst_translate_to_normal_form (path, tmpfile_path, eol_style, eol, FALSE, keywords, special, pool)); } /* Open our contents file, either the original path or the temporary copy we might have made above. */ SVN_ERR(svn_io_file_open(&f, tmpfile_path ? tmpfile_path : path, APR_READ, APR_OS_DEFAULT, pool)); contents = svn_stream_from_aprfile(f, pool); /* Send the file's contents to the delta-window handler. */ SVN_ERR(svn_txdelta_send_stream(contents, handler, handler_baton, digest, pool)); /* Close our contents file. */ SVN_ERR(svn_io_file_close(f, pool)); /* The temp file is removed by the pool cleanup run by the caller */ return SVN_NO_ERROR;}/* Import file PATH as EDIT_PATH in the repository directory indicated * by DIR_BATON in EDITOR. * * Accumulate file paths and their batons in FILES, which must be * non-null. (These are used to send postfix textdeltas later). * * If CTX->NOTIFY_FUNC is non-null, invoke it with CTX->NOTIFY_BATON * for each file. * * Use POOL for any temporary allocation. */static svn_error_t *import_file(const svn_delta_editor_t *editor, void *dir_baton, const char *path, const char *edit_path, import_ctx_t *import_ctx, svn_client_ctx_t *ctx, apr_pool_t *pool){ void *file_baton; const char *mimetype = NULL; unsigned char digest[APR_MD5_DIGESTSIZE]; const char *text_checksum; apr_hash_t* properties; apr_hash_index_t *hi; svn_node_kind_t kind; svn_boolean_t is_special; SVN_ERR(svn_path_check_valid(path, pool)); SVN_ERR(svn_io_check_special_path(path, &kind, &is_special, pool)); if (kind == svn_node_unknown) { return svn_error_createf (SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("Unknown or unversionable type for '%s'"), svn_path_local_style(path, pool)); } /* Add the file, using the pool from the FILES hash. */ SVN_ERR(editor->add_file(edit_path, dir_baton, NULL, SVN_INVALID_REVNUM, pool, &file_baton)); /* Remember that the repository was modified */ import_ctx->repos_changed = TRUE; if (! is_special) { /* add automatic properties */ SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, path, ctx, pool)); } else properties = apr_hash_make(pool); if (properties) { for (hi = apr_hash_first(pool, properties); hi; hi = apr_hash_next(hi)) { const void *pname; void *pval; apr_hash_this(hi, &pname, NULL, &pval); SVN_ERR(editor->change_file_prop(file_baton, pname, pval, pool)); } } if (ctx->notify_func2) { svn_wc_notify_t *notify = svn_wc_create_notify(path, svn_wc_notify_commit_added, pool); notify->kind = svn_node_file; notify->mime_type = mimetype; notify->content_state = notify->prop_state = svn_wc_notify_state_inapplicable; notify->lock_state = svn_wc_notify_lock_state_inapplicable; (*ctx->notify_func2)(ctx->notify_baton2, notify, pool); } /* If this is a special file, we need to set the svn:special property and create a temporary detranslated version in order to send to the server. */ if (is_special) { apr_hash_set(properties, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING, svn_string_create(SVN_PROP_SPECIAL_VALUE, pool)); SVN_ERR(editor->change_file_prop(file_baton, SVN_PROP_SPECIAL, apr_hash_get(properties, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING), pool)); } /* Now, transmit the file contents. */ SVN_ERR(send_file_contents(path, file_baton, editor, properties, digest, pool)); /* Finally, close the file. */ text_checksum = svn_md5_digest_to_cstring(digest, pool); SVN_ERR(editor->close_file(file_baton, text_checksum, pool)); return SVN_NO_ERROR;} /* Import directory PATH into the repository directory indicated by * DIR_BATON in EDITOR. EDIT_PATH is the path imported as the root * directory, so all edits are relative to that. * * Accumulate file paths and their batons in FILES, which must be * non-null. (These are used to send postfix textdeltas later). * * 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 * directory. * * Use POOL for any temporary allocation. */static svn_error_t *import_dir(const svn_delta_editor_t *editor, void *dir_baton, const char *path, const char *edit_path, svn_boolean_t nonrecursive, apr_hash_t *excludes, svn_boolean_t no_ignore, import_ctx_t *import_ctx, svn_client_ctx_t *ctx, apr_pool_t *pool){ apr_pool_t *subpool = svn_pool_create(pool); /* iteration pool */ apr_hash_t *dirents; apr_hash_index_t *hi; apr_array_header_t *ignores; SVN_ERR(svn_path_check_valid(path, pool)); if (!no_ignore) SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool)); SVN_ERR(svn_io_get_dirents2(&dirents, path, pool)); for (hi = apr_hash_first(pool, dirents); hi; hi = apr_hash_next(hi)) { const char *this_path, *this_edit_path, *abs_path; const svn_io_dirent_t *dirent; const char *filename; const void *key; void *val; svn_pool_clear(subpool); apr_hash_this(hi, &key, NULL, &val); filename = key; dirent = val; if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); if (svn_wc_is_adm_dir(filename, subpool)) { /* If someone's trying to import a directory named the same as our administrative directories, that's probably not what they wanted to do. If they are importing a file with that name, something is bound to blow up when they checkout what they've imported. So, just skip items with that name. */ if (ctx->notify_func2) { svn_wc_notify_t *notify = svn_wc_create_notify(svn_path_join(path, filename, subpool), svn_wc_notify_skip, subpool); notify->kind = svn_node_dir; notify->content_state = notify->prop_state = svn_wc_notify_state_inapplicable; notify->lock_state = svn_wc_notify_lock_state_inapplicable; (*ctx->notify_func2)(ctx->notify_baton2, notify, subpool); } continue; } /* Typically, we started importing from ".", in which case edit_path is "". So below, this_path might become "./blah", and this_edit_path might become "blah", for example. */ this_path = svn_path_join(path, filename, subpool); this_edit_path = svn_path_join(edit_path, filename, subpool); /* If this is an excluded path, exclude it. */ SVN_ERR(svn_path_get_absolute(&abs_path, this_path, subpool)); if (apr_hash_get(excludes, abs_path, APR_HASH_KEY_STRING)) continue; if ((!no_ignore) && svn_cstring_match_glob_list(filename, ignores)) continue; /* We only import subdirectories when we're doing a regular recursive import. */ if ((dirent->kind == svn_node_dir) && (! nonrecursive)) { void *this_dir_baton; /* Add the new subdirectory, getting a descent baton from the editor. */ SVN_ERR(editor->add_directory(this_edit_path, dir_baton, NULL, SVN_INVALID_REVNUM, subpool, &this_dir_baton)); /* Remember that the repository was modified */ import_ctx->repos_changed = TRUE; /* By notifying before the recursive call below, we display a directory add before displaying adds underneath the directory. To do it the other way around, just move this after the recursive call. */ if (ctx->notify_func2) { svn_wc_notify_t *notify = svn_wc_create_notify(this_path, svn_wc_notify_commit_added, subpool); notify->kind = svn_node_dir; notify->content_state = notify->prop_state = svn_wc_notify_state_inapplicable; notify->lock_state = svn_wc_notify_lock_state_inapplicable; (*ctx->notify_func2)(ctx->notify_baton2, notify, subpool); } /* Recurse. */ SVN_ERR(import_dir(editor, this_dir_baton, this_path, this_edit_path, FALSE, excludes, no_ignore, import_ctx, ctx, subpool)); /* Finally, close the sub-directory. */ SVN_ERR(editor->close_directory(this_dir_baton, subpool)); } else if (dirent->kind == svn_node_file) { /* Import a file. */ SVN_ERR(import_file(editor, dir_baton, this_path, this_edit_path, import_ctx, ctx, subpool)); } /* We're silently ignoring things that aren't files or directories. If we stop doing that, here is the place to change your world. */ } svn_pool_destroy(subpool); return SVN_NO_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -