Пример #1
0
int
main(int argc, const char *argv[])
{
  apr_pool_t *pool;
  int exit_code = EXIT_SUCCESS;
  svn_error_t *err;

  /* Initialize the app.  Send all error messages to 'stderr'.  */
  if (svn_cmdline_init(argv[0], stderr) != EXIT_SUCCESS)
    return EXIT_FAILURE;

  pool = svn_pool_create(NULL);

  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)
    {
      if (exit_code == 0)
        exit_code = EXIT_FAILURE;
      svn_cmdline_handle_exit_error(err, NULL, "svnauthz: ");
    }

  svn_pool_destroy(pool);
  return exit_code;
}
Пример #2
0
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("svnraisetreeconflict", 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, "svnraisetreeconflict: ");
    }

  svn_pool_destroy(pool);
  return exit_code;
}
Пример #3
0
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("svnserve", stderr) != EXIT_SUCCESS)
    return EXIT_FAILURE;

  /* Create our top-level pool. */
  pool = apr_allocator_owner_get(svn_pool_create_allocator(TRUE));

  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, "svnserve: ");
    }

#if APR_HAS_THREADS
  /* Explicitly wait for all threads to exit.  As we found out with similar
     code in our C test framework, the memory pool cleanup below cannot be
     trusted to do the right thing. */
  if (threads)
    apr_thread_pool_destroy(threads);
#endif

  /* this will also close the server's socket */
  svn_pool_destroy(pool);
  return exit_code;
}
Пример #4
0
static svn_error_t *
apply_textdelta(void *file_baton,
                const char *base_checksum,
                apr_pool_t *pool,
                svn_txdelta_window_handler_t *handler,
                void **handler_baton)
{
  node_baton_t *fb = file_baton;
  edit_baton_t *eb = fb->edit_baton;

  if (! eb->quiet)
    {
      if (! eb->got_textdeltas)
        SVN_ERR(svn_cmdline_printf(pool, _("Transmitting file data ")));
      SVN_ERR(svn_cmdline_printf(pool, "."));
      SVN_ERR(svn_cmdline_fflush(stdout));
    }

  eb->got_textdeltas = TRUE;
  return eb->wrapped_editor->apply_textdelta(fb->wrapped_node_baton,
                                             base_checksum, pool,
                                             handler, handler_baton);
}
Пример #5
0
/*
 * Why is this not an svn subcommand?  I have this vague idea that it could
 * be run as part of the build process, with the output embedded in the svn
 * program.  Obviously we don't want to have to run svn when building svn.
 */
int
main(int argc, const char *argv[])
{
  const char *wc_path, *trail_url;
  apr_allocator_t *allocator;
  apr_pool_t *pool;
  int wc_format;
  svn_wc_revision_status_t *res;
  svn_boolean_t no_newline = FALSE, committed = FALSE;
  svn_error_t *err;
  apr_getopt_t *os;
  const apr_getopt_option_t options[] =
    {
      {"no-newline", 'n', 0, N_("do not output the trailing newline")},
      {"committed",  'c', 0, N_("last changed rather than current revisions")},
      {"help", 'h', 0, N_("display this help")},
      {"version", SVNVERSION_OPT_VERSION, 0,
       N_("show program version information")},
      {0,             0,  0,  0}
    };

  /* Initialize the app. */
  if (svn_cmdline_init("svnversion", stderr) != EXIT_SUCCESS)
    return EXIT_FAILURE;

  /* Create our top-level pool.  Use a separate mutexless allocator,
   * given this application is single threaded.
   */
  if (apr_allocator_create(&allocator))
    return EXIT_FAILURE;

  apr_allocator_max_free_set(allocator, SVN_ALLOCATOR_RECOMMENDED_MAX_FREE);

  pool = svn_pool_create_ex(NULL, allocator);
  apr_allocator_owner_set(allocator, pool);

  /* Check library versions */
  err = check_lib_versions();
  if (err)
    return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");

#if defined(WIN32) || defined(__CYGWIN__)
  /* Set the working copy administrative directory name. */
  if (getenv("SVN_ASP_DOT_NET_HACK"))
    {
      err = svn_wc_set_adm_dir("_svn", pool);
      if (err)
        return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");
    }
#endif

  err = svn_cmdline__getopt_init(&os, argc, argv, pool);
  if (err)
    return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");

  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);
          return EXIT_FAILURE;
        }
      switch (opt)
        {
        case 'n':
          no_newline = TRUE;
          break;
        case 'c':
          committed = TRUE;
          break;
        case 'h':
          help(options, pool);
          break;
        case SVNVERSION_OPT_VERSION:
          SVN_INT_ERR(version(pool));
          exit(0);
          break;
        default:
          usage(pool);
          return EXIT_FAILURE;
        }
    }

  if (os->ind > argc || os->ind < argc - 2)
    {
      usage(pool);
      return EXIT_FAILURE;
    }

  SVN_INT_ERR(svn_utf_cstring_to_utf8
              (&wc_path, (os->ind < argc) ? os->argv[os->ind] : ".",
               pool));
  wc_path = svn_path_internal_style(wc_path, pool);

  if (os->ind+1 < argc)
    SVN_INT_ERR(svn_utf_cstring_to_utf8
                (&trail_url, os->argv[os->ind+1], pool));
  else
    trail_url = NULL;

  SVN_INT_ERR(svn_wc_check_wc(wc_path, &wc_format, pool));
  if (! wc_format)
    {
      svn_node_kind_t kind;
      SVN_INT_ERR(svn_io_check_path(wc_path, &kind, pool));
      if (kind == svn_node_dir)
        {
          SVN_INT_ERR(svn_cmdline_printf(pool, _("exported%s"),
                                         no_newline ? "" : "\n"));
          svn_pool_destroy(pool);
          return EXIT_SUCCESS;
        }
      else
        {
          svn_error_clear
            (svn_cmdline_fprintf(stderr, pool,
                                 _("'%s' not versioned, and not exported\n"),
                                 wc_path));
          svn_pool_destroy(pool);
          return EXIT_FAILURE;
        }
    }


  SVN_INT_ERR(svn_wc_revision_status(&res, wc_path, trail_url, committed,
                                     NULL, NULL, pool));

  /* Build compact '123[:456]M?S?' string. */
  SVN_INT_ERR(svn_cmdline_printf(pool, "%ld", res->min_rev));
  if (res->min_rev != res->max_rev)
    SVN_INT_ERR(svn_cmdline_printf(pool, ":%ld", res->max_rev));
  if (res->modified)
    SVN_INT_ERR(svn_cmdline_fputs("M", stdout, pool));
  if (res->switched)
    SVN_INT_ERR(svn_cmdline_fputs("S", stdout, pool));
  if (res->sparse_checkout)
    SVN_INT_ERR(svn_cmdline_fputs("P", stdout, pool));

  if (! no_newline)
    SVN_INT_ERR(svn_cmdline_fputs("\n", stdout, pool));

  svn_pool_destroy(pool);

  /* Flush stdout to make sure that the user will see any printing errors. */
  SVN_INT_ERR(svn_cmdline_fflush(stdout));

  return EXIT_SUCCESS;
}
Пример #6
0
/* Print STATUS and PATH in a format determined by DETAILED and
   SHOW_LAST_COMMITTED. */
static svn_error_t *
print_status(const char *path,
             svn_boolean_t detailed,
             svn_boolean_t show_last_committed,
             svn_boolean_t repos_locks,
             svn_wc_status2_t *status,
             apr_pool_t *pool)
{
  if (detailed)
    {
      char ood_status, lock_status;
      const char *working_rev;

      if (! status->entry)
        working_rev = "";
      else if (! SVN_IS_VALID_REVNUM(status->entry->revision))
        working_rev = " ? ";
      else if (status->copied)
        working_rev = "-";
      else
        working_rev = apr_psprintf(pool, "%ld", status->entry->revision);

      if (status->repos_text_status != svn_wc_status_none
          || status->repos_prop_status != svn_wc_status_none)
        ood_status = '*';
      else
        ood_status = ' ';

      if (repos_locks)
        {
          if (status->repos_lock)
            {
              if (status->entry && status->entry->lock_token)
                {
                  if (strcmp(status->repos_lock->token, status->entry->lock_token)
                      == 0)
                    lock_status = 'K';
                  else
                    lock_status = 'T';
                }
              else
                lock_status = 'O';
            }
          else if (status->entry && status->entry->lock_token)
            lock_status = 'B';
          else
            lock_status = ' ';
        }
      else
        lock_status = (status->entry && status->entry->lock_token) ? 'K' : ' ';

      if (show_last_committed)
        {
          const char *commit_rev;
          const char *commit_author;

          if (status->entry && SVN_IS_VALID_REVNUM(status->entry->cmt_rev))
            commit_rev = apr_psprintf(pool, "%ld", status->entry->cmt_rev);
          else if (status->entry)
            commit_rev = " ? ";
          else
            commit_rev = "";

          if (status->entry && status->entry->cmt_author)
            commit_author = status->entry->cmt_author;
          else if (status->entry)
            commit_author = " ? ";
          else
            commit_author = "";

          SVN_ERR
            (svn_cmdline_printf(pool,
                                "%c%c%c%c%c%c %c   %6s   %6s %-12s %s\n",
                                generate_status_code(status->text_status),
                                generate_status_code(status->prop_status),
                                status->locked ? 'L' : ' ',
                                status->copied ? '+' : ' ',
                                status->switched ? 'S' : ' ',
                                lock_status,
                                ood_status,
                                working_rev,
                                commit_rev,
                                commit_author,
                                path));
        }
      else
        SVN_ERR
          (svn_cmdline_printf(pool, "%c%c%c%c%c%c %c   %6s   %s\n",
                              generate_status_code(status->text_status),
                              generate_status_code(status->prop_status),
                              status->locked ? 'L' : ' ',
                              status->copied ? '+' : ' ',
                              status->switched ? 'S' : ' ',
                              lock_status,
                              ood_status,
                              working_rev,
                              path));
    }
  else
    SVN_ERR
      (svn_cmdline_printf(pool, "%c%c%c%c%c%c %s\n",
                          generate_status_code(status->text_status),
                          generate_status_code(status->prop_status),
                          status->locked ? 'L' : ' ',
                          status->copied ? '+' : ' ',
                          status->switched ? 'S' : ' ',
                          ((status->entry && status->entry->lock_token)
                           ? 'K' : ' '),
                          path));

  SVN_ERR(svn_cmdline_fflush(stdout));

  return SVN_NO_ERROR;
}
Пример #7
0
int
main(int argc, const char *argv[])
{
  const char *repos_path;
  apr_pool_t *pool;
  svn_boolean_t prop = FALSE, data = FALSE;
  svn_boolean_t quiet = FALSE;
  svn_error_t *err;
  apr_getopt_t *os;
  const apr_getopt_option_t options[] =
    {
      {"data", OPT_DATA, 0, N_("display data reps stats")},
      {"prop", OPT_PROP, 0, N_("display prop reps stats")},
      {"both", OPT_BOTH, 0, N_("display combined (data+prop) reps stats")},
      {"quiet", 'q', 0, N_("no progress (only errors) to stderr")},
      {"help", 'h', 0, N_("display this help")},
      {"version", OPT_VERSION, 0,
       N_("show program version information")},
      {0,             0,  0,  0}
    };

  /* Initialize the app. */
  if (svn_cmdline_init("svn-rep-sharing-stats", 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));

  /* Check library versions */
  err = check_lib_versions();
  if (err)
    return svn_cmdline_handle_exit_error(err, pool, "svn-rep-sharing-stats: ");

  err = svn_cmdline__getopt_init(&os, argc, argv, pool);
  if (err)
    return svn_cmdline_handle_exit_error(err, pool, "svn-rep-sharing-stats: ");

  SVN_INT_ERR(check_experimental());

  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);
          return EXIT_FAILURE;
        }
      switch (opt)
        {
        case OPT_DATA:
          data = TRUE;
          break;
        /* It seems we don't actually rep-share props yet. */
        case OPT_PROP:
          prop = TRUE;
          break;
        case OPT_BOTH:
          data = TRUE;
          prop = TRUE;
          break;
        case 'q':
          quiet = TRUE;
          break;
        case 'h':
          help(options, pool);
          break;
        case OPT_VERSION:
          SVN_INT_ERR(version(pool));
          exit(0);
          break;
        default:
          usage(pool);
          return EXIT_FAILURE;
        }
    }

  /* Exactly 1 non-option argument,
   * and at least one of "--data"/"--prop"/"--both".
   */
  if (os->ind + 1 != argc || (!data && !prop))
    {
      usage(pool);
      return EXIT_FAILURE;
    }

  /* Grab REPOS_PATH from argv. */
  SVN_INT_ERR(svn_utf_cstring_to_utf8(&repos_path, os->argv[os->ind], pool));
  repos_path = svn_dirent_internal_style(repos_path, pool);

  set_up_cancellation();

  /* Do something. */
  SVN_INT_ERR(process(repos_path, prop, data, quiet, pool));

  /* We're done. */

  svn_pool_destroy(pool);
  /* Flush stdout to make sure that the user will see any printing errors. */
  SVN_INT_ERR(svn_cmdline_fflush(stdout));

  return EXIT_SUCCESS;
}
Пример #8
0
Файл: main.c Проект: ejrh/ejrh
int
main (int argc, const char * const *argv)
{
  svn_error_t *err;
  apr_status_t apr_err;
  apr_allocator_t *allocator;
  apr_pool_t *pool;

  const svn_opt_subcommand_desc_t *subcommand = NULL;
  struct svnindex_opt_state opt_state;
  apr_getopt_t *os;  
  int opt_id;
  apr_array_header_t *received_opts;
  int i;

  /* Initialize the app. */
  if (svn_cmdline_init ("svnindex", stderr) != EXIT_SUCCESS)
    return EXIT_FAILURE;

  /* Create our top-level pool.  Use a seperate mutexless allocator,
   * given this application is single threaded.
   */
  if (apr_allocator_create (&allocator))
    return EXIT_FAILURE;

  apr_allocator_max_free_set (allocator, SVN_ALLOCATOR_RECOMMENDED_MAX_FREE);

  pool = svn_pool_create_ex (NULL, allocator);
  apr_allocator_owner_set (allocator, pool);

  received_opts = apr_array_make (pool, SVN_OPT_MAX_OPTIONS, sizeof (int));

  /* Check library versions */
  err = check_lib_versions ();
  if (err)
    return svn_cmdline_handle_exit_error (err, pool, "svnindex: ");

  /* Initialize the FS library. */
  err = svn_fs_initialize (pool);
  if (err)
    return svn_cmdline_handle_exit_error (err, pool, "svnindex: ");

  if (argc <= 1)
    {
      subcommand_help (NULL, NULL, pool);
      svn_pool_destroy (pool);
      return EXIT_FAILURE;
    }

  /* Initialize opt_state. */
  memset (&opt_state, 0, sizeof (opt_state));
  opt_state.start_revision.kind = svn_opt_revision_unspecified;
  opt_state.end_revision.kind = svn_opt_revision_unspecified;

  /* Parse options. */
  apr_getopt_init (&os, pool, argc, argv);
  os->interleave = 1;

  while (1)
    {
      const char *opt_arg;
      const char *utf8_opt_arg;

      /* Parse the next option. */
      apr_err = apr_getopt_long (os, options_table, &opt_id, &opt_arg);
      if (APR_STATUS_IS_EOF (apr_err))
        break;
      else if (apr_err)
        {
          subcommand_help (NULL, NULL, pool);
          svn_pool_destroy (pool);
          return EXIT_FAILURE;
        }

      /* Stash the option code in an array before parsing it. */
      APR_ARRAY_PUSH (received_opts, int) = opt_id;

      switch (opt_id) {
      case 'r':
        {
          if (opt_state.start_revision.kind != svn_opt_revision_unspecified)
            {
              err = svn_error_create
                (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                 _("Multiple revision arguments encountered; "
                   "try '-r M:N' instead of '-r M -r N'"));
              return svn_cmdline_handle_exit_error (err, pool, "svnindex: ");
            }
          if (svn_opt_parse_revision (&(opt_state.start_revision),
                                      &(opt_state.end_revision),
                                      opt_arg, pool) != 0)
            {
              err = svn_utf_cstring_to_utf8 (&utf8_opt_arg, opt_arg,
                                             pool);

              if (! err)
                err = svn_error_createf
                  (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                   _("Syntax error in revision argument '%s'"),
                   utf8_opt_arg);
              return svn_cmdline_handle_exit_error (err, pool, "svnindex: ");
            }
        }
        break;
      case 'q':
        opt_state.quiet = TRUE;
        break;
      case 'h':
      case '?':
        opt_state.help = TRUE;
        break;
      case svnindex__version:
        opt_state.version = TRUE;
        opt_state.help = TRUE;
        break;
      case svnindex__db:
        err = svn_utf_cstring_to_utf8 (&opt_state.db, opt_arg,
                                       pool);
        if (err)
          return svn_cmdline_handle_exit_error (err, pool, "svnindex: ");
        break;
      case 'v':
        opt_state.verbose = TRUE;
        break;
      default:
        {
          subcommand_help (NULL, NULL, pool);
          svn_pool_destroy (pool);
          return EXIT_FAILURE;
        }
      }  /* close `switch' */
    }  /* close `while' */
  
  /* If the user asked for help, then the rest of the arguments are
     the names of subcommands to get help on (if any), or else they're
     just typos/mistakes.  Whatever the case, the subcommand to
     actually run is subcommand_help(). */
  if (opt_state.help)
    subcommand = svn_opt_get_canonical_subcommand (cmd_table, "help");

  /* If we're not running the `help' subcommand, then look for a
     subcommand in the first argument. */
  if (subcommand == NULL)
    {
      if (os->ind >= os->argc)
        {
          svn_error_clear
            (svn_cmdline_fprintf (stderr, pool,
                                  _("subcommand argument required\n")));
          subcommand_help (NULL, NULL, pool);
          svn_pool_destroy (pool);
          return EXIT_FAILURE;
        }
      else
        {
          const char *first_arg = os->argv[os->ind++];
          subcommand = svn_opt_get_canonical_subcommand (cmd_table, first_arg);
          if (subcommand == NULL)
            {
              const char* first_arg_utf8;
              err = svn_utf_cstring_to_utf8 (&first_arg_utf8, first_arg, pool);
              if (err)
                return svn_cmdline_handle_exit_error (err, pool, "svnindex: ");
              svn_error_clear
                (svn_cmdline_fprintf (stderr, pool,
                                      _("Unknown command: '%s'\n"),
                                      first_arg_utf8));
              subcommand_help (NULL, NULL, pool);
              svn_pool_destroy (pool);
              return EXIT_FAILURE;
            }
        }
    }

  /* If there's a second argument, it's probably the repository.
     Every subcommand except `help' requires one, so we parse it out
     here and store it in opt_state. */
  if (subcommand->cmd_func != subcommand_help)
    {
      err = parse_local_repos_path (os, 
                                    &(opt_state.repository_path), 
                                    pool);
      if(err)
        {
          svn_handle_error2 (err, stderr, FALSE, "svnindex: ");
          svn_opt_subcommand_help (subcommand->name, cmd_table,
                                   options_table, pool);
          svn_error_clear (err);
          svn_pool_destroy (pool);
          return EXIT_FAILURE;
        }

    }


  /* Check that the subcommand wasn't passed any inappropriate options. */
  for (i = 0; i < received_opts->nelts; i++)
    {
      opt_id = APR_ARRAY_IDX (received_opts, i, int);

      /* All commands implicitly accept --help, so just skip over this
         when we see it. Note that we don't want to include this option
         in their "accepted options" list because it would be awfully
         redundant to display it in every commands' help text. */
      if (opt_id == 'h' || opt_id == '?')
        continue;

      if (! svn_opt_subcommand_takes_option (subcommand, opt_id))
        {
          const char *optstr;
          const apr_getopt_option_t *badopt = 
            svn_opt_get_option_from_code (opt_id, options_table);
          svn_opt_format_option (&optstr, badopt, FALSE, pool);
          svn_error_clear
            (svn_cmdline_fprintf
             (stderr, pool, _("subcommand '%s' doesn't accept option '%s'\n"
                              "Type 'svnindex help %s' for usage.\n"),
              subcommand->name, optstr, subcommand->name));
          svn_pool_destroy (pool);
          return EXIT_FAILURE;
        }
    }

  /* Set up our cancellation support. */
  setup_cancellation_signals (signal_handler);

#ifdef SIGPIPE
  /* Disable SIGPIPE generation for the platforms that have it. */
  apr_signal(SIGPIPE, SIG_IGN);
#endif

  /* Run the subcommand. */
  err = (*subcommand->cmd_func) (os, &opt_state, pool);
  if (err)
    {
      if (err->apr_err == SVN_ERR_CL_ARG_PARSING_ERROR)
        {
          svn_handle_error2 (err, stderr, FALSE, "svnindex: ");
          svn_opt_subcommand_help (subcommand->name, cmd_table,
                                   options_table, pool);
        }
      else
        svn_handle_error2 (err, stderr, FALSE, "svnindex: ");
      svn_error_clear (err);
      svn_pool_destroy (pool);
      return EXIT_FAILURE;
    }
  else
    {
      svn_pool_destroy (pool);
      /* Ensure that everything is written to stdout, so the user will
         see any print errors. */
      err = svn_cmdline_fflush (stdout);
      if (err) {
        svn_handle_error2 (err, stderr, FALSE, "svnindex: ");
        svn_error_clear (err);
        return EXIT_FAILURE;
      }
      return EXIT_SUCCESS;
    }
}
Пример #9
0
/* Implement `svn_log_entry_receiver_t', printing the logs in
 * a human-readable and machine-parseable format.
 *
 * BATON is of type `struct log_receiver_baton'.
 *
 * First, print a header line.  Then if CHANGED_PATHS is non-null,
 * print all affected paths in a list headed "Changed paths:\n",
 * immediately following the header line.  Then print a newline
 * followed by the message body, unless BATON->omit_log_message is true.
 *
 * Here are some examples of the output:
 *
 * $ svn log -r1847:1846
 * ------------------------------------------------------------------------
 * rev 1847:  cmpilato | Wed 1 May 2002 15:44:26 | 7 lines
 *
 * Fix for Issue #694.
 *
 * * subversion/libsvn_repos/delta.c
 *   (delta_files): Rework the logic in this function to only call
 * send_text_deltas if there are deltas to send, and within that case,
 * only use a real delta stream if the caller wants real text deltas.
 *
 * ------------------------------------------------------------------------
 * rev 1846:  whoever | Wed 1 May 2002 15:23:41 | 1 line
 *
 * imagine an example log message here
 * ------------------------------------------------------------------------
 *
 * Or:
 *
 * $ svn log -r1847:1846 -v
 * ------------------------------------------------------------------------
 * rev 1847:  cmpilato | Wed 1 May 2002 15:44:26 | 7 lines
 * Changed paths:
 *    M /trunk/subversion/libsvn_repos/delta.c
 *
 * Fix for Issue #694.
 *
 * * subversion/libsvn_repos/delta.c
 *   (delta_files): Rework the logic in this function to only call
 * send_text_deltas if there are deltas to send, and within that case,
 * only use a real delta stream if the caller wants real text deltas.
 *
 * ------------------------------------------------------------------------
 * rev 1846:  whoever | Wed 1 May 2002 15:23:41 | 1 line
 * Changed paths:
 *    M /trunk/notes/fs_dumprestore.txt
 *    M /trunk/subversion/libsvn_repos/dump.c
 *
 * imagine an example log message here
 * ------------------------------------------------------------------------
 *
 * Or:
 *
 * $ svn log -r1847:1846 -q
 * ------------------------------------------------------------------------
 * rev 1847:  cmpilato | Wed 1 May 2002 15:44:26
 * ------------------------------------------------------------------------
 * rev 1846:  whoever | Wed 1 May 2002 15:23:41
 * ------------------------------------------------------------------------
 *
 * Or:
 *
 * $ svn log -r1847:1846 -qv
 * ------------------------------------------------------------------------
 * rev 1847:  cmpilato | Wed 1 May 2002 15:44:26
 * Changed paths:
 *    M /trunk/subversion/libsvn_repos/delta.c
 * ------------------------------------------------------------------------
 * rev 1846:  whoever | Wed 1 May 2002 15:23:41
 * Changed paths:
 *    M /trunk/notes/fs_dumprestore.txt
 *    M /trunk/subversion/libsvn_repos/dump.c
 * ------------------------------------------------------------------------
 *
 */
