Example #1
0
File: opt.c Project: DJEX93/dsploit
svn_error_t *
svn_opt__print_version_info(const char *pgm_name,
                            const char *footer,
                            svn_boolean_t quiet,
                            apr_pool_t *pool)
{
  if (quiet)
    return svn_cmdline_printf(pool, "%s\n", SVN_VER_NUMBER);

  SVN_ERR(svn_cmdline_printf(pool, _("%s, version %s\n"
                                     "   compiled %s, %s\n\n"), pgm_name,
                             SVN_VERSION, __DATE__, __TIME__));
  SVN_ERR(svn_cmdline_fputs(
             _("Copyright (C) 2013 The Apache Software Foundation.\n"
               "This software consists of contributions made by many "
               "people; see the NOTICE\n"
               "file for more information.\n"
               "Subversion is open source software, see "
               "http://subversion.apache.org/\n\n"),
             stdout, pool));

  if (footer)
    {
      SVN_ERR(svn_cmdline_printf(pool, "%s\n", footer));
    }

  return SVN_NO_ERROR;
}
Example #2
0
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;
}
Example #3
0
svn_error_t *
svn_cl__print_commit_info(const svn_commit_info_t *commit_info,
                          void *baton,
                          apr_pool_t *pool)
{
  /* Be very careful with returning errors from this callback as those
     will be returned as errors from editor->close_edit(...), which may
     cause callers to assume that the commit itself failed.

     See log message of r1659867 and the svn_ra_get_commit_editor3
     documentation for details on error scenarios. */

  if (SVN_IS_VALID_REVNUM(commit_info->revision))
    SVN_ERR(svn_cmdline_printf(pool, _("Committed revision %ld%s.\n"),
                               commit_info->revision,
                               commit_info->revision == 42 &&
                               getenv("SVN_I_LOVE_PANGALACTIC_GARGLE_BLASTERS")
                                 ?  _(" (the answer to life, the universe, "
                                      "and everything)")
                                 : ""));

  /* Writing to stdout, as there maybe systems that consider the
   * presence of stderr as an indication of commit failure.
   * OTOH, this is only of informational nature to the user as
   * the commit has succeeded. */
  if (commit_info->post_commit_err)
    SVN_ERR(svn_cmdline_printf(pool, _("\nWarning: %s\n"),
                               commit_info->post_commit_err));

  return SVN_NO_ERROR;
}
Example #4
0
svn_error_t *
svn_opt__print_version_info(const char *pgm_name,
                            const char *footer,
                            svn_boolean_t quiet,
                            apr_pool_t *pool)
{
    if (quiet)
        return svn_cmdline_printf(pool, "%s\n", SVN_VER_NUMBER);

    SVN_ERR(svn_cmdline_printf(pool, _("%s, version %s\n"
                                       "   compiled %s, %s\n\n"), pgm_name,
                               SVN_VERSION, __DATE__, __TIME__));
    SVN_ERR(svn_cmdline_fputs(_("Copyright (C) 2000-2009 CollabNet.\n"
                                "Subversion is open source software, see"
                                " http://subversion.tigris.org/\n"
                                "This product includes software developed by "
                                "CollabNet (http://www.Collab.Net/).\n\n"),
                              stdout, pool));

    if (footer)
    {
        SVN_ERR(svn_cmdline_printf(pool, "%s\n", footer));
    }

    return SVN_NO_ERROR;
}
Example #5
0
/* Print REPS_REF_COUNT (a hash as for process_one_revision())
 * to stdout in "refcount => sha1" format.  A sha1 may appear
 * more than once if not all its instances are shared.  Prepend
 * each line by NAME.
 *
 * Use SCRATCH_POOL for temporary allocations.
 */
static svn_error_t *
pretty_print(const char *name,
             apr_hash_t *reps_ref_counts,
             apr_pool_t *scratch_pool)
{
  apr_hash_index_t *hi;

  if (reps_ref_counts == NULL)
    return SVN_NO_ERROR;

  for (hi = apr_hash_first(scratch_pool, reps_ref_counts);
       hi; hi = apr_hash_next(hi))
    {
      struct value_t *value;

      SVN_ERR(cancel_func(NULL));

      value = svn__apr_hash_index_val(hi);
      SVN_ERR(svn_cmdline_printf(scratch_pool, "%s %" APR_UINT64_T_FMT " %s\n",
                                 name, value->refcount,
                                 svn_checksum_to_cstring_display(
                                   value->sha1_checksum,
                                   scratch_pool)));
    }

  return SVN_NO_ERROR;
}
static svn_error_t *
obtain_lock(const char *path, svn_boolean_t recursive,
            apr_pool_t *scratch_pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;

  SVN_ERR(svn_path_cstring_to_utf8(&path, path, scratch_pool));
  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));

      SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, scratch_pool,
                                    scratch_pool));

  if (recursive)
    {
      /* The WC-NG way */
      SVN_ERR(svn_wc__acquire_write_lock(NULL, wc_ctx, local_abspath, FALSE,
                                         scratch_pool, scratch_pool));
    }
  else
    {
      SVN_ERR(svn_wc__db_wclock_obtain(wc_ctx->db, local_abspath, 0, FALSE,
                                       scratch_pool));
    }

  SVN_ERR(svn_cmdline_printf(scratch_pool, "Lock on '%s' obtained, and we "
                             "are not going to release it.\n",
                             svn_dirent_local_style(local_abspath,
                                                    scratch_pool)));

  return SVN_NO_ERROR;
}
Example #7
0
static void
copy_warning_notify_func(void *baton,
                         const svn_wc_notify_t *notify,
                         apr_pool_t *pool)
{
    struct copy_warning_notify_baton *b = baton;

    /* Call the wrapped notification system (if any). */
    if (b->wrapped_func)
        b->wrapped_func(b->wrapped_baton, notify, pool);

    /* If we're being notified about a copy of a directory when our
       commit depth is less-than-infinite, and we've not already warned
       about this situation, then warn about it (and remember that we
       now have.)  */
    if ((! b->warned)
            && (b->depth < svn_depth_infinity)
            && (notify->kind == svn_node_dir)
            && ((notify->action == svn_wc_notify_commit_copied) ||
                (notify->action == svn_wc_notify_commit_copied_replaced)))
    {
        svn_error_t *err;
        err = svn_cmdline_printf(pool,
                                 _("svn: The depth of this commit is '%s', "
                                   "but copies are always performed "
                                   "recursively in the repository.\n"),
                                 svn_depth_to_word(b->depth));
        /* ### FIXME: Try to return this error showhow? */
        svn_error_clear(err);

        /* We'll only warn once. */
        b->warned = TRUE;
    }
}
Example #8
0
static svn_error_t *
close_edit(void *edit_baton,
           apr_pool_t *pool)
{
  edit_baton_t *eb = edit_baton;

  /* If we haven't opened the root yet, that means we're transfering
     an empty revision, probably because we aren't allowed to see the
     contents for some reason.  In any event, we need to open the root
     and close it again, before we can close out the edit, or the
     commit will fail. */

  if (! eb->called_open_root)
    {
      void *baton;
      SVN_ERR(eb->wrapped_editor->open_root(eb->wrapped_edit_baton,
                                            eb->base_revision, pool,
                                            &baton));
      SVN_ERR(eb->wrapped_editor->close_directory(baton, pool));
    }

  if (! eb->quiet)
    {
      if (eb->got_textdeltas)
        SVN_ERR(svn_cmdline_printf(pool, "\n"));
      if (eb->mergeinfo_tweaked)
        SVN_ERR(svn_cmdline_printf(pool,
                                   "NOTE: Adjusted Subversion mergeinfo in "
                                   "this revision.\n"));
      if (eb->mergeinfo_stripped)
        SVN_ERR(svn_cmdline_printf(pool,
                                   "NOTE: Dropped Subversion mergeinfo "
                                   "from this revision.\n"));
      if (eb->svnmerge_migrated)
        SVN_ERR(svn_cmdline_printf(pool,
                                   "NOTE: Migrated 'svnmerge-integrated' in "
                                   "this revision.\n"));
      if (eb->svnmerge_blocked)
        SVN_ERR(svn_cmdline_printf(pool,
                                   "NOTE: Saw 'svnmerge-blocked' in this "
                                   "revision (but didn't migrate it).\n"));
    }

  return eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool);
}
Example #9
0
/* Implements `svn_ra__lock_retry_func_t'. */
static svn_error_t *
lock_retry_func(void *baton,
                const svn_string_t *reposlocktoken,
                apr_pool_t *pool)
{
  return svn_cmdline_printf(pool,
                            _("Failed to get lock on destination "
                              "repos, currently held by '%s'\n"),
                            reposlocktoken->data);
}
Example #10
0
static svn_error_t *
svn_cl__info_print_time(apr_time_t atime,
                        const char *desc,
                        apr_pool_t *pool)
{
  const char *time_utf8;

  time_utf8 = svn_time_to_human_cstring(atime, pool);
  return svn_cmdline_printf(pool, "%s: %s\n", desc, time_utf8);
}
Example #11
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__null_export(apr_getopt_t *os,
                    void *baton,
                    apr_pool_t *pool)
{
    svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
    svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
    const char *from;
    apr_array_header_t *targets;
    svn_error_t *err;
    svn_opt_revision_t peg_revision;
    const char *truefrom;
    edit_baton_t eb = { 0 };

    SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
            opt_state->targets,
            ctx, FALSE, pool));

    /* We want exactly 1 or 2 targets for this subcommand. */
    if (targets->nelts < 1)
        return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
    if (targets->nelts > 2)
        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);

    /* The first target is the `from' path. */
    from = APR_ARRAY_IDX(targets, 0, const char *);

    /* Get the peg revision if present. */
    SVN_ERR(svn_opt_parse_path(&peg_revision, &truefrom, from, pool));

    if (opt_state->depth == svn_depth_unknown)
        opt_state->depth = svn_depth_infinity;

    /* Do the export. */
    err = bench_null_export(NULL, truefrom, &peg_revision,
                            &(opt_state->start_revision),
                            opt_state->depth,
                            &eb,
                            ctx, opt_state->quiet, pool);

    if (!opt_state->quiet)
        SVN_ERR(svn_cmdline_printf(pool,
                                   _("%15s directories\n"
                                     "%15s files\n"
                                     "%15s bytes in files\n"
                                     "%15s properties\n"
                                     "%15s bytes in properties\n"),
                                   svn__ui64toa_sep(eb.dir_count, ',', pool),
                                   svn__ui64toa_sep(eb.file_count, ',', pool),
                                   svn__ui64toa_sep(eb.byte_count, ',', pool),
                                   svn__ui64toa_sep(eb.prop_count, ',', pool),
                                   svn__ui64toa_sep(eb.prop_byte_count, ',', pool)));

    return svn_error_trace(err);
}
Example #12
0
static svn_error_t *
commit_callback(const svn_commit_info_t *commit_info,
                void *baton,
                apr_pool_t *pool)
{
  SVN_ERR(svn_cmdline_printf(pool, "r%ld committed by %s at %s\n",
                             commit_info->revision,
                             (commit_info->author
                              ? commit_info->author : "(no author)"),
                             commit_info->date));
  return SVN_NO_ERROR;
}
Example #13
0
/* Print conflict stats accumulated in status baton SB.
 * Do temporary allocations in POOL. */
static svn_error_t *
print_conflict_stats(struct status_baton *sb, apr_pool_t *pool)
{
  if (sb->text_conflicts > 0 || sb->prop_conflicts > 0 ||
      sb->tree_conflicts > 0)
      SVN_ERR(svn_cmdline_printf(pool, "%s", _("Summary of conflicts:\n")));

  if (sb->text_conflicts > 0)
    SVN_ERR(svn_cmdline_printf
      (pool, _("  Text conflicts: %u\n"), sb->text_conflicts));

  if (sb->prop_conflicts > 0)
    SVN_ERR(svn_cmdline_printf
      (pool, _("  Property conflicts: %u\n"), sb->prop_conflicts));

  if (sb->tree_conflicts > 0)
    SVN_ERR(svn_cmdline_printf
      (pool, _("  Tree conflicts: %u\n"), sb->tree_conflicts));

  return SVN_NO_ERROR;
}
Example #14
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);
}
Example #15
0
svn_error_t *
svn_cl__print_conflict_stats(void *notify_baton, apr_pool_t *pool)
{
  struct notify_baton *nb = notify_baton;
  unsigned int text_conflicts;
  unsigned int prop_conflicts;
  unsigned int tree_conflicts;
  unsigned int skipped_paths;

  text_conflicts = nb->text_conflicts;
  prop_conflicts = nb->prop_conflicts;
  tree_conflicts = nb->tree_conflicts;
  skipped_paths = nb->skipped_paths;

  if (text_conflicts > 0 || prop_conflicts > 0
    || tree_conflicts > 0 || skipped_paths > 0)
      SVN_ERR(svn_cmdline_printf(pool, "%s", _("Summary of conflicts:\n")));

  if (text_conflicts > 0)
    SVN_ERR(svn_cmdline_printf
      (pool, _("  Text conflicts: %u\n"), text_conflicts));

  if (prop_conflicts > 0)
    SVN_ERR(svn_cmdline_printf
      (pool, _("  Property conflicts: %u\n"), prop_conflicts));

  if (tree_conflicts > 0)
    SVN_ERR(svn_cmdline_printf
      (pool, _("  Tree conflicts: %u\n"), tree_conflicts));

  if (skipped_paths > 0)
    SVN_ERR(svn_cmdline_printf
      (pool, _("  Skipped paths: %u\n"), skipped_paths));

  return SVN_NO_ERROR;
}
Example #16
0
svn_error_t *
svn_cl__print_commit_info(const svn_commit_info_t *commit_info,
                          void *baton,
                          apr_pool_t *pool)
{
  if (SVN_IS_VALID_REVNUM(commit_info->revision))
    SVN_ERR(svn_cmdline_printf(pool, _("\nCommitted revision %ld%s.\n"),
                               commit_info->revision,
                               commit_info->revision == 42 &&
                               getenv("SVN_I_LOVE_PANGALACTIC_GARGLE_BLASTERS")
                                 ?  _(" (the answer to life, the universe, "
                                      "and everything)")
                                 : ""));

  /* Writing to stdout, as there maybe systems that consider the
   * presence of stderr as an indication of commit failure.
   * OTOH, this is only of informational nature to the user as
   * the commit has succeeded. */
  if (commit_info->post_commit_err)
    SVN_ERR(svn_cmdline_printf(pool, _("\nWarning: %s\n"),
                               commit_info->post_commit_err));

  return SVN_NO_ERROR;
}
Example #17
0
/* This implements the svn_proplist_receiver_t interface. */
static svn_error_t *
proplist_receiver(void *baton,
                  const char *path,
                  apr_hash_t *prop_hash,
                  apr_pool_t *pool)
{
  svn_cl__opt_state_t *opt_state = ((proplist_baton_t *)baton)->opt_state;
  svn_boolean_t is_url = ((proplist_baton_t *)baton)->is_url;
  const char *name_local;

  if (! is_url)
    name_local = svn_path_local_style(path, pool);
  else
    name_local = path;

  if (!opt_state->quiet)
    SVN_ERR(svn_cmdline_printf(pool, _("Properties on '%s':\n"), name_local));
  return svn_cl__print_prop_hash(prop_hash, (! opt_state->verbose), pool);
}
Example #18
0
static svn_error_t *
commit_callback(const svn_commit_info_t *commit_info,
                void *baton,
                apr_pool_t *pool)
{
  struct revision_baton *rb = baton;
  struct parse_baton *pb = rb->pb;

  /* ### Don't print directly; generate a notification. */
  if (! pb->quiet)
    SVN_ERR(svn_cmdline_printf(pool, "* Loaded revision %ld.\n",
                               commit_info->revision));

  /* Add the mapping of the dumpstream revision to the committed revision. */
  set_revision_mapping(pb->rev_map, rb->rev, commit_info->revision);

  /* If the incoming dump stream has non-contiguous revisions (e.g. from
     using svndumpfilter --drop-empty-revs without --renumber-revs) then
     we must account for the missing gaps in PB->REV_MAP.  Otherwise we
     might not be able to map all mergeinfo source revisions to the correct
     revisions in the target repos. */
  if ((pb->last_rev_mapped != SVN_INVALID_REVNUM)
      && (rb->rev != pb->last_rev_mapped + 1))
    {
      svn_revnum_t i;

      for (i = pb->last_rev_mapped + 1; i < rb->rev; i++)
        {
          set_revision_mapping(pb->rev_map, i, pb->last_rev_mapped);
        }
    }

  /* Update our "last revision mapped". */
  pb->last_rev_mapped = rb->rev;

  return SVN_NO_ERROR;
}
Example #19
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__status(apr_getopt_t *os,
               void *baton,
               apr_pool_t *pool)
{
    svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
    svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
    apr_array_header_t *targets;
    apr_pool_t *subpool;
    apr_hash_t *master_cl_hash = apr_hash_make(pool);
    int i;
    svn_opt_revision_t rev;
    struct status_baton sb;

    SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
            opt_state->targets,
            ctx, pool));

    /* Add "." if user passed 0 arguments */
    svn_opt_push_implicit_dot_target(targets, pool);

    /* We want our -u statuses to be against HEAD. */
    rev.kind = svn_opt_revision_head;

    /* The notification callback, leave the notifier as NULL in XML mode */
    if (! opt_state->xml)
        svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE,
                             FALSE, FALSE, pool);

    subpool = svn_pool_create(pool);

    sb.had_print_error = FALSE;

    if (opt_state->xml)
    {
        /* If output is not incremental, output the XML header and wrap
           everything in a top-level element. This makes the output in
           its entirety a well-formed XML document. */
        if (! opt_state->incremental)
            SVN_ERR(svn_cl__xml_print_header("status", pool));
    }
    else
    {
        if (opt_state->incremental)
            return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                    _("'incremental' option only valid in XML "
                                      "mode"));
    }

    sb.detailed = (opt_state->verbose || opt_state->update);
    sb.show_last_committed = opt_state->verbose;
    sb.skip_unrecognized = opt_state->quiet;
    sb.repos_locks = opt_state->update;
    sb.xml_mode = opt_state->xml;
    sb.cached_changelists = master_cl_hash;
    sb.cl_pool = pool;

    SVN_ERR(svn_opt__eat_peg_revisions(&targets, targets, pool));

    for (i = 0; i < targets->nelts; i++)
    {
        const char *target = APR_ARRAY_IDX(targets, i, const char *);
        svn_revnum_t repos_rev = SVN_INVALID_REVNUM;

        svn_pool_clear(subpool);

        SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));

        if (opt_state->xml)
            SVN_ERR(print_start_target_xml(svn_path_local_style(target, subpool),
                                           subpool));

        /* Retrieve a hash of status structures with the information
           requested by the user. */
        SVN_ERR(svn_cl__try(svn_client_status4(&repos_rev, target, &rev,
                                               print_status, &sb,
                                               opt_state->depth,
                                               opt_state->verbose,
                                               opt_state->update,
                                               opt_state->no_ignore,
                                               opt_state->ignore_externals,
                                               opt_state->changelists,
                                               ctx, subpool),
                            NULL, opt_state->quiet,
                            /* not versioned: */
                            SVN_ERR_WC_NOT_DIRECTORY,
                            SVN_NO_ERROR));

        if (opt_state->xml)
            SVN_ERR(print_finish_target_xml(repos_rev, subpool));
    }

    /* If any paths were cached because they were associatied with
       changelists, we can now display them as grouped changelists. */
    if (apr_hash_count(master_cl_hash) > 0)
    {
        apr_hash_index_t *hi;
        svn_stringbuf_t *buf;

        if (opt_state->xml)
            buf = svn_stringbuf_create("", pool);

        for (hi = apr_hash_first(pool, master_cl_hash); hi;
                hi = apr_hash_next(hi))
        {
            const char *changelist_name;
            apr_array_header_t *path_array;
            const void *key;
            void *val;
            int j;

            apr_hash_this(hi, &key, NULL, &val);
            changelist_name = key;
            path_array = val;

            /* ### TODO: For non-XML output, we shouldn't print the
               ### leading \n on the first changelist if there were no
               ### non-changelist entries. */
            if (opt_state->xml)
            {
                svn_stringbuf_set(buf, "");
                svn_xml_make_open_tag(&buf, pool, svn_xml_normal, "changelist",
                                      "name", changelist_name, NULL);
                SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout));
            }
            else
                SVN_ERR(svn_cmdline_printf(pool, _("\n--- Changelist '%s':\n"),
                                           changelist_name));

            for (j = 0; j < path_array->nelts; j++)
            {
                struct status_cache *scache =
                    APR_ARRAY_IDX(path_array, j, struct status_cache *);
                SVN_ERR(print_status_normal_or_xml(&sb, scache->path,
                                                   scache->status, pool));
            }

            if (opt_state->xml)
            {
                svn_stringbuf_set(buf, "");
                svn_xml_make_close_tag(&buf, pool, "changelist");
                SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout));
            }
        }
    }
Example #20
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);
}
Example #21
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__status(apr_getopt_t *os,
               void *baton,
               apr_pool_t *scratch_pool)
{
  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
  apr_array_header_t *targets;
  apr_pool_t *iterpool;
  apr_hash_t *master_cl_hash = apr_hash_make(scratch_pool);
  int i;
  svn_opt_revision_t rev;
  struct status_baton sb;

  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                      opt_state->targets,
                                                      ctx, FALSE,
                                                      scratch_pool));

  /* Add "." if user passed 0 arguments */
  svn_opt_push_implicit_dot_target(targets, scratch_pool);

  SVN_ERR(svn_cl__check_targets_are_local_paths(targets));

  /* We want our -u statuses to be against HEAD by default. */
  if (opt_state->start_revision.kind == svn_opt_revision_unspecified)
    rev.kind = svn_opt_revision_head;
  else if (! opt_state->update)
    return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                        _("--revision (-r) option valid only with "
                          "--show-updates (-u) option"));
  else
    rev = opt_state->start_revision;

  sb.had_print_error = FALSE;

  if (opt_state->xml)
    {
      /* If output is not incremental, output the XML header and wrap
         everything in a top-level element. This makes the output in
         its entirety a well-formed XML document. */
      if (! opt_state->incremental)
        SVN_ERR(svn_cl__xml_print_header("status", scratch_pool));
    }
  else
    {
      if (opt_state->incremental)
        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                _("'incremental' option only valid in XML "
                                  "mode"));
    }

  sb.suppress_externals_placeholders = (opt_state->quiet
                                        && (! opt_state->verbose));
  sb.detailed = (opt_state->verbose || opt_state->update);
  sb.show_last_committed = opt_state->verbose;
  sb.skip_unrecognized = opt_state->quiet;
  sb.repos_locks = opt_state->update;
  sb.xml_mode = opt_state->xml;
  sb.cached_changelists = master_cl_hash;
  sb.cl_pool = scratch_pool;
  sb.text_conflicts = 0;
  sb.prop_conflicts = 0;
  sb.tree_conflicts = 0;
  sb.ctx = ctx;

  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));

  iterpool = svn_pool_create(scratch_pool);
  for (i = 0; i < targets->nelts; i++)
    {
      const char *target = APR_ARRAY_IDX(targets, i, const char *);
      svn_revnum_t repos_rev = SVN_INVALID_REVNUM;

      svn_pool_clear(iterpool);

      SVN_ERR(svn_dirent_get_absolute(&(sb.target_abspath), target,
                                      scratch_pool));
      sb.target_path = target;

      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));

      if (opt_state->xml)
        SVN_ERR(print_start_target_xml(svn_dirent_local_style(target, iterpool),
                                       iterpool));

      /* Retrieve a hash of status structures with the information
         requested by the user. */
      SVN_ERR(svn_cl__try(svn_client_status6(&repos_rev, ctx, target, &rev,
                                             opt_state->depth,
                                             opt_state->verbose,
                                             opt_state->update,
                                             TRUE /* check_working_copy */,
                                             opt_state->no_ignore,
                                             opt_state->ignore_externals,
                                             FALSE /* depth_as_sticky */,
                                             opt_state->changelists,
                                             print_status, &sb,
                                             iterpool),
                          NULL, opt_state->quiet,
                          /* not versioned: */
                          SVN_ERR_WC_NOT_WORKING_COPY,
                          SVN_ERR_WC_PATH_NOT_FOUND,
                          0));

      if (opt_state->xml)
        SVN_ERR(print_finish_target_xml(repos_rev, iterpool));
    }

  /* If any paths were cached because they were associated with
     changelists, we can now display them as grouped changelists. */
  if (apr_hash_count(master_cl_hash) > 0)
    {
      apr_hash_index_t *hi;
      svn_stringbuf_t *buf;

      if (opt_state->xml)
        buf = svn_stringbuf_create_empty(scratch_pool);

      for (hi = apr_hash_first(scratch_pool, master_cl_hash); hi;
           hi = apr_hash_next(hi))
        {
          const char *changelist_name = apr_hash_this_key(hi);
          apr_array_header_t *path_array = apr_hash_this_val(hi);
          int j;

          /* ### TODO: For non-XML output, we shouldn't print the
             ### leading \n on the first changelist if there were no
             ### non-changelist entries. */
          if (opt_state->xml)
            {
              svn_stringbuf_setempty(buf);
              svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal,
                                    "changelist", "name", changelist_name,
                                    SVN_VA_NULL);
              SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout));
            }
          else
            SVN_ERR(svn_cmdline_printf(scratch_pool,
                                       _("\n--- Changelist '%s':\n"),
                                       changelist_name));

          for (j = 0; j < path_array->nelts; j++)
            {
              struct status_cache *scache =
                APR_ARRAY_IDX(path_array, j, struct status_cache *);
              sb.target_abspath = scache->target_abspath;
              sb.target_path = scache->target_path;
              SVN_ERR(print_status_normal_or_xml(&sb, scache->path,
                                                 scache->status, scratch_pool));
            }

          if (opt_state->xml)
            {
              svn_stringbuf_setempty(buf);
              svn_xml_make_close_tag(&buf, scratch_pool, "changelist");
              SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout));
            }
        }
    }
        // 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);
        }
Example #23
0
static svn_error_t *
subcommand_accessof(apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
  svn_authz_t *authz;
  svn_boolean_t read_access = FALSE, write_access = FALSE;
  svn_boolean_t check_r = FALSE, check_rw = FALSE, check_no = FALSE;
  svn_error_t *err;
  struct svnauthz_opt_state *opt_state = baton;
  const char *user = opt_state->username;
  const char *path = opt_state->fspath;
  const char *repos = opt_state->repos_name;
  const char *is = opt_state->is;
  svn_repos_authz_access_t request;

  if (opt_state->recursive && !path)
    return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                            ("--recursive not valid without --path"));

  /* Handle is argument parsing/allowed values */
  if (is) {
      if (0 == strcmp(is, "rw"))
        check_rw = TRUE;
      else if (0 == strcmp(is, "r"))
        check_r = TRUE;
      else if (0 == strcmp(is, "no"))
        check_no = TRUE;
      else
        return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                 ("'%s' is not a valid argument for --is"), is);
  }

  SVN_ERR(get_authz(&authz, opt_state, pool));


  request = svn_authz_write;
  if (opt_state->recursive)
    request |= svn_authz_recursive;
  err = svn_repos_authz_check_access(authz, repos, path, user,
                                     request, &write_access,
                                     pool);

  if (!write_access && !err)
    {
      request = svn_authz_read;
      if (opt_state->recursive)
        request |= svn_authz_recursive;
      err = svn_repos_authz_check_access(authz, repos, path, user,
                                         request, &read_access,
                                         pool);
    }

  if (!err)
    {
      const char *access_str = write_access ? "rw" : read_access ? "r" : "no";

      if (is)
        {
          /* Check that --is argument matches.
           * The errors returned here are not strictly correct, but
           * none of the other code paths will generate them and they
           * roughly mean what we're saying here. */
          if (check_rw && !write_access)
            err = svn_error_createf(SVN_ERR_AUTHZ_UNWRITABLE, NULL,
                                    ("%s is '%s', not writable"),
                                    path ? path : ("Repository"), access_str);
          else if (check_r && !read_access)
            err = svn_error_createf(SVN_ERR_AUTHZ_UNREADABLE, NULL,
                                    ("%s is '%s', not read only"),
                                    path ? path : ("Repository"), access_str);
          else if (check_no && (read_access || write_access))
            err = svn_error_createf(SVN_ERR_AUTHZ_PARTIALLY_READABLE,
                                    NULL, ("%s is '%s', not no access"),
                                    path ? path : ("Repository"), access_str);
        }
      else
        {
          err = svn_cmdline_printf(pool, "%s\n", access_str);
        }
    }

  return err;
}
Example #24
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;
}
/* This implements the svn_client_list_func_t API, printing a single
   directory entry in text format. */
static svn_error_t *
print_dirent(void *baton,
             const char *path,
             const svn_dirent_t *dirent,
             const svn_lock_t *lock,
             const char *abs_path,
             apr_pool_t *pool)
{
  struct print_baton *pb = baton;
  const char *entryname;

  if (pb->ctx->cancel_func)
    SVN_ERR(pb->ctx->cancel_func(pb->ctx->cancel_baton));

  if (strcmp(path, "") == 0)
    {
      if (dirent->kind == svn_node_file)
        entryname = svn_dirent_basename(abs_path, pool);
      else if (pb->verbose)
        entryname = ".";
      else
        /* Don't bother to list if no useful information will be shown. */
        return SVN_NO_ERROR;
    }
  else
    entryname = path;

  if (pb->verbose)
    {
      apr_time_t now = apr_time_now();
      apr_time_exp_t exp_time;
      apr_status_t apr_err;
      apr_size_t size;
      char timestr[20];
      const char *sizestr, *utf8_timestr;

      /* svn_time_to_human_cstring gives us something *way* too long
         to use for this, so we have to roll our own.  We include
         the year if the entry's time is not within half a year. */
      apr_time_exp_lt(&exp_time, dirent->time);
      if (apr_time_sec(now - dirent->time) < (365 * 86400 / 2)
          && apr_time_sec(dirent->time - now) < (365 * 86400 / 2))
        {
          apr_err = apr_strftime(timestr, &size, sizeof(timestr),
                                 _("%b %d %H:%M"), &exp_time);
        }
      else
        {
          apr_err = apr_strftime(timestr, &size, sizeof(timestr),
                                 _("%b %d  %Y"), &exp_time);
        }

      /* if that failed, just zero out the string and print nothing */
      if (apr_err)
        timestr[0] = '\0';

      /* we need it in UTF-8. */
      SVN_ERR(svn_utf_cstring_to_utf8(&utf8_timestr, timestr, pool));

      sizestr = apr_psprintf(pool, "%" SVN_FILESIZE_T_FMT, dirent->size);

      return svn_cmdline_printf
              (pool, "%7ld %-8.8s %c %10s %12s %s%s\n",
               dirent->created_rev,
               dirent->last_author ? dirent->last_author : " ? ",
               lock ? 'O' : ' ',
               (dirent->kind == svn_node_file) ? sizestr : "",
               utf8_timestr,
               entryname,
               (dirent->kind == svn_node_dir) ? "/" : "");
    }
  else
    {
      return svn_cmdline_printf(pool, "%s%s\n", entryname,
                                (dirent->kind == svn_node_dir)
                                ? "/" : "");
    }
}
Example #26
0
svn_error_t *
svn_opt__print_version_info(const char *pgm_name,
                            const char *footer,
                            const svn_version_extended_t *info,
                            svn_boolean_t quiet,
                            svn_boolean_t verbose,
                            apr_pool_t *pool)
{
  if (quiet)
    return svn_cmdline_printf(pool, "%s\n", SVN_VER_NUMBER);

  SVN_ERR(svn_cmdline_printf(pool, _("%s, version %s\n"
                                     "   compiled %s, %s on %s\n\n"),
                             pgm_name, SVN_VERSION,
                             svn_version_ext_build_date(info),
                             svn_version_ext_build_time(info),
                             svn_version_ext_build_host(info)));
  SVN_ERR(svn_cmdline_printf(pool, "%s\n", svn_version_ext_copyright(info)));

  if (footer)
    {
      SVN_ERR(svn_cmdline_printf(pool, "%s\n", footer));
    }

  if (verbose)
    {
      const apr_array_header_t *libs;

      SVN_ERR(svn_cmdline_fputs(_("System information:\n\n"), stdout, pool));
      SVN_ERR(svn_cmdline_printf(pool, _("* running on %s\n"),
                                 svn_version_ext_runtime_host(info)));
      if (svn_version_ext_runtime_osname(info))
        {
          SVN_ERR(svn_cmdline_printf(pool, _("  - %s\n"),
                                     svn_version_ext_runtime_osname(info)));
        }

      libs = svn_version_ext_linked_libs(info);
      if (libs && libs->nelts)
        {
          const svn_version_ext_linked_lib_t *lib;
          int i;

          SVN_ERR(svn_cmdline_fputs(_("* linked dependencies:\n"),
                                    stdout, pool));
          for (i = 0; i < libs->nelts; ++i)
            {
              lib = &APR_ARRAY_IDX(libs, i, svn_version_ext_linked_lib_t);
              if (lib->runtime_version)
                SVN_ERR(svn_cmdline_printf(pool,
                                           "  - %s %s (compiled with %s)\n",
                                           lib->name,
                                           lib->runtime_version,
                                           lib->compiled_version));
              else
                SVN_ERR(svn_cmdline_printf(pool,
                                           "  - %s %s (static)\n",
                                           lib->name,
                                           lib->compiled_version));
            }
        }

      libs = svn_version_ext_loaded_libs(info);
      if (libs && libs->nelts)
        {
          const svn_version_ext_loaded_lib_t *lib;
          int i;

          SVN_ERR(svn_cmdline_fputs(_("* loaded shared libraries:\n"),
                                    stdout, pool));
          for (i = 0; i < libs->nelts; ++i)
            {
              lib = &APR_ARRAY_IDX(libs, i, svn_version_ext_loaded_lib_t);
              if (lib->version)
                SVN_ERR(svn_cmdline_printf(pool,
                                           "  - %s   (%s)\n",
                                           lib->name, lib->version));
              else
                SVN_ERR(svn_cmdline_printf(pool, "  - %s\n", lib->name));
            }
        }
    }

  return SVN_NO_ERROR;
}
Example #27
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;
}
Example #28
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);
}
Example #29
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;
}
Example #30
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__log(apr_getopt_t *os,
            void *baton,
            apr_pool_t *pool)
{
  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
  apr_array_header_t *targets;
  struct log_receiver_baton lb;
  const char *target;
  int i;
  svn_opt_revision_t peg_revision;
  const char *true_path;
  apr_array_header_t *revprops;

  if (!opt_state->xml)
    {
      if (opt_state->all_revprops)
        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                _("'with-all-revprops' option only valid in"
                                  " XML mode"));
      if (opt_state->revprop_table != NULL)
        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                _("'with-revprop' option only valid in"
                                  " XML mode"));
    }

  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                      opt_state->targets, 
                                                      pool));

  /* Add "." if user passed 0 arguments */
  svn_opt_push_implicit_dot_target(targets, pool);

  target = APR_ARRAY_IDX(targets, 0, const char *);

  /* Determine if they really want a two-revision range. */
  if (opt_state->used_change_arg)
    {
      if (opt_state->start_revision.value.number < 
          opt_state->end_revision.value.number)
        opt_state->start_revision = opt_state->end_revision;
      else
        opt_state->end_revision = opt_state->start_revision;
    }

  /* Strip peg revision if targets contains an URI. */
  SVN_ERR(svn_opt_parse_path(&peg_revision, &true_path, target, pool));
  APR_ARRAY_IDX(targets, 0, const char *) = true_path;

  if ((opt_state->start_revision.kind != svn_opt_revision_unspecified)
      && (opt_state->end_revision.kind == svn_opt_revision_unspecified))
    {
      /* If the user specified exactly one revision, then start rev is
         set but end is not.  We show the log message for just that
         revision by making end equal to start.

         Note that if the user requested a single dated revision, then
         this will cause the same date to be resolved twice.  The
         extra code complexity to get around this slight inefficiency
         doesn't seem worth it, however.  */

      opt_state->end_revision = opt_state->start_revision;
    }
  else if (opt_state->start_revision.kind == svn_opt_revision_unspecified)
    {
      /* Default to any specified peg revision.  Otherwise, if the
         first target is an URL, then we default to HEAD:0.  Lastly,
         the default is BASE:0 since WC@HEAD may not exist. */
      if (peg_revision.kind == svn_opt_revision_unspecified)
        {
          if (svn_path_is_url(target))
            opt_state->start_revision.kind = svn_opt_revision_head;
          else
            opt_state->start_revision.kind = svn_opt_revision_base;
        }
      else
        opt_state->start_revision = peg_revision;

      if (opt_state->end_revision.kind == svn_opt_revision_unspecified)
        {
          opt_state->end_revision.kind = svn_opt_revision_number;
          opt_state->end_revision.value.number = 0;
        }
    }

  if (svn_path_is_url(target))
    {
      for (i = 1; i < targets->nelts; i++)
        {
          target = APR_ARRAY_IDX(targets, i, const char *);

          if (svn_path_is_url(target))
            return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                                    _("Only relative paths can be specified "
                                      "after a URL"));
        }
    }

  lb.cancel_func = ctx->cancel_func;
  lb.cancel_baton = ctx->cancel_baton;
  lb.omit_log_message = opt_state->quiet;
  lb.merge_stack = apr_array_make(pool, 0, sizeof(svn_revnum_t));
  lb.pool = pool;

  if (! opt_state->quiet)
    svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE,
                         FALSE, FALSE, pool);

  if (opt_state->xml)
    {
      /* If output is not incremental, output the XML header and wrap
         everything in a top-level element. This makes the output in
         its entirety a well-formed XML document. */
      if (! opt_state->incremental)
        SVN_ERR(svn_cl__xml_print_header("log", pool));

      if (opt_state->all_revprops)
        revprops = NULL;
      else if (opt_state->revprop_table != NULL)
        {
          apr_hash_index_t *hi;
          revprops = apr_array_make(pool,
                                    apr_hash_count(opt_state->revprop_table),
                                    sizeof(char *));
          for (hi = apr_hash_first(pool, opt_state->revprop_table);
               hi != NULL;
               hi = apr_hash_next(hi))
            {
              char *property;
              svn_string_t *value;
              apr_hash_this(hi, (void *)&property, NULL, (void *)&value);
              if (value && value->data[0] != '\0')
                return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                         _("cannot assign with 'with-revprop'"
                                           " option (drop the '=')"));
              APR_ARRAY_PUSH(revprops, char *) = property;
            }
        }
      else
        {
          revprops = apr_array_make(pool, 3, sizeof(char *));
          APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_AUTHOR;
          APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_DATE;
          if (!opt_state->quiet)
            APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
        }
      SVN_ERR(svn_client_log4(targets,
                              &peg_revision,
                              &(opt_state->start_revision),
                              &(opt_state->end_revision),
                              opt_state->limit,
                              opt_state->verbose,
                              opt_state->stop_on_copy,
                              opt_state->use_merge_history,
                              revprops,
                              log_entry_receiver_xml,
                              &lb,
                              ctx,
                              pool));

      if (! opt_state->incremental)
        SVN_ERR(svn_cl__xml_print_footer("log", pool));
    }
  else  /* default output format */
    {
      revprops = apr_array_make(pool, 3, sizeof(char *));
      APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_AUTHOR;
      APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_DATE;
      if (!opt_state->quiet)
        APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
      SVN_ERR(svn_client_log4(targets,
                              &peg_revision,
                              &(opt_state->start_revision),
                              &(opt_state->end_revision),
                              opt_state->limit,
                              opt_state->verbose,
                              opt_state->stop_on_copy,
                              opt_state->use_merge_history,
                              revprops,
                              log_entry_receiver,
                              &lb,
                              ctx,
                              pool));

      if (! opt_state->incremental)
        SVN_ERR(svn_cmdline_printf(pool, SEP_STRING));
    }

  return SVN_NO_ERROR;
}