📄 main.c
字号:
/* Return here if the node has no children. */
tmp_node = node->child;
if (! tmp_node)
return SVN_NO_ERROR;
/* Recursively handle the node's children. */
subpool = svn_pool_create (pool);
full_path = svn_path_join (path, tmp_node->name, subpool);
SVN_ERR (print_dirs_changed_tree (tmp_node, full_path, subpool));
while (tmp_node->sibling)
{
svn_pool_clear (subpool);
tmp_node = tmp_node->sibling;
full_path = svn_path_join (path, tmp_node->name, subpool);
SVN_ERR (print_dirs_changed_tree (tmp_node, full_path, subpool));
}
svn_pool_destroy (subpool);
return SVN_NO_ERROR;
}
/* Recursively print all nodes in the tree that have been modified
(do not include directories affected only by "bubble-up"). */
static svn_error_t *
print_changed_tree (svn_repos_node_t *node,
const char *path /* UTF-8! */,
apr_pool_t *pool)
{
const char *full_path;
char status[3] = "_ ";
int print_me = 1;
apr_pool_t *subpool;
SVN_ERR (check_cancel (NULL));
if (! node)
return SVN_NO_ERROR;
/* Print the node. */
if (node->action == 'A')
status[0] = 'A';
else if (node->action == 'D')
status[0] = 'D';
else if (node->action == 'R')
{
if ((! node->text_mod) && (! node->prop_mod))
print_me = 0;
if (node->text_mod)
status[0] = 'U';
if (node->prop_mod)
status[1] = 'U';
}
else
print_me = 0;
/* Print this node unless told to skip it. */
if (print_me)
{
SVN_ERR (svn_cmdline_printf (pool, "%s %s%s\n",
status,
path,
node->kind == svn_node_dir ? "/" : ""));
}
/* 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);
full_path = svn_path_join (path, node->name, subpool);
SVN_ERR (print_changed_tree (node, full_path, subpool));
while (node->sibling)
{
svn_pool_clear (subpool);
node = node->sibling;
full_path = svn_path_join (path, node->name, subpool);
SVN_ERR (print_changed_tree (node, full_path, subpool));
}
svn_pool_destroy (subpool);
return SVN_NO_ERROR;
}
static svn_error_t *
open_writable_binary_file (apr_file_t **fh,
const char *path /* UTF-8! */,
apr_pool_t *pool)
{
apr_array_header_t *path_pieces;
svn_error_t *err;
int i;
const char *full_path, *dir;
/* Try the easy way to open the file. */
err = svn_io_file_open (fh, path,
APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY,
APR_OS_DEFAULT, pool);
if (! err)
return SVN_NO_ERROR;
svn_path_split (path, &dir, NULL, pool);
/* If the file path has no parent, then we've already tried to open
it as best as we care to try above. */
if (svn_path_is_empty (dir))
return err;
path_pieces = svn_path_decompose (dir, pool);
if (! path_pieces->nelts)
return SVN_NO_ERROR;
full_path = "";
for (i = 0; i < path_pieces->nelts; i++)
{
svn_node_kind_t kind;
const char *piece = ((const char **) (path_pieces->elts))[i];
full_path = svn_path_join (full_path, piece, pool);
SVN_ERR (svn_io_check_resolved_path (full_path, &kind, pool));
/* Does this path component exist at all? */
if (kind == svn_node_none)
{
SVN_ERR (svn_io_dir_make (full_path, APR_OS_DEFAULT, pool));
}
else if (kind != svn_node_dir)
{
return svn_error_createf (err->apr_err, err,
"Error creating dir '%s' (path exists)",
full_path);
}
}
/* Now that we are ensured that the parent path for this file
exists, try once more to open it. */
svn_error_clear (err);
return svn_io_file_open (fh, path,
APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY,
APR_OS_DEFAULT, pool);
}
static svn_error_t *
dump_contents (apr_file_t *fh,
svn_fs_root_t *root,
const char *path /* UTF-8! */,
apr_pool_t *pool)
{
svn_stream_t *contents, *file_stream;
/* Grab the contents and copy them into fh. */
SVN_ERR (svn_fs_file_contents (&contents, root, path, pool));
file_stream = svn_stream_from_aprfile (fh, pool);
SVN_ERR (svn_stream_copy (contents, file_stream, pool));
return SVN_NO_ERROR;
}
/* Prepare temporary files *TMPFILE1 and *TMPFILE2 for diffing
PATH1@ROOT1 versus PATH2@ROOT2. If either ROOT1 or ROOT2 is NULL,
the temporary file for its path/root will be an empty one.
Otherwise, its temporary file will contain the contents of that
path/root in the repository.
An exception to this is when either path/root has an svn:mime-type
property set on it which indicates that the file contains
non-textual data -- in this case, the *IS_BINARY flag is set and no
temporary files are created.
Use POOL for all that allocation goodness. */
static svn_error_t *
prepare_tmpfiles (const char **tmpfile1,
const char **tmpfile2,
svn_boolean_t *is_binary,
svn_fs_root_t *root1,
const char *path1,
svn_fs_root_t *root2,
const char *path2,
const char *tmpdir,
apr_pool_t *pool)
{
svn_string_t *mimetype;
apr_file_t *fh;
/* Init the return values. */
*tmpfile1 = NULL;
*tmpfile2 = NULL;
*is_binary = FALSE;
assert (path1 && path2);
/* Check for binary mimetypes. If either file has a binary
mimetype, get outta here. */
if (root1)
{
SVN_ERR (svn_fs_node_prop (&mimetype, root1, path1,
SVN_PROP_MIME_TYPE, pool));
if (mimetype && svn_mime_type_is_binary (mimetype->data))
{
*is_binary = TRUE;
return SVN_NO_ERROR;
}
}
if (root2)
{
SVN_ERR (svn_fs_node_prop (&mimetype, root2, path2,
SVN_PROP_MIME_TYPE, pool));
if (mimetype && svn_mime_type_is_binary (mimetype->data))
{
*is_binary = TRUE;
return SVN_NO_ERROR;
}
}
/* Now, prepare the two temporary files, each of which will either
be empty, or will have real contents. The first file we will
make in our temporary directory. */
*tmpfile2 = svn_path_join (tmpdir, path2, pool);
SVN_ERR (open_writable_binary_file (&fh, *tmpfile2, pool));
if (root2)
SVN_ERR (dump_contents (fh, root2, path2, pool));
apr_file_close (fh);
/* The second file is constructed from the first one's path. */
SVN_ERR (svn_io_open_unique_file (&fh, tmpfile1, *tmpfile2,
NULL, FALSE, pool));
if (root1)
SVN_ERR (dump_contents (fh, root1, path1, pool));
apr_file_close (fh);
return SVN_NO_ERROR;
}
/* Generate a diff label for PATH in ROOT, allocating in POOL. */
static svn_error_t *
generate_label (const char **label,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool)
{
svn_fs_t *fs = svn_fs_root_fs (root);
svn_string_t *date;
const char *datestr;
const char *name = NULL;
svn_revnum_t rev = SVN_INVALID_REVNUM;
if (svn_fs_is_revision_root (root))
{
rev = svn_fs_revision_root_revision (root);
SVN_ERR (svn_fs_revision_prop (&date, fs, rev,
SVN_PROP_REVISION_DATE, pool));
}
else
{
svn_fs_txn_t *txn;
name = svn_fs_txn_root_name (root, pool);
SVN_ERR (svn_fs_open_txn (&txn, fs, name, pool));
SVN_ERR (svn_fs_txn_prop (&date, txn, SVN_PROP_REVISION_DATE, pool));
}
if (date)
{
datestr = date->data;
((char *)datestr)[10] = ' ';
((char *)datestr)[19] = '\0';
}
else
{
datestr = " ";
}
if (name)
*label = apr_psprintf (pool, "%s\t%s UTC (txn %s)",
path, datestr, name);
else
*label = apr_psprintf (pool, "%s\t%s UTC (rev %ld)",
path, datestr, rev);
return SVN_NO_ERROR;
}
/*
* Constant diff output separator strings
*/
static const char equal_string[] =
"===================================================================";
static const char under_string[] =
"___________________________________________________________________";
/* Helper function to display differences in properties of a file */
static svn_error_t *
display_prop_diffs (const apr_array_header_t *prop_diffs,
apr_hash_t *orig_props,
const char *path,
apr_pool_t *pool)
{
int i;
SVN_ERR (svn_cmdline_printf (pool, "\nProperty changes on: %s\n%s\n",
path, under_string));
for (i = 0; i < prop_diffs->nelts; i++)
{
const svn_string_t *orig_value;
const svn_prop_t *pc = &APR_ARRAY_IDX (prop_diffs, i, svn_prop_t);
SVN_ERR (check_cancel (NULL));
if (orig_props)
orig_value = apr_hash_get (orig_props, pc->name, APR_HASH_KEY_STRING);
else
orig_value = NULL;
SVN_ERR (svn_cmdline_printf (pool, _("Name: %s\n"), pc->name));
/* For now, we have a rather simple heuristic: if this is an
"svn:" property, then assume the value is UTF-8 and must
therefore be converted before printing. Otherwise, just
print whatever's there and hope for the best.
### We don't use svn_cmdline_printf here, since we don't know if the
values are UTF-8. */
{
svn_boolean_t val_to_utf8 = svn_prop_is_svn_prop (pc->name);
const char *printable_val;
if (orig_value != NULL)
{
if (val_to_utf8)
SVN_ERR (svn_cmdline_cstring_from_utf8 (&printable_val,
orig_value->data, pool));
else
printable_val = orig_value->data;
printf (" - %s\n", printable_val);
}
if (pc->value != NULL)
{
if (val_to_utf8)
SVN_ERR (svn_cmdline_cstring_from_utf8
(&printable_val, pc->value->data, pool));
else
printable_val = pc->value->data;
printf (" + %s\n", printable_val);
}
}
}
SVN_ERR (svn_cmdline_printf (pool, "\n"));
return svn_cmdline_fflush (stdout);
}
/* Recursively print all nodes in the tree that have been modified
(do not include directories affected only by "bubble-up"). */
static svn_error_t *
print_diff_tree (svn_fs_root_t *root,
svn_fs_root_t *base_root,
svn_repos_node_t *node,
const char *path /* UTF-8! */,
const char *base_path /* UTF-8! */,
svn_boolean_t no_diff_deleted,
const char *tmpdir,
apr_pool_t *pool)
{
const char *orig_path = NULL, *new_path = NULL;
svn_boolean_t do_diff = FALSE;
svn_boolean_t is_copy = FALSE;
svn_boolean_t binary = FALSE;
apr_pool_t *subpool;
SVN_ERR (check_cancel (NULL));
if (! node)
return SVN_NO_ERROR;
/* Print copyfrom history for the top node of a copied tree. */
if ((SVN_IS_VALID_REVNUM (node->copyfrom_rev))
&& (node->copyfrom_path != NULL))
{
/* This is ... a copy. */
is_copy = TRUE;
/* Propagate the new base. Copyfrom paths usually start with a
slash; we remove it for consistency with the target path.
### Yes, it would be *much* better for something in the path
library to be taking care of this! */
if (node->copyfrom_path[0] == '/')
base_path = apr_pstrdup (pool, node->copyfrom_path + 1);
else
base_path = apr_pstrdup (pool, node->copyfrom_path);
SVN_ERR (svn_cmdline_printf (pool, _("Copied: %s (from rev %ld, %s)\n"),
path, node->copyfrom_rev, base_path));
SVN_ERR (svn_fs_revision_root (&base_root,
svn_fs_root_fs (base_root),
node->copyfrom_rev, pool));
}
/*** First, we'll just print file content diffs. ***/
if (node->kind == svn_node_file)
{
/* Here's the generalized way we do our diffs:
- First, we'll check for svn:mime-type properties on the old
and new files. If either has such a property, and it
represents a binary type, we won't actually be doing a real
diff.
- First, dump the contents of the new version of the file
into the svnlook temporary directory, building out the
actual directories that need to be created in order to
fully represent the filesystem path inside the tmp
directory.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -