55
55
return SVN_NO_ERROR;
58
/* Draw a diagram (by printing text to the console) summarizing the state
59
* of merging between two branches, given the merge description
60
* indicated by YCA, BASE, RIGHT, TARGET, REINTEGRATE_LIKE. */
62
mergeinfo_diagram(const char *yca_url,
64
const char *right_url,
65
const char *target_url,
67
svn_revnum_t base_rev,
68
svn_revnum_t right_rev,
69
svn_revnum_t target_rev,
70
const char *repos_root_url,
71
svn_boolean_t target_is_wc,
72
svn_boolean_t reintegrate_like,
75
/* The graph occupies 4 rows of text, and the annotations occupy
76
* another 2 rows above and 2 rows below. The graph is constructed
77
* from left to right in discrete sections ("columns"), each of which
78
* can have a different width (measured in characters). Each element in
79
* the array is either a text string of the appropriate width, or can
80
* be NULL to draw a blank cell. */
83
const char *g[ROWS][COLS] = {{0}};
87
/* The YCA (that is, the branching point). And an ellipsis, because we
88
* don't show information about earlier merges */
89
g[0][0] = apr_psprintf(pool, " %-8ld ", yca_rev);
91
if (strcmp(yca_url, right_url) == 0)
93
g[2][0] = "-------| |--";
98
else if (strcmp(yca_url, target_url) == 0)
100
g[2][0] = " --| |--";
103
g[5][0] = "-------| |--";
107
g[2][0] = " --| |--";
110
g[5][0] = " --| |--";
113
/* The last full merge */
114
if ((base_rev > yca_rev) && reintegrate_like)
116
g[2][2] = "---------";
119
g[5][2] = "---------";
121
g[7][2] = apr_psprintf(pool, "%-8ld ", base_rev);
123
else if (base_rev > yca_rev)
125
g[0][2] = apr_psprintf(pool, "%-8ld ", base_rev);
127
g[2][2] = "---------";
130
g[5][2] = "---------";
134
g[2][2] = "---------";
137
g[5][2] = "---------";
140
/* The tips of the branches */
142
g[0][3] = apr_psprintf(pool, "%-8ld", right_rev);
149
g[7][3] = target_is_wc ? "WC "
150
: apr_psprintf(pool, "%-8ld", target_rev);
153
/* Find the width of each column, so we know how to print blank cells */
154
for (col = 0; col < COLS; col++)
157
for (row = 0; row < ROWS; row++)
159
if (g[row][col] && ((int)strlen(g[row][col]) > col_width[col]))
160
col_width[col] = (int)strlen(g[row][col]);
164
/* Column headings */
165
SVN_ERR(svn_cmdline_printf(pool,
171
_("youngest common ancestor"), _("last full merge"),
172
_("tip of branch"), _("repository path")));
174
/* Print the diagram, row by row */
175
for (row = 0; row < ROWS; row++)
177
SVN_ERR(svn_cmdline_fputs(" ", stdout, pool));
178
for (col = 0; col < COLS; col++)
182
SVN_ERR(svn_cmdline_fputs(g[row][col], stdout, pool));
186
/* Print <column-width> spaces */
187
SVN_ERR(svn_cmdline_printf(pool, "%*s", col_width[col], ""));
191
SVN_ERR(svn_cmdline_printf(pool, " %s",
192
svn_uri_skip_ancestor(repos_root_url, right_url, pool)));
194
SVN_ERR(svn_cmdline_printf(pool, " %s",
195
svn_uri_skip_ancestor(repos_root_url, target_url, pool)));
196
SVN_ERR(svn_cmdline_fputs("\n", stdout, pool));
202
/* Display a summary of the state of merging between the two branches
203
* SOURCE_PATH_OR_URL@SOURCE_REVISION and
204
* TARGET_PATH_OR_URL@TARGET_REVISION. */
207
const char *source_path_or_url,
208
const svn_opt_revision_t *source_revision,
209
const char *target_path_or_url,
210
const svn_opt_revision_t *target_revision,
211
svn_client_ctx_t *ctx,
214
const char *yca_url, *base_url, *right_url, *target_url;
215
svn_revnum_t yca_rev, base_rev, right_rev, target_rev;
216
const char *repos_root_url;
217
svn_boolean_t target_is_wc, is_reintegration;
219
target_is_wc = (! svn_path_is_url(target_path_or_url))
220
&& (target_revision->kind == svn_opt_revision_unspecified
221
|| target_revision->kind == svn_opt_revision_working);
222
SVN_ERR(svn_client_get_merging_summary(
225
&base_url, &base_rev,
226
&right_url, &right_rev,
227
&target_url, &target_rev,
229
source_path_or_url, source_revision,
230
target_path_or_url, target_revision,
233
SVN_ERR(mergeinfo_diagram(yca_url, base_url, right_url, target_url,
234
yca_rev, base_rev, right_rev, target_rev,
235
repos_root_url, target_is_wc, is_reintegration,
58
241
/* This implements the `svn_opt_subcommand_t' interface. */
60
243
svn_cl__mergeinfo(apr_getopt_t *os,
66
249
apr_array_header_t *targets;
67
250
const char *source, *target;
68
251
svn_opt_revision_t src_peg_revision, tgt_peg_revision;
252
svn_opt_revision_t *src_start_revision, *src_end_revision;
69
253
/* Default to depth empty. */
70
svn_depth_t depth = opt_state->depth == svn_depth_unknown
71
? svn_depth_empty : opt_state->depth;
254
svn_depth_t depth = (opt_state->depth == svn_depth_unknown)
255
? svn_depth_empty : opt_state->depth;
73
257
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
74
258
opt_state->targets,
75
259
ctx, FALSE, pool));
77
/* We expect a single source URL followed by a single target --
78
nothing more, nothing less. */
261
/* Parse the arguments: SOURCE[@REV] optionally followed by TARGET[@REV]. */
79
262
if (targets->nelts < 1)
80
263
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
81
264
_("Not enough arguments given"));
82
265
if (targets->nelts > 2)
83
266
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
84
267
_("Too many arguments given"));
86
/* Parse the SOURCE-URL[@REV] argument. */
87
268
SVN_ERR(svn_opt_parse_path(&src_peg_revision, &source,
88
269
APR_ARRAY_IDX(targets, 0, const char *), pool));
90
/* Parse the TARGET[@REV] argument (if provided). */
91
270
if (targets->nelts == 2)
93
272
SVN_ERR(svn_opt_parse_path(&tgt_peg_revision, &target,
114
297
tgt_peg_revision.kind = svn_opt_revision_base;
300
src_start_revision = &(opt_state->start_revision);
301
if (opt_state->end_revision.kind == svn_opt_revision_unspecified)
302
src_end_revision = src_start_revision;
304
src_end_revision = &(opt_state->end_revision);
117
306
/* Do the real work, depending on the requested data flavor. */
118
307
if (opt_state->show_revs == svn_cl__show_revs_merged)
120
SVN_ERR(svn_client_mergeinfo_log(TRUE, target, &tgt_peg_revision,
121
source, &src_peg_revision,
123
TRUE, depth, NULL, ctx,
309
apr_array_header_t *revprops;
311
/* We need only revisions number, not revision properties. */
312
revprops = apr_array_make(pool, 0, sizeof(const char *));
314
SVN_ERR(svn_client_mergeinfo_log2(TRUE, target, &tgt_peg_revision,
315
source, &src_peg_revision,
319
TRUE, depth, revprops, ctx,
126
322
else if (opt_state->show_revs == svn_cl__show_revs_eligible)
128
SVN_ERR(svn_client_mergeinfo_log(FALSE, target, &tgt_peg_revision,
129
source, &src_peg_revision,
131
TRUE, depth, NULL, ctx,
324
apr_array_header_t *revprops;
326
/* We need only revisions number, not revision properties. */
327
revprops = apr_array_make(pool, 0, sizeof(const char *));
329
SVN_ERR(svn_client_mergeinfo_log2(FALSE, target, &tgt_peg_revision,
330
source, &src_peg_revision,
334
TRUE, depth, revprops, ctx,
339
if ((opt_state->start_revision.kind != svn_opt_revision_unspecified)
340
|| (opt_state->end_revision.kind != svn_opt_revision_unspecified))
341
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
342
_("--revision (-r) option valid only with "
343
"--show-revs option"));
344
if (opt_state->depth != svn_depth_unknown)
345
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
346
_("Depth specification options valid only "
347
"with --show-revs option"));
349
SVN_ERR(mergeinfo_summary(source, &src_peg_revision,
350
target, &tgt_peg_revision,
134
353
return SVN_NO_ERROR;