commit.c
来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 1,448 行 · 第 1/4 页
C
1,448 行
/*
* commit.c: wrappers around wc commit functionality.
*
* ====================================================================
* Copyright (c) 2000-2004 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_test.h"
#include "svn_io.h"
#include "svn_md5.h"
#include "svn_time.h"
#include "svn_sorts.h"
#include "client.h"
#include "svn_private_config.h"
/* 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 = NULL;
svn_error_t *err = SVN_NO_ERROR;
const svn_string_t *eol_style_val = NULL, *keywords_val = NULL;
svn_boolean_t special = FALSE;
/* 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 we have EOL styles or keywords to de-translate, do it. Any
EOL style gets translated to "\n", the repository-normal format.
Keywords get unexpanded. */
if (eol_style_val || keywords_val || special)
{
svn_subst_keywords_t keywords = {0};
const char *temp_dir;
apr_file_t *tmp_f;
/* 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_file
(&tmp_f, &tmpfile_path,
svn_path_join (temp_dir, "svn-import", pool),
".tmp", FALSE, pool));
SVN_ERR (svn_io_file_close (tmp_f, pool));
/* Generate a keyword structure. */
if (keywords_val)
SVN_ERR (svn_subst_build_keywords (&keywords, keywords_val->data,
APR_STRINGIFY(SVN_INVALID_REVNUM),
"", 0, "", pool));
if ((err = svn_subst_copy_and_translate2 (path, tmpfile_path,
eol_style_val ? "\n" : NULL,
FALSE,
keywords_val ? &keywords : NULL,
FALSE,
special,
pool)))
goto cleanup;
}
/* Open our contents file, either the original path or the temporary
copy we might have made above. */
if ((err = svn_io_file_open (&f, tmpfile_path ? tmpfile_path : path,
APR_READ, APR_OS_DEFAULT, pool)))
goto cleanup;
contents = svn_stream_from_aprfile (f, pool);
/* Send the file's contents to the delta-window handler. */
if ((err = svn_txdelta_send_stream (contents, handler, handler_baton,
digest, pool)))
goto cleanup;
/* Close our contents file. */
if ((err = svn_io_file_close (f, pool)))
goto cleanup;
cleanup:
if (tmpfile_path)
{
/* If we used a tempfile, we need to close and remove it, too. */
svn_error_t *err2 = svn_io_remove_file (tmpfile_path, pool);
if (err && err2)
svn_error_compose (err, err2);
else if (err2)
err = err2;
}
return err;
}
/* 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,
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;
/* 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));
SVN_ERR (svn_io_check_special_path (path, &kind, &is_special, pool));
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_func)
(*ctx->notify_func) (ctx->notify_baton,
path,
svn_wc_notify_commit_added,
svn_node_file,
mimetype,
svn_wc_notify_state_inapplicable,
svn_wc_notify_state_inapplicable,
SVN_INVALID_REVNUM);
/* 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).
*
* If CTX->NOTIFY_FUNC is non-null, invoke it with CTX->NOTIFY_BATON for each
* directory.
*
* EXCLUDES is a hash whose keys are absolute paths to exclude from
* the import (values are unused).
*
* 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_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_wc_get_default_ignores (&ignores, ctx->config, pool));
SVN_ERR (svn_io_get_dirents (&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_node_kind_t *filetype;
const char *filename;
const void *key;
void *val;
svn_pool_clear (subpool);
apr_hash_this (hi, &key, NULL, &val);
filename = key;
filetype = val;
if (ctx->cancel_func)
SVN_ERR (ctx->cancel_func (ctx->cancel_baton));
if (strcmp (filename, SVN_WC_ADM_DIR_NAME) == 0)
{
/* 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_func)
(*ctx->notify_func) (ctx->notify_baton,
svn_path_join (path, filename, subpool),
svn_wc_notify_skip,
svn_node_dir,
NULL,
svn_wc_notify_state_inapplicable,
svn_wc_notify_state_inapplicable,
SVN_INVALID_REVNUM);
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 (svn_cstring_match_glob_list (filename, ignores))
continue;
/* We only import subdirectories when we're doing a regular
recursive import. */
if ((*filetype == 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));
/* 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_func)
(*ctx->notify_func) (ctx->notify_baton,
this_path,
svn_wc_notify_commit_added,
svn_node_dir,
NULL,
svn_wc_notify_state_inapplicable,
svn_wc_notify_state_inapplicable,
SVN_INVALID_REVNUM);
/* Recurse. */
SVN_ERR (import_dir (editor, this_dir_baton,
this_path, this_edit_path,
FALSE, excludes, ctx, subpool));
/* Finally, close the sub-directory. */
SVN_ERR (editor->close_directory (this_dir_baton, subpool));
}
else if (*filetype == svn_node_file)
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?