1
/* svnraisetreeconflict
3
* This is a crude command line tool that publishes API to create
4
* tree-conflict markings in a working copy.
6
* To compile this, go to the root of the Subversion source tree and
7
* call `make svnraisetreeconflict'. You will find the executable file
8
* next to this source file.
10
* If you want to "install" svnraisetreeconflict, you may call
11
* `make install-tools' in the Subversion source tree root.
12
* (Note: This also installs any other installable tools.)
14
* svnraisetreeconflict cannot be compiled separate from a Subversion
17
* ====================================================================
18
* Licensed to the Apache Software Foundation (ASF) under one
19
* or more contributor license agreements. See the NOTICE file
20
* distributed with this work for additional information
21
* regarding copyright ownership. The ASF licenses this file
22
* to you under the Apache License, Version 2.0 (the
23
* "License"); you may not use this file except in compliance
24
* with the License. You may obtain a copy of the License at
26
* http://www.apache.org/licenses/LICENSE-2.0
28
* Unless required by applicable law or agreed to in writing,
29
* software distributed under the License is distributed on an
30
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
31
* KIND, either express or implied. See the License for the
32
* specific language governing permissions and limitations
34
* ====================================================================
37
#include "svn_cmdline.h"
38
#include "svn_pools.h"
43
#include "svn_version.h"
45
#include "private/svn_wc_private.h"
46
#include "private/svn_cmdline_private.h"
48
#include "svn_private_config.h"
50
#define OPT_VERSION SVN_OPT_FIRST_LONGOPT_ID
52
/** A statement macro, similar to @c SVN_INT_ERR, but issues a
53
* message saying "svnraisetreeconflict:" instead of "svn:".
55
* Evaluate @a expr. If it yields an error, handle that error and
56
* return @c EXIT_FAILURE.
58
#define SVNRAISETC_INT_ERR(expr) \
60
svn_error_t *svn_err__temp = (expr); \
61
if (svn_err__temp) { \
62
svn_handle_error2(svn_err__temp, stderr, FALSE, \
63
"svnraisetreeconflict: "); \
64
svn_error_clear(svn_err__temp); \
65
return EXIT_FAILURE; } \
69
version(apr_pool_t *pool)
71
return svn_opt_print_help4(NULL, "svnraisetreeconflict", TRUE, FALSE, FALSE,
72
NULL, NULL, NULL, NULL, NULL, NULL, pool);
76
usage(apr_pool_t *pool)
78
svn_error_clear(svn_cmdline_fprintf
80
_("Type 'svnraisetreeconflict --help' for usage.\n")));
84
/***************************************************************************
85
* "enum mapping" functions copied from subversion/libsvn_wc/tree_conflicts.c
86
**************************************************************************/
88
/* A mapping between a string STR and an enumeration value VAL. */
89
typedef struct enum_mapping_t
95
/* A map for svn_node_kind_t values. */
96
static const enum_mapping_t node_kind_map[] =
98
{ "none", svn_node_none },
99
{ "file", svn_node_file },
100
{ "dir", svn_node_dir },
101
{ "unknown", svn_node_unknown },
105
/* A map for svn_wc_operation_t values. */
106
static const enum_mapping_t operation_map[] =
108
{ "update", svn_wc_operation_update },
109
{ "switch", svn_wc_operation_switch },
110
{ "merge", svn_wc_operation_merge },
114
/* A map for svn_wc_conflict_action_t values. */
115
static const enum_mapping_t action_map[] =
117
{ "edit", svn_wc_conflict_action_edit },
118
{ "delete", svn_wc_conflict_action_delete },
119
{ "add", svn_wc_conflict_action_add },
123
/* A map for svn_wc_conflict_reason_t values. */
124
static const enum_mapping_t reason_map[] =
126
{ "edited", svn_wc_conflict_reason_edited },
127
{ "deleted", svn_wc_conflict_reason_deleted },
128
{ "missing", svn_wc_conflict_reason_missing },
129
{ "obstructed", svn_wc_conflict_reason_obstructed },
130
{ "added", svn_wc_conflict_reason_added },
134
/* Parse the enumeration field pointed to by *START into *RESULT as a plain
135
* 'int', using MAP to convert from strings to enumeration values.
136
* In MAP, a null STR field marks the end of the map.
137
* Don't read further than END.
138
* After reading, make *START point to the character after the field.
141
read_enum_field(int *result,
142
const enum_mapping_t *map,
148
/* Find STR in MAP; error if not found. */
151
if (map[i].str == NULL)
152
return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
153
"Unrecognised parameter value: '%s'", str);
154
if (strcmp(str, map[i].str) == 0)
158
*result = map[i].val;
163
get_enum_str(const enum_mapping_t *map,
167
for (i = 0; map[i].str != NULL; i++)
169
if (map[i].val == enum_val)
176
print_enum_map(const enum_mapping_t *map,
180
for (i = 0; map[i].str != NULL; i++)
181
svn_error_clear(svn_cmdline_fprintf(stdout, pool,
186
raise_tree_conflict(int argc, const char **argv, apr_pool_t *pool)
189
svn_wc_conflict_version_t *left, *right;
190
svn_wc_conflict_description2_t *c;
191
svn_wc_context_t *wc_ctx;
193
/* Conflict description parameters */
194
const char *wc_path, *wc_abspath;
195
const char *repos_url1, *repos_url2, *path_in_repos1, *path_in_repos2;
196
int operation, action, reason;
197
long peg_rev1, peg_rev2;
198
int kind, kind1, kind2;
201
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
202
"Wrong number of arguments");
204
/* Read the parameters */
205
wc_path = svn_dirent_internal_style(argv[i++], pool);
206
SVN_ERR(read_enum_field(&kind, node_kind_map, argv[i++], pool));
207
SVN_ERR(read_enum_field(&operation, operation_map, argv[i++], pool));
208
SVN_ERR(read_enum_field(&action, action_map, argv[i++], pool));
209
SVN_ERR(read_enum_field(&reason, reason_map, argv[i++], pool));
210
repos_url1 = argv[i++];
211
path_in_repos1 = argv[i++];
212
peg_rev1 = atol(argv[i++]);
213
SVN_ERR(read_enum_field(&kind1, node_kind_map, argv[i++], pool));
214
repos_url2 = argv[i++];
215
path_in_repos2 = argv[i++];
216
peg_rev2 = atol(argv[i++]);
217
SVN_ERR(read_enum_field(&kind2, node_kind_map, argv[i++], pool));
220
/* Allocate and fill in the description data structures */
221
SVN_ERR(svn_dirent_get_absolute(&wc_abspath, wc_path, pool));
222
left = svn_wc_conflict_version_create2(repos_url1, NULL, path_in_repos1,
223
peg_rev1, kind1, pool);
224
right = svn_wc_conflict_version_create2(repos_url2, NULL, path_in_repos2,
225
peg_rev2, kind2, pool);
226
c = svn_wc_conflict_description_create_tree2(wc_abspath, kind,
227
operation, left, right, pool);
228
c->action = (svn_wc_conflict_action_t)action;
229
c->reason = (svn_wc_conflict_reason_t)reason;
231
/* Raise the conflict */
232
SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool));
233
SVN_ERR(svn_wc__add_tree_conflict(wc_ctx, c, pool));
240
help(const apr_getopt_option_t *options, apr_pool_t *pool)
245
_("usage: svnraisetreeconflict [OPTIONS] WC_PATH NODE_KIND OPERATION ACTION REASON REPOS_URL1 PATH_IN_REPOS1 PEG_REV1 NODE_KIND1 REPOS_URL2 PATH_IN_REPOS2 PEG_REV2 NODE_KIND2\n\n"
246
" Mark the working-copy node WC_PATH as being the victim of a tree conflict.\n"
248
" WC_PATH's parent directory must be a working copy, otherwise a\n"
249
" tree conflict cannot be raised.\n"
251
"Valid options:\n")));
252
while (options->description)
255
svn_opt_format_option(&optstr, options, TRUE, pool);
256
svn_error_clear(svn_cmdline_fprintf(stdout, pool, " %s\n", optstr));
259
svn_error_clear(svn_cmdline_fprintf(stdout, pool,
261
"Valid enum argument values:\n"
262
" NODE_KIND, NODE_KIND1, NODE_KIND2:\n"
264
print_enum_map(node_kind_map, pool);
265
svn_error_clear(svn_cmdline_fprintf(stdout, pool,
269
print_enum_map(operation_map, pool);
270
svn_error_clear(svn_cmdline_fprintf(stdout, pool,
272
" ACTION (what svn tried to do):\n"
274
print_enum_map(action_map, pool);
275
svn_error_clear(svn_cmdline_fprintf(stdout, pool,
277
" REASON (what local change made svn fail):\n"
279
print_enum_map(reason_map, pool);
280
svn_error_clear(svn_cmdline_fprintf(stdout, pool,
282
" REPOS_URL1, REPOS_URL2:\n"
283
" The URL of the repository itself, e.g.: file://usr/repos\n"
284
" PATH_IN_REPOS1, PATH_IN_REPOS2:\n"
285
" The complete path of the node in the repository, e.g.: sub/dir/foo\n"
286
" PEG_REV1, PEG_REV2:\n"
287
" The revision number at which the given path is relevant.\n"
290
" svnraisetreeconflict ./foo %s %s %s %s file://usr/repos sub/dir/foo 1 %s file://usr/repos sub/dir/foo 3 %s\n\n"),
291
get_enum_str(node_kind_map, svn_node_file),
292
get_enum_str(operation_map, svn_wc_operation_update),
293
get_enum_str(action_map, svn_wc_conflict_action_delete),
294
get_enum_str(reason_map, svn_wc_conflict_reason_deleted),
295
get_enum_str(node_kind_map, svn_node_file),
296
get_enum_str(node_kind_map, svn_node_none)
302
/* Version compatibility check */
304
check_lib_versions(void)
306
static const svn_version_checklist_t checklist[] =
308
{ "svn_subr", svn_subr_version },
309
{ "svn_wc", svn_wc_version },
312
SVN_VERSION_DEFINE(my_version);
314
return svn_ver_check_list(&my_version, checklist);
318
main(int argc, const char *argv[])
323
const apr_getopt_option_t options[] =
325
{"help", 'h', 0, N_("display this help")},
326
{"version", OPT_VERSION, 0,
327
N_("show program version information")},
330
apr_array_header_t *remaining_argv;
332
/* Initialize the app. */
333
if (svn_cmdline_init("svnraisetreeconflict", stderr) != EXIT_SUCCESS)
336
/* Create our top-level pool. Use a separate mutexless allocator,
337
* given this application is single threaded.
339
pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
341
/* Check library versions */
342
err = check_lib_versions();
344
return svn_cmdline_handle_exit_error(err, pool, "svnraisetreeconflict: ");
346
#if defined(WIN32) || defined(__CYGWIN__)
347
/* Set the working copy administrative directory name. */
348
if (getenv("SVN_ASP_DOT_NET_HACK"))
350
err = svn_wc_set_adm_dir("_svn", pool);
352
return svn_cmdline_handle_exit_error(err, pool, "svnraisetreeconflict: ");
356
err = svn_cmdline__getopt_init(&os, argc, argv, pool);
358
return svn_cmdline_handle_exit_error(err, pool, "svnraisetreeconflict: ");
365
apr_status_t status = apr_getopt_long(os, options, &opt, &arg);
366
if (APR_STATUS_IS_EOF(status))
368
if (status != APR_SUCCESS)
369
usage(pool); /* this will exit() */
377
SVNRAISETC_INT_ERR(version(pool));
381
usage(pool); /* this will exit() */
385
/* Convert the remaining arguments to UTF-8. */
386
remaining_argv = apr_array_make(pool, 0, sizeof(const char *));
387
while (os->ind < argc)
391
SVNRAISETC_INT_ERR(svn_utf_cstring_to_utf8(&s, os->argv[os->ind++],
393
APR_ARRAY_PUSH(remaining_argv, const char *) = s;
396
if (remaining_argv->nelts < 1)
397
usage(pool); /* this will exit() */
399
/* Do the main task */
400
SVNRAISETC_INT_ERR(raise_tree_conflict(remaining_argv->nelts,
401
(const char **)remaining_argv->elts,
404
svn_pool_destroy(pool);
406
/* Flush stdout to make sure that the user will see any printing errors. */
407
SVNRAISETC_INT_ERR(svn_cmdline_fflush(stdout));