Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h (revision 13821)
+++ subversion/include/svn_wc.h (working copy)
@@ -543,7 +543,10 @@
svn_wc_notify_failed_lock,
/** @since New in 1.2. Failed to unlock a path. */
- svn_wc_notify_failed_unlock
+ svn_wc_notify_failed_unlock,
+
+ /** The last notification in a status xml (including status on externals). */
+ svn_wc_notify_status_xml_completed,
} svn_wc_notify_action_t;
Index: subversion/libsvn_client/status.c
===================================================================
--- subversion/libsvn_client/status.c (revision 13821)
+++ subversion/libsvn_client/status.c (working copy)
@@ -324,8 +324,11 @@
if (ctx->notify_func2 && update)
{
- svn_wc_notify_t *notify
- = svn_wc_create_notify (path, svn_wc_notify_status_completed, pool);
+ svn_wc_notify_t *notify;
+ if ( *((svn_boolean_t*)status_baton))
+ notify = svn_wc_create_notify (path, svn_wc_notify_status_xml_completed, pool);
+ else
+ notify = svn_wc_create_notify (path, svn_wc_notify_status_completed, pool);
notify->revision = edit_revision;
(ctx->notify_func2) (ctx->notify_baton2, notify, pool);
}
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h (revision 13821)
+++ subversion/clients/cmdline/cl.h (working copy)
@@ -249,6 +249,7 @@
as broken WC locks. */
svn_error_t *svn_cl__print_status (const char *path,
svn_wc_status2_t *status,
+ svn_boolean_t xml_mode,
svn_boolean_t detailed,
svn_boolean_t show_last_committed,
svn_boolean_t skip_unrecognized,
Index: subversion/clients/cmdline/status.c
===================================================================
--- subversion/clients/cmdline/status.c (revision 13821)
+++ subversion/clients/cmdline/status.c (working copy)
@@ -24,6 +24,7 @@
#include "svn_cmdline.h"
#include "svn_wc.h"
#include "svn_path.h"
+#include "svn_xml.h"
#include "cl.h"
@@ -51,10 +52,132 @@
}
}
+static svn_error_t *
+print_statents_xml (apr_pool_t *pool,
+ char item_stat,
+ char prop_stat,
+ char locked,
+ char copied,
+ char switched,
+ char reposlock,
+ char ood_stat,
+ const char *working_rev,
+ const char *commit_rev,
+ const char *commit_author,
+ const char *path)
+{
+ char statcode[2] = {'\0', '\0'};
+ svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "entry",
+ "file", path[0] == '\0' ? "." : path,
+ NULL);
+ /* x */
+ statcode[0] = item_stat;
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "item-status", NULL);
+ svn_xml_escape_cdata_cstring (&sb, statcode, pool);
+ svn_xml_make_close_tag (&sb, pool, "item-status");
+
+ /* x */
+ statcode[0] = prop_stat;
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "prop-status", NULL);
+ svn_xml_escape_cdata_cstring (&sb, statcode, pool);
+ svn_xml_make_close_tag (&sb, pool, "prop-status");
+
+ /* x */
+ if (locked)
+ {
+ statcode[0] = locked;
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "locked", NULL);
+ svn_xml_escape_cdata_cstring (&sb, statcode, pool);
+ svn_xml_make_close_tag (&sb, pool, "locked");
+ }
+
+ /* x */
+ if (copied)
+ {
+ statcode[0] = copied;
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "scheduled", NULL);
+ svn_xml_escape_cdata_cstring (&sb, statcode, pool);
+ svn_xml_make_close_tag (&sb, pool, "scheduled");
+ }
+
+ /* x */
+ if (switched)
+ {
+ statcode[0] = switched;
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "switched", NULL);
+ svn_xml_escape_cdata_cstring (&sb, statcode, pool);
+ svn_xml_make_close_tag (&sb, pool, "switched");
+ }
+
+ /* x */
+ if (reposlock)
+ {
+ statcode[0] = reposlock;
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "repos-lock", NULL);
+ svn_xml_escape_cdata_cstring (&sb, statcode, pool);
+ svn_xml_make_close_tag (&sb, pool, "repos-lock");
+ }
+
+ /* x */
+ if (ood_stat)
+ {
+ statcode[0] = ood_stat;
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "out-of-date", NULL);
+ svn_xml_escape_cdata_cstring (&sb, statcode, pool);
+ svn_xml_make_close_tag (&sb, pool, "out-of-date");
+ }
+
+ /* xx */
+ if (working_rev)
+ {
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "revision", NULL);
+ svn_xml_escape_cdata_cstring (&sb, working_rev, pool);
+ svn_xml_make_close_tag (&sb, pool, "revision");
+ }
+
+ /* xx */
+ if (commit_rev)
+ {
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "rev-last-commit", NULL);
+ svn_xml_escape_cdata_cstring (&sb, commit_rev, pool);
+ svn_xml_make_close_tag (&sb, pool, "rev-last-commit");
+ }
+
+ /* xx */
+ if (commit_author)
+ {
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "author-last-commit", NULL);
+ svn_xml_escape_cdata_cstring (&sb, commit_author, pool);
+ svn_xml_make_close_tag (&sb, pool, "author-last-commit");
+ }
+
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "entry");
+
+ SVN_ERR (svn_cl__error_checked_fputs (sb->data, stdout));
+
+ return SVN_NO_ERROR;
+}
+
+
/* Print STATUS and PATH in a format determined by DETAILED and
SHOW_LAST_COMMITTED. */
static svn_error_t *
print_status (const char *path,
+ svn_boolean_t xml_mode,
svn_boolean_t detailed,
svn_boolean_t show_last_committed,
svn_boolean_t repos_locks,
@@ -123,53 +246,106 @@
else
commit_author = "";
- SVN_ERR
- (svn_cmdline_printf (pool,
- "%c%c%c%c%c%c %c %6s %6s %-12s %s\n",
- generate_status_code(status->text_status),
- generate_status_code (status->prop_status),
- status->locked ? 'L' : ' ',
- status->copied ? '+' : ' ',
- status->switched ? 'S' : ' ',
- lock_status,
- ood_status,
- working_rev,
- commit_rev,
- commit_author,
- path));
+ if (xml_mode)
+ SVN_ERR
+ (print_statents_xml (pool,
+ generate_status_code(status->text_status),
+ generate_status_code (status->prop_status),
+ status->locked ? 'L' : ' ',
+ status->copied ? '+' : ' ',
+ status->switched ? 'S' : ' ',
+ lock_status,
+ ood_status,
+ working_rev,
+ commit_rev,
+ commit_author,
+ path));
+
+ else
+ SVN_ERR
+ (svn_cmdline_printf (pool,
+ "%c%c%c%c%c%c %c %6s %6s %-12s %s\n",
+ generate_status_code(status->text_status),
+ generate_status_code (status->prop_status),
+ status->locked ? 'L' : ' ',
+ status->copied ? '+' : ' ',
+ status->switched ? 'S' : ' ',
+ lock_status,
+ ood_status,
+ working_rev,
+ commit_rev,
+ commit_author,
+ path));
}
else
+ {
+ if (xml_mode)
+ SVN_ERR
+ (print_statents_xml (pool,
+ generate_status_code (status->text_status),
+ generate_status_code (status->prop_status),
+ status->locked ? 'L' : ' ',
+ status->copied ? '+' : ' ',
+ status->switched ? 'S' : ' ',
+ lock_status,
+ ood_status,
+ working_rev,
+ NULL,
+ NULL,
+ path));
+ else
+ SVN_ERR
+ (svn_cmdline_printf (pool, "%c%c%c%c%c%c %c %6s %s\n",
+ generate_status_code (status->text_status),
+ generate_status_code (status->prop_status),
+ status->locked ? 'L' : ' ',
+ status->copied ? '+' : ' ',
+ status->switched ? 'S' : ' ',
+ lock_status,
+ ood_status,
+ working_rev,
+ path));
+ }
+ }
+ else
+ {
+ if (xml_mode)
SVN_ERR
- (svn_cmdline_printf (pool, "%c%c%c%c%c%c %c %6s %s\n",
+ (print_statents_xml (pool,
generate_status_code (status->text_status),
generate_status_code (status->prop_status),
status->locked ? 'L' : ' ',
status->copied ? '+' : ' ',
status->switched ? 'S' : ' ',
- lock_status,
- ood_status,
- working_rev,
+ ((status->entry && status->entry->lock_token)
+ ? 'K' : ' '),
+ '\0',
+ '\0',
+ NULL,
+ NULL,
path));
+ else
+ SVN_ERR
+ (svn_cmdline_printf (pool, "%c%c%c%c%c%c %s\n",
+ generate_status_code (status->text_status),
+ generate_status_code (status->prop_status),
+ status->locked ? 'L' : ' ',
+ status->copied ? '+' : ' ',
+ status->switched ? 'S' : ' ',
+ ((status->entry && status->entry->lock_token)
+ ? 'K' : ' '),
+ path));
}
- else
- SVN_ERR
- (svn_cmdline_printf (pool, "%c%c%c%c%c%c %s\n",
- generate_status_code (status->text_status),
- generate_status_code (status->prop_status),
- status->locked ? 'L' : ' ',
- status->copied ? '+' : ' ',
- status->switched ? 'S' : ' ',
- ((status->entry && status->entry->lock_token)
- ? 'K' : ' '),
- path));
-
return SVN_NO_ERROR;
}
+
+
/* Called by status-cmd.c */
svn_error_t *
svn_cl__print_status (const char *path,
svn_wc_status2_t *status,
+ svn_boolean_t xml_mode,
svn_boolean_t detailed,
svn_boolean_t show_last_committed,
svn_boolean_t skip_unrecognized,
@@ -182,7 +358,7 @@
&& status->repos_text_status == svn_wc_status_none))
return SVN_NO_ERROR;
- return print_status (svn_path_local_style (path, pool),
+ return print_status (svn_path_local_style (path, pool), xml_mode,
detailed, show_last_committed, repos_locks, status,
pool);
}
Index: subversion/clients/cmdline/notify.c
===================================================================
--- subversion/clients/cmdline/notify.c (revision 13821)
+++ subversion/clients/cmdline/notify.c (working copy)
@@ -29,6 +29,7 @@
#include "svn_cmdline.h"
#include "svn_pools.h"
#include "svn_path.h"
+#include "svn_xml.h"
#include "cl.h"
#include "svn_private_config.h"
@@ -55,8 +56,10 @@
{
struct notify_baton *nb = baton;
char statchar_buf[5] = " ";
+ const char *staton_rev;
const char *path_local;
svn_error_t *err;
+ svn_stringbuf_t *sb;
path_local = svn_path_local_style (n->path, pool);
@@ -364,6 +367,26 @@
svn_handle_error (n->err, stderr, FALSE);
break;
+ case svn_wc_notify_status_xml_completed:
+ if (SVN_IS_VALID_REVNUM (n->revision))
+ sb = svn_stringbuf_create ("", pool);
+ staton_rev = apr_psprintf (pool, "%ld", n->revision);
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal,
+ "status-against", NULL);
+
+ /* "xx" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "rev", NULL);
+ svn_xml_escape_cdata_cstring (&sb, staton_rev, pool);
+ svn_xml_make_close_tag (&sb, pool, "rev");
+
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "status-against");
+
+ svn_cl__error_checked_fputs (sb->data, stdout);
+ break;
+
default:
break;
}
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c (revision 13821)
+++ subversion/clients/cmdline/main.c (working copy)
@@ -672,7 +672,8 @@
" 965 687 joe wc/zig.c\n"
" Head revision: 981\n"),
{ 'u', 'v', 'N', 'q', svn_cl__no_ignore_opt, SVN_CL__AUTH_OPTIONS,
- svn_cl__config_dir_opt, svn_cl__ignore_externals_opt} },
+ svn_cl__config_dir_opt, svn_cl__ignore_externals_opt, svn_cl__xml_opt,
+ svn_cl__incremental_opt} },
{ "switch", svn_cl__switch, {"sw"},
N_("Update the working copy to a different URL.\n"
Index: subversion/clients/cmdline/status-cmd.c
===================================================================
--- subversion/clients/cmdline/status-cmd.c (revision 13821)
+++ subversion/clients/cmdline/status-cmd.c (working copy)
@@ -26,8 +26,12 @@
#include "svn_client.h"
#include "svn_error.h"
#include "svn_pools.h"
+#include "svn_xml.h"
#include "cl.h"
+#include "svn_private_config.h"
+
+
/*** Code. ***/
@@ -35,6 +39,7 @@
{
/* These fields all correspond to the ones in the
svn_cl__print_status() interface. */
+ svn_boolean_t xml_mode;
svn_boolean_t detailed;
svn_boolean_t show_last_committed;
svn_boolean_t skip_unrecognized;
@@ -46,6 +51,31 @@
};
+static svn_error_t *
+print_header_xml (apr_pool_t *pool)
+{
+ svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+
+ /* */
+ svn_xml_make_header (&sb, pool);
+
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "status", NULL);
+
+ return svn_cl__error_checked_fputs (sb->data, stdout);
+}
+
+
+static svn_error_t *
+print_footer_xml (apr_pool_t *pool)
+{
+ /* "" */
+ svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+ svn_xml_make_close_tag (&sb, pool, "status");
+ return svn_cl__error_checked_fputs (sb->data, stdout);
+}
+
+
/* A status callback function for printing STATUS for PATH. */
static void
print_status (void *baton,
@@ -55,8 +85,8 @@
struct status_baton *sb = baton;
svn_error_t *err;
- err = svn_cl__print_status (path, status, sb->detailed,
- sb->show_last_committed,
+ err = svn_cl__print_status (path, status, sb->xml_mode,
+ sb->detailed, sb->show_last_committed,
sb->skip_unrecognized, sb->repos_locks,
sb->pool);
@@ -104,6 +134,23 @@
sb.had_print_error = FALSE;
+ if (opt_state->xml)
+ {
+ /* If output is not incremental, output the XML header and wrap
+ everything in a top-level element. This makes the output in
+ its entirety a well-formed XML document. */
+ if (! opt_state->incremental)
+ SVN_ERR (print_header_xml (pool));
+
+ }
+ else
+ {
+ if (opt_state->incremental)
+ return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'incremental' option only valid in XML "
+ "mode"));
+ }
+
for (i = 0; i < targets->nelts; i++)
{
const char *target = ((const char **) (targets->elts))[i];
@@ -119,7 +166,9 @@
sb.show_last_committed = opt_state->verbose;
sb.skip_unrecognized = opt_state->quiet;
sb.repos_locks = opt_state->update;
+ sb.xml_mode = opt_state->xml;
sb.pool = subpool;
+
SVN_ERR (svn_client_status2 (NULL, target, &rev, print_status, &sb,
opt_state->nonrecursive ? FALSE : TRUE,
opt_state->verbose,
@@ -127,9 +176,15 @@
opt_state->no_ignore,
opt_state->ignore_externals,
ctx, subpool));
+
}
svn_pool_destroy (subpool);
-
+ if (opt_state->xml)
+ {
+ if (! opt_state->incremental)
+ SVN_ERR (print_footer_xml (pool));
+ }
+
return SVN_NO_ERROR;
}
Index: subversion/clients/cmdline/dtd/status.dtd
===================================================================
--- subversion/clients/cmdline/dtd/status.dtd (revision 0)
+++ subversion/clients/cmdline/dtd/status.dtd (revision 0)
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: subversion/tests/clients/cmdline/stat_tests.py
===================================================================
--- subversion/tests/clients/cmdline/stat_tests.py (revision 13821)
+++ subversion/tests/clients/cmdline/stat_tests.py (working copy)
@@ -817,6 +817,69 @@
svntest.actions.run_and_verify_status(wc_dir, expected_status)
+def status_in_xml(sbox):
+ "status output in XML format"
+
+
+ output, error = svntest.actions.run_and_verify_svn (None, None, [],
+ 'help', 'status')
+## TODO: is it neccessary to check output for NULL before using it
+
+ # Checks for --xml option in status help
+ output_omsg = "--xml"
+ output_dmsg = ": output in XML"
+
+ for line in output:
+ if line.find (output_omsg) > 0 and \
+ line.find (output_dmsg) > 0:
+ break
+ else:
+ print "'--xml' option not found in: [svn help status]"
+ raise svntest.Failure
+
+ # Checks for --incremental option in status help
+ output_omsg = "--incremental"
+ output_dmsg = ": give output suitable for concatenation"
+
+ for line in output:
+ if line.find (output_omsg) > 0 and \
+ line.find (output_dmsg) > 0:
+ break
+ else:
+ print "'--incremental' option not found in: [svn help status]"
+ raise svntest.Failure
+
+ # TODO: Checks wheather output of the cmd 'status --xml' is in XML format
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ file_name = "iota"
+ file_path = os.path.join (wc_dir, file_name)
+ svntest.main.file_append(file_path, "This line added in iota to test svn st --xml\n")
+
+ template = ["\n",
+ "\n",
+ "\n" % (file_path),
+ "M\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "\n",
+ "\n",
+ ]
+
+
+ output, error = svntest.actions.run_and_verify_svn (None, None, [],
+ 'status', wc_dir, '--xml')
+
+ for i in range(0, len(output)):
+ if output[i] != template[i]:
+ raise svntest.Failure
+
#----------------------------------------------------------------------
@@ -842,6 +905,7 @@
status_on_unversioned_dotdot,
status_on_partially_nonrecursive_wc,
missing_dir_in_anchor,
+ status_in_xml,
]
if __name__ == '__main__':