In the command-line client, forbid
[svn.git] / subversion / svn / mergeinfo-cmd.c
blob2ee56c019062de17ee0f5470a669095c99acebf9
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_opt_args_to_target_array2(&targets, os,
135 opt_state->targets, pool));
137 /* Add "." if user passed 0 arguments. */
138 svn_opt_push_implicit_dot_target(targets, pool);
140 for (i = 0; i < targets->nelts; i++)
142 const char *target = APR_ARRAY_IDX(targets, i, const char *);
143 const char *truepath;
144 svn_opt_revision_t peg_revision;
145 apr_hash_t *mergeinfo;
146 const char *root_url;
147 apr_hash_index_t *hi;
149 svn_pool_clear(subpool);
150 SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
152 /* Parse the path into a path and peg revision. */
153 SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target, subpool));
155 /* If no peg-rev was attached to a URL target, then assume HEAD. */
156 if ((peg_revision.kind == svn_opt_revision_unspecified)
157 && svn_path_is_url(target))
158 peg_revision.kind = svn_opt_revision_head;
160 /* If no peg-rev was attached to a non-URL target, then assume BASE. */
161 if ((peg_revision.kind == svn_opt_revision_unspecified)
162 && (! svn_path_is_url(target)))
163 peg_revision.kind = svn_opt_revision_base;
165 /* Get the already-merged information. */
166 SVN_ERR(svn_client_mergeinfo_get_merged(&mergeinfo, truepath,
167 &peg_revision, ctx, subpool));
169 svn_cmdline_printf(pool, _("Path: %s\n"),
170 svn_path_local_style(truepath, pool));
171 if (mergeinfo == NULL)
172 mergeinfo = apr_hash_make(pool);
174 SVN_ERR(svn_client_root_url_from_path(&root_url, truepath, ctx, pool));
176 if (opt_state->from_source)
178 apr_array_header_t *merged_ranges =
179 apr_hash_get(mergeinfo, opt_state->from_source,
180 APR_HASH_KEY_STRING);
181 if (! merged_ranges)
182 merged_ranges = apr_array_make(pool, 1,
183 sizeof(svn_merge_range_t *));
184 SVN_ERR(show_mergeinfo_for_source(opt_state->from_source,
185 merged_ranges, truepath,
186 &peg_revision, root_url,
187 ctx, subpool));
189 else if (apr_hash_count(mergeinfo) > 0)
191 apr_pool_t *iterpool = svn_pool_create(subpool);
192 for (hi = apr_hash_first(NULL, mergeinfo);
193 hi; hi = apr_hash_next(hi))
195 const void *key;
196 void *val;
198 svn_pool_clear(iterpool);
199 apr_hash_this(hi, &key, NULL, &val);
200 SVN_ERR(show_mergeinfo_for_source(key, val, truepath,
201 &peg_revision, root_url,
202 ctx, iterpool));
204 svn_pool_destroy(iterpool);
206 svn_cmdline_printf(subpool, "\n");
209 svn_pool_destroy(subpool);
210 return SVN_NO_ERROR;