📄 main.c
字号:
create_unique_tmpdir (const char **name, apr_pool_t *pool)
{
const char *unique_name;
const char *sys_tmp_dir;
const char *base;
unsigned int i;
SVN_ERR (svn_io_temp_dir (&sys_tmp_dir, pool));
base = svn_path_join (sys_tmp_dir, "svnlook", pool);
for (i = 1; i <= 99999; i++)
{
svn_error_t *err;
unique_name = apr_psprintf (pool, "%s.%u", base, i);
err = svn_io_dir_make (unique_name, APR_OS_DEFAULT, pool);
if (!err)
{
*name = unique_name;
return SVN_NO_ERROR;
}
if (! APR_STATUS_IS_EEXIST (err->apr_err))
return err;
svn_error_clear (err);
}
*name = NULL;
return svn_error_createf (SVN_ERR_IO_UNIQUE_NAMES_EXHAUSTED,
NULL, _("Can't create temporary directory"));
}
/* Print some diff-y stuff in a TBD way. :-) */
static svn_error_t *
do_diff (svnlook_ctxt_t *c, apr_pool_t *pool)
{
svn_fs_root_t *root, *base_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)
{
const char *tmpdir;
svn_error_t *err;
SVN_ERR (svn_fs_revision_root (&base_root, c->fs, base_rev_id, pool));
SVN_ERR (create_unique_tmpdir (&tmpdir, pool));
err = print_diff_tree (root, base_root, tree, "", "",
c->no_diff_deleted, tmpdir, pool);
if (err)
{
svn_error_clear (svn_io_remove_dir (tmpdir, pool));
return err;
}
SVN_ERR (svn_io_remove_dir (tmpdir, pool));
}
return SVN_NO_ERROR;
}
/* Callback baton for print_history() (and do_history()). */
struct print_history_baton
{
svn_fs_t *fs;
svn_boolean_t show_ids;
};
/* Implements svn_repos_history_func_t interface. Print the history
that's reported through this callback, possibly finding and
displaying node-rev-ids. */
static svn_error_t *
print_history (void *baton,
const char *path,
svn_revnum_t revision,
apr_pool_t *pool)
{
struct print_history_baton *phb = baton;
SVN_ERR (check_cancel (NULL));
if (phb->show_ids)
{
const svn_fs_id_t *node_id;
svn_fs_root_t *rev_root;
svn_string_t *id_string;
SVN_ERR (svn_fs_revision_root (&rev_root, phb->fs, revision, pool));
SVN_ERR (svn_fs_node_id (&node_id, rev_root, path, pool));
id_string = svn_fs_unparse_id (node_id, pool);
SVN_ERR (svn_cmdline_printf (pool, "%8ld %s <%s>\n",
revision, path, id_string->data));
}
else
{
SVN_ERR (svn_cmdline_printf (pool, "%8ld %s\n", revision, path));
}
return SVN_NO_ERROR;
}
/* Print a tabular display of history location points for PATH in
revision C->rev_id. Optionally, SHOW_IDS. Use POOL for
allocations. */
static svn_error_t *
do_history (svnlook_ctxt_t *c,
const char *path,
svn_boolean_t show_ids,
apr_pool_t *pool)
{
struct print_history_baton args;
if (show_ids)
{
SVN_ERR (svn_cmdline_printf (pool, _("REVISION PATH <ID>\n"
"-------- ---------\n")));
}
else
{
SVN_ERR (svn_cmdline_printf (pool, _("REVISION PATH\n"
"-------- ----\n")));
}
/* Call our history crawler. We want the whole lifetime of the path
(prior to the user-supplied revision, of course), across all
copies. */
args.fs = c->fs;
args.show_ids = show_ids;
SVN_ERR (svn_repos_history (c->fs, path, print_history, &args,
0, c->rev_id, 1, pool));
return SVN_NO_ERROR;
}
/* Print the value of property PROPNAME on PATH in the repository.
Error with SVN_ERR_FS_NOT_FOUND if PATH does not exist, or with
SVN_ERR_PROPERTY_NOT_FOUND if no such property on PATH. */
static svn_error_t *
do_pget (svnlook_ctxt_t *c,
const char *propname,
const char *path,
apr_pool_t *pool)
{
svn_fs_root_t *root;
svn_string_t *prop;
svn_node_kind_t kind;
svn_stream_t *stdout_stream;
apr_size_t len;
SVN_ERR (get_root (&root, c, pool));
SVN_ERR (verify_path (&kind, root, path, pool));
SVN_ERR (svn_fs_node_prop (&prop, root, path, propname, pool));
if (prop == NULL)
return svn_error_createf
(SVN_ERR_PROPERTY_NOT_FOUND, NULL,
_("Property '%s' not found on path '%s'"), propname, path);
/* Else. */
SVN_ERR (svn_stream_for_stdout (&stdout_stream, pool));
/* Unlike the command line client, we don't translate the property
value or print a trailing newline here. We just output the raw
bytes of whatever's in the repository, as svnlook is more likely
to be used for automated inspections. */
len = prop->len;
SVN_ERR (svn_stream_write (stdout_stream, prop->data, &len));
return SVN_NO_ERROR;
}
/* Print the property names of all properties on PATH in the repository.
If VERBOSE, print their values too.
Error with SVN_ERR_FS_NOT_FOUND if PATH does not exist, or with
SVN_ERR_PROPERTY_NOT_FOUND if no such property on PATH. */
static svn_error_t *
do_plist (svnlook_ctxt_t *c,
const char *path,
svn_boolean_t verbose,
apr_pool_t *pool)
{
svn_stream_t *stdout_stream;
svn_fs_root_t *root;
apr_hash_t *props;
apr_hash_index_t *hi;
svn_node_kind_t kind;
SVN_ERR (get_root (&root, c, pool));
SVN_ERR (verify_path (&kind, root, path, pool));
SVN_ERR (svn_fs_node_proplist (&props, root, path, pool));
SVN_ERR (svn_stream_for_stdout (&stdout_stream, pool));
for (hi = apr_hash_first (pool, props); hi; hi = apr_hash_next (hi))
{
const void *key;
void *val;
const char *pname;
svn_string_t *propval;
SVN_ERR (check_cancel (NULL));
apr_hash_this (hi, &key, NULL, &val);
pname = key;
propval = val;
/* Since we're already adding a trailing newline (and possible a
colon and some spaces) anyway, just mimic the output of the
command line client proplist. Compare to 'svnlook propget',
which sends the raw bytes to stdout, untranslated. */
/* We leave printf calls here, since we don't always know the encoding
of the prop value. */
if (svn_prop_needs_translation (pname))
SVN_ERR (svn_subst_detranslate_string (&propval, propval, TRUE, pool));
if (verbose)
{
const char *pname_stdout;
SVN_ERR (svn_cmdline_cstring_from_utf8 (&pname_stdout, pname, pool));
printf (" %s : %s\n", pname_stdout, propval->data);
}
else
printf (" %s\n", pname);
}
return SVN_NO_ERROR;
}
/* Print the diff between revision 0 and our root. */
static svn_error_t *
do_tree (svnlook_ctxt_t *c,
const char *path,
svn_boolean_t show_ids,
apr_pool_t *pool)
{
svn_fs_root_t *root;
const svn_fs_id_t *id;
svn_boolean_t is_dir;
SVN_ERR (get_root (&root, c, pool));
SVN_ERR (svn_fs_node_id (&id, root, path, pool));
SVN_ERR (svn_fs_is_dir (&is_dir, root, path, pool));
SVN_ERR (print_tree (root, path, id, is_dir, 0, show_ids, pool));
return SVN_NO_ERROR;
}
/* Custom filesystem warning function. */
static void
warning_func (void *baton,
svn_error_t *err)
{
if (! err)
return;
svn_handle_error (err, stderr, FALSE);
}
/* Factory function for the context baton. */
static svn_error_t *
get_ctxt_baton (svnlook_ctxt_t **baton_p,
struct svnlook_opt_state *opt_state,
apr_pool_t *pool)
{
svnlook_ctxt_t *baton = apr_pcalloc (pool, sizeof (*baton));
SVN_ERR (svn_repos_open (&(baton->repos), opt_state->repos_path, pool));
baton->fs = svn_repos_fs (baton->repos);
svn_fs_set_warning_func (baton->fs, warning_func, NULL);
baton->show_ids = opt_state->show_ids;
baton->no_diff_deleted = opt_state->no_diff_deleted;
baton->is_revision = opt_state->txn ? FALSE : TRUE;
baton->rev_id = opt_state->rev;
baton->txn_name = apr_pstrdup (pool, opt_state->txn);
if (baton->txn_name)
SVN_ERR (svn_fs_open_txn (&(baton->txn), baton->fs,
baton->txn_name, pool));
else if (baton->rev_id == SVN_INVALID_REVNUM)
SVN_ERR (svn_fs_youngest_rev (&(baton->rev_id), baton->fs, pool));
*baton_p = baton;
return SVN_NO_ERROR;
}
/*** Subcommands. ***/
/* This implements `svn_opt_subcommand_t'. */
static svn_error_t *
subcommand_author (apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
struct svnlook_opt_state *opt_state = baton;
svnlook_ctxt_t *c;
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
SVN_ERR (do_author (c, pool));
return SVN_NO_ERROR;
}
/* This implements `svn_opt_subcommand_t'. */
static svn_error_t *
subcommand_cat (apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
struct svnlook_opt_state *opt_state = baton;
svnlook_ctxt_t *c;
if (opt_state->arg1 == NULL)
return svn_error_createf
(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
_("Missing repository path argument"));
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
SVN_ERR (do_cat (c, opt_state->arg1, pool));
return SVN_NO_ERROR;
}
/* This implements `svn_opt_subcommand_t'. */
static svn_error_t *
subcommand_changed (apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
struct svnlook_opt_state *opt_state = baton;
svnlook_ctxt_t *c;
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
SVN_ERR (do_changed (c, pool));
return SVN_NO_ERROR;
}
/* This implements `svn_opt_subcommand_t'. */
static svn_error_t *
subcommand_date (apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
struct svnlook_opt_state *opt_state = baton;
svnlook_ctxt_t *c;
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
SVN_ERR (do_date (c, pool));
return SVN_NO_ERROR;
}
/* This implements `svn_opt_subcommand_t'. */
static svn_error_t *
subcommand_diff (apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
struct svnlook_opt_state *opt_state = baton;
svnlook_ctxt_t *c;
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
SVN_ERR (do_diff (c, pool));
return SVN_NO_ERROR;
}
/* This implements `svn_opt_subcommand_t'. */
static svn_error_t *
subcommand_dirschanged (apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
struct svnlook_opt_state *opt_state = baton;
svnlook_ctxt_t *c;
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
SVN_ERR (do_dirs_changed (c, pool));
return SVN_NO_ERROR;
}
/* This implements `svn_opt_subcommand_t'. */
static svn_error_t *
subcommand_help (apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
struct svnlook_opt_state *opt_state = baton;
const char *header =
_("general usage: svnlook SUBCOMMAND REPOS_PATH [ARGS & OPTIONS ...]\n"
"Note: any subcommand which takes the '--revision' and '--transaction'\n"
" options will, if invoked without one of those options, act on\n"
" the repository's youngest revision.\n"
"Type \"svnlook help <subcommand>\" for help on a specific subcommand.\n"
"\n"
"Available subcommands:\n");
SVN_ERR (svn_opt_print_help (os, "svnlook",
opt_state ? opt_state->version : FALSE,
FALSE, NULL,
header, cmd_table, options_table, NULL,
pool));
return SVN_NO_ERROR;
}
/* This implements `svn_opt_subcommand_t'. */
static svn_error_t *
subcommand_history (apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
struct svnlook_opt_state *opt_state = baton;
svnlook_ctxt_t *c;
const char *path = "/";
if (opt_state->arg1)
path = opt_state->arg1;
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
SVN_ERR (do_history (c, path, opt_state->show_ids, pool));
return SVN_NO_ERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -