📄 util.c
字号:
/* * util.c: Subversion command line client utility functions. Any * functions that need to be shared across subcommands should be put * in here. * * ==================================================================== * 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 <ctype.h>#include <assert.h>#include <apr_errno.h>#include <apr_strings.h>#include <apr_tables.h>#include <apr_general.h>#include <apr_lib.h>#include "svn_client.h"#include "svn_cmdline.h"#include "svn_string.h"#include "svn_path.h"#include "svn_error.h"#include "svn_io.h"#include "svn_utf.h"#include "svn_subst.h"#include "svn_config.h"#include "svn_xml.h"#include "svn_private_config.h"#include "cl.h"svn_error_t *svn_cl__print_commit_info(svn_commit_info_t *commit_info, apr_pool_t *pool){ if (commit_info) { if (SVN_IS_VALID_REVNUM(commit_info->revision)) SVN_ERR(svn_cmdline_printf(pool, _("\nCommitted revision %ld.\n"), commit_info->revision)); /* Writing to stdout, as there maybe systems that consider the * presence of stderr as an indication of commit failure. * OTOH, this is only of informational nature to the user as * the commit has succeeded. */ if (commit_info->post_commit_err) SVN_ERR(svn_cmdline_printf(pool, _("\nWarning: %s\n"), commit_info->post_commit_err)); } return SVN_NO_ERROR;}svn_error_t *svn_cl__edit_externally(svn_string_t **edited_contents /* UTF-8! */, const char **tmpfile_left /* UTF-8! */, const char *editor_cmd, const char *base_dir /* UTF-8! */, const svn_string_t *contents /* UTF-8! */, const char *prefix, apr_hash_t *config, svn_boolean_t as_text, const char *encoding, apr_pool_t *pool){ const char *editor; const char *cmd; apr_file_t *tmp_file; const char *tmpfile_name; const char *tmpfile_native; const char *tmpfile_apr, *base_dir_apr; svn_string_t *translated_contents; apr_status_t apr_err, apr_err2; apr_size_t written; apr_finfo_t finfo_before, finfo_after; svn_error_t *err = SVN_NO_ERROR, *err2; char *old_cwd; int sys_err; svn_boolean_t remove_file = TRUE; struct svn_config_t *cfg; /* Use the editor specified on the command line via --editor-cmd, if any. */ editor = editor_cmd; /* Otherwise look for the Subversion-specific environment variable. */ if (! editor) editor = getenv("SVN_EDITOR"); /* If not found then fall back on the config file. */ if (! editor) { cfg = config ? apr_hash_get(config, SVN_CONFIG_CATEGORY_CONFIG, APR_HASH_KEY_STRING) : NULL; svn_config_get(cfg, &editor, SVN_CONFIG_SECTION_HELPERS, SVN_CONFIG_OPTION_EDITOR_CMD, NULL); } /* If not found yet then try general purpose environment variables. */ if (! editor) editor = getenv("VISUAL"); if (! editor) editor = getenv("EDITOR");#ifdef SVN_CLIENT_EDITOR /* If still not found then fall back on the hard-coded default. */ if (! editor) editor = SVN_CLIENT_EDITOR;#endif /* Abort if there is no editor specified */ if (! editor) return svn_error_create (SVN_ERR_CL_NO_EXTERNAL_EDITOR, NULL, _("None of the environment variables SVN_EDITOR, VISUAL or EDITOR is " "set, and no 'editor-cmd' run-time configuration option was found")); /* Convert file contents from UTF-8/LF if desired. */ if (as_text) { const char *translated; SVN_ERR(svn_subst_translate_cstring2(contents->data, &translated, APR_EOL_STR, FALSE, NULL, FALSE, pool)); translated_contents = svn_string_create("", pool); if (encoding) SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated_contents->data, translated, encoding, pool)); else SVN_ERR(svn_utf_cstring_from_utf8(&translated_contents->data, translated, pool)); translated_contents->len = strlen(translated_contents->data); } else translated_contents = svn_string_dup(contents, pool); /* Move to BASE_DIR to avoid getting characters that need quoting into tmpfile_name */ apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool); if (apr_err) return svn_error_wrap_apr(apr_err, _("Can't get working directory")); /* APR doesn't like "" directories */ if (base_dir[0] == '\0') base_dir_apr = "."; else SVN_ERR(svn_path_cstring_from_utf8(&base_dir_apr, base_dir, pool)); apr_err = apr_filepath_set(base_dir_apr, pool); if (apr_err) { return svn_error_wrap_apr (apr_err, _("Can't change working directory to '%s'"), base_dir); } /*** From here on, any problems that occur require us to cd back!! ***/ /* Ask the working copy for a temporary file that starts with PREFIX. */ err = svn_io_open_unique_file2(&tmp_file, &tmpfile_name, prefix, ".tmp", svn_io_file_del_none, pool); if (err && APR_STATUS_IS_EACCES(err->apr_err)) { const char *temp_dir_apr; svn_error_clear(err); SVN_ERR(svn_io_temp_dir(&base_dir, pool)); SVN_ERR(svn_path_cstring_from_utf8(&temp_dir_apr, base_dir, pool)); apr_err = apr_filepath_set(temp_dir_apr, pool); if (apr_err) { return svn_error_wrap_apr (apr_err, _("Can't change working directory to '%s'"), base_dir); } err = svn_io_open_unique_file2(&tmp_file, &tmpfile_name, prefix, ".tmp", svn_io_file_del_none, pool); } if (err) goto cleanup2; /*** From here on, any problems that occur require us to cleanup the file we just created!! ***/ /* Dump initial CONTENTS to TMP_FILE. */ apr_err = apr_file_write_full(tmp_file, translated_contents->data, translated_contents->len, &written); apr_err2 = apr_file_close(tmp_file); if (! apr_err) apr_err = apr_err2; /* Make sure the whole CONTENTS were written, else return an error. */ if (apr_err) { err = svn_error_wrap_apr(apr_err, _("Can't write to '%s'"), tmpfile_name); goto cleanup; } err = svn_path_cstring_from_utf8(&tmpfile_apr, tmpfile_name, pool); if (err) goto cleanup; /* Get information about the temporary file before the user has been allowed to edit its contents. */ apr_err = apr_stat(&finfo_before, tmpfile_apr, APR_FINFO_MTIME | APR_FINFO_SIZE, pool); if (apr_err) { err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name); goto cleanup; } /* Now, run the editor command line. */ err = svn_utf_cstring_from_utf8(&tmpfile_native, tmpfile_name, pool); if (err) goto cleanup; cmd = apr_psprintf(pool, "%s %s", editor, tmpfile_native); sys_err = system(cmd); if (sys_err != 0) { /* Extracting any meaning from sys_err is platform specific, so just use the raw value. */ err = svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, _("system('%s') returned %d"), cmd, sys_err); goto cleanup; } /* Get information about the temporary file after the assumed editing. */ apr_err = apr_stat(&finfo_after, tmpfile_apr, APR_FINFO_MTIME | APR_FINFO_SIZE, pool); if (apr_err) { err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name); goto cleanup; } /* If the caller wants us to leave the file around, return the path of the file we used, and make a note not to destroy it. */ if (tmpfile_left) { *tmpfile_left = svn_path_join(base_dir, tmpfile_name, pool); remove_file = FALSE; } /* If the file looks changed... */ if ((finfo_before.mtime != finfo_after.mtime) || (finfo_before.size != finfo_after.size)) { svn_stringbuf_t *edited_contents_s; err = svn_stringbuf_from_file(&edited_contents_s, tmpfile_name, pool); if (err) goto cleanup; *edited_contents = svn_string_create_from_buf(edited_contents_s, pool); /* Translate back to UTF8/LF if desired. */ if (as_text) { err = svn_subst_translate_string(edited_contents, *edited_contents, encoding, pool); if (err) goto cleanup; } } else { /* No edits seem to have been made */ *edited_contents = NULL; } cleanup: if (remove_file) { /* Remove the file from disk. */ err2 = svn_io_remove_file(tmpfile_name, pool); /* Only report remove error if there was no previous error. */ if (! err && err2) err = err2; else svn_error_clear(err2); } cleanup2: /* If we against all probability can't cd back, all further relative file references would be screwed up, so we have to abort. */ apr_err = apr_filepath_set(old_cwd, pool); if (apr_err) { svn_handle_error2(svn_error_wrap_apr (apr_err, _("Can't restore working directory")), stderr, TRUE /* fatal */, "svn: "); } return err;}struct log_msg_baton{ const char *editor_cmd; /* editor specified via --editor-cmd, else NULL */ const char *message; /* the message. */ const char *message_encoding; /* the locale/encoding of the message. */ const char *base_dir; /* the base directory for an external edit. UTF-8! */ const char *tmpfile_left; /* the tmpfile left by an external edit. UTF-8! */ svn_boolean_t non_interactive; /* if true, don't pop up an editor */ apr_hash_t *config; /* client configuration hash */ svn_boolean_t keep_locks; /* Keep repository locks? */ apr_pool_t *pool; /* a pool. */};svn_error_t *svn_cl__make_log_msg_baton(void **baton, svn_cl__opt_state_t *opt_state, const char *base_dir /* UTF-8! */, apr_hash_t *config, apr_pool_t *pool){ struct log_msg_baton *lmb = apr_palloc(pool, sizeof(*lmb)); if (opt_state->filedata) { if (strlen(opt_state->filedata->data) < opt_state->filedata->len) { /* The data contains a zero byte, and therefore can't be represented as a C string. Punt now; it's probably not a deliberate encoding, and even if it is, we still can't handle it. */ return svn_error_create(SVN_ERR_CL_BAD_LOG_MESSAGE, NULL, _("Log message contains a zero byte")); } lmb->message = opt_state->filedata->data; } else { lmb->message = opt_state->message; } lmb->editor_cmd = opt_state->editor_cmd; if (opt_state->encoding) { lmb->message_encoding = opt_state->encoding; } else if (config) { svn_config_t *cfg = apr_hash_get(config, SVN_CONFIG_CATEGORY_CONFIG, APR_HASH_KEY_STRING); svn_config_get(cfg, &(lmb->message_encoding), SVN_CONFIG_SECTION_MISCELLANY, SVN_CONFIG_OPTION_LOG_ENCODING, NULL); } lmb->base_dir = base_dir ? base_dir : ""; lmb->tmpfile_left = NULL; lmb->config = config; lmb->keep_locks = opt_state->no_unlock; lmb->non_interactive = opt_state->non_interactive; lmb->pool = pool; *baton = lmb; return SVN_NO_ERROR;}svn_error_t *svn_cl__cleanup_log_msg(void *log_msg_baton, svn_error_t *commit_err)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -