blob: efd176dc7cdd08fd7de9b2ad60934b2529b36711 [file] [log] [blame]
/*
* resolve-cmd.c -- Subversion resolve subcommand
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
/* ==================================================================== */
/*** Includes. ***/
#include "svn_path.h"
#include "svn_client.h"
#include "svn_error.h"
#include "svn_pools.h"
#include "svn_hash.h"
#include "cl.h"
#include "svn_private_config.h"
/*** Code. ***/
struct conflict_walker_baton
{
svn_client_ctx_t *ctx;
svn_cl__accept_t accept_which;
svn_boolean_t quit;
svn_boolean_t external_failed;
svn_boolean_t printed_summary;
const char *editor_cmd;
const char *path_prefix;
svn_cmdline_prompt_baton_t *pb;
svn_cl__conflict_stats_t *conflict_stats;
};
/* Implements svn_client_conflict_walk_func_t. */
static svn_error_t *
conflict_walker(void *baton, svn_client_conflict_t *conflict,
apr_pool_t *scratch_pool)
{
struct conflict_walker_baton *cwb = baton;
SVN_ERR(svn_cl__resolve_conflict(&cwb->quit, &cwb->external_failed,
&cwb->printed_summary, conflict,
cwb->accept_which, cwb->editor_cmd,
cwb->path_prefix, cwb->pb,
cwb->conflict_stats,
cwb->ctx, scratch_pool));
if (cwb->quit)
return svn_error_create(SVN_ERR_CANCELLED, NULL, NULL);
return SVN_NO_ERROR;
}
svn_error_t *
svn_cl__walk_conflicts(apr_array_header_t *targets,
svn_cl__conflict_stats_t *conflict_stats,
svn_cl__opt_state_t *opt_state,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
svn_boolean_t had_error = FALSE;
svn_cmdline_prompt_baton_t *pb = apr_palloc(scratch_pool, sizeof(*pb));
struct conflict_walker_baton cwb = { 0 };
const char *path_prefix;
svn_error_t *err;
int i;
apr_pool_t *iterpool;
SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", scratch_pool));
pb->cancel_func = ctx->cancel_func;
pb->cancel_baton = ctx->cancel_baton;
cwb.ctx = ctx;
cwb.accept_which = opt_state->accept_which;
cwb.quit = FALSE;
cwb.external_failed = FALSE;
cwb.printed_summary = FALSE;
cwb.editor_cmd = opt_state->editor_cmd;
cwb.path_prefix = path_prefix;
cwb.pb = pb;
cwb.conflict_stats = conflict_stats;
iterpool = svn_pool_create(scratch_pool);
for (i = 0; i < targets->nelts; i++)
{
const char *target = APR_ARRAY_IDX(targets, i, const char *);
const char *local_abspath;
svn_client_conflict_t *conflict;
svn_pool_clear(iterpool);
SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
SVN_ERR(svn_dirent_get_absolute(&local_abspath, target, iterpool));
if (opt_state->depth == svn_depth_empty)
{
SVN_ERR(svn_client_conflict_get(&conflict, local_abspath, ctx,
iterpool, iterpool));
err = svn_cl__resolve_conflict(&cwb.quit, &cwb.external_failed,
&cwb.printed_summary,
conflict, opt_state->accept_which,
opt_state->editor_cmd,
path_prefix, pb, conflict_stats,
ctx, iterpool);
}
else
err = svn_client_conflict_walk(local_abspath, opt_state->depth,
conflict_walker, &cwb, ctx, iterpool);
if (err)
{
svn_error_t *root = svn_error_root_cause(err);
if (root->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
{
/* ### Ignore. These errors can happen due to the working copy
* ### being re-arranged during tree conflict resolution. */
svn_error_clear(err);
continue;
}
else if (root->apr_err == SVN_ERR_CANCELLED)
{
svn_error_clear(err);
break;
}
svn_handle_warning2(stderr, svn_error_root_cause(err), "svn: ");
svn_error_clear(err);
had_error = TRUE;
}
}
svn_pool_destroy(iterpool);
if (had_error)
return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Failure occurred resolving one or more "
"conflicts"));
return SVN_NO_ERROR;
}
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__resolve(apr_getopt_t *os,
void *baton,
apr_pool_t *scratch_pool)
{
svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
svn_cl__conflict_stats_t *conflict_stats =
((svn_cl__cmd_baton_t *) baton)->conflict_stats;
svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
apr_array_header_t *targets;
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
opt_state->targets,
ctx, FALSE,
scratch_pool));
if (! targets->nelts)
svn_opt_push_implicit_dot_target(targets, scratch_pool);
if (opt_state->depth == svn_depth_unknown)
{
if (opt_state->accept_which == svn_cl__accept_unspecified)
opt_state->depth = svn_depth_infinity;
else
opt_state->depth = svn_depth_empty;
}
SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));
SVN_ERR(svn_cl__check_targets_are_local_paths(targets));
if (opt_state->accept_which == svn_cl__accept_unspecified &&
opt_state->non_interactive)
{
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("missing --accept option"));
}
else if (opt_state->accept_which == svn_cl__accept_postpone ||
opt_state->accept_which == svn_cl__accept_edit ||
opt_state->accept_which == svn_cl__accept_launch)
{
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("invalid 'accept' ARG"));
}
SVN_ERR(svn_cl__walk_conflicts(targets, conflict_stats,
opt_state, ctx, scratch_pool));
return SVN_NO_ERROR;
}