Followup to r29625: fix getopt tests.
[svn.git] / subversion / svn / mergeinfo-cmd.c
blob254179b80a81cb81e8ffc950ec2365f00e4d637e
1 /*
2 * mergeinfo-cmd.c -- Query merge-relative info.
4 * ====================================================================
5 * Copyright (c) 2007 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. ***/
25 #include "svn_pools.h"
26 #include "svn_client.h"
27 #include "svn_cmdline.h"
28 #include "svn_path.h"
29 #include "svn_error.h"
30 #include "svn_error_codes.h"
31 #include "svn_types.h"
32 #include "cl.h"
34 #include "svn_private_config.h"
37 /*** Code. ***/
39 static void
40 print_merge_ranges(apr_array_header_t *ranges, apr_pool_t *pool)
42 int i;
43 for (i = 0; i < ranges->nelts; i++)
45 svn_merge_range_t *range = APR_ARRAY_IDX(ranges, i, svn_merge_range_t *);
46 svn_cmdline_printf(pool, "r%ld:%ld%s", range->start, range->end,
47 (i == (ranges->nelts - 1)) ? "" : ", ");
49 svn_cmdline_printf(pool, "\n");
53 static const char *
54 relative_path(const char *root_url,
55 const char *url,
56 apr_pool_t *pool)
58 const char *relurl = svn_path_is_child(root_url, url, pool);
59 return relurl ? apr_pstrcat(pool, "/",
60 svn_path_uri_decode(relurl, pool), NULL)
61 : "/";
65 static svn_error_t *
66 show_mergeinfo_for_source(const char *merge_source,
67 apr_array_header_t *merge_ranges,
68 const char *path,
69 svn_opt_revision_t *peg_revision,
70 const char *root_url,
71 svn_client_ctx_t *ctx,
72 apr_pool_t *pool)
74 apr_array_header_t *available_ranges;
75 svn_error_t *err;
77 svn_cmdline_printf(pool, _(" Source path: %s\n"),
78 relative_path(root_url, merge_source, pool));
79 svn_cmdline_printf(pool, _(" Merged ranges: "));
80 print_merge_ranges(merge_ranges, pool);
82 /* Now fetch the available merges for this source. */
84 /* ### FIXME: There's no reason why this API should fail to
85 ### answer the question (when asked of a 1.5+ server),
86 ### short of something being quite wrong with the
87 ### question. Certainly, that the merge source URL can't
88 ### be found in HEAD shouldn't mean we can't get any
89 ### decent information about it out of the system. It
90 ### may just mean the system has to work harder to
91 ### provide that information.
93 svn_cmdline_printf(pool, _(" Eligible ranges: "));
94 err = svn_client_mergeinfo_get_available(&available_ranges,
95 path,
96 peg_revision,
97 merge_source,
98 ctx,
99 pool);
100 if (err)
102 if ((err->apr_err == SVN_ERR_FS_NOT_FOUND)
103 || (err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND))
105 svn_error_clear(err);
106 svn_cmdline_printf(pool, _("(source no longer available "
107 "in HEAD)\n"));
109 else
111 svn_cmdline_printf(pool, "\n");
112 return err;
115 else
117 print_merge_ranges(available_ranges, pool);
119 return SVN_NO_ERROR;
122 /* This implements the `svn_opt_subcommand_t' interface. */
123 svn_error_t *
124 svn_cl__mergeinfo(apr_getopt_t *os,
125 void *baton,
126 apr_pool_t *pool)
128 svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
129 svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
130 apr_array_header_t *targets;
131 apr_pool_t *subpool = svn_pool_create(pool);
132 int i;
134 SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
135 opt_state->targets,
136 pool));
138 /* Add "." if user passed 0 arguments. */
139 svn_opt_push_implicit_dot_target(targets, pool);
141 for (i = 0; i < targets->nelts; i++)
143 const char *target = APR_ARRAY_IDX(targets, i, const char *);
144 const char *truepath;
145 svn_opt_revision_t peg_revision;
146 svn_mergeinfo_t mergeinfo;
147 const char *root_url;
148 apr_hash_index_t *hi;
150 svn_pool_clear(subpool);
151 SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
153 /* Parse the path into a path and peg revision. */
154 SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target, subpool));
156 /* If no peg-rev was attached to a URL target, then assume HEAD. */
157 if ((peg_revision.kind == svn_opt_revision_unspecified)
158 && svn_path_is_url(target))
159 peg_revision.kind = svn_opt_revision_head;
161 /* If no peg-rev was attached to a non-URL target, then assume BASE. */
162 if ((peg_revision.kind == svn_opt_revision_unspecified)
163 && (! svn_path_is_url(target)))
164 peg_revision.kind = svn_opt_revision_base;
166 /* Get the already-merged information. */
167 SVN_ERR(svn_client_mergeinfo_get_merged(&mergeinfo, truepath,
168 &peg_revision, ctx, subpool));
170 svn_cmdline_printf(pool, _("Path: %s\n"),
171 svn_path_local_style(truepath, pool));
172 if (mergeinfo == NULL)
173 mergeinfo = apr_hash_make(pool);
175 SVN_ERR(svn_client_root_url_from_path(&root_url, truepath, ctx, pool));
177 if (opt_state->from_source)
179 apr_array_header_t *merged_ranges =
180 apr_hash_get(mergeinfo, opt_state->from_source,
181 APR_HASH_KEY_STRING);
182 if (! merged_ranges)
183 merged_ranges = apr_array_make(pool, 1,
184 sizeof(svn_merge_range_t *));
185 SVN_ERR(show_mergeinfo_for_source(opt_state->from_source,
186 merged_ranges, truepath,
187 &peg_revision, root_url,
188 ctx, subpool));
190 else if (apr_hash_count(mergeinfo) > 0)
192 apr_pool_t *iterpool = svn_pool_create(subpool);
193 for (hi = apr_hash_first(NULL, mergeinfo);
194 hi; hi = apr_hash_next(hi))
196 const void *key;
197 void *val;
199 svn_pool_clear(iterpool);
200 apr_hash_this(hi, &key, NULL, &val);
201 SVN_ERR(show_mergeinfo_for_source(key, val, truepath,
202 &peg_revision, root_url,
203 ctx, iterpool));
205 svn_pool_destroy(iterpool);
207 svn_cmdline_printf(subpool, "\n");
210 svn_pool_destroy(subpool);
211 return SVN_NO_ERROR;