/*
* status.c: the command-line's portion of the "svn status" command
*
* ====================================================================
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://subversion.tigris.org/license-1.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://subversion.tigris.org/.
* ====================================================================
*/
/* ==================================================================== */
/*** Includes. ***/
#include "svn_cmdline.h"
#include "svn_wc.h"
#include "svn_path.h"
#include "svn_xml.h"
#include "svn_time.h"
#include "cl.h"
#include "svn_private_config.h"
/* Return the single character representation of STATUS */
static char
generate_status_code(enum svn_wc_status_kind status)
{
switch (status)
{
case svn_wc_status_none: return ' ';
case svn_wc_status_normal: return ' ';
case svn_wc_status_added: return 'A';
case svn_wc_status_missing: return '!';
case svn_wc_status_incomplete: return '!';
case svn_wc_status_deleted: return 'D';
case svn_wc_status_replaced: return 'R';
case svn_wc_status_modified: return 'M';
case svn_wc_status_merged: return 'G';
case svn_wc_status_conflicted: return 'C';
case svn_wc_status_obstructed: return '~';
case svn_wc_status_ignored: return 'I';
case svn_wc_status_external: return 'X';
case svn_wc_status_unversioned: return '?';
default: return '?';
}
}
/* Return the detailed string representation of STATUS */
static const char *
generate_status_desc(enum svn_wc_status_kind status)
{
switch (status)
{
case svn_wc_status_none: return "none";
case svn_wc_status_normal: return "normal";
case svn_wc_status_added: return "added";
case svn_wc_status_missing: return "missing";
case svn_wc_status_incomplete: return "incomplete";
case svn_wc_status_deleted: return "deleted";
case svn_wc_status_replaced: return "replaced";
case svn_wc_status_modified: return "modified";
case svn_wc_status_merged: return "merged";
case svn_wc_status_conflicted: return "conflicted";
case svn_wc_status_obstructed: return "obstructed";
case svn_wc_status_ignored: return "ignored";
case svn_wc_status_external: return "external";
case svn_wc_status_unversioned: return "unversioned";
default: abort();
}
}
/* 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 detailed,
svn_boolean_t show_last_committed,
svn_boolean_t repos_locks,
svn_wc_status2_t *status,
apr_pool_t *pool)
{
if (detailed)
{
char ood_status, lock_status;
const char *working_rev;
if (! status->entry)
working_rev = "";
else if (! SVN_IS_VALID_REVNUM(status->entry->revision))
working_rev = " ? ";
else if (status->copied)
working_rev = "-";
else
working_rev = apr_psprintf(pool, "%ld", status->entry->revision);
if (status->repos_text_status != svn_wc_status_none
|| status->repos_prop_status != svn_wc_status_none)
ood_status = '*';
else
ood_status = ' ';
if (repos_locks)
{
if (status->repos_lock)
{
if (status->entry && status->entry->lock_token)
{
if (strcmp(status->repos_lock->token, status->entry->lock_token)
== 0)
lock_status = 'K';
else
lock_status = 'T';
}
else
lock_status = 'O';
}
else if (status->entry && status->entry->lock_token)
lock_status = 'B';
else
lock_status = ' ';
}
else
lock_status = (status->entry && status->entry->lock_token) ? 'K' : ' ';
if (show_last_committed)
{
const char *commit_rev;
const char *commit_author;
if (status->entry && SVN_IS_VALID_REVNUM(status->entry->cmt_rev))
commit_rev = apr_psprintf(pool, "%ld", status->entry->cmt_rev);
else if (status->entry)
commit_rev = " ? ";
else
commit_rev = "";
if (status->entry && status->entry->cmt_author)
commit_author = status->entry->cmt_author;
else if (status->entry)
commit_author = " ? ";
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));
}
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
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));
SVN_ERR(svn_cmdline_fflush(stdout));
return SVN_NO_ERROR;
}
svn_error_t *
svn_cl__print_status_xml(const char *path,
svn_wc_status2_t *status,
apr_pool_t *pool)
{
svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
apr_hash_t *att_hash;
if (status->text_status == svn_wc_status_none
&& status->repos_text_status == svn_wc_status_none)
return SVN_NO_ERROR;
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
"path", svn_path_local_style(path, pool), NULL);
att_hash = apr_hash_make(pool);
apr_hash_set(att_hash, "item", APR_HASH_KEY_STRING,
generate_status_desc(status->text_status));
apr_hash_set(att_hash, "props", APR_HASH_KEY_STRING,
generate_status_desc(status->prop_status));
if (status->locked)
apr_hash_set(att_hash, "wc-locked", APR_HASH_KEY_STRING, "true");
if (status->copied)
apr_hash_set(att_hash, "copied", APR_HASH_KEY_STRING, "true");
if (status->switched)
apr_hash_set(att_hash, "switched", APR_HASH_KEY_STRING, "true");
if (status->entry && ! status->entry->copied)
apr_hash_set(att_hash, "revision", APR_HASH_KEY_STRING,
apr_psprintf(pool, "%ld", status->entry->revision));
svn_xml_make_open_tag_hash(&sb, pool, svn_xml_normal, "wc-status",
att_hash);
if (status->entry && SVN_IS_VALID_REVNUM(status->entry->cmt_rev))
{
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "commit",
"revision",
apr_psprintf(pool, "%ld",
status->entry->cmt_rev),
NULL);
svn_cl__xml_tagged_cdata(&sb, pool, "author",
status->entry->cmt_author);
if (status->entry->cmt_date)
svn_cl__xml_tagged_cdata(&sb, pool, "date",
svn_time_to_cstring
(status->entry->cmt_date, pool));
svn_xml_make_close_tag(&sb, pool, "commit");
}
if (status->entry && status->entry->lock_token)
{
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "lock", NULL);
svn_cl__xml_tagged_cdata(&sb, pool, "token", status->entry->lock_token);
/* If lock_owner is NULL, assume WC is corrupt. */
if (status->entry->lock_owner)
svn_cl__xml_tagged_cdata(&sb, pool, "owner",
status->entry->lock_owner);
else
return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
_("'%s' has lock token, but no lock owner"),
svn_path_local_style(path, pool));
svn_cl__xml_tagged_cdata(&sb, pool, "comment",
status->entry->lock_comment);
svn_cl__xml_tagged_cdata(&sb, pool, "created",
svn_time_to_cstring
(status->entry->lock_creation_date, pool));
svn_xml_make_close_tag(&sb, pool, "lock");
}
svn_xml_make_close_tag(&sb, pool, "wc-status");
if (status->repos_text_status != svn_wc_status_none
|| status->repos_prop_status != svn_wc_status_none
|| status->repos_lock)
{
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "repos-status",
"item",
generate_status_desc(status->repos_text_status),
"props",
generate_status_desc(status->repos_prop_status),
NULL);
if (status->repos_lock)
{
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "lock", NULL);
svn_cl__xml_tagged_cdata(&sb, pool, "token",
status->repos_lock->token);
svn_cl__xml_tagged_cdata(&sb, pool, "owner",
status->repos_lock->owner);
svn_cl__xml_tagged_cdata(&sb, pool, "comment",
status->repos_lock->comment);
svn_cl__xml_tagged_cdata(&sb, pool, "created",
svn_time_to_cstring
(status->repos_lock->creation_date,
pool));
if (status->repos_lock->expiration_date != 0)
{
svn_cl__xml_tagged_cdata(&sb, pool, "expires",
svn_time_to_cstring
(status->repos_lock->expiration_date,
pool));
}
svn_xml_make_close_tag(&sb, pool, "lock");
}
svn_xml_make_close_tag(&sb, pool, "repos-status");
}
svn_xml_make_close_tag(&sb, pool, "entry");
return svn_cl__error_checked_fputs(sb->data, stdout);
}
/* Called by status-cmd.c */
svn_error_t *
svn_cl__print_status(const char *path,
svn_wc_status2_t *status,
svn_boolean_t detailed,
svn_boolean_t show_last_committed,
svn_boolean_t skip_unrecognized,
svn_boolean_t repos_locks,
apr_pool_t *pool)
{
if (! status
|| (skip_unrecognized && ! status->entry)
|| (status->text_status == svn_wc_status_none
&& status->repos_text_status == svn_wc_status_none))
return SVN_NO_ERROR;
return print_status(svn_path_local_style(path, pool),
detailed, show_last_committed, repos_locks, status,
pool);
}
syntax highlighted by Code2HTML, v. 0.9.1