1/*
2 * mergeinfo.h : Client library-internal mergeinfo APIs.
3 *
4 * ====================================================================
5 *    Licensed to the Apache Software Foundation (ASF) under one
6 *    or more contributor license agreements.  See the NOTICE file
7 *    distributed with this work for additional information
8 *    regarding copyright ownership.  The ASF licenses this file
9 *    to you under the Apache License, Version 2.0 (the
10 *    "License"); you may not use this file except in compliance
11 *    with the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 *    Unless required by applicable law or agreed to in writing,
16 *    software distributed under the License is distributed on an
17 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 *    KIND, either express or implied.  See the License for the
19 *    specific language governing permissions and limitations
20 *    under the License.
21 * ====================================================================
22 */
23
24#ifndef SVN_LIBSVN_CLIENT_MERGEINFO_H
25#define SVN_LIBSVN_CLIENT_MERGEINFO_H
26
27#include "svn_wc.h"
28#include "svn_client.h"
29#include "private/svn_client_private.h"
30
31
32/*** Data Structures ***/
33
34
35/* Structure to store information about working copy paths that need special
36   consideration during a mergeinfo aware merge -- See the
37   'THE CHILDREN_WITH_MERGEINFO ARRAY' meta comment and the doc string for the
38   function get_mergeinfo_paths() in libsvn_client/merge.c.
39*/
40typedef struct svn_client__merge_path_t
41{
42  const char *abspath;               /* Absolute working copy path. */
43  svn_boolean_t missing_child;       /* ABSPATH has an immediate child which
44                                        is missing, but is not switched. */
45  svn_boolean_t switched_child;      /* ABSPATH has an immediate child which
46                                        is switched. */
47  svn_boolean_t switched;            /* ABSPATH is switched. */
48  svn_boolean_t has_noninheritable;  /* ABSPATH has svn:mergeinfo set on it
49                                        which includes non-inheritable
50                                        revision ranges. */
51  svn_boolean_t absent;              /* ABSPATH is absent from the WC,
52                                        probably due to authz
53                                        restrictions. */
54
55  svn_boolean_t child_of_noninheritable; /* ABSPATH has no explicit mergeinfo
56                                            itself but is the child of a
57                                            path with noniheritable
58                                            mergeinfo. */
59
60  /* The remaining ranges to be merged to ABSPATH.  When describing a forward
61     merge this rangelist adheres to the rules for rangelists described in
62     svn_mergeinfo.h.  However, when describing reverse merges this
63     rangelist can contain reverse merge ranges that are not sorted per
64     svn_sort_compare_ranges(), but rather are sorted such that the ranges
65     with the youngest start revisions come first.  In both the forward and
66     reverse merge cases the ranges should never overlap.  This rangelist
67     may be empty but should never be NULL unless ABSENT is true. */
68  svn_rangelist_t *remaining_ranges;
69
70  svn_mergeinfo_t pre_merge_mergeinfo;  /* Explicit or inherited mergeinfo
71                                           on ABSPATH prior to a merge.
72                                           May be NULL. */
73  svn_mergeinfo_t implicit_mergeinfo;   /* Implicit mergeinfo on ABSPATH
74                                           prior to a merge.  May be NULL. */
75  svn_boolean_t inherited_mergeinfo;    /* Whether PRE_MERGE_MERGEINFO was
76                                           explicit or inherited. */
77  svn_boolean_t immediate_child_dir;    /* ABSPATH is an immediate child
78                                           directory of the merge target,
79                                           has no explicit mergeinfo prior
80                                           to the merge, and the operational
81                                           depth of the merge is
82                                           svn_depth_immediates. */
83  svn_boolean_t record_mergeinfo;       /* Mergeinfo needs to be recorded
84                                           on ABSPATH to describe the
85                                           merge. */
86  svn_boolean_t record_noninheritable;  /* Non-inheritable mergeinfo needs to
87                                           be recorded on ABSPATH to describe
88                                           the merge. Implies RECORD_MERGEINFO
89                                           is true. */
90} svn_client__merge_path_t;
91
92/* Return a deep copy of the merge-path structure OLD, allocated in POOL. */
93svn_client__merge_path_t *
94svn_client__merge_path_dup(const svn_client__merge_path_t *old,
95                           apr_pool_t *pool);
96
97/* Create a new merge path structure, allocated in POOL.  Initialize the
98 * 'abspath' member to a deep copy of ABSPATH and all other fields to zero
99 * bytes. */
100svn_client__merge_path_t *
101svn_client__merge_path_create(const char *abspath,
102                              apr_pool_t *pool);
103
104
105
106/*** Functions ***/
107
108/* Find explicit or inherited WC mergeinfo for LOCAL_ABSPATH, and return it
109   in *MERGEINFO (NULL if no mergeinfo is set).  Set *INHERITED to
110   whether the mergeinfo was inherited (TRUE or FALSE), if INHERITED is
111   non-null.
112
113   This function will search for inherited mergeinfo in the parents of
114   LOCAL_ABSPATH only if the base revision of LOCAL_ABSPATH falls within
115   the range of the parent's last committed revision to the parent's base
116   revision (inclusive) or is LOCAL_ABSPATH is a local addition.  If asking
117   for the inherited mergeinfo of an added path (i.e. one with no base
118   revision), that path may inherit mergeinfo from its nearest parent
119   with a base revision and explicit mergeinfo.
120
121   INHERIT indicates whether explicit, explicit or inherited, or only
122   inherited mergeinfo for LOCAL_ABSPATH is retrieved.
123
124   Don't look for inherited mergeinfo any higher than LIMIT_ABSPATH
125   (ignored if NULL) or beyond any switched path.
126
127   Set *WALKED_PATH to the path climbed from LOCAL_ABSPATH to find inherited
128   mergeinfo, or "" if none was found. (ignored if NULL).
129
130   If IGNORE_INVALID_MERGEINFO is true, then syntactically invalid explicit
131   mergeinfo on found on LOCAL_ABSPATH is ignored and *MERGEINFO is set to an
132   empty hash.  If IGNORE_INVALID_MERGEINFO is false, then syntactically
133   invalid explicit mergeinfo on found on LOCAL_ABSPATH results in a
134   SVN_ERR_MERGEINFO_PARSE_ERROR error.  Regardless of
135   IGNORE_INVALID_MERGEINFO, if LOCAL_ABSPATH inherits invalid mergeinfo,
136   then *MERGEINFO is always set to an empty hash and no parse error is
137   raised. */
138svn_error_t *
139svn_client__get_wc_mergeinfo(svn_mergeinfo_t *mergeinfo,
140                             svn_boolean_t *inherited,
141                             svn_mergeinfo_inheritance_t inherit,
142                             const char *local_abspath,
143                             const char *limit_abspath,
144                             const char **walked_path,
145                             svn_boolean_t ignore_invalid_mergeinfo,
146                             svn_client_ctx_t *ctx,
147                             apr_pool_t *result_pool,
148                             apr_pool_t *scratch_pool);
149
150/* If INCLUDE_DESCENDANTS is FALSE, behave exactly like
151   svn_client__get_wc_mergeinfo() except the mergeinfo for LOCAL_ABSPATH is
152   put in the mergeinfo catalog MERGEINFO_CAT, mapped from LOCAL_ABSPATH's
153   repository root-relative path.
154
155   If INCLUDE_DESCENDANTS is true, then any subtrees under LOCAL_ABSPATH with
156   explicit mergeinfo are also included in MERGEINFO_CAT and again the
157   keys are the repository root-relative paths of the subtrees.  If no
158   mergeinfo is found, then *MERGEINFO_CAT is set to NULL. */
159svn_error_t *
160svn_client__get_wc_mergeinfo_catalog(svn_mergeinfo_catalog_t *mergeinfo_cat,
161                                     svn_boolean_t *inherited,
162                                     svn_boolean_t include_descendants,
163                                     svn_mergeinfo_inheritance_t inherit,
164                                     const char *local_abspath,
165                                     const char *limit_path,
166                                     const char **walked_path,
167                                     svn_boolean_t ignore_invalid_mergeinfo,
168                                     svn_client_ctx_t *ctx,
169                                     apr_pool_t *result_pool,
170                                     apr_pool_t *scratch_pool);
171
172/* Obtain any mergeinfo for URL from the repository, and set
173   it in *TARGET_MERGEINFO.
174
175   INHERIT indicates whether explicit, explicit or inherited, or only
176   inherited mergeinfo for URL is obtained.
177
178   If URL does not exist at REV, SVN_ERR_FS_NOT_FOUND or
179   SVN_ERR_RA_DAV_REQUEST_FAILED is returned and *TARGET_MERGEINFO
180   is untouched.
181
182   If there is no mergeinfo available for URL, or if the server
183   doesn't support a mergeinfo capability and SQUELCH_INCAPABLE is
184   TRUE, set *TARGET_MERGEINFO to NULL. If the server doesn't support
185   a mergeinfo capability and SQUELCH_INCAPABLE is FALSE, return an
186   SVN_ERR_UNSUPPORTED_FEATURE error.
187
188   RA_SESSION is an open RA session to the repository in which URL lives;
189   it may be temporarily reparented by this function.
190*/
191svn_error_t *
192svn_client__get_repos_mergeinfo(svn_mergeinfo_t *target_mergeinfo,
193                                svn_ra_session_t *ra_session,
194                                const char *url,
195                                svn_revnum_t rev,
196                                svn_mergeinfo_inheritance_t inherit,
197                                svn_boolean_t squelch_incapable,
198                                apr_pool_t *pool);
199
200/* If INCLUDE_DESCENDANTS is FALSE, behave exactly like
201   svn_client__get_repos_mergeinfo() except the mergeinfo for URL
202   is put in the mergeinfo catalog MERGEINFO_CAT, with the key being
203   the repository root-relative path of URL.
204
205   If INCLUDE_DESCENDANTS is true, then any subtrees under URL
206   with explicit mergeinfo are also included in MERGEINFO_CAT.  The
207   keys for the subtree mergeinfo are the repository root-relative
208   paths of the subtrees.  If no mergeinfo is found, then
209   *TARGET_MERGEINFO_CAT is set to NULL. */
210svn_error_t *
211svn_client__get_repos_mergeinfo_catalog(svn_mergeinfo_catalog_t *mergeinfo_cat,
212                                        svn_ra_session_t *ra_session,
213                                        const char *url,
214                                        svn_revnum_t rev,
215                                        svn_mergeinfo_inheritance_t inherit,
216                                        svn_boolean_t squelch_incapable,
217                                        svn_boolean_t include_descendants,
218                                        apr_pool_t *result_pool,
219                                        apr_pool_t *scratch_pool);
220
221/* Retrieve the direct mergeinfo for the TARGET_WCPATH from the WC's
222   mergeinfo prop, or that inherited from its nearest ancestor if the
223   target has no info of its own.
224
225   If no mergeinfo can be obtained from the WC or REPOS_ONLY is TRUE,
226   get it from the repository.  If the repository is contacted for mergeinfo
227   and RA_SESSION does not point to TARGET_WCPATH's URL, then it is
228   temporarily reparented.  If RA_SESSION is NULL, then a temporary session
229   is opened as needed.
230
231   Store any mergeinfo obtained for TARGET_WCPATH in
232   *TARGET_MERGEINFO, if no mergeinfo is found *TARGET_MERGEINFO is
233   NULL.
234
235   Like svn_client__get_wc_mergeinfo(), this function considers no
236   inherited mergeinfo to be found in the WC when trying to crawl into
237   a parent path with a different working revision.
238
239   INHERIT indicates whether explicit, explicit or inherited, or only
240   inherited mergeinfo for TARGET_WCPATH is retrieved.
241
242   If FROM_REPOS is not NULL, then set *FROM_REPOS to true if
243   *TARGET_MERGEINFO is inherited and the repository was contacted to
244   obtain it.  Set *FROM_REPOS to false otherwise.
245
246   If TARGET_WCPATH inherited its mergeinfo from a working copy ancestor
247   or if it was obtained from the repository, set *INHERITED to TRUE, set it
248   to FALSE otherwise, if INHERITED is non-null. */
249svn_error_t *
250svn_client__get_wc_or_repos_mergeinfo(svn_mergeinfo_t *target_mergeinfo,
251                                      svn_boolean_t *inherited,
252                                      svn_boolean_t *from_repos,
253                                      svn_boolean_t repos_only,
254                                      svn_mergeinfo_inheritance_t inherit,
255                                      svn_ra_session_t *ra_session,
256                                      const char *target_wcpath,
257                                      svn_client_ctx_t *ctx,
258                                      apr_pool_t *pool);
259
260/* If INCLUDE_DESCENDANTS is false then behaves exactly like
261   svn_client__get_wc_or_repos_mergeinfo() except the mergeinfo for
262   TARGET_WCPATH is put in the mergeinfo catalog
263   TARGET_MERGEINFO_CATALOG, mapped from TARGET_WCPATH's repository
264   root-relative path.
265
266   IGNORE_INVALID_MERGEINFO behaves as per the argument of the same
267   name to svn_client__get_wc_mergeinfo().  It is applicable only if
268   the mergeinfo for TARGET_WCPATH is obtained from the working copy.
269
270   If INCLUDE_DESCENDANTS is true, then any subtrees under
271   TARGET_WCPATH with explicit mergeinfo are also included in
272   TARGET_MERGEINFO_CATALOG and again the keys are the repository
273   root-relative paths of the subtrees.  If no mergeinfo is found,
274   then *TARGET_MERGEINFO_CAT is set to NULL. */
275svn_error_t *
276svn_client__get_wc_or_repos_mergeinfo_catalog(
277  svn_mergeinfo_catalog_t *target_mergeinfo_catalog,
278  svn_boolean_t *inherited,
279  svn_boolean_t *from_repos,
280  svn_boolean_t include_descendants,
281  svn_boolean_t repos_only,
282  svn_boolean_t ignore_invalid_mergeinfo,
283  svn_mergeinfo_inheritance_t inherit,
284  svn_ra_session_t *ra_session,
285  const char *target_wcpath,
286  svn_client_ctx_t *ctx,
287  apr_pool_t *result_pool,
288  apr_pool_t *scratch_pool);
289
290/* Set *MERGEINFO_P to a mergeinfo constructed solely from the
291   natural history of PATHREV.
292
293   If RANGE_YOUNGEST and RANGE_OLDEST are valid, use them as inclusive
294   bounds on the revision ranges of returned mergeinfo.  PATHREV->rev,
295   RANGE_YOUNGEST and RANGE_OLDEST are governed by the same rules as the
296   PEG_REVISION, START_REV, and END_REV parameters (respectively) of
297   svn_ra_get_location_segments().
298
299   If HAS_REV_ZERO_HISTORY is not NULL, then set *HAS_REV_ZERO_HISTORY to
300   TRUE if the natural history includes revision 0, else to FALSE.
301
302   RA_SESSION is an open RA session to the repository of PATHREV;
303   it may be temporarily reparented by this function.
304*/
305svn_error_t *
306svn_client__get_history_as_mergeinfo(svn_mergeinfo_t *mergeinfo_p,
307                                     svn_boolean_t *has_rev_zero_history,
308                                     const svn_client__pathrev_t *pathrev,
309                                     svn_revnum_t range_youngest,
310                                     svn_revnum_t range_oldest,
311                                     svn_ra_session_t *ra_session,
312                                     svn_client_ctx_t *ctx,
313                                     apr_pool_t *pool);
314
315/* Parse any explicit mergeinfo on LOCAL_ABSPATH and store it in
316   *MERGEINFO.  If no record of any mergeinfo exists, set *MERGEINFO to NULL.
317   Does not acount for inherited mergeinfo.
318
319   Allocate the result deeply in @a result_pool. */
320svn_error_t *
321svn_client__parse_mergeinfo(svn_mergeinfo_t *mergeinfo,
322                            svn_wc_context_t *wc_ctx,
323                            const char *local_abspath,
324                            apr_pool_t *result_pool,
325                            apr_pool_t *scratch_pool);
326
327/* Write MERGEINFO into the WC for LOCAL_ABSPATH.  If MERGEINFO is NULL,
328   remove any SVN_PROP_MERGEINFO for LOCAL_ABSPATH.  If MERGEINFO is empty,
329   record an empty property value (e.g. "").  If CTX->NOTIFY_FUNC2 is
330   not null call it with notification type svn_wc_notify_merge_record_info
331   if DO_NOTIFICATION is true.
332
333   Use WC_CTX to access the working copy, and SCRATCH_POOL for any temporary
334   allocations. */
335svn_error_t *
336svn_client__record_wc_mergeinfo(const char *local_abspath,
337                                svn_mergeinfo_t mergeinfo,
338                                svn_boolean_t do_notification,
339                                svn_client_ctx_t *ctx,
340                                apr_pool_t *scratch_pool);
341
342/* Write mergeinfo into the WC.
343 *
344 * For each path in RESULT_CATALOG, set the SVN_PROP_MERGEINFO
345 * property to represent the given mergeinfo, or remove the property
346 * if the given mergeinfo is null, and notify the change.  Leave
347 * other paths unchanged.  RESULT_CATALOG maps (const char *) WC paths
348 * to (svn_mergeinfo_t) mergeinfo. */
349svn_error_t *
350svn_client__record_wc_mergeinfo_catalog(apr_hash_t *result_catalog,
351                                        svn_client_ctx_t *ctx,
352                                        apr_pool_t *scratch_pool);
353
354/* Elide any svn:mergeinfo set on TARGET_ABSPATH to its nearest working
355   copy (or possibly repository) ancestor with equivalent mergeinfo.
356
357   If WC_ELISION_LIMIT_ABSPATH is NULL check up to the root of the
358   working copy or the nearest switched parent for an elision
359   destination, if none is found check the repository, otherwise check
360   as far as WC_ELISION_LIMIT_ABSPATH within the working copy.
361
362   Elision occurs if:
363
364     A) TARGET_ABSPATH has empty mergeinfo and no parent path with
365        explicit mergeinfo can be found in either the WC or the
366        repository (WC_ELISION_LIMIT_PATH must be NULL for this to
367        occur).
368
369     B) TARGET_ABSPATH has empty mergeinfo and its nearest parent also
370        has empty mergeinfo.
371
372     C) TARGET_ABSPATH has the same mergeinfo as its nearest parent
373        when that parent's mergeinfo is adjusted for the path
374        difference between the two, e.g.:
375
376           TARGET_ABSPATH                = A_COPY/D/H
377           TARGET_ABSPATH's mergeinfo    = '/A/D/H:3'
378           TARGET_ABSPATH nearest parent = A_COPY
379           Parent's mergeinfo            = '/A:3'
380           Path difference               = 'D/H'
381           Parent's adjusted mergeinfo   = '/A/D/H:3'
382
383   If Elision occurs remove the svn:mergeinfo property from
384   TARGET_ABSPATH. */
385svn_error_t *
386svn_client__elide_mergeinfo(const char *target_abspath,
387                            const char *wc_elision_limit_abspath,
388                            svn_client_ctx_t *ctx,
389                            apr_pool_t *pool);
390
391/* Simplify a mergeinfo catalog, if possible, via elision.
392
393   For each path in MERGEINFO_CATALOG, check if the path's mergeinfo can
394   elide to the path's nearest path-wise parent in MERGEINFO_CATALOG.  If
395   so, remove that path from MERGEINFO_CATALOG.  Elidability is determined
396   as per svn_client__elide_mergeinfo except that elision to the repository
397   is not considered.
398
399   SCRATCH_POOL is used for temporary allocations. */
400svn_error_t *
401svn_client__elide_mergeinfo_catalog(svn_mergeinfo_catalog_t mergeinfo_catalog,
402                                    apr_pool_t *scratch_pool);
403
404/* Set *MERGEINFO_CHANGES to TRUE if LOCAL_ABSPATH has locally modified
405   mergeinfo, set *MERGEINFO_CHANGES to FALSE otherwise. */
406svn_error_t *
407svn_client__mergeinfo_status(svn_boolean_t *mergeinfo_changes,
408                             svn_wc_context_t *wc_ctx,
409                             const char *local_abspath,
410                             apr_pool_t *scratch_pool);
411
412#endif /* SVN_LIBSVN_CLIENT_MERGEINFO_H */
413