📄 main.c
字号:
- Then, dump the contents of the old version of the file into
the top level of the svnlook temporary directory using a
unique temporary file name (we do this *after* putting the
new version of the file there in case something actually
versioned has a name that looks like one of our unique
identifiers).
- Next, we run 'diff', passing the repository path as the
label.
- Finally, we delete the temporary files (but leave the
built-out directories in place until after all diff
handling has been finished). */
if ((node->action == 'R') && (node->text_mod))
{
do_diff = TRUE;
SVN_ERR (prepare_tmpfiles (&orig_path, &new_path, &binary,
base_root, base_path, root, path,
tmpdir, pool));
}
if ((node->action == 'A') && (node->text_mod))
{
do_diff = TRUE;
SVN_ERR (prepare_tmpfiles (&orig_path, &new_path, &binary,
NULL, base_path, root, path,
tmpdir, pool));
}
if (node->action == 'D')
{
do_diff = TRUE;
SVN_ERR (prepare_tmpfiles (&orig_path, &new_path, &binary,
base_root, base_path, NULL, path,
tmpdir, pool));
}
}
if (do_diff)
{
if (! is_copy)
SVN_ERR (svn_cmdline_printf (pool, "%s: %s\n",
((node->action == 'A') ? _("Added") :
((node->action == 'D') ? _("Deleted") :
((node->action == 'R') ? _("Modified")
: _("Index")))),
path));
if ((! no_diff_deleted) || (node->action != 'D'))
{
svn_diff_t *diff;
SVN_ERR (svn_cmdline_printf (pool, "%s\n", equal_string));
SVN_ERR (svn_cmdline_fflush (stdout));
if (binary)
{
SVN_ERR (svn_cmdline_printf (pool,
_("(Binary files differ)\n")));
}
else
{
SVN_ERR (svn_diff_file_diff (&diff, orig_path, new_path, pool));
if (svn_diff_contains_diffs (diff))
{
svn_stream_t *ostream;
const char *orig_label, *new_label;
SVN_ERR (svn_stream_for_stdout (&ostream, pool));
SVN_ERR (generate_label (&orig_label, base_root,
base_path, pool));
SVN_ERR (generate_label (&new_label, root, path, pool));
SVN_ERR (svn_diff_file_output_unified (ostream, diff,
orig_path, new_path,
orig_label, new_label,
pool));
SVN_ERR (svn_stream_close (ostream));
}
}
}
SVN_ERR (svn_cmdline_printf (pool, "\n"));
SVN_ERR (svn_cmdline_fflush (stdout));
}
else if (is_copy)
{
SVN_ERR (svn_cmdline_printf (pool, "\n"));
}
/* Make sure we delete any temporary files. */
if (orig_path)
SVN_ERR (svn_io_remove_file (orig_path, pool));
if (new_path)
SVN_ERR (svn_io_remove_file (new_path, pool));
/*** Now handle property diffs ***/
if ((node->prop_mod) && (node->action != 'D'))
{
apr_hash_t *local_proptable;
apr_hash_t *base_proptable;
apr_array_header_t *propchanges, *props;
SVN_ERR (svn_fs_node_proplist (&local_proptable, root, path, pool));
if (node->action == 'A')
base_proptable = apr_hash_make (pool);
else
SVN_ERR (svn_fs_node_proplist (&base_proptable, base_root,
base_path, pool));
SVN_ERR (svn_prop_diffs (&propchanges, local_proptable,
base_proptable, pool));
SVN_ERR (svn_categorize_props (propchanges, NULL, NULL, &props, pool));
if (props->nelts > 0)
SVN_ERR (display_prop_diffs (props, base_proptable, path, pool));
}
/* Return here if the node has no children. */
node = node->child;
if (! node)
return SVN_NO_ERROR;
/* Recursively handle the node's children. */
subpool = svn_pool_create (pool);
SVN_ERR (print_diff_tree (root, base_root, node,
svn_path_join (path, node->name, subpool),
svn_path_join (base_path, node->name, subpool),
no_diff_deleted,
tmpdir,
subpool));
while (node->sibling)
{
svn_pool_clear (subpool);
node = node->sibling;
SVN_ERR (print_diff_tree (root, base_root, node,
svn_path_join (path, node->name, subpool),
svn_path_join (base_path, node->name, subpool),
no_diff_deleted,
tmpdir,
subpool));
}
apr_pool_destroy (subpool);
return SVN_NO_ERROR;
}
/* Recursively print all nodes, and (optionally) their node revision ids.
ROOT is the revision or transaction root used to build that tree.
PATH and ID are the current path and node revision id being
printed, and INDENTATION the number of spaces to prepent to that
path's printed output. ID may be NULL if SHOW_IDS is FALSE (in
which case, ids won't be printed at all).
Use POOL for all allocations. */
static svn_error_t *
print_tree (svn_fs_root_t *root,
const char *path /* UTF-8! */,
const svn_fs_id_t *id,
svn_boolean_t is_dir,
int indentation,
svn_boolean_t show_ids,
apr_pool_t *pool)
{
apr_pool_t *subpool;
int i;
const char *name_native;
apr_hash_t *entries;
apr_hash_index_t *hi;
SVN_ERR (check_cancel (NULL));
/* Print the indentation. */
for (i = 0; i < indentation; i++)
{
SVN_ERR (svn_cmdline_fputs (" ", stdout, pool));
}
/* Print the node. */
SVN_ERR (svn_utf_cstring_from_utf8 (&name_native,
svn_path_basename (path, pool),
pool));
SVN_ERR (svn_cmdline_printf (pool, "%s%s",
svn_path_basename (path, pool),
is_dir ? "/" : ""));
if (show_ids)
{
svn_string_t *unparsed_id = NULL;
if (id)
unparsed_id = svn_fs_unparse_id (id, pool);
SVN_ERR (svn_cmdline_printf (pool, " <%s>",
unparsed_id
? unparsed_id->data
: _("unknown")));
}
SVN_ERR (svn_cmdline_fputs ("\n", stdout, pool));
/* Return here if PATH is not a directory. */
if (! is_dir)
return SVN_NO_ERROR;
/* Recursively handle the node's children. */
SVN_ERR (svn_fs_dir_entries (&entries, root, path, pool));
subpool = svn_pool_create (pool);
for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
{
const void *key;
apr_ssize_t keylen;
void *val;
svn_fs_dirent_t *entry;
apr_hash_this (hi, &key, &keylen, &val);
entry = val;
SVN_ERR (print_tree (root, svn_path_join (path, entry->name, pool),
entry->id, (entry->kind == svn_node_dir),
indentation + 1, show_ids, subpool));
svn_pool_clear (subpool);
}
svn_pool_destroy (subpool);
return SVN_NO_ERROR;
}
/*** Subcommand handlers. ***/
/* Print the revision's log message to stdout, followed by a newline. */
static svn_error_t *
do_log (svnlook_ctxt_t *c, svn_boolean_t print_size, apr_pool_t *pool)
{
svn_string_t *prop_value;
svn_string_t *prop_value_native;
SVN_ERR (get_property (&prop_value, c, SVN_PROP_REVISION_LOG, pool));
if (! (prop_value && prop_value->data))
{
SVN_ERR (svn_cmdline_printf (pool, "%s\n", print_size ? "0" : ""));
return SVN_NO_ERROR;
}
if (print_size)
{
/* svn_cmdline_printf will convert to the native locale and eol-style
for us, but we need the size of the converted message. */
SVN_ERR (svn_subst_detranslate_string (&prop_value_native, prop_value,
TRUE, pool));
SVN_ERR (svn_cmdline_printf (pool, "%" APR_SIZE_T_FMT "\n",
prop_value_native->len));
}
SVN_ERR (svn_cmdline_printf (pool, "%s\n", prop_value->data));
return SVN_NO_ERROR;
}
/* Print the timestamp of the commit (in the revision case) or the
empty string (in the transaction case) to stdout, followed by a
newline. */
static svn_error_t *
do_date (svnlook_ctxt_t *c, apr_pool_t *pool)
{
svn_string_t *prop_value;
SVN_ERR (get_property (&prop_value, c, SVN_PROP_REVISION_DATE, pool));
if (prop_value && prop_value->data)
{
/* Convert the date for humans. */
apr_time_t aprtime;
const char *time_utf8;
SVN_ERR (svn_time_from_cstring (&aprtime, prop_value->data, pool));
time_utf8 = svn_time_to_human_cstring (aprtime, pool);
SVN_ERR (svn_cmdline_printf (pool, "%s", time_utf8));
}
SVN_ERR (svn_cmdline_printf (pool, "\n"));
return SVN_NO_ERROR;
}
/* Print the author of the commit to stdout, followed by a newline. */
static svn_error_t *
do_author (svnlook_ctxt_t *c, apr_pool_t *pool)
{
svn_string_t *prop_value;
SVN_ERR (get_property (&prop_value, c,
SVN_PROP_REVISION_AUTHOR, pool));
if (prop_value && prop_value->data)
SVN_ERR (svn_cmdline_printf (pool, "%s", prop_value->data));
SVN_ERR (svn_cmdline_printf (pool, "\n"));
return SVN_NO_ERROR;
}
/* Print a list of all directories in which files, or directory
properties, have been modified. */
static svn_error_t *
do_dirs_changed (svnlook_ctxt_t *c, apr_pool_t *pool)
{
svn_fs_root_t *root;
svn_revnum_t base_rev_id;
svn_repos_node_t *tree;
SVN_ERR (get_root (&root, c, pool));
if (c->is_revision)
base_rev_id = c->rev_id - 1;
else
base_rev_id = svn_fs_txn_base_revision (c->txn);
if (! SVN_IS_VALID_REVNUM (base_rev_id))
return svn_error_createf
(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
_("Transaction '%s' is not based on a revision; how odd"),
c->txn_name);
SVN_ERR (generate_delta_tree (&tree, c->repos, root, base_rev_id,
TRUE, pool));
if (tree)
SVN_ERR (print_dirs_changed_tree (tree, "", pool));
return SVN_NO_ERROR;
}
/* Set *KIND to PATH's kind, if PATH exists.
*
* If PATH does not exist, then error; the text of the error depends
* on whether PATH looks like a URL or not.
*/
static svn_error_t *
verify_path (svn_node_kind_t *kind,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool)
{
SVN_ERR (svn_fs_check_path (kind, root, path, pool));
if (*kind == svn_node_none)
{
if (svn_path_is_url (path)) /* check for a common mistake. */
return svn_error_createf
(SVN_ERR_FS_NOT_FOUND, NULL,
_("'%s' is a URL, probably should be a path"), path);
else
return svn_error_createf
(SVN_ERR_FS_NOT_FOUND, NULL, _("Path '%s' does not exist"), path);
}
return SVN_NO_ERROR;
}
/* Print the contents of the file at PATH in the repository.
Error with SVN_ERR_FS_NOT_FOUND if PATH does not exist, or with
SVN_ERR_FS_NOT_FILE if PATH exists but is not a file. */
static svn_error_t *
do_cat (svnlook_ctxt_t *c, const char *path, apr_pool_t *pool)
{
svn_fs_root_t *root;
svn_node_kind_t kind;
svn_stream_t *fstream, *stdout_stream;
char buf[BUFSIZ];
apr_size_t len = BUFSIZ;
SVN_ERR (get_root (&root, c, pool));
SVN_ERR (verify_path (&kind, root, path, pool));
if (kind != svn_node_file)
return svn_error_createf
(SVN_ERR_FS_NOT_FILE, NULL, _("Path '%s' is not a file"), path);
/* Else. */
SVN_ERR (svn_fs_file_contents (&fstream, root, path, pool));
SVN_ERR (svn_stream_for_stdout (&stdout_stream, pool));
do
{
SVN_ERR (check_cancel (NULL));
SVN_ERR (svn_stream_read (fstream, buf, &len));
SVN_ERR (svn_stream_write (stdout_stream, buf, &len));
}
while (len == BUFSIZ);
return SVN_NO_ERROR;
}
/* Print a list of all paths modified in a format compatible with `svn
update'. */
static svn_error_t *
do_changed (svnlook_ctxt_t *c, apr_pool_t *pool)
{
svn_fs_root_t *root;
svn_revnum_t base_rev_id;
svn_repos_node_t *tree;
SVN_ERR (get_root (&root, c, pool));
if (c->is_revision)
base_rev_id = c->rev_id - 1;
else
base_rev_id = svn_fs_txn_base_revision (c->txn);
if (! SVN_IS_VALID_REVNUM (base_rev_id))
return svn_error_createf
(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
_("Transaction '%s' is not based on a revision; how odd"),
c->txn_name);
SVN_ERR (generate_delta_tree (&tree, c->repos, root, base_rev_id,
TRUE, pool));
if (tree)
SVN_ERR (print_changed_tree (tree, "", pool));
return SVN_NO_ERROR;
}
/* Create a new temporary directory with an 'svnlook' prefix. */
static svn_error_t *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -