| /* svn-wc-db-tester.c |
| * |
| * This is a crude command line tool that makes it possible to |
| * run the wc-db validation checks directly. |
| * |
| * ==================================================================== |
| * 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. |
| * ==================================================================== |
| */ |
| |
| #include "svn_cmdline.h" |
| #include "svn_pools.h" |
| #include "svn_wc.h" |
| #include "svn_utf.h" |
| #include "svn_path.h" |
| #include "svn_opt.h" |
| #include "svn_version.h" |
| |
| #include "private/svn_wc_private.h" |
| #include "private/svn_cmdline_private.h" |
| |
| #include "../../subversion/libsvn_wc/wc.h" |
| #include "../../subversion/libsvn_wc/wc_db.h" |
| |
| #include "svn_private_config.h" |
| |
| #define OPT_VERSION SVN_OPT_FIRST_LONGOPT_ID |
| |
| static svn_error_t * |
| version(apr_pool_t *pool) |
| { |
| return svn_opt_print_help4(NULL, "svn-wc-db-tester", TRUE, FALSE, FALSE, |
| NULL, NULL, NULL, NULL, NULL, NULL, pool); |
| } |
| |
| static void |
| usage(apr_pool_t *pool) |
| { |
| svn_error_clear(svn_cmdline_fprintf |
| (stderr, pool, |
| _("Type 'svn-wc-db-tester --help' for usage.\n"))); |
| } |
| |
| struct verify_baton |
| { |
| svn_boolean_t found_err; |
| }; |
| |
| static svn_error_t * |
| verify_cb(void *baton, |
| const char *wc_abspath, |
| const char *local_relpath, |
| int op_depth, |
| int id, |
| const char *msg, |
| apr_pool_t *scratch_pool) |
| { |
| struct verify_baton *vb = baton; |
| |
| if (op_depth >= 0) |
| { |
| SVN_ERR(svn_cmdline_printf(scratch_pool, "%s (depth=%d) DBV%04d: %s\n", |
| local_relpath, op_depth, id, msg)); |
| } |
| else |
| { |
| SVN_ERR(svn_cmdline_printf(scratch_pool, "%s DBV%04d: %s\n", |
| local_relpath, id, msg)); |
| } |
| |
| vb->found_err = TRUE; |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| verify_db(int argc, const char *path, apr_pool_t *pool) |
| { |
| const char *local_abspath; |
| svn_wc_context_t *wc_ctx; |
| struct verify_baton vb = { FALSE }; |
| |
| /* Read the parameters */ |
| path = svn_dirent_internal_style(path, pool); |
| |
| SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool)); |
| |
| SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool)); |
| |
| SVN_ERR(svn_wc__db_verify_db_full(wc_ctx->db, local_abspath, |
| verify_cb, &vb, pool)); |
| |
| if (vb.found_err) |
| return svn_error_create(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, |
| _("Found one or more potential wc.db inconsistencies")); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| |
| static void |
| help(const apr_getopt_option_t *options, apr_pool_t *pool) |
| { |
| svn_error_clear |
| (svn_cmdline_fprintf |
| (stdout, pool, |
| _("usage: svn-wc-db-tester [OPTIONS] WC_PATH\n\n" |
| " Run verifications on the working copy\n" |
| "\n" |
| " WC_PATH's parent directory must be a working copy, otherwise a\n" |
| " tree conflict cannot be raised.\n" |
| "\n" |
| "Valid options:\n"))); |
| while (options->description) |
| { |
| const char *optstr; |
| svn_opt_format_option(&optstr, options, TRUE, pool); |
| svn_error_clear(svn_cmdline_fprintf(stdout, pool, " %s\n", optstr)); |
| ++options; |
| } |
| } |
| |
| |
| /* Version compatibility check */ |
| static svn_error_t * |
| check_lib_versions(void) |
| { |
| static const svn_version_checklist_t checklist[] = |
| { |
| { "svn_subr", svn_subr_version }, |
| { "svn_wc", svn_wc_version }, |
| { NULL, NULL } |
| }; |
| SVN_VERSION_DEFINE(my_version); |
| |
| return svn_ver_check_list2(&my_version, checklist, svn_ver_equal); |
| } |
| |
| /* |
| * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error, |
| * either return an error to be displayed, or set *EXIT_CODE to non-zero and |
| * return SVN_NO_ERROR. |
| */ |
| static svn_error_t * |
| sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool) |
| { |
| apr_getopt_t *os; |
| const apr_getopt_option_t options[] = |
| { |
| {"help", 'h', 0, N_("display this help")}, |
| {"version", OPT_VERSION, 0, |
| N_("show program version information")}, |
| {0, 0, 0, 0} |
| }; |
| apr_array_header_t *remaining_argv; |
| |
| /* Check library versions */ |
| SVN_ERR(check_lib_versions()); |
| |
| #if defined(WIN32) || defined(__CYGWIN__) |
| /* Set the working copy administrative directory name. */ |
| if (getenv("SVN_ASP_DOT_NET_HACK")) |
| { |
| SVN_ERR(svn_wc_set_adm_dir("_svn", pool)); |
| } |
| #endif |
| |
| SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool)); |
| |
| os->interleave = 1; |
| while (1) |
| { |
| int opt; |
| const char *arg; |
| apr_status_t status = apr_getopt_long(os, options, &opt, &arg); |
| if (APR_STATUS_IS_EOF(status)) |
| break; |
| if (status != APR_SUCCESS) |
| { |
| usage(pool); |
| *exit_code = EXIT_FAILURE; |
| return SVN_NO_ERROR; |
| } |
| |
| switch (opt) |
| { |
| case 'h': |
| help(options, pool); |
| return SVN_NO_ERROR; |
| case OPT_VERSION: |
| SVN_ERR(version(pool)); |
| return SVN_NO_ERROR; |
| default: |
| usage(pool); |
| *exit_code = EXIT_FAILURE; |
| return SVN_NO_ERROR; |
| } |
| } |
| |
| /* Convert the remaining arguments to UTF-8. */ |
| remaining_argv = apr_array_make(pool, 0, sizeof(const char *)); |
| while (os->ind < argc) |
| { |
| const char *s; |
| |
| SVN_ERR(svn_utf_cstring_to_utf8(&s, os->argv[os->ind++], pool)); |
| APR_ARRAY_PUSH(remaining_argv, const char *) = s; |
| } |
| |
| if (remaining_argv->nelts != 1) |
| { |
| usage(pool); |
| *exit_code = EXIT_FAILURE; |
| return SVN_NO_ERROR; |
| } |
| |
| /* Do the main task */ |
| SVN_ERR(verify_db(remaining_argv->nelts, |
| APR_ARRAY_IDX(remaining_argv, 0, const char *), |
| pool)); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| int |
| main(int argc, const char *argv[]) |
| { |
| apr_pool_t *pool; |
| int exit_code = EXIT_SUCCESS; |
| svn_error_t *err; |
| |
| /* Initialize the app. */ |
| if (svn_cmdline_init("svn-wc-db-tester", stderr) != EXIT_SUCCESS) |
| return EXIT_FAILURE; |
| |
| /* Create our top-level pool. Use a separate mutexless allocator, |
| * given this application is single threaded. |
| */ |
| pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE)); |
| |
| err = sub_main(&exit_code, argc, argv, pool); |
| |
| /* Flush stdout and report if it fails. It would be flushed on exit anyway |
| but this makes sure that output is not silently lost if it fails. */ |
| err = svn_error_compose_create(err, svn_cmdline_fflush(stdout)); |
| |
| if (err) |
| { |
| exit_code = EXIT_FAILURE; |
| svn_cmdline_handle_exit_error(err, NULL, "svn-wc-db-tester: "); |
| } |
| |
| svn_pool_destroy(pool); |
| return exit_code; |
| } |