In the command-line client, forbid
[svn.git] / subversion / svn / status.c
blob4adbab372404d3aff330a9f16ec9593717459a5f
1 /*
2 * status.c: the command-line's portion of the "svn status" command
4 * ====================================================================
5 * Copyright (c) 2000-2004 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 /* ==================================================================== */
23 /*** Includes. ***/
24 #include "svn_cmdline.h"
25 #include "svn_wc.h"
26 #include "svn_path.h"
27 #include "svn_xml.h"
28 #include "svn_time.h"
29 #include "cl.h"
30 #include "svn_private_config.h"
32 /* Return the single character representation of STATUS */
33 static char
34 generate_status_code(enum svn_wc_status_kind status)
36 switch (status)
38 case svn_wc_status_none: return ' ';
39 case svn_wc_status_normal: return ' ';
40 case svn_wc_status_added: return 'A';
41 case svn_wc_status_missing: return '!';
42 case svn_wc_status_incomplete: return '!';
43 case svn_wc_status_deleted: return 'D';
44 case svn_wc_status_replaced: return 'R';
45 case svn_wc_status_modified: return 'M';
46 case svn_wc_status_merged: return 'G';
47 case svn_wc_status_conflicted: return 'C';
48 case svn_wc_status_obstructed: return '~';
49 case svn_wc_status_ignored: return 'I';
50 case svn_wc_status_external: return 'X';
51 case svn_wc_status_unversioned: return '?';
52 default: return '?';
57 /* Return the detailed string representation of STATUS */
58 static const char *
59 generate_status_desc(enum svn_wc_status_kind status)
61 switch (status)
63 case svn_wc_status_none: return "none";
64 case svn_wc_status_normal: return "normal";
65 case svn_wc_status_added: return "added";
66 case svn_wc_status_missing: return "missing";
67 case svn_wc_status_incomplete: return "incomplete";
68 case svn_wc_status_deleted: return "deleted";
69 case svn_wc_status_replaced: return "replaced";
70 case svn_wc_status_modified: return "modified";
71 case svn_wc_status_merged: return "merged";
72 case svn_wc_status_conflicted: return "conflicted";
73 case svn_wc_status_obstructed: return "obstructed";
74 case svn_wc_status_ignored: return "ignored";
75 case svn_wc_status_external: return "external";
76 case svn_wc_status_unversioned: return "unversioned";
77 default: abort();
79 return NULL;
83 /* Print STATUS and PATH in a format determined by DETAILED and
84 SHOW_LAST_COMMITTED. */
85 static svn_error_t *
86 print_status(const char *path,
87 svn_boolean_t detailed,
88 svn_boolean_t show_last_committed,
89 svn_boolean_t repos_locks,
90 svn_wc_status2_t *status,
91 apr_pool_t *pool)
93 if (detailed)
95 char ood_status, lock_status;
96 const char *working_rev;
98 if (! status->entry)
99 working_rev = "";
100 else if (! SVN_IS_VALID_REVNUM(status->entry->revision))
101 working_rev = " ? ";
102 else if (status->copied)
103 working_rev = "-";
104 else
105 working_rev = apr_psprintf(pool, "%ld", status->entry->revision);
107 if (status->repos_text_status != svn_wc_status_none
108 || status->repos_prop_status != svn_wc_status_none)
109 ood_status = '*';
110 else
111 ood_status = ' ';
113 if (repos_locks)
115 if (status->repos_lock)
117 if (status->entry && status->entry->lock_token)
119 if (strcmp(status->repos_lock->token, status->entry->lock_token)
120 == 0)
121 lock_status = 'K';
122 else
123 lock_status = 'T';
125 else
126 lock_status = 'O';
128 else if (status->entry && status->entry->lock_token)
129 lock_status = 'B';
130 else
131 lock_status = ' ';
133 else
134 lock_status = (status->entry && status->entry->lock_token) ? 'K' : ' ';
136 if (show_last_committed)
138 const char *commit_rev;
139 const char *commit_author;
141 if (status->entry && SVN_IS_VALID_REVNUM(status->entry->cmt_rev))
142 commit_rev = apr_psprintf(pool, "%ld", status->entry->cmt_rev);
143 else if (status->entry)
144 commit_rev = " ? ";
145 else
146 commit_rev = "";
148 if (status->entry && status->entry->cmt_author)
149 commit_author = status->entry->cmt_author;
150 else if (status->entry)
151 commit_author = " ? ";
152 else
153 commit_author = "";
155 SVN_ERR
156 (svn_cmdline_printf(pool,
157 "%c%c%c%c%c%c %c %6s %6s %-12s %s\n",
158 generate_status_code(status->text_status),
159 generate_status_code(status->prop_status),
160 status->locked ? 'L' : ' ',
161 status->copied ? '+' : ' ',
162 status->switched ? 'S' : ' ',
163 lock_status,
164 ood_status,
165 working_rev,
166 commit_rev,
167 commit_author,
168 path));
170 else
171 SVN_ERR
172 (svn_cmdline_printf(pool, "%c%c%c%c%c%c %c %6s %s\n",
173 generate_status_code(status->text_status),
174 generate_status_code(status->prop_status),
175 status->locked ? 'L' : ' ',
176 status->copied ? '+' : ' ',
177 status->switched ? 'S' : ' ',
178 lock_status,
179 ood_status,
180 working_rev,
181 path));
183 else
184 SVN_ERR
185 (svn_cmdline_printf(pool, "%c%c%c%c%c%c %s\n",
186 generate_status_code(status->text_status),
187 generate_status_code(status->prop_status),
188 status->locked ? 'L' : ' ',
189 status->copied ? '+' : ' ',
190 status->switched ? 'S' : ' ',
191 ((status->entry && status->entry->lock_token)
192 ? 'K' : ' '),
193 path));
195 SVN_ERR(svn_cmdline_fflush(stdout));
197 return SVN_NO_ERROR;
201 svn_error_t *
202 svn_cl__print_status_xml(const char *path,
203 svn_wc_status2_t *status,
204 apr_pool_t *pool)
206 svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
207 apr_hash_t *att_hash;
209 if (status->text_status == svn_wc_status_none
210 && status->repos_text_status == svn_wc_status_none)
211 return SVN_NO_ERROR;
213 svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
214 "path", svn_path_local_style(path, pool), NULL);
216 att_hash = apr_hash_make(pool);
217 apr_hash_set(att_hash, "item", APR_HASH_KEY_STRING,
218 generate_status_desc(status->text_status));
219 apr_hash_set(att_hash, "props", APR_HASH_KEY_STRING,
220 generate_status_desc(status->prop_status));
221 if (status->locked)
222 apr_hash_set(att_hash, "wc-locked", APR_HASH_KEY_STRING, "true");
223 if (status->copied)
224 apr_hash_set(att_hash, "copied", APR_HASH_KEY_STRING, "true");
225 if (status->switched)
226 apr_hash_set(att_hash, "switched", APR_HASH_KEY_STRING, "true");
227 if (status->entry && ! status->entry->copied)
228 apr_hash_set(att_hash, "revision", APR_HASH_KEY_STRING,
229 apr_psprintf(pool, "%ld", status->entry->revision));
230 svn_xml_make_open_tag_hash(&sb, pool, svn_xml_normal, "wc-status",
231 att_hash);
233 if (status->entry && SVN_IS_VALID_REVNUM(status->entry->cmt_rev))
235 svn_cl__print_xml_commit(&sb, status->entry->cmt_rev,
236 status->entry->cmt_author,
237 svn_time_to_cstring(status->entry->cmt_date,
238 pool),
239 pool);
242 if (status->entry && status->entry->lock_token)
244 svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "lock", NULL);
246 svn_cl__xml_tagged_cdata(&sb, pool, "token", status->entry->lock_token);
248 /* If lock_owner is NULL, assume WC is corrupt. */
249 if (status->entry->lock_owner)
250 svn_cl__xml_tagged_cdata(&sb, pool, "owner",
251 status->entry->lock_owner);
252 else
253 return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
254 _("'%s' has lock token, but no lock owner"),
255 svn_path_local_style(path, pool));
257 svn_cl__xml_tagged_cdata(&sb, pool, "comment",
258 status->entry->lock_comment);
260 svn_cl__xml_tagged_cdata(&sb, pool, "created",
261 svn_time_to_cstring
262 (status->entry->lock_creation_date, pool));
264 svn_xml_make_close_tag(&sb, pool, "lock");
267 svn_xml_make_close_tag(&sb, pool, "wc-status");
269 if (status->repos_text_status != svn_wc_status_none
270 || status->repos_prop_status != svn_wc_status_none
271 || status->repos_lock)
273 svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "repos-status",
274 "item",
275 generate_status_desc(status->repos_text_status),
276 "props",
277 generate_status_desc(status->repos_prop_status),
278 NULL);
279 if (status->repos_lock)
281 svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "lock", NULL);
283 svn_cl__xml_tagged_cdata(&sb, pool, "token",
284 status->repos_lock->token);
286 svn_cl__xml_tagged_cdata(&sb, pool, "owner",
287 status->repos_lock->owner);
289 svn_cl__xml_tagged_cdata(&sb, pool, "comment",
290 status->repos_lock->comment);
292 svn_cl__xml_tagged_cdata(&sb, pool, "created",
293 svn_time_to_cstring
294 (status->repos_lock->creation_date,
295 pool));
297 if (status->repos_lock->expiration_date != 0)
299 svn_cl__xml_tagged_cdata(&sb, pool, "expires",
300 svn_time_to_cstring
301 (status->repos_lock->expiration_date,
302 pool));
305 svn_xml_make_close_tag(&sb, pool, "lock");
307 svn_xml_make_close_tag(&sb, pool, "repos-status");
310 svn_xml_make_close_tag(&sb, pool, "entry");
312 return svn_cl__error_checked_fputs(sb->data, stdout);
315 /* Called by status-cmd.c */
316 svn_error_t *
317 svn_cl__print_status(const char *path,
318 svn_wc_status2_t *status,
319 svn_boolean_t detailed,
320 svn_boolean_t show_last_committed,
321 svn_boolean_t skip_unrecognized,
322 svn_boolean_t repos_locks,
323 apr_pool_t *pool)
325 if (! status
326 || (skip_unrecognized && ! status->entry)
327 || (status->text_status == svn_wc_status_none
328 && status->repos_text_status == svn_wc_status_none))
329 return SVN_NO_ERROR;
331 return print_status(svn_path_local_style(path, pool),
332 detailed, show_last_committed, repos_locks, status,
333 pool);