static svn_error_t *
log_entry_receiver(void *baton,
                   svn_log_entry_t *log_entry,
                   apr_pool_t *pool)
{
  struct log_receiver_baton *lb = baton;
  const char *author;
  const char *date;
  const char *message;

  /* Number of lines in the msg. */
  int lines;

  if (lb->cancel_func)
    SVN_ERR(lb->cancel_func(lb->cancel_baton));

  svn_compat_log_revprops_out(&author, &date, &message, log_entry->revprops);

  if (log_entry->revision == 0 && message == NULL)
    return SVN_NO_ERROR;

  if (! SVN_IS_VALID_REVNUM(log_entry->revision))
    {
      apr_array_pop(lb->merge_stack);
      return SVN_NO_ERROR;
    }

  /* ### See http://subversion.tigris.org/issues/show_bug.cgi?id=807
     for more on the fallback fuzzy conversions below. */

  if (author == NULL)
    author = _("(no author)");

  if (date && date[0])
    /* Convert date to a format for humans. */
    SVN_ERR(svn_cl__time_cstring_to_human_cstring(&date, date, pool));
  else
    date = _("(no date)");

  if (! lb->omit_log_message && message == NULL)
    message = "";

  SVN_ERR(svn_cmdline_printf(pool,
                             SEP_STRING "r%ld | %s | %s",
                             log_entry->revision, author, date));

  if (message != NULL)
    {
      lines = svn_cstring_count_newlines(message) + 1;
      SVN_ERR(svn_cmdline_printf(pool,
                                 (lines != 1)
                                 ? " | %d lines"
                                 : " | %d line", lines));
    }

  SVN_ERR(svn_cmdline_printf(pool, "\n"));

  if (log_entry->changed_paths)
    {
      apr_array_header_t *sorted_paths;
      int i;

      /* Get an array of sorted hash keys. */
      sorted_paths = svn_sort__hash(log_entry->changed_paths,
                                    svn_sort_compare_items_as_paths, pool);

      SVN_ERR(svn_cmdline_printf(pool,
                                 _("Changed paths:\n")));
      for (i = 0; i < sorted_paths->nelts; i++)
        {
          svn_sort__item_t *item = &(APR_ARRAY_IDX(sorted_paths, i,
                                                   svn_sort__item_t));
          const char *path = item->key;
          svn_log_changed_path_t *log_item
            = apr_hash_get(log_entry->changed_paths, item->key, item->klen);
          const char *copy_data = "";

          if (log_item->copyfrom_path
              && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
            {
              copy_data
                = apr_psprintf(pool,
                               _(" (from %s:%ld)"),
                               log_item->copyfrom_path,
                               log_item->copyfrom_rev);
            }
          SVN_ERR(svn_cmdline_printf(pool, "   %c %s%s\n",
                                     log_item->action, path,
                                     copy_data));
        }
    }

  if (lb->merge_stack->nelts > 0)
    {
      int i;

      /* Print the result of merge line */
      SVN_ERR(svn_cmdline_printf(pool, _("Merged via:")));
      for (i = 0; i < lb->merge_stack->nelts; i++)
        {
          svn_revnum_t rev = APR_ARRAY_IDX(lb->merge_stack, i, svn_revnum_t);

          SVN_ERR(svn_cmdline_printf(pool, " r%ld%c", rev,
                                     i == lb->merge_stack->nelts - 1 ?
                                                                  '\n' : ','));
        }
    }

  if (message != NULL)
    {
      /* A blank line always precedes the log message. */
      SVN_ERR(svn_cmdline_printf(pool, "\n%s\n", message));
    }

  SVN_ERR(svn_cmdline_fflush(stdout));

  if (log_entry->has_children)
    APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;

  return SVN_NO_ERROR;
}
Пример #10
0
/* This implements `svn_wc_notify_func2_t'.
 * NOTE: This function can't fail, so we just ignore any print errors. */
static void
notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
{
  struct notify_baton *nb = baton;
  char statchar_buf[5] = "    ";
  const char *path_local;
  svn_error_t *err;

  if (n->url)
    path_local = n->url;
  else
    {
      if (n->path_prefix)
        path_local = svn_cl__local_style_skip_ancestor(n->path_prefix, n->path,
                                                       pool);
      else /* skip nb->path_prefix, if it's non-null */
        path_local = svn_cl__local_style_skip_ancestor(nb->path_prefix, n->path,
                                                       pool);
    }

  switch (n->action)
    {
    case svn_wc_notify_skip:
      nb->skipped_paths++;
      if (n->content_state == svn_wc_notify_state_missing)
        {
          if ((err = svn_cmdline_printf
               (pool, _("Skipped missing target: '%s'\n"),
                path_local)))
            goto print_error;
        }
      else if (n->content_state == svn_wc_notify_state_source_missing)
        {
          if ((err = svn_cmdline_printf
               (pool, _("Skipped target: '%s' -- copy-source is missing\n"),
                path_local)))
            goto print_error;
        }
      else
        {
          if ((err = svn_cmdline_printf
               (pool, _("Skipped '%s'\n"), path_local)))
            goto print_error;
        }
      break;
    case svn_wc_notify_update_skip_obstruction:
      nb->skipped_paths++;
      if ((err = svn_cmdline_printf(
            pool, _("Skipped '%s' -- An obstructing working copy was found\n"),
            path_local)))
        goto print_error;
      break;
    case svn_wc_notify_update_skip_working_only:
      nb->skipped_paths++;
      if ((err = svn_cmdline_printf(
            pool, _("Skipped '%s' -- Has no versioned parent\n"),
            path_local)))
        goto print_error;
      break;
    case svn_wc_notify_update_skip_access_denied:
      nb->skipped_paths++;
      if ((err = svn_cmdline_printf(
            pool, _("Skipped '%s' -- Access denied\n"),
            path_local)))
        goto print_error;
      break;
    case svn_wc_notify_skip_conflicted:
      nb->skipped_paths++;
      if ((err = svn_cmdline_printf(
            pool, _("Skipped '%s' -- Node remains in conflict\n"),
            path_local)))
        goto print_error;
      break;
    case svn_wc_notify_update_delete:
    case svn_wc_notify_exclude:
      nb->received_some_change = TRUE;
      if ((err = svn_cmdline_printf(pool, "D    %s\n", path_local)))
        goto print_error;
      break;

    case svn_wc_notify_update_external_removed:
      nb->received_some_change = TRUE;
      if (n->err && n->err->message)
        {
          if ((err = svn_cmdline_printf(pool, "Removed external '%s': %s\n",
              path_local, n->err->message)))
            goto print_error;
        }
      else
        {
          if ((err = svn_cmdline_printf(pool, "Removed external '%s'\n",
                                        path_local)))
            goto print_error;
        }
      break;

    case svn_wc_notify_update_replace:
      nb->received_some_change = TRUE;
      if ((err = svn_cmdline_printf(pool, "R    %s\n", path_local)))
        goto print_error;
      break;

    case svn_wc_notify_update_add:
      nb->received_some_change = TRUE;
      if (n->content_state == svn_wc_notify_state_conflicted)
        {
          nb->text_conflicts++;
          if ((err = svn_cmdline_printf(pool, "C    %s\n", path_local)))
            goto print_error;
        }
      else
        {
          if ((err = svn_cmdline_printf(pool, "A    %s\n", path_local)))
            goto print_error;
        }
      break;

    case svn_wc_notify_exists:
      nb->received_some_change = TRUE;
      if (n->content_state == svn_wc_notify_state_conflicted)
        {
          nb->text_conflicts++;
          statchar_buf[0] = 'C';
        }
      else
        statchar_buf[0] = 'E';

      if (n->prop_state == svn_wc_notify_state_conflicted)
        {
          nb->prop_conflicts++;
          statchar_buf[1] = 'C';
        }
      else if (n->prop_state == svn_wc_notify_state_merged)
        statchar_buf[1] = 'G';

      if ((err = svn_cmdline_printf(pool, "%s %s\n", statchar_buf, path_local)))
        goto print_error;
      break;

    case svn_wc_notify_restore:
      if ((err = svn_cmdline_printf(pool, _("Restored '%s'\n"),
                                    path_local)))
        goto print_error;
      break;

    case svn_wc_notify_revert:
      if ((err = svn_cmdline_printf(pool, _("Reverted '%s'\n"),
                                    path_local)))
        goto print_error;
      break;

    case svn_wc_notify_failed_revert:
      if (( err = svn_cmdline_printf(pool, _("Failed to revert '%s' -- "
                                             "try updating instead.\n"),
                                     path_local)))
        goto print_error;
      break;

    case svn_wc_notify_resolved:
      if ((err = svn_cmdline_printf(pool,
                                    _("Resolved conflicted state of '%s'\n"),
                                    path_local)))
        goto print_error;
      break;

    case svn_wc_notify_add:
      /* We *should* only get the MIME_TYPE if PATH is a file.  If we
         do get it, and the mime-type is not textual, note that this
         is a binary addition. */
      if (n->mime_type && (svn_mime_type_is_binary(n->mime_type)))
        {
          if ((err = svn_cmdline_printf(pool, "A  (bin)  %s\n",
                                        path_local)))
            goto print_error;
        }
      else
        {
          if ((err = svn_cmdline_printf(pool, "A         %s\n",
                                        path_local)))
            goto print_error;
        }
      break;

    case svn_wc_notify_delete:
      nb->received_some_change = TRUE;
      if ((err = svn_cmdline_printf(pool, "D         %s\n",
                                    path_local)))
        goto print_error;
      break;

    case svn_wc_notify_patch:
      {
        nb->received_some_change = TRUE;
        if (n->content_state == svn_wc_notify_state_conflicted)
          {
            nb->text_conflicts++;
            statchar_buf[0] = 'C';
          }
        else if (n->kind == svn_node_file)
          {
            if (n->content_state == svn_wc_notify_state_merged)
              statchar_buf[0] = 'G';
            else if (n->content_state == svn_wc_notify_state_changed)
              statchar_buf[0] = 'U';
          }

        if (n->prop_state == svn_wc_notify_state_conflicted)
          {
            nb->prop_conflicts++;
            statchar_buf[1] = 'C';
          }
        else if (n->prop_state == svn_wc_notify_state_changed)
              statchar_buf[1] = 'U';

        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
          {
            if ((err = svn_cmdline_printf(pool, "%s      %s\n",
                                          statchar_buf, path_local)))
              goto print_error;
          }
      }
      break;

    case svn_wc_notify_patch_applied_hunk:
      nb->received_some_change = TRUE;
      if (n->hunk_original_start != n->hunk_matched_line)
        {
          apr_uint64_t off;
          const char *s;
          const char *minus;

          if (n->hunk_matched_line > n->hunk_original_start)
            {
              off = n->hunk_matched_line - n->hunk_original_start;
              minus = "";
            }
          else
            {
              off = n->hunk_original_start - n->hunk_matched_line;
              minus = "-";
            }

          /* ### We're creating the localized strings without
           * ### APR_INT64_T_FMT since it isn't translator-friendly */
          if (n->hunk_fuzz)
            {

              if (n->prop_name)
                {
                  s = _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
                        "with offset %s");

                  err = svn_cmdline_printf(pool,
                                           apr_pstrcat(pool, s,
                                                       "%"APR_UINT64_T_FMT
                                                       " and fuzz %lu (%s)\n",
                                                       (char *)NULL),
                                           n->hunk_original_start,
                                           n->hunk_original_length,
                                           n->hunk_modified_start,
                                           n->hunk_modified_length,
                                           minus, off, n->hunk_fuzz,
                                           n->prop_name);
                }
              else
                {
                  s = _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
                        "with offset %s");

                  err = svn_cmdline_printf(pool,
                                           apr_pstrcat(pool, s,
                                                       "%"APR_UINT64_T_FMT
                                                       " and fuzz %lu\n",
                                                       (char *)NULL),
                                           n->hunk_original_start,
                                           n->hunk_original_length,
                                           n->hunk_modified_start,
                                           n->hunk_modified_length,
                                           minus, off, n->hunk_fuzz);
                }

              if (err)
                goto print_error;
            }
          else
            {

              if (n->prop_name)
                {
                  s = _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
                        "with offset %s");
                  err = svn_cmdline_printf(pool,
                                            apr_pstrcat(pool, s,
                                                        "%"APR_UINT64_T_FMT" (%s)\n",
                                                        (char *)NULL),
                                            n->hunk_original_start,
                                            n->hunk_original_length,
                                            n->hunk_modified_start,
                                            n->hunk_modified_length,
                                            minus, off, n->prop_name);
                }
              else
                {
                  s = _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
                        "with offset %s");
                  err = svn_cmdline_printf(pool,
                                           apr_pstrcat(pool, s,
                                                       "%"APR_UINT64_T_FMT"\n",
                                                       (char *)NULL),
                                           n->hunk_original_start,
                                           n->hunk_original_length,
                                           n->hunk_modified_start,
                                           n->hunk_modified_length,
                                           minus, off);
                }

              if (err)
                goto print_error;
            }
        }
      else if (n->hunk_fuzz)
        {
          if (n->prop_name)
            err = svn_cmdline_printf(pool,
                          _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
                                        "with fuzz %lu (%s)\n"),
                                        n->hunk_original_start,
                                        n->hunk_original_length,
                                        n->hunk_modified_start,
                                        n->hunk_modified_length,
                                        n->hunk_fuzz,
                                        n->prop_name);
          else
            err = svn_cmdline_printf(pool,
                          _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
                                        "with fuzz %lu\n"),
                                        n->hunk_original_start,
                                        n->hunk_original_length,
                                        n->hunk_modified_start,
                                        n->hunk_modified_length,
                                        n->hunk_fuzz);
          if (err)
            goto print_error;

        }
      break;

    case svn_wc_notify_patch_rejected_hunk:
      nb->received_some_change = TRUE;

      if (n->prop_name)
        err = svn_cmdline_printf(pool,
                                 _(">         rejected hunk "
                                   "## -%lu,%lu +%lu,%lu ## (%s)\n"),
                                 n->hunk_original_start,
                                 n->hunk_original_length,
                                 n->hunk_modified_start,
                                 n->hunk_modified_length,
                                 n->prop_name);
      else
        err = svn_cmdline_printf(pool,
                                 _(">         rejected hunk "
                                   "@@ -%lu,%lu +%lu,%lu @@\n"),
                                 n->hunk_original_start,
                                 n->hunk_original_length,
                                 n->hunk_modified_start,
                                 n->hunk_modified_length);
      if (err)
        goto print_error;
      break;

    case svn_wc_notify_patch_hunk_already_applied:
      nb->received_some_change = TRUE;
      if (n->prop_name)
        err = svn_cmdline_printf(pool,
                                 _(">         hunk "
                                   "## -%lu,%lu +%lu,%lu ## "
                                   "already applied (%s)\n"),
                                 n->hunk_original_start,
                                 n->hunk_original_length,
                                 n->hunk_modified_start,
                                 n->hunk_modified_length,
                                 n->prop_name);
      else
        err = svn_cmdline_printf(pool,
                                 _(">         hunk "
                                   "@@ -%lu,%lu +%lu,%lu @@ "
                                   "already applied\n"),
                                 n->hunk_original_start,
                                 n->hunk_original_length,
                                 n->hunk_modified_start,
                                 n->hunk_modified_length);
      if (err)
        goto print_error;
      break;

    case svn_wc_notify_update_update:
    case svn_wc_notify_merge_record_info:
      {
        if (n->content_state == svn_wc_notify_state_conflicted)
          {
            nb->text_conflicts++;
            statchar_buf[0] = 'C';
          }
        else if (n->kind == svn_node_file)
          {
            if (n->content_state == svn_wc_notify_state_merged)
              statchar_buf[0] = 'G';
            else if (n->content_state == svn_wc_notify_state_changed)
              statchar_buf[0] = 'U';
          }

        if (n->prop_state == svn_wc_notify_state_conflicted)
          {
            nb->prop_conflicts++;
            statchar_buf[1] = 'C';
          }
        else if (n->prop_state == svn_wc_notify_state_merged)
          statchar_buf[1] = 'G';
        else if (n->prop_state == svn_wc_notify_state_changed)
          statchar_buf[1] = 'U';

        if (n->lock_state == svn_wc_notify_lock_state_unlocked)
          statchar_buf[2] = 'B';

        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
          nb->received_some_change = TRUE;

        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' '
            || statchar_buf[2] != ' ')
          {
            if ((err = svn_cmdline_printf(pool, "%s %s\n",
                                          statchar_buf, path_local)))
              goto print_error;
          }
      }
      break;

    case svn_wc_notify_update_external:
      /* Remember that we're now "inside" an externals definition. */
      nb->in_external = TRUE;

      /* Currently this is used for checkouts and switches too.  If we
         want different output, we'll have to add new actions. */
      if ((err = svn_cmdline_printf(pool,
                                    _("\nFetching external item into '%s':\n"),
                                    path_local)))
        goto print_error;
      break;

    case svn_wc_notify_failed_external:
      /* If we are currently inside the handling of an externals
         definition, then we can simply present n->err as a warning
         and feel confident that after this, we aren't handling that
         externals definition any longer. */
      if (nb->in_external)
        {
          svn_handle_warning2(stderr, n->err, "svn: ");
          nb->in_external = FALSE;
          if ((err = svn_cmdline_printf(pool, "\n")))
            goto print_error;
        }
      /* Otherwise, we'll just print two warnings.  Why?  Because
         svn_handle_warning2() only shows the single "best message",
         but we have two pretty important ones: that the external at
         '/some/path' didn't pan out, and then the more specific
         reason why (from n->err). */
      else
        {
          svn_error_t *warn_err =
            svn_error_createf(SVN_ERR_BASE, NULL,
                              _("Error handling externals definition for '%s':"),
                              path_local);
          svn_handle_warning2(stderr, warn_err, "svn: ");
          svn_error_clear(warn_err);
          svn_handle_warning2(stderr, n->err, "svn: ");
        }
      break;

    case svn_wc_notify_update_started:
      if (! (nb->in_external ||
             nb->is_checkout ||
             nb->is_export))
        {
          if ((err = svn_cmdline_printf(pool, _("Updating '%s':\n"),
                                        path_local)))
            goto print_error;
        }
      break;

    case svn_wc_notify_update_completed:
      {
        if (SVN_IS_VALID_REVNUM(n->revision))
          {
            if (nb->is_export)
              {
                if ((err = svn_cmdline_printf
                     (pool, nb->in_external
                      ? _("Exported external at revision %ld.\n")
                      : _("Exported revision %ld.\n"),
                      n->revision)))
                  goto print_error;
              }
            else if (nb->is_checkout)
              {
                if ((err = svn_cmdline_printf
                     (pool, nb->in_external
                      ? _("Checked out external at revision %ld.\n")
                      : _("Checked out revision %ld.\n"),
                      n->revision)))
                  goto print_error;
              }
            else
              {
                if (nb->received_some_change)
                  {
                    nb->received_some_change = FALSE;
                    if ((err = svn_cmdline_printf
                         (pool, nb->in_external
                          ? _("Updated external to revision %ld.\n")
                          : _("Updated to revision %ld.\n"),
                          n->revision)))
                      goto print_error;
                  }
                else
                  {
                    if ((err = svn_cmdline_printf
                         (pool, nb->in_external
                          ? _("External at revision %ld.\n")
                          : _("At revision %ld.\n"),
                          n->revision)))
                      goto print_error;
                  }
              }
          }
        else  /* no revision */
          {
            if (nb->is_export)
              {
                if ((err = svn_cmdline_printf
                     (pool, nb->in_external
                      ? _("External export complete.\n")
                      : _("Export complete.\n"))))
                  goto print_error;
              }
            else if (nb->is_checkout)
              {
                if ((err = svn_cmdline_printf
                     (pool, nb->in_external
                      ? _("External checkout complete.\n")
                      : _("Checkout complete.\n"))))
                  goto print_error;
              }
            else
              {
                if ((err = svn_cmdline_printf
                     (pool, nb->in_external
                      ? _("External update complete.\n")
                      : _("Update complete.\n"))))
                  goto print_error;
              }
          }
      }

      if (nb->in_external)
        {
          nb->in_external = FALSE;
          if ((err = svn_cmdline_printf(pool, "\n")))
            goto print_error;
        }
      break;

    case svn_wc_notify_status_external:
      if ((err = svn_cmdline_printf
           (pool, _("\nPerforming status on external item at '%s':\n"),
            path_local)))
        goto print_error;
      break;

    case svn_wc_notify_status_completed:
      if (SVN_IS_VALID_REVNUM(n->revision))
        if ((err = svn_cmdline_printf(pool,
                                      _("Status against revision: %6ld\n"),
                                      n->revision)))
          goto print_error;
      break;

    case svn_wc_notify_commit_modified:
      /* xgettext: Align the %s's on this and the following 4 messages */
      if ((err = svn_cmdline_printf(pool,
                                    nb->is_wc_to_repos_copy
                                      ? _("Sending copy of       %s\n")
                                      : _("Sending        %s\n"),
                                    path_local)))
        goto print_error;
      break;

    case svn_wc_notify_commit_added:
    case svn_wc_notify_commit_copied:
      if (n->mime_type && svn_mime_type_is_binary(n->mime_type))
        {
          if ((err = svn_cmdline_printf(pool,
                                        nb->is_wc_to_repos_copy
                                          ? _("Adding copy of (bin)  %s\n")
                                          : _("Adding  (bin)  %s\n"),
                                        path_local)))
          goto print_error;
        }
      else
        {
          if ((err = svn_cmdline_printf(pool,
                                        nb->is_wc_to_repos_copy
                                          ? _("Adding copy of        %s\n")
                                          : _("Adding         %s\n"),
                                        path_local)))
            goto print_error;
        }
      break;

    case svn_wc_notify_commit_deleted:
      if ((err = svn_cmdline_printf(pool,
                                    nb->is_wc_to_repos_copy
                                      ? _("Deleting copy of      %s\n")
                                      : _("Deleting       %s\n"),
                                    path_local)))
        goto print_error;
      break;

    case svn_wc_notify_commit_replaced:
    case svn_wc_notify_commit_copied_replaced:
      if ((err = svn_cmdline_printf(pool,
                                    nb->is_wc_to_repos_copy
                                      ? _("Replacing copy of     %s\n")
                                      : _("Replacing      %s\n"),
                                    path_local)))
        goto print_error;
      break;

    case svn_wc_notify_commit_postfix_txdelta:
      if (! nb->sent_first_txdelta)
        {
          nb->sent_first_txdelta = TRUE;
          if ((err = svn_cmdline_printf(pool,
                                        _("Transmitting file data "))))
            goto print_error;
        }

      if ((err = svn_cmdline_printf(pool, ".")))
        goto print_error;
      break;

    case svn_wc_notify_locked:
      if ((err = svn_cmdline_printf(pool, _("'%s' locked by user '%s'.\n"),
                                    path_local, n->lock->owner)))
        goto print_error;
      break;

    case svn_wc_notify_unlocked:
      if ((err = svn_cmdline_printf(pool, _("'%s' unlocked.\n"),
                                    path_local)))
        goto print_error;
      break;

    case svn_wc_notify_failed_lock:
    case svn_wc_notify_failed_unlock:
      svn_handle_warning2(stderr, n->err, "svn: ");
      break;

    case svn_wc_notify_changelist_set:
      if ((err = svn_cmdline_printf(pool, "A [%s] %s\n",
                                    n->changelist_name, path_local)))
        goto print_error;
      break;

    case svn_wc_notify_changelist_clear:
    case svn_wc_notify_changelist_moved:
      if ((err = svn_cmdline_printf(pool,
                                    "D [%s] %s\n",
                                    n->changelist_name, path_local)))
        goto print_error;
      break;

    case svn_wc_notify_merge_begin:
      if (n->merge_range == NULL)
        err = svn_cmdline_printf(pool,
                                 _("--- Merging differences between "
                                   "repository URLs into '%s':\n"),
                                 path_local);
      else if (n->merge_range->start == n->merge_range->end - 1
          || n->merge_range->start == n->merge_range->end)
        err = svn_cmdline_printf(pool, _("--- Merging r%ld into '%s':\n"),
                                 n->merge_range->end, path_local);
      else if (n->merge_range->start - 1 == n->merge_range->end)
        err = svn_cmdline_printf(pool,
                                 _("--- Reverse-merging r%ld into '%s':\n"),
                                 n->merge_range->start, path_local);
      else if (n->merge_range->start < n->merge_range->end)
        err = svn_cmdline_printf(pool,
                                 _("--- Merging r%ld through r%ld into "
                                   "'%s':\n"),
                                 n->merge_range->start + 1,
                                 n->merge_range->end, path_local);
      else /* n->merge_range->start > n->merge_range->end - 1 */
        err = svn_cmdline_printf(pool,
                                 _("--- Reverse-merging r%ld through r%ld "
                                   "into '%s':\n"),
                                 n->merge_range->start,
                                 n->merge_range->end + 1, path_local);
      if (err)
        goto print_error;
      break;

    case svn_wc_notify_merge_record_info_begin:
      if (!n->merge_range)
        {
          err = svn_cmdline_printf(pool,
                                   _("--- Recording mergeinfo for merge "
                                     "between repository URLs into '%s':\n"),
                                   path_local);
        }
      else
        {
          if (n->merge_range->start == n->merge_range->end - 1
              || n->merge_range->start == n->merge_range->end)
            err = svn_cmdline_printf(
              pool,
              _("--- Recording mergeinfo for merge of r%ld into '%s':\n"),
              n->merge_range->end, path_local);
          else if (n->merge_range->start - 1 == n->merge_range->end)
            err = svn_cmdline_printf(
              pool,
              _("--- Recording mergeinfo for reverse merge of r%ld into '%s':\n"),
              n->merge_range->start, path_local);
           else if (n->merge_range->start < n->merge_range->end)
             err = svn_cmdline_printf(
               pool,
               _("--- Recording mergeinfo for merge of r%ld through r%ld into '%s':\n"),
               n->merge_range->start + 1, n->merge_range->end, path_local);
           else /* n->merge_range->start > n->merge_range->end - 1 */
             err = svn_cmdline_printf(
               pool,
               _("--- Recording mergeinfo for reverse merge of r%ld through r%ld into '%s':\n"),
               n->merge_range->start, n->merge_range->end + 1, path_local);
        }

      if (err)
        goto print_error;
      break;

    case svn_wc_notify_merge_elide_info:
      if ((err = svn_cmdline_printf(pool,
                                    _("--- Eliding mergeinfo from '%s':\n"),
                                    path_local)))
        goto print_error;
      break;

    case svn_wc_notify_foreign_merge_begin:
      if (n->merge_range == NULL)
        err = svn_cmdline_printf(pool,
                                 _("--- Merging differences between "
                                   "foreign repository URLs into '%s':\n"),
                                 path_local);
      else if (n->merge_range->start == n->merge_range->end - 1
          || n->merge_range->start == n->merge_range->end)
        err = svn_cmdline_printf(pool,
                                 _("--- Merging (from foreign repository) "
                                   "r%ld into '%s':\n"),
                                 n->merge_range->end, path_local);
      else if (n->merge_range->start - 1 == n->merge_range->end)
        err = svn_cmdline_printf(pool,
                                 _("--- Reverse-merging (from foreign "
                                   "repository) r%ld into '%s':\n"),
                                 n->merge_range->start, path_local);
      else if (n->merge_range->start < n->merge_range->end)
        err = svn_cmdline_printf(pool,
                                 _("--- Merging (from foreign repository) "
                                   "r%ld through r%ld into '%s':\n"),
                                 n->merge_range->start + 1,
                                 n->merge_range->end, path_local);
      else /* n->merge_range->start > n->merge_range->end - 1 */
        err = svn_cmdline_printf(pool,
                                 _("--- Reverse-merging (from foreign "
                                   "repository) r%ld through r%ld into "
                                   "'%s':\n"),
                                 n->merge_range->start,
                                 n->merge_range->end + 1, path_local);
      if (err)
        goto print_error;
      break;

    case svn_wc_notify_tree_conflict:
      nb->tree_conflicts++;
      if ((err = svn_cmdline_printf(pool, "   C %s\n", path_local)))
        goto print_error;
      break;

    case svn_wc_notify_update_shadowed_add:
      nb->received_some_change = TRUE;
      if ((err = svn_cmdline_printf(pool, "   A %s\n", path_local)))
        goto print_error;
      break;

    case svn_wc_notify_update_shadowed_update:
      nb->received_some_change = TRUE;
      if ((err = svn_cmdline_printf(pool, "   U %s\n", path_local)))
        goto print_error;
      break;

    case svn_wc_notify_update_shadowed_delete:
      nb->received_some_change = TRUE;
      if ((err = svn_cmdline_printf(pool, "   D %s\n", path_local)))
        goto print_error;
      break;

    case svn_wc_notify_property_modified:
    case svn_wc_notify_property_added:
        err = svn_cmdline_printf(pool,
                                 _("property '%s' set on '%s'\n"),
                                 n->prop_name, path_local);
        if (err)
          goto print_error;
      break;

    case svn_wc_notify_property_deleted:
        err = svn_cmdline_printf(pool,
                                 _("property '%s' deleted from '%s'.\n"),
                                 n->prop_name, path_local);
        if (err)
          goto print_error;
      break;

    case svn_wc_notify_property_deleted_nonexistent:
        err = svn_cmdline_printf(pool,
                                 _("Attempting to delete nonexistent "
                                   "property '%s' on '%s'\n"), n->prop_name,
                                   path_local);
        if (err)
          goto print_error;
      break;

    case svn_wc_notify_revprop_set:
        err = svn_cmdline_printf(pool,
                          _("property '%s' set on repository revision %ld\n"),
                          n->prop_name, n->revision);
        if (err)
          goto print_error;
      break;

    case svn_wc_notify_revprop_deleted:
        err = svn_cmdline_printf(pool,
                     _("property '%s' deleted from repository revision %ld\n"),
                     n->prop_name, n->revision);
        if (err)
          goto print_error;
      break;

    case svn_wc_notify_upgraded_path:
        err = svn_cmdline_printf(pool, _("Upgraded '%s'\n"), path_local);
        if (err)
          goto print_error;
      break;

    case svn_wc_notify_url_redirect:
      err = svn_cmdline_printf(pool, _("Redirecting to URL '%s':\n"),
                               n->url);
      if (err)
        goto print_error;
      break;

    case svn_wc_notify_path_nonexistent:
      err = svn_cmdline_printf(pool, _("'%s' is not under version control"),
                               path_local);
      if (err)
        goto print_error;
      break;

    default:
      break;
    }

  if ((err = svn_cmdline_fflush(stdout)))
    goto print_error;

  return;

 print_error:
  /* If we had no errors before, print this error to stderr. Else, don't print
     anything.  The user already knows there were some output errors,
     so there is no point in flooding her with an error per notification. */
  if (!nb->had_print_error)
    {
      nb->had_print_error = TRUE;
      /* Issue #3014:
       * Don't print anything on broken pipes. The pipe was likely
       * closed by the process at the other end. We expect that
       * process to perform error reporting as necessary.
       *
       * ### This assumes that there is only one error in a chain for
       * ### SVN_ERR_IO_PIPE_WRITE_ERROR. See svn_cmdline_fputs(). */
      if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
        svn_handle_error2(err, stderr, FALSE, "svn: ");
    }
  svn_error_clear(err);
}
        // notify is pretty much copied from subversion 1.8.10, with some
        // things removed, partly since they don't apply and partly to get it
        // to compile with SVN 1.6.
        void notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *subpool) {
            notify_baton *nb = (notify_baton*)baton;
            char statchar_buf[5] = "    ";
            const char *path_local;
            svn_error_t *err;

            if (n->url)
                path_local = n->url;
            else
            {
                if (n->path_prefix)
                    path_local = local_style_skip_ancestor(n->path_prefix, n->path, subpool);
                else
                    path_local = local_style_skip_ancestor(nb->path_prefix, n->path, subpool);
            }

            switch (n->action) {
                case svn_wc_notify_skip:
                    if ((err = svn_cmdline_printf(subpool, "Skipped '%s'\n", path_local)))
                        goto print_error;
                    break;
                case svn_wc_notify_update_delete:
                    if ((err = svn_cmdline_printf(subpool, "D    %s\n", path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_update_replace:
                    if ((err = svn_cmdline_printf(subpool, "R    %s\n", path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_update_add:
                    if (n->content_state == svn_wc_notify_state_conflicted) {
                        if ((err = svn_cmdline_printf(subpool, "C    %s\n", path_local)))
                            goto print_error;
                    } else {
                        if ((err = svn_cmdline_printf(subpool, "A    %s\n", path_local)))
                            goto print_error;
                    }
                    break;

                case svn_wc_notify_exists:
                    if (n->content_state == svn_wc_notify_state_conflicted)
                        statchar_buf[0] = 'C';
                    else
                        statchar_buf[0] = 'E';

                    if (n->prop_state == svn_wc_notify_state_conflicted)
                        statchar_buf[1] = 'C';
                    else if (n->prop_state == svn_wc_notify_state_merged)
                        statchar_buf[1] = 'G';

                    if ((err = svn_cmdline_printf(subpool, "%s %s\n", statchar_buf, path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_restore:
                    if ((err = svn_cmdline_printf(subpool, "Restored '%s'\n", path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_revert:
                    if ((err = svn_cmdline_printf(subpool, "Reverted '%s'\n", path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_failed_revert:
                    if ((err = svn_cmdline_printf(subpool, "Failed to revert '%s' -- try updating instead.\n", path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_resolved:
                    if ((err = svn_cmdline_printf(subpool, "Resolved conflicted state of '%s'\n", path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_add:
                    /* We *should* only get the MIME_TYPE if PATH is a file.  If we
                       do get it, and the mime-type is not textual, note that this
                       is a binary addition. */
                    if (n->mime_type && (svn_mime_type_is_binary(n->mime_type))) {
                        if ((err = svn_cmdline_printf(subpool, "A  (bin)  %s\n", path_local)))
                            goto print_error;
                    } else {
                        if ((err = svn_cmdline_printf(subpool, "A         %s\n", path_local)))
                            goto print_error;
                    }
                    break;

                case svn_wc_notify_delete:
                    if ((err = svn_cmdline_printf(subpool, "D         %s\n", path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_update_update:
                    {
                        if (n->content_state == svn_wc_notify_state_conflicted) {
                            statchar_buf[0] = 'C';
                        } else if (n->kind == svn_node_file) {
                            if (n->content_state == svn_wc_notify_state_merged)
                                statchar_buf[0] = 'G';
                            else if (n->content_state == svn_wc_notify_state_changed)
                                statchar_buf[0] = 'U';
                        }

                        if (n->prop_state == svn_wc_notify_state_conflicted)
                            statchar_buf[1] = 'C';
                        else if (n->prop_state == svn_wc_notify_state_merged)
                            statchar_buf[1] = 'G';
                        else if (n->prop_state == svn_wc_notify_state_changed)
                            statchar_buf[1] = 'U';

                        if (n->lock_state == svn_wc_notify_lock_state_unlocked)
                            statchar_buf[2] = 'B';

                        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ' || statchar_buf[2] != ' ') {
                            if ((err = svn_cmdline_printf(subpool, "%s %s\n", statchar_buf, path_local)))
                                goto print_error;
                        }
                    }
                    break;

                case svn_wc_notify_locked:
                    if ((err = svn_cmdline_printf(subpool, "'%s' locked by user '%s'.\n", path_local, n->lock->owner)))
                        goto print_error;
                    break;

                case svn_wc_notify_unlocked:
                    if ((err = svn_cmdline_printf(subpool, "'%s' unlocked.\n", path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_failed_lock:
                case svn_wc_notify_failed_unlock:
                    svn_handle_warning2(stderr, n->err, "svn: ");
                    break;

                case svn_wc_notify_changelist_set:
                    if ((err = svn_cmdline_printf(subpool, "A [%s] %s\n", n->changelist_name, path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_changelist_clear:
                case svn_wc_notify_changelist_moved:
                    if ((err = svn_cmdline_printf(subpool, "D [%s] %s\n", n->changelist_name, path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_tree_conflict:
                    if ((err = svn_cmdline_printf(subpool, "   C %s\n", path_local)))
                        goto print_error;
                    break;

                case svn_wc_notify_property_modified:
                case svn_wc_notify_property_added:
                    err = svn_cmdline_printf(subpool, "property '%s' set on '%s'\n", n->prop_name, path_local);
                    if (err)
                        goto print_error;
                    break;

                case svn_wc_notify_property_deleted:
                    err = svn_cmdline_printf(subpool, "property '%s' deleted from '%s'.\n", n->prop_name, path_local);
                    if (err)
                        goto print_error;
                    break;

                case svn_wc_notify_property_deleted_nonexistent:
                    err = svn_cmdline_printf(subpool, "Attempting to delete nonexistent property '%s' on '%s'\n", n->prop_name, path_local);
                    if (err)
                        goto print_error;
                    break;

                case svn_wc_notify_revprop_set:
                    err = svn_cmdline_printf(subpool, "property '%s' set on repository revision %ld\n", n->prop_name, n->revision);
                    if (err)
                        goto print_error;
                    break;

                case svn_wc_notify_revprop_deleted:
                    err = svn_cmdline_printf(subpool, "property '%s' deleted from repository revision %ld\n", n->prop_name, n->revision);
                    if (err)
                        goto print_error;
                    break;

                default:
                    break;
            }

            if ((err = svn_cmdline_fflush(stdout)))
                goto print_error;

            return;

print_error:
            /* If we had no errors before, print this error to stderr. Else, don't print
               anything.  The user already knows there were some output errors,
               so there is no point in flooding her with an error per notification. */
            if (!nb->had_print_error) {
                nb->had_print_error = true;
                svn_handle_error2(err, stderr, FALSE, "svn: ");
            }
            svn_error_clear(err);
        }
Пример #12
0
/* Print STATUS and PATH in a format determined by DETAILED and
   SHOW_LAST_COMMITTED. */
static svn_error_t *
print_status(const char *cwd_abspath, const char *path,
             svn_boolean_t detailed,
             svn_boolean_t show_last_committed,
             svn_boolean_t repos_locks,
             const svn_client_status_t *status,
             unsigned int *text_conflicts,
             unsigned int *prop_conflicts,
             unsigned int *tree_conflicts,
             svn_client_ctx_t *ctx,
             apr_pool_t *pool)
{
  enum svn_wc_status_kind node_status = status->node_status;
  enum svn_wc_status_kind prop_status = status->prop_status;
  char tree_status_code = ' ';
  const char *tree_desc_line = "";
  const char *moved_from_line = "";
  const char *moved_to_line = "";

  path = make_relpath(cwd_abspath, path, pool, pool);

  /* For historic reasons svn ignores the property status for added nodes, even
     if these nodes were copied and have local property changes.

     Note that it doesn't do this on replacements, or children of copies.

     ### Our test suite would catch more errors if we reported property
         changes on copies. */
  if (node_status == svn_wc_status_added)
      prop_status = svn_wc_status_none;

  /* To indicate this node is the victim of a tree conflict, we show
     'C' in the tree-conflict column, overriding any other status.
     We also print a separate line describing the nature of the tree
     conflict. */
  if (status->conflicted)
    {
      const char *desc;
      const char *local_abspath = status->local_abspath;
      svn_boolean_t text_conflicted;
      svn_boolean_t prop_conflicted;
      svn_boolean_t tree_conflicted;

      if (status->versioned)
        {
          svn_error_t *err;

          err = svn_wc_conflicted_p3(&text_conflicted,
                                     &prop_conflicted,
                                     &tree_conflicted, ctx->wc_ctx,
                                     local_abspath, pool);

          if (err && err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
            {
              svn_error_clear(err);
              text_conflicted = FALSE;
              prop_conflicted = FALSE;
              tree_conflicted = FALSE;
            }
          else
            SVN_ERR(err);
        }
      else
        {
          text_conflicted = FALSE;
          prop_conflicted = FALSE;
          tree_conflicted = TRUE;
        }

      if (tree_conflicted)
        {
          const svn_wc_conflict_description2_t *tree_conflict;
          SVN_ERR(svn_wc__get_tree_conflict(&tree_conflict, ctx->wc_ctx,
                                            local_abspath, pool, pool));
          SVN_ERR_ASSERT(tree_conflict != NULL);

          tree_status_code = 'C';
          SVN_ERR(svn_cl__get_human_readable_tree_conflict_description(
                            &desc, tree_conflict, pool));
          tree_desc_line = apr_psprintf(pool, "\n      >   %s", desc);
          (*tree_conflicts)++;
        }
      else if (text_conflicted)
        (*text_conflicts)++;
      else if (prop_conflicted)
        (*prop_conflicts)++;
    }

  /* Note that moved-from and moved-to information is only available in STATUS
   * for (op-)roots of a move. Those are exactly the nodes we want to show
   * move info for in 'svn status'. See also comments in svn_wc_status3_t. */
  if (status->moved_from_abspath && status->moved_to_abspath &&
      strcmp(status->moved_from_abspath, status->moved_to_abspath) == 0)
    {
      const char *relpath;

      relpath = make_relpath(cwd_abspath, status->moved_from_abspath,
                             pool, pool);
      relpath = svn_dirent_local_style(relpath, pool);
      moved_from_line = apr_pstrcat(pool, "\n        > ",
                                    apr_psprintf(pool,
                                                 _("swapped places with %s"),
                                                 relpath),
                                    (char *)NULL);
    }
  else if (status->moved_from_abspath || status->moved_to_abspath)
    {
      const char *relpath;

      if (status->moved_from_abspath)
        {
          relpath = make_relpath(cwd_abspath, status->moved_from_abspath,
                                 pool, pool);
          relpath = svn_dirent_local_style(relpath, pool);
          moved_from_line = apr_pstrcat(pool, "\n        > ",
                                        apr_psprintf(pool, _("moved from %s"),
                                                     relpath),
                                        (char *)NULL);
        }

      if (status->moved_to_abspath)
        {
          relpath = make_relpath(cwd_abspath, status->moved_to_abspath,
                                 pool, pool);
          relpath = svn_dirent_local_style(relpath, pool);
          moved_to_line = apr_pstrcat(pool, "\n        > ",
                                      apr_psprintf(pool, _("moved to %s"),
                                                   relpath),
                                      (char *)NULL);
        }
    }

  if (detailed)
    {
      char ood_status, lock_status;
      const char *working_rev;

      if (! status->versioned)
        working_rev = "";
      else if (status->copied
               || ! SVN_IS_VALID_REVNUM(status->revision))
        working_rev = "-";
      else
        working_rev = apr_psprintf(pool, "%ld", status->revision);

      if (status->repos_node_status != svn_wc_status_none)
        ood_status = '*';
      else
        ood_status = ' ';

      if (repos_locks)
        {
          if (status->repos_lock)
            {
              if (status->lock)
                {
                  if (strcmp(status->repos_lock->token, status->lock->token)
                      == 0)
                    lock_status = 'K';
                  else
                    lock_status = 'T';
                }
              else
                lock_status = 'O';
            }
          else if (status->lock)
            lock_status = 'B';
          else
            lock_status = ' ';
        }
      else
        lock_status = (status->lock) ? 'K' : ' ';

      if (show_last_committed)
        {
          const char *commit_rev;
          const char *commit_author;

          if (SVN_IS_VALID_REVNUM(status->changed_rev))
            commit_rev = apr_psprintf(pool, "%ld", status->changed_rev);
          else if (status->versioned)
            commit_rev = " ? ";
          else
            commit_rev = "";

          if (status->changed_author)
            commit_author = status->changed_author;
          else if (status->versioned)
            commit_author = " ? ";
          else
            commit_author = "";

          SVN_ERR
            (svn_cmdline_printf(pool,
                                "%c%c%c%c%c%c%c %c %8s %8s %-12s %s%s%s%s\n",
                                generate_status_code(combined_status(status)),
                                generate_status_code(prop_status),
                                status->wc_is_locked ? 'L' : ' ',
                                status->copied ? '+' : ' ',
                                generate_switch_column_code(status),
                                lock_status,
                                tree_status_code,
                                ood_status,
                                working_rev,
                                commit_rev,
                                commit_author,
                                path,
                                moved_to_line,
                                moved_from_line,
                                tree_desc_line));
        }
      else
        SVN_ERR(
           svn_cmdline_printf(pool, "%c%c%c%c%c%c%c %c %8s   %s%s%s%s\n",
                              generate_status_code(combined_status(status)),
                              generate_status_code(prop_status),
                              status->wc_is_locked ? 'L' : ' ',
                              status->copied ? '+' : ' ',
                              generate_switch_column_code(status),
                              lock_status,
                              tree_status_code,
                              ood_status,
                              working_rev,
                              path,
                              moved_to_line,
                              moved_from_line,
                              tree_desc_line));
    }
  else
    SVN_ERR(
       svn_cmdline_printf(pool, "%c%c%c%c%c%c%c %s%s%s%s\n",
                          generate_status_code(combined_status(status)),
                          generate_status_code(prop_status),
                          status->wc_is_locked ? 'L' : ' ',
                          status->copied ? '+' : ' ',
                          generate_switch_column_code(status),
                          ((status->lock)
                           ? 'K' : ' '),
                          tree_status_code,
                          path,
                          moved_to_line,
                          moved_from_line,
                          tree_desc_line));

  return svn_cmdline_fflush(stdout);
}
Пример #13
0
/*
 * Why is this not an svn subcommand?  I have this vague idea that it could
 * be run as part of the build process, with the output embedded in the svn
 * program.  Obviously we don't want to have to run svn when building svn.
 */
int
main(int argc, const char *argv[])
{
  const char *wc_path, *trail_url;
  const char *local_abspath;
  apr_pool_t *pool;
  svn_wc_revision_status_t *res;
  svn_boolean_t no_newline = FALSE, committed = FALSE;
  svn_error_t *err;
  apr_getopt_t *os;
  svn_wc_context_t *wc_ctx;
  svn_boolean_t quiet = FALSE;
  svn_boolean_t is_version = FALSE;
  const apr_getopt_option_t options[] =
    {
      {"no-newline", 'n', 0, N_("do not output the trailing newline")},
      {"committed",  'c', 0, N_("last changed rather than current revisions")},
      {"help", 'h', 0, N_("display this help")},
      {"version", SVNVERSION_OPT_VERSION, 0,
       N_("show program version information")},
      {"quiet",         'q', 0,
       N_("no progress (only errors) to stderr")},
      {0,             0,  0,  0}
    };

  /* Initialize the app. */
  if (svn_cmdline_init("svnversion", 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));

  /* Check library versions */
  err = check_lib_versions();
  if (err)
    return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");

#if defined(WIN32) || defined(__CYGWIN__)
  /* Set the working copy administrative directory name. */
  if (getenv("SVN_ASP_DOT_NET_HACK"))
    {
      err = svn_wc_set_adm_dir("_svn", pool);
      if (err)
        return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");
    }
#endif

  err = svn_cmdline__getopt_init(&os, argc, argv, pool);
  if (err)
    return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");

  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);  /* this will exit() */

      switch (opt)
        {
        case 'n':
          no_newline = TRUE;
          break;
        case 'c':
          committed = TRUE;
          break;
        case 'q':
          quiet = TRUE;
          break;
        case 'h':
          help(options, pool);
          break;
        case SVNVERSION_OPT_VERSION:
          is_version = TRUE;
          break;
        default:
          usage(pool);  /* this will exit() */
        }
    }

  if (is_version)
    {
      SVN_INT_ERR(version(quiet, pool));
      exit(0);
    }
  if (os->ind > argc || os->ind < argc - 2)
    usage(pool);  /* this will exit() */

  SVN_INT_ERR(svn_utf_cstring_to_utf8(&wc_path,
                                      (os->ind < argc) ? os->argv[os->ind]
                                                       : ".",
                                      pool));

  SVN_INT_ERR(svn_opt__arg_canonicalize_path(&wc_path, wc_path, pool));
  SVN_INT_ERR(svn_dirent_get_absolute(&local_abspath, wc_path, pool));
  SVN_INT_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool));

  if (os->ind+1 < argc)
    SVN_INT_ERR(svn_utf_cstring_to_utf8(&trail_url, os->argv[os->ind+1],
                                        pool));
  else
    trail_url = NULL;

  err = svn_wc_revision_status2(&res, wc_ctx, local_abspath, trail_url,
                                committed, NULL, NULL, pool, pool);

  if (err && (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND
              || err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY))
    {
      svn_node_kind_t kind;
      svn_boolean_t special;

      svn_error_clear(err);

      SVN_INT_ERR(svn_io_check_special_path(local_abspath, &kind, &special,
                                            pool));

      if (special)
        SVN_INT_ERR(svn_cmdline_printf(pool, _("Unversioned symlink%s"),
                                       no_newline ? "" : "\n"));
      else if (kind == svn_node_dir)
        SVN_INT_ERR(svn_cmdline_printf(pool, _("Unversioned directory%s"),
                                       no_newline ? "" : "\n"));
      else if (kind == svn_node_file)
        SVN_INT_ERR(svn_cmdline_printf(pool, _("Unversioned file%s"),
                                       no_newline ? "" : "\n"));
      else
        {
          SVN_INT_ERR(svn_cmdline_fprintf(stderr, pool,
                                          kind == svn_node_none
                                           ? _("'%s' doesn't exist\n")
                                           : _("'%s' is of unknown type\n"),
                                          svn_dirent_local_style(local_abspath,
                                                                 pool)));
          svn_pool_destroy(pool);
          return EXIT_FAILURE;
        }
      svn_pool_destroy(pool);
      return EXIT_SUCCESS;
    }

  SVN_INT_ERR(err);

  if (! SVN_IS_VALID_REVNUM(res->min_rev))
    {
      /* Local uncommitted modifications, no revision info was found. */
      SVN_INT_ERR(svn_cmdline_printf(pool, _("Uncommitted local addition, "
                                             "copy or move%s"),
                                             no_newline ? "" : "\n"));
      svn_pool_destroy(pool);
      return EXIT_SUCCESS;
    }

  /* Build compact '123[:456]M?S?' string. */
  SVN_INT_ERR(svn_cmdline_printf(pool, "%ld", res->min_rev));
  if (res->min_rev != res->max_rev)
    SVN_INT_ERR(svn_cmdline_printf(pool, ":%ld", res->max_rev));
  if (res->modified)
    SVN_INT_ERR(svn_cmdline_fputs("M", stdout, pool));
  if (res->switched)
    SVN_INT_ERR(svn_cmdline_fputs("S", stdout, pool));
  if (res->sparse_checkout)
    SVN_INT_ERR(svn_cmdline_fputs("P", stdout, pool));

  if (! no_newline)
    SVN_INT_ERR(svn_cmdline_fputs("\n", stdout, pool));

  svn_pool_destroy(pool);

  /* Flush stdout to make sure that the user will see any printing errors. */
  SVN_INT_ERR(svn_cmdline_fflush(stdout));

  return EXIT_SUCCESS;
}