139
/* Make a relative path containing '..' elements as needed.
140
TARGET_ABSPATH shall be the absolute version of TARGET_PATH.
141
TARGET_ABSPATH, TARGET_PATH and PATH shall be canonical.
143
If above conditions are met, a relative path that leads to PATH
144
from TARGET_PATH is returned, but there is no error checking involved.
146
The returned path is allocated from RESULT_POOL, all other
147
allocations are made in SCRATCH_POOL. */
149
make_relpath(const char *target_abspath,
150
const char *target_path,
152
apr_pool_t *result_pool,
153
apr_pool_t *scratch_pool)
156
const char *parent_dir_els = "";
157
const char *abspath, *relative;
158
svn_error_t *err = svn_dirent_get_absolute(&abspath, path, scratch_pool);
162
/* We probably got passed some invalid path. */
163
svn_error_clear(err);
164
return apr_pstrdup(result_pool, path);
167
relative = svn_dirent_skip_ancestor(target_abspath, abspath);
170
return svn_dirent_join(target_path, relative, result_pool);
174
* relative_to_path = /a/b/c
176
* result = ../../x/y/z
178
* Another example (Windows specific):
179
* relative_to_path = F:/wc
184
/* Skip the common ancestor of both paths, here '/a'. */
185
la = svn_dirent_get_longest_ancestor(target_abspath, abspath,
189
/* Nothing in common: E.g. C:/ vs F:/ on Windows */
190
return apr_pstrdup(result_pool, path);
192
relative = svn_dirent_skip_ancestor(la, target_abspath);
193
path = svn_dirent_skip_ancestor(la, path);
195
/* In above example, we'd now have:
196
* relative_to_path = b/c
199
/* Count the elements of relative_to_path and prepend as many '..' elements
203
svn_dirent_split(&relative, NULL, relative,
205
parent_dir_els = svn_dirent_join(parent_dir_els, "..", scratch_pool);
208
return svn_dirent_join(parent_dir_els, path, result_pool);
139
212
/* Print STATUS and PATH in a format determined by DETAILED and
140
213
SHOW_LAST_COMMITTED. */
141
214
static svn_error_t *
142
print_status(const char *path,
215
print_status(const char *target_abspath,
216
const char *target_path,
143
218
svn_boolean_t detailed,
144
219
svn_boolean_t show_last_committed,
145
220
svn_boolean_t repos_locks,
222
301
(*prop_conflicts)++;
304
/* Note that moved-from and moved-to information is only available in STATUS
305
* for (op-)roots of a move. Those are exactly the nodes we want to show
306
* move info for in 'svn status'. See also comments in svn_wc_status3_t. */
307
if (status->moved_from_abspath && status->moved_to_abspath &&
308
strcmp(status->moved_from_abspath, status->moved_to_abspath) == 0)
312
relpath = make_relpath(target_abspath, target_path,
313
status->moved_from_abspath,
315
relpath = svn_dirent_local_style(relpath, pool);
316
moved_from_line = apr_pstrcat(pool, "\n > ",
318
_("swapped places with %s"),
322
else if (status->moved_from_abspath || status->moved_to_abspath)
326
if (status->moved_from_abspath)
328
relpath = make_relpath(target_abspath, target_path,
329
status->moved_from_abspath,
331
relpath = svn_dirent_local_style(relpath, pool);
332
moved_from_line = apr_pstrcat(pool, "\n > ",
333
apr_psprintf(pool, _("moved from %s"),
338
if (status->moved_to_abspath)
340
relpath = make_relpath(target_abspath, target_path,
341
status->moved_to_abspath,
343
relpath = svn_dirent_local_style(relpath, pool);
344
moved_to_line = apr_pstrcat(pool, "\n > ",
345
apr_psprintf(pool, _("moved to %s"),
351
path = svn_dirent_local_style(path, pool);
227
355
char ood_status, lock_status;
351
487
SVN_ERR(svn_wc_conflicted_p3(NULL, NULL, &tree_conflicted,
352
488
ctx->wc_ctx, local_abspath, pool));
490
path = make_relpath(target_abspath, target_path, path, pool, pool);
354
492
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
355
493
"path", svn_dirent_local_style(path, pool), NULL);
357
495
att_hash = apr_hash_make(pool);
358
apr_hash_set(att_hash, "item", APR_HASH_KEY_STRING,
359
generate_status_desc(combined_status(status)));
496
svn_hash_sets(att_hash, "item",
497
generate_status_desc(combined_status(status)));
361
apr_hash_set(att_hash, "props", APR_HASH_KEY_STRING,
362
generate_status_desc(
363
(status->node_status != svn_wc_status_deleted)
364
? status->prop_status
365
: svn_wc_status_none));
499
svn_hash_sets(att_hash, "props",
500
generate_status_desc(
501
(status->node_status != svn_wc_status_deleted)
502
? status->prop_status
503
: svn_wc_status_none));
366
504
if (status->wc_is_locked)
367
apr_hash_set(att_hash, "wc-locked", APR_HASH_KEY_STRING, "true");
505
svn_hash_sets(att_hash, "wc-locked", "true");
368
506
if (status->copied)
369
apr_hash_set(att_hash, "copied", APR_HASH_KEY_STRING, "true");
507
svn_hash_sets(att_hash, "copied", "true");
370
508
if (status->switched)
371
apr_hash_set(att_hash, "switched", APR_HASH_KEY_STRING, "true");
509
svn_hash_sets(att_hash, "switched", "true");
372
510
if (status->file_external)
373
apr_hash_set(att_hash, "file-external", APR_HASH_KEY_STRING, "true");
511
svn_hash_sets(att_hash, "file-external", "true");
374
512
if (status->versioned && ! status->copied)
375
apr_hash_set(att_hash, "revision", APR_HASH_KEY_STRING,
376
apr_psprintf(pool, "%ld", status->revision));
513
svn_hash_sets(att_hash, "revision",
514
apr_psprintf(pool, "%ld", status->revision));
377
515
if (tree_conflicted)
378
apr_hash_set(att_hash, "tree-conflicted", APR_HASH_KEY_STRING,
516
svn_hash_sets(att_hash, "tree-conflicted", "true");
517
if (status->moved_from_abspath || status->moved_to_abspath)
521
if (status->moved_from_abspath)
523
relpath = make_relpath(target_abspath, target_path,
524
status->moved_from_abspath,
526
relpath = svn_dirent_local_style(relpath, pool);
527
svn_hash_sets(att_hash, "moved-from", relpath);
529
if (status->moved_to_abspath)
531
relpath = make_relpath(target_abspath, target_path,
532
status->moved_to_abspath,
534
relpath = svn_dirent_local_style(relpath, pool);
535
svn_hash_sets(att_hash, "moved-to", relpath);
380
538
svn_xml_make_open_tag_hash(&sb, pool, svn_xml_normal, "wc-status",
437
598
&& status->repos_node_status == svn_wc_status_none))
438
599
return SVN_NO_ERROR;
440
return print_status(svn_dirent_local_style(path, pool),
601
/* If we're trying not to print boring "X /path/to/external"
603
if (suppress_externals_placeholders)
605
/* ... skip regular externals unmodified in the repository. */
606
if ((status->node_status == svn_wc_status_external)
607
&& (status->repos_node_status == svn_wc_status_none)
608
&& (! status->conflicted))
611
/* ... skip file externals that aren't modified locally or
612
remotely, changelisted, or locked (in either sense of the
614
if ((status->file_external)
615
&& (status->repos_node_status == svn_wc_status_none)
616
&& ((status->node_status == svn_wc_status_normal)
617
|| (status->node_status == svn_wc_status_none))
618
&& ((status->prop_status == svn_wc_status_normal)
619
|| (status->prop_status == svn_wc_status_none))
620
&& (! status->changelist)
622
&& (! status->wc_is_locked)
623
&& (! status->conflicted))
627
return print_status(target_abspath, target_path, path,
441
628
detailed, show_last_committed, repos_locks, status,
442
629
text_conflicts, prop_conflicts, tree_conflicts,