In the command-line client, forbid
[svn.git] / subversion / libsvn_ra_neon / mergeinfo.c
blob8968dec6ed3b405ba926830fa28bc51504ff284f
1 /*
2 * mergeinfo.c : routines for requesting and parsing mergeinfo reports
4 * ====================================================================
5 * Copyright (c) 2006 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 * ====================================================================
21 #include <apr_pools.h>
22 #include <apr_tables.h>
23 #include <apr_strings.h>
24 #include <apr_xml.h>
26 #include <ne_socket.h>
28 #include "svn_error.h"
29 #include "svn_pools.h"
30 #include "svn_path.h"
31 #include "svn_xml.h"
32 #include "svn_mergeinfo.h"
33 #include "private/svn_dav_protocol.h"
34 #include "../libsvn_ra/ra_loader.h"
36 #include "ra_neon.h"
38 /* Baton for accumulating mergeinfo. RESULT stores the final
39 mergeinfo hash result we are going to hand back to the caller of
40 get_mergeinfo. curr_path and curr_info contain the value of the
41 CDATA from the mergeinfo items as we get them from the server. */
43 struct mergeinfo_baton
45 apr_pool_t *pool;
46 const char *curr_path;
47 svn_stringbuf_t *curr_info;
48 apr_hash_t *result;
49 svn_error_t *err;
52 static const svn_ra_neon__xml_elm_t mergeinfo_report_elements[] =
54 { SVN_XML_NAMESPACE, SVN_DAV__MERGEINFO_REPORT, ELEM_mergeinfo_report, 0 },
55 { SVN_XML_NAMESPACE, SVN_DAV__MERGEINFO_ITEM, ELEM_mergeinfo_item, 0 },
56 { SVN_XML_NAMESPACE, SVN_DAV__MERGEINFO_PATH, ELEM_mergeinfo_path,
57 SVN_RA_NEON__XML_CDATA },
58 { SVN_XML_NAMESPACE, SVN_DAV__MERGEINFO_INFO, ELEM_mergeinfo_info,
59 SVN_RA_NEON__XML_CDATA },
60 { NULL }
63 static svn_error_t *
64 start_element(int *elem, void *baton, int parent_state, const char *nspace,
65 const char *elt_name, const char **atts)
67 struct mergeinfo_baton *mb = baton;
69 const svn_ra_neon__xml_elm_t *elm
70 = svn_ra_neon__lookup_xml_elem(mergeinfo_report_elements, nspace,
71 elt_name);
72 if (! elm)
74 *elem = NE_XML_DECLINE;
75 return SVN_NO_ERROR;
78 if (parent_state == ELEM_root)
80 /* If we're at the root of the tree, the element has to be the editor
81 * report itself. */
82 if (elm->id != ELEM_mergeinfo_report)
83 return UNEXPECTED_ELEMENT(nspace, elt_name);
86 if (elm->id == ELEM_mergeinfo_item)
88 svn_stringbuf_setempty(mb->curr_info);
89 mb->curr_path = NULL;
92 SVN_ERR(mb->err);
94 *elem = elm->id;
95 return SVN_NO_ERROR;
98 static svn_error_t *
99 end_element(void *baton, int state, const char *nspace, const char *elt_name)
101 struct mergeinfo_baton *mb = baton;
103 const svn_ra_neon__xml_elm_t *elm
104 = svn_ra_neon__lookup_xml_elem(mergeinfo_report_elements, nspace,
105 elt_name);
106 if (! elm)
107 return UNEXPECTED_ELEMENT(nspace, elt_name);
109 if (elm->id == ELEM_mergeinfo_item)
111 if (mb->curr_info && mb->curr_path)
113 apr_hash_t *path_mergeinfo;
115 mb->err = svn_mergeinfo_parse(&path_mergeinfo, mb->curr_info->data,
116 mb->pool);
117 SVN_ERR(mb->err);
119 apr_hash_set(mb->result, mb->curr_path, APR_HASH_KEY_STRING,
120 path_mergeinfo);
124 return SVN_NO_ERROR;
127 static svn_error_t *
128 cdata_handler(void *baton, int state, const char *cdata, size_t len)
130 struct mergeinfo_baton *mb = baton;
131 apr_size_t nlen = len;
133 switch (state)
135 case ELEM_mergeinfo_path:
136 mb->curr_path = apr_pstrndup(mb->pool, cdata, nlen);
137 break;
139 case ELEM_mergeinfo_info:
140 if (mb->curr_info)
141 svn_stringbuf_appendbytes(mb->curr_info, cdata, nlen);
142 break;
144 default:
145 break;
147 SVN_ERR(mb->err);
149 return SVN_NO_ERROR;
152 /* Request a mergeinfo-report from the URL attached to SESSION,
153 and fill in the MERGEINFO hash with the results. */
154 svn_error_t *
155 svn_ra_neon__get_mergeinfo(svn_ra_session_t *session,
156 apr_hash_t **mergeinfo,
157 const apr_array_header_t *paths,
158 svn_revnum_t revision,
159 svn_mergeinfo_inheritance_t inherit,
160 apr_pool_t *pool)
162 int i, status_code;
163 svn_ra_neon__session_t *ras = session->priv;
164 svn_stringbuf_t *request_body = svn_stringbuf_create("", pool);
165 struct mergeinfo_baton mb;
166 svn_string_t bc_url, bc_relative;
167 const char *final_bc_url;
169 static const char minfo_report_head[] =
170 "<S:" SVN_DAV__MERGEINFO_REPORT " xmlns:S=\"" SVN_XML_NAMESPACE "\">"
171 DEBUG_CR;
173 static const char minfo_report_tail[] =
174 "</S:" SVN_DAV__MERGEINFO_REPORT ">" DEBUG_CR;
176 /* Construct the request body. */
177 svn_stringbuf_appendcstr(request_body, minfo_report_head);
178 svn_stringbuf_appendcstr(request_body,
179 apr_psprintf(pool,
180 "<S:revision>%ld"
181 "</S:revision>", revision));
182 svn_stringbuf_appendcstr(request_body,
183 apr_psprintf(pool,
184 "<S:inherit>%s"
185 "</S:inherit>",
186 svn_inheritance_to_word(inherit)));
187 if (paths)
189 for (i = 0; i < paths->nelts; i++)
191 const char *this_path =
192 apr_xml_quote_string(pool,
193 ((const char **)paths->elts)[i],
195 svn_stringbuf_appendcstr(request_body, "<S:path>");
196 svn_stringbuf_appendcstr(request_body, this_path);
197 svn_stringbuf_appendcstr(request_body, "</S:path>");
201 svn_stringbuf_appendcstr(request_body, minfo_report_tail);
203 mb.pool = pool;
204 mb.curr_path = NULL;
205 mb.curr_info = svn_stringbuf_create("", pool);
206 mb.result = apr_hash_make(pool);
207 mb.err = SVN_NO_ERROR;
209 /* ras's URL may not exist in HEAD, and thus it's not safe to send
210 it as the main argument to the REPORT request; it might cause
211 dav_get_resource() to choke on the server. So instead, we pass a
212 baseline-collection URL, which we get from END. */
213 SVN_ERR(svn_ra_neon__get_baseline_info(NULL, &bc_url, &bc_relative, NULL,
214 ras, ras->url->data, revision,
215 pool));
216 final_bc_url = svn_path_url_add_component(bc_url.data, bc_relative.data,
217 pool);
219 SVN_ERR(svn_ra_neon__parsed_request(ras,
220 "REPORT",
221 final_bc_url,
222 request_body->data,
223 NULL, NULL,
224 start_element,
225 cdata_handler,
226 end_element,
227 &mb,
228 NULL,
229 &status_code,
230 FALSE,
231 pool));
233 if (mb.err == SVN_NO_ERROR)
234 *mergeinfo = mb.result;
236 return mb.err;