/* Implement `svn_log_entry_receiver_t', printing the logs in * a human-readable and machine-parseable format. * * BATON is of type `struct log_receiver_baton'. * * First, print a header line. Then if CHANGED_PATHS is non-null, * print all affected paths in a list headed "Changed paths:\n", * immediately following the header line. Then print a newline * followed by the message body, unless BATON->omit_log_message is true. * * Here are some examples of the output: * * $ svn log -r1847:1846 * ------------------------------------------------------------------------ * rev 1847: cmpilato | Wed 1 May 2002 15:44:26 | 7 lines * * Fix for Issue #694. * * * subversion/libsvn_repos/delta.c * (delta_files): Rework the logic in this function to only call * send_text_deltas if there are deltas to send, and within that case, * only use a real delta stream if the caller wants real text deltas. * * ------------------------------------------------------------------------ * rev 1846: whoever | Wed 1 May 2002 15:23:41 | 1 line * * imagine an example log message here * ------------------------------------------------------------------------ * * Or: * * $ svn log -r1847:1846 -v * ------------------------------------------------------------------------ * rev 1847: cmpilato | Wed 1 May 2002 15:44:26 | 7 lines * Changed paths: * M /trunk/subversion/libsvn_repos/delta.c * * Fix for Issue #694. * * * subversion/libsvn_repos/delta.c * (delta_files): Rework the logic in this function to only call * send_text_deltas if there are deltas to send, and within that case, * only use a real delta stream if the caller wants real text deltas. * * ------------------------------------------------------------------------ * rev 1846: whoever | Wed 1 May 2002 15:23:41 | 1 line * Changed paths: * M /trunk/notes/fs_dumprestore.txt * M /trunk/subversion/libsvn_repos/dump.c * * imagine an example log message here * ------------------------------------------------------------------------ * * Or: * * $ svn log -r1847:1846 -q * ------------------------------------------------------------------------ * rev 1847: cmpilato | Wed 1 May 2002 15:44:26 * ------------------------------------------------------------------------ * rev 1846: whoever | Wed 1 May 2002 15:23:41 * ------------------------------------------------------------------------ * * Or: * * $ svn log -r1847:1846 -qv * ------------------------------------------------------------------------ * rev 1847: cmpilato | Wed 1 May 2002 15:44:26 * Changed paths: * M /trunk/subversion/libsvn_repos/delta.c * ------------------------------------------------------------------------ * rev 1846: whoever | Wed 1 May 2002 15:23:41 * Changed paths: * M /trunk/notes/fs_dumprestore.txt * M /trunk/subversion/libsvn_repos/dump.c * ------------------------------------------------------------------------ * */ static svn_error_t * log_entry_receiver(void *baton, svn_log_entry_t *log_entry, apr_pool_t *pool) { struct log_receiver_baton *lb = baton; const char *author; const char *date; const char *message; /* Number of lines in the msg. */ int lines; if (lb->cancel_func) SVN_ERR(lb->cancel_func(lb->cancel_baton)); svn_compat_log_revprops_out(&author, &date, &message, log_entry->revprops); if (log_entry->revision == 0 && message == NULL) return SVN_NO_ERROR; if (! SVN_IS_VALID_REVNUM(log_entry->revision)) { apr_array_pop(lb->merge_stack); return SVN_NO_ERROR; } /* ### See http://subversion.tigris.org/issues/show_bug.cgi?id=807 for more on the fallback fuzzy conversions below. */ if (author == NULL) author = _("(no author)"); if (date && date[0]) /* Convert date to a format for humans. */ SVN_ERR(svn_cl__time_cstring_to_human_cstring(&date, date, pool)); else date = _("(no date)"); if (! lb->omit_log_message && message == NULL) message = ""; SVN_ERR(svn_cmdline_printf(pool, SEP_STRING "r%ld | %s | %s", log_entry->revision, author, date)); if (message != NULL) { lines = svn_cstring_count_newlines(message) + 1; SVN_ERR(svn_cmdline_printf(pool, (lines != 1) ? " | %d lines" : " | %d line", lines)); } SVN_ERR(svn_cmdline_printf(pool, "\n")); if (log_entry->changed_paths) { apr_array_header_t *sorted_paths; int i; /* Get an array of sorted hash keys. */ sorted_paths = svn_sort__hash(log_entry->changed_paths, svn_sort_compare_items_as_paths, pool); SVN_ERR(svn_cmdline_printf(pool, _("Changed paths:\n"))); for (i = 0; i < sorted_paths->nelts; i++) { svn_sort__item_t *item = &(APR_ARRAY_IDX(sorted_paths, i, svn_sort__item_t)); const char *path = item->key; svn_log_changed_path_t *log_item = apr_hash_get(log_entry->changed_paths, item->key, item->klen); const char *copy_data = ""; if (log_item->copyfrom_path && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev)) { copy_data = apr_psprintf(pool, _(" (from %s:%ld)"), log_item->copyfrom_path, log_item->copyfrom_rev); } SVN_ERR(svn_cmdline_printf(pool, " %c %s%s\n", log_item->action, path, copy_data)); } } if (lb->merge_stack->nelts > 0) { int i; /* Print the result of merge line */ SVN_ERR(svn_cmdline_printf(pool, _("Merged via:"))); for (i = 0; i < lb->merge_stack->nelts; i++) { svn_revnum_t rev = APR_ARRAY_IDX(lb->merge_stack, i, svn_revnum_t); SVN_ERR(svn_cmdline_printf(pool, " r%ld%c", rev, i == lb->merge_stack->nelts - 1 ? '\n' : ',')); } } if (message != NULL) { /* A blank line always precedes the log message. */ SVN_ERR(svn_cmdline_printf(pool, "\n%s\n", message)); } SVN_ERR(svn_cmdline_fflush(stdout)); if (log_entry->has_children) APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision; return SVN_NO_ERROR; }
/* A callback of type svn_info_receiver_t. */ static svn_error_t * print_info(void *baton, const char *target, const svn_info_t *info, apr_pool_t *pool) { SVN_ERR(svn_cmdline_printf(pool, _("Path: %s\n"), svn_path_local_style(target, pool))); /* ### remove this someday: it's only here for cmdline output compatibility with svn 1.1 and older. */ if (info->kind != svn_node_dir) SVN_ERR(svn_cmdline_printf(pool, _("Name: %s\n"), svn_path_basename(target, pool))); if (info->URL) SVN_ERR(svn_cmdline_printf(pool, _("URL: %s\n"), info->URL)); if (info->repos_root_URL) SVN_ERR(svn_cmdline_printf(pool, _("Repository Root: %s\n"), info->repos_root_URL)); if (info->repos_UUID) SVN_ERR(svn_cmdline_printf(pool, _("Repository UUID: %s\n"), info->repos_UUID)); if (SVN_IS_VALID_REVNUM(info->rev)) SVN_ERR(svn_cmdline_printf(pool, _("Revision: %ld\n"), info->rev)); switch (info->kind) { case svn_node_file: SVN_ERR(svn_cmdline_printf(pool, _("Node Kind: file\n"))); break; case svn_node_dir: SVN_ERR(svn_cmdline_printf(pool, _("Node Kind: directory\n"))); break; case svn_node_none: SVN_ERR(svn_cmdline_printf(pool, _("Node Kind: none\n"))); break; case svn_node_unknown: default: SVN_ERR(svn_cmdline_printf(pool, _("Node Kind: unknown\n"))); break; } if (info->has_wc_info) { switch (info->schedule) { case svn_wc_schedule_normal: SVN_ERR(svn_cmdline_printf(pool, _("Schedule: normal\n"))); break; case svn_wc_schedule_add: SVN_ERR(svn_cmdline_printf(pool, _("Schedule: add\n"))); break; case svn_wc_schedule_delete: SVN_ERR(svn_cmdline_printf(pool, _("Schedule: delete\n"))); break; case svn_wc_schedule_replace: SVN_ERR(svn_cmdline_printf(pool, _("Schedule: replace\n"))); break; default: break; } switch (info->depth) { case svn_depth_unknown: /* Unknown depth is the norm for remote directories anyway (although infinity would be equally appropriate). Let's not bother to print it. */ break; case svn_depth_empty: SVN_ERR(svn_cmdline_printf(pool, _("Depth: empty\n"))); break; case svn_depth_files: SVN_ERR(svn_cmdline_printf(pool, _("Depth: files\n"))); break; case svn_depth_immediates: SVN_ERR(svn_cmdline_printf(pool, _("Depth: immediates\n"))); break; case svn_depth_infinity: /* Infinity is the default depth for working copy directories. Let's not print it, it's not special enough to be worth mentioning. */ break; default: /* Other depths should never happen here. */ SVN_ERR(svn_cmdline_printf(pool, _("Depth: INVALID\n"))); } if (info->copyfrom_url) SVN_ERR(svn_cmdline_printf(pool, _("Copied From URL: %s\n"), info->copyfrom_url)); if (SVN_IS_VALID_REVNUM(info->copyfrom_rev)) SVN_ERR(svn_cmdline_printf(pool, _("Copied From Rev: %ld\n"), info->copyfrom_rev)); } if (info->last_changed_author) SVN_ERR(svn_cmdline_printf(pool, _("Last Changed Author: %s\n"), info->last_changed_author)); if (SVN_IS_VALID_REVNUM(info->last_changed_rev)) SVN_ERR(svn_cmdline_printf(pool, _("Last Changed Rev: %ld\n"), info->last_changed_rev)); if (info->last_changed_date) SVN_ERR(svn_cl__info_print_time(info->last_changed_date, _("Last Changed Date"), pool)); if (info->has_wc_info) { if (info->text_time) SVN_ERR(svn_cl__info_print_time(info->text_time, _("Text Last Updated"), pool)); if (info->checksum) SVN_ERR(svn_cmdline_printf(pool, _("Checksum: %s\n"), info->checksum)); if (info->conflict_old) SVN_ERR(svn_cmdline_printf(pool, _("Conflict Previous Base File: %s\n"), svn_path_local_style(info->conflict_old, pool))); if (info->conflict_wrk) SVN_ERR(svn_cmdline_printf (pool, _("Conflict Previous Working File: %s\n"), svn_path_local_style(info->conflict_wrk, pool))); if (info->conflict_new) SVN_ERR(svn_cmdline_printf(pool, _("Conflict Current Base File: %s\n"), svn_path_local_style(info->conflict_new, pool))); if (info->prejfile) SVN_ERR(svn_cmdline_printf(pool, _("Conflict Properties File: %s\n"), svn_path_local_style(info->prejfile, pool))); } if (info->lock) { if (info->lock->token) SVN_ERR(svn_cmdline_printf(pool, _("Lock Token: %s\n"), info->lock->token)); if (info->lock->owner) SVN_ERR(svn_cmdline_printf(pool, _("Lock Owner: %s\n"), info->lock->owner)); if (info->lock->creation_date) SVN_ERR(svn_cl__info_print_time(info->lock->creation_date, _("Lock Created"), pool)); if (info->lock->expiration_date) SVN_ERR(svn_cl__info_print_time(info->lock->expiration_date, _("Lock Expires"), pool)); if (info->lock->comment) { int comment_lines; /* NOTE: The stdio will handle newline translation. */ comment_lines = svn_cstring_count_newlines(info->lock->comment) + 1; SVN_ERR(svn_cmdline_printf(pool, Q_("Lock Comment (%i line):\n%s\n", "Lock Comment (%i lines):\n%s\n", comment_lines), comment_lines, info->lock->comment)); } } if (info->changelist) SVN_ERR(svn_cmdline_printf(pool, _("Changelist: %s\n"), info->changelist)); if (info->tree_conflict) { const char *desc, *src_left_version, *src_right_version; SVN_ERR(svn_cl__get_human_readable_tree_conflict_description( &desc, info->tree_conflict, pool)); src_left_version = svn_cl__node_description(info->tree_conflict->src_left_version, pool); src_right_version = svn_cl__node_description(info->tree_conflict->src_right_version, pool); svn_cmdline_printf(pool, "%s: %s\n", _("Tree conflict"), desc); if (src_left_version) svn_cmdline_printf(pool, " %s: %s\n", _("Source left"), /* (1) */ src_left_version); /* (1): Sneaking in a space in "Source left" so that it is the * same length as "Source right" while it still starts in the same * column. That's just a tiny tweak in the English `svn'. */ if (src_right_version) svn_cmdline_printf(pool, " %s: %s\n", _("Source right"), src_right_version); } /* Print extra newline separator. */ return svn_cmdline_printf(pool, "\n"); }