Example #1
0
/* Discover the youngest revision in a repository.  */
static svn_error_t *
get_youngest_rev(const char **msg,
                 svn_boolean_t msg_only,
                 svn_test_opts_t *opts,
                 apr_pool_t *pool)
{
  svn_ra_session_t *session;
  svn_revnum_t latest_rev;

  *msg = "get the youngest revision in a repository";

  if (msg_only)
    return SVN_NO_ERROR;

  SVN_ERR(make_and_open_local_repos(&session,
                                    "test-repo-getrev", opts,
                                    pool));

  /* Get the youngest revision and make sure it's 0. */
  SVN_ERR(svn_ra_get_latest_revnum(session, &latest_rev, pool));

  if (latest_rev != 0)
    return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
                            "youngest rev isn't 0!");

  return SVN_NO_ERROR;
}
Example #2
0
static svn_error_t *
new_revision_record(void **revision_baton,
                    apr_hash_t *headers,
                    void *parse_baton,
                    apr_pool_t *pool)
{
  struct revision_baton *rb;
  struct parse_baton *pb;
  apr_hash_index_t *hi;
  svn_revnum_t head_rev;

  rb = apr_pcalloc(pool, sizeof(*rb));
  pb = parse_baton;
  rb->pool = svn_pool_create(pool);
  rb->pb = pb;
  rb->db = NULL;

  for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
    {
      const char *hname = svn__apr_hash_index_key(hi);
      const char *hval = svn__apr_hash_index_val(hi);

      if (strcmp(hname, SVN_REPOS_DUMPFILE_REVISION_NUMBER) == 0)
        rb->rev = atoi(hval);
    }

  SVN_ERR(svn_ra_get_latest_revnum(pb->session, &head_rev, pool));

  /* FIXME: This is a lame fallback loading multiple segments of dump in
     several separate operations. It is highly susceptible to race conditions.
     Calculate the revision 'offset' for finding copyfrom sources.
     It might be positive or negative. */
  rb->rev_offset = (apr_int32_t) ((rb->rev) - (head_rev + 1));

  /* Stash the oldest (non-zero) dumpstream revision seen. */
  if ((rb->rev > 0) && (!SVN_IS_VALID_REVNUM(pb->oldest_dumpstream_rev)))
    pb->oldest_dumpstream_rev = rb->rev;

  /* Set the commit_editor/ commit_edit_baton to NULL and wait for
     them to be created in new_node_record */
  rb->pb->commit_editor = NULL;
  rb->pb->commit_edit_baton = NULL;
  rb->revprop_table = apr_hash_make(rb->pool);

  *revision_baton = rb;
  return SVN_NO_ERROR;
}
Example #3
0
int
main(int argc, const char **argv)
{
    svn_error_t *err = SVN_NO_ERROR;
    const svn_opt_subcommand_desc2_t *subcommand = NULL;
    opt_baton_t *opt_baton;
    svn_revnum_t latest_revision = SVN_INVALID_REVNUM;
    apr_pool_t *pool = NULL;
    const char *config_dir = NULL;
    const char *username = NULL;
    const char *password = NULL;
    svn_boolean_t no_auth_cache = FALSE;
    svn_boolean_t trust_server_cert = FALSE;
    svn_boolean_t non_interactive = FALSE;
    apr_array_header_t *config_options = NULL;
    apr_getopt_t *os;
    const char *first_arg;
    apr_array_header_t *received_opts;
    apr_allocator_t *allocator;
    int i;

    if (svn_cmdline_init ("svnrdump", 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);

    opt_baton = apr_pcalloc(pool, sizeof(*opt_baton));
    opt_baton->start_revision.kind = svn_opt_revision_unspecified;
    opt_baton->end_revision.kind = svn_opt_revision_unspecified;
    opt_baton->url = NULL;

    SVNRDUMP_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));

    os->interleave = TRUE; /* Options and arguments can be interleaved */

    /* Set up our cancellation support. */
    apr_signal(SIGINT, signal_handler);
#ifdef SIGBREAK
    /* SIGBREAK is a Win32 specific signal generated by ctrl-break. */
    apr_signal(SIGBREAK, signal_handler);
#endif
#ifdef SIGHUP
    apr_signal(SIGHUP, signal_handler);
#endif
#ifdef SIGTERM
    apr_signal(SIGTERM, signal_handler);
#endif
#ifdef SIGPIPE
    /* Disable SIGPIPE generation for the platforms that have it. */
    apr_signal(SIGPIPE, SIG_IGN);
#endif
#ifdef SIGXFSZ
    /* Disable SIGXFSZ generation for the platforms that have it, otherwise
     * working with large files when compiled against an APR that doesn't have
     * large file support will crash the program, which is uncool. */
    apr_signal(SIGXFSZ, SIG_IGN);
#endif

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

    while (1)
    {
        int opt;
        const char *opt_arg;
        apr_status_t status = apr_getopt_long(os, svnrdump__options, &opt,
                                              &opt_arg);

        if (APR_STATUS_IS_EOF(status))
            break;
        if (status != APR_SUCCESS)
        {
            SVNRDUMP_ERR(usage(argv[0], pool));
            exit(EXIT_FAILURE);
        }

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

        switch(opt)
        {
        case 'r':
        {
            /* Make sure we've not seen -r already. */
            if (opt_baton->start_revision.kind != svn_opt_revision_unspecified)
            {
                err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                       _("Multiple revision arguments "
                                         "encountered; try '-r N:M' instead "
                                         "of '-r N -r M'"));
                return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
            }
            /* Parse the -r argument. */
            if (svn_opt_parse_revision(&(opt_baton->start_revision),
                                       &(opt_baton->end_revision),
                                       opt_arg, pool) != 0)
            {
                const char *utf8_opt_arg;
                err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool);
                if (! err)
                    err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                            _("Syntax error in revision "
                                              "argument '%s'"), utf8_opt_arg);
                return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
            }
        }
        break;
        case 'q':
            opt_baton->quiet = TRUE;
            break;
        case opt_config_dir:
            config_dir = opt_arg;
            break;
        case opt_version:
            opt_baton->version = TRUE;
            break;
        case 'h':
            opt_baton->help = TRUE;
            break;
        case opt_auth_username:
            SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&username, opt_arg, pool));
            break;
        case opt_auth_password:
            SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&password, opt_arg, pool));
            break;
        case opt_auth_nocache:
            no_auth_cache = TRUE;
            break;
        case opt_non_interactive:
            non_interactive = TRUE;
            break;
        case opt_incremental:
            opt_baton->incremental = TRUE;
            break;
        case opt_trust_server_cert:
            trust_server_cert = TRUE;
            break;
        case opt_config_option:
            if (!config_options)
                config_options =
                    apr_array_make(pool, 1,
                                   sizeof(svn_cmdline__config_argument_t*));

            SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
            SVNRDUMP_ERR(svn_cmdline__parse_config_option(config_options,
                         opt_arg, pool));
        }
    }

    if (opt_baton->help)
    {
        subcommand = svn_opt_get_canonical_subcommand2(svnrdump__cmd_table,
                     "help");
    }
    if (subcommand == NULL)
    {
        if (os->ind >= os->argc)
        {
            if (opt_baton->version)
            {
                /* Use the "help" subcommand to handle the "--version" option. */
                static const svn_opt_subcommand_desc2_t pseudo_cmd =
                {   "--version", help_cmd, {0}, "",
                    {   opt_version,  /* must accept its own option */
                        'q',  /* --quiet */
                    }
                };
                subcommand = &pseudo_cmd;
            }

            else
            {
                SVNRDUMP_ERR(help_cmd(NULL, NULL, pool));
                svn_pool_destroy(pool);
                exit(EXIT_FAILURE);
            }
        }
        else
        {
            first_arg = os->argv[os->ind++];
            subcommand = svn_opt_get_canonical_subcommand2(svnrdump__cmd_table,
                         first_arg);

            if (subcommand == NULL)
            {
                const char *first_arg_utf8;
                err = svn_utf_cstring_to_utf8(&first_arg_utf8, first_arg, pool);
                if (err)
                    return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
                svn_error_clear(svn_cmdline_fprintf(stderr, pool,
                                                    _("Unknown command: '%s'\n"),
                                                    first_arg_utf8));
                SVNRDUMP_ERR(help_cmd(NULL, NULL, pool));
                svn_pool_destroy(pool);
                exit(EXIT_FAILURE);
            }
        }
    }

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

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

        if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, NULL))
        {
            const char *optstr;
            const apr_getopt_option_t *badopt =
                svn_opt_get_option_from_code2(opt_id, svnrdump__options,
                                              subcommand, pool);
            svn_opt_format_option(&optstr, badopt, FALSE, pool);
            if (subcommand->name[0] == '-')
                SVN_INT_ERR(help_cmd(NULL, NULL, pool));
            else
                svn_error_clear(svn_cmdline_fprintf(
                                    stderr, pool,
                                    _("Subcommand '%s' doesn't accept option '%s'\n"
                                      "Type 'svnrdump help %s' for usage.\n"),
                                    subcommand->name, optstr, subcommand->name));
            svn_pool_destroy(pool);
            return EXIT_FAILURE;
        }
    }

    if (subcommand && strcmp(subcommand->name, "--version") == 0)
    {
        SVNRDUMP_ERR(version(argv[0], opt_baton->quiet, pool));
        svn_pool_destroy(pool);
        exit(EXIT_SUCCESS);
    }

    if (subcommand && strcmp(subcommand->name, "help") == 0)
    {
        SVNRDUMP_ERR(help_cmd(os, opt_baton, pool));
        svn_pool_destroy(pool);
        exit(EXIT_SUCCESS);
    }

    /* --trust-server-cert can only be used with --non-interactive */
    if (trust_server_cert && !non_interactive)
    {
        err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                               _("--trust-server-cert requires "
                                 "--non-interactive"));
        return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
    }

    /* Expect one more non-option argument:  the repository URL. */
    if (os->ind != os->argc - 1)
    {
        SVNRDUMP_ERR(usage(argv[0], pool));
        svn_pool_destroy(pool);
        exit(EXIT_FAILURE);
    }
    else
    {
        const char *repos_url;

        SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&repos_url,
                                             os->argv[os->ind], pool));
        if (! svn_path_is_url(repos_url))
        {
            err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, 0,
                                    "Target '%s' is not a URL",
                                    repos_url);
            SVNRDUMP_ERR(err);
            svn_pool_destroy(pool);
            exit(EXIT_FAILURE);
        }
        opt_baton->url = svn_uri_canonicalize(repos_url, pool);
    }

    SVNRDUMP_ERR(init_client_context(&(opt_baton->ctx),
                                     non_interactive,
                                     username,
                                     password,
                                     config_dir,
                                     no_auth_cache,
                                     trust_server_cert,
                                     config_options,
                                     pool));

    SVNRDUMP_ERR(svn_client_open_ra_session(&(opt_baton->session),
                                            opt_baton->url,
                                            opt_baton->ctx, pool));

    /* Have sane opt_baton->start_revision and end_revision defaults if
       unspecified.  */
    SVNRDUMP_ERR(svn_ra_get_latest_revnum(opt_baton->session,
                                          &latest_revision, pool));

    /* Make sure any provided revisions make sense. */
    SVNRDUMP_ERR(validate_and_resolve_revisions(opt_baton,
                 latest_revision, pool));

    /* Dispatch the subcommand */
    SVNRDUMP_ERR((*subcommand->cmd_func)(os, opt_baton, pool));

    svn_pool_destroy(pool);

    return EXIT_SUCCESS;
}
Example #4
0
static int cmd_isvn_clone(int argc, const char **cargv, const char *prefix)
{
	svn_revnum_t latest_rev = SVN_INVALID_REVNUM;
	struct isvn_client_ctx *first_client;
	char *dir, *key, **argv;
	const char *repo_name;
	svn_error_t *err;

	git_repository_init_options initopts;
	git_config *config;
	int rc;

	argv = __DECONST(cargv, char **);
	argc = isvn_parse_opts(argc, argv, isvn_clone_options,
	    isvn_clone_usage);

	if (argc < 1)
		isvn_usage(isvn_clone_usage, isvn_clone_options,
		    "You must specify a repository to clone.");
	else if (argc < 2)
		isvn_usage(isvn_clone_usage, isvn_clone_options,
		    "You must specify a destination directory.");
	else if (argc > 2)
		isvn_usage(isvn_clone_usage, isvn_clone_options,
		    "Too many arguments.");

	if (!option_origin)
		option_origin = "origin";
	option_cloning = true;
	if (option_maxrev < 0)
		isvn_usage(isvn_clone_usage, isvn_clone_options,
		    "Maxrev cannot be negative");

	repo_name = argv[0];
	if (argc == 2)
		dir = xstrdup(argv[1]);
	else
		dir = guess_dir_name(repo_name);

	initopts = (git_repository_init_options) GIT_REPOSITORY_INIT_OPTIONS_INIT;
	initopts.flags = GIT_REPOSITORY_INIT_MKDIR |
	    GIT_REPOSITORY_INIT_NO_REINIT |
	    GIT_REPOSITORY_INIT_MKPATH;

	rc = git_repository_init_ext(&g_git_repo, dir, &initopts);
	if (rc < 0)
		die("Error creating git repository: %d", rc);

	rc = git_repository_config(&config, g_git_repo);
	if (rc)
		die("git_repository_config: %d", rc);

	xasprintf(&key, "remote.%s.url", option_origin);
	rc = git_config_set_string(config, key, repo_name);
	if (rc)
		die("git_config_set_string: %d", rc);
	g_svn_url = xstrdup(repo_name);
	free(key);

	/* Initialize APR / libsvn */
	if (svn_cmdline_init("git-isvn", stderr) != EXIT_SUCCESS)
		die("svn_cmdline_init");

	first_client = get_svn_ctx();
	if (first_client == NULL)
		die("Could not connect to SVN server.");

	err = svn_ra_get_latest_revnum(first_client->svn_session, &latest_rev,
		first_client->svn_pool);
	assert_noerr(err, "svn_ra_get_latest_revnum");

	if (option_verbosity >= 2)
		printf("Maximum SVN repository revision: %ju\n",
		    (uintmax_t)latest_rev);

	if (option_maxrev == 0 || option_maxrev > latest_rev)
		option_maxrev = latest_rev;

	isvn_fetch(first_client);

	/* Branch 'master' from remote trunk and checkout. */
	checkout(g_git_repo);

	git_config_free(config);
	git_repository_free(g_git_repo);
	g_git_repo = NULL;

	free(dir);
	return 0;
}
Example #5
0
svn_error_t *
svn_client__get_revision_number(svn_revnum_t *revnum,
                                svn_revnum_t *youngest_rev,
                                svn_wc_context_t *wc_ctx,
                                const char *local_abspath,
                                svn_ra_session_t *ra_session,
                                const svn_opt_revision_t *revision,
                                apr_pool_t *scratch_pool)
{
  switch (revision->kind)
    {
    case svn_opt_revision_unspecified:
      *revnum = SVN_INVALID_REVNUM;
      break;

    case svn_opt_revision_number:
      *revnum = revision->value.number;
      break;

    case svn_opt_revision_head:
      /* If our caller provided a value for HEAD that he wants us to
         use, we'll use it.  Otherwise, we have to query the
         repository (and possible return our fetched value in
         *YOUNGEST_REV, too). */
      if (youngest_rev && SVN_IS_VALID_REVNUM(*youngest_rev))
        {
          *revnum = *youngest_rev;
        }
      else
        {
          if (! ra_session)
            return svn_error_create(SVN_ERR_CLIENT_RA_ACCESS_REQUIRED,
                                    NULL, NULL);
          SVN_ERR(svn_ra_get_latest_revnum(ra_session, revnum, scratch_pool));
          if (youngest_rev)
            *youngest_rev = *revnum;
        }
      break;

    case svn_opt_revision_working:
    case svn_opt_revision_base:
      {
        svn_error_t *err;

        /* Sanity check. */
        if (local_abspath == NULL)
          return svn_error_create(SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED,
                                  NULL, NULL);

        /* The BASE, COMMITTED, and PREV revision keywords do not
           apply to URLs. */
        if (svn_path_is_url(local_abspath))
          goto invalid_rev_arg;

        err = svn_wc__node_get_origin(NULL, revnum, NULL, NULL, NULL, NULL,
                                      wc_ctx, local_abspath, TRUE,
                                      scratch_pool, scratch_pool);

        /* Return the same error as older code did (before and at r935091).
           At least svn_client_proplist4 promises SVN_ERR_ENTRY_NOT_FOUND. */
        if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
          {
            svn_error_clear(err);
            return svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL,
                                     _("'%s' is not under version control"),
                                     svn_dirent_local_style(local_abspath,
                                                            scratch_pool));
          }
        else
          SVN_ERR(err);

        if (! SVN_IS_VALID_REVNUM(*revnum))
          return svn_error_createf(SVN_ERR_CLIENT_BAD_REVISION, NULL,
                                   _("Path '%s' has no committed "
                                     "revision"),
                                   svn_dirent_local_style(local_abspath,
                                                          scratch_pool));
      }
      break;

    case svn_opt_revision_committed:
    case svn_opt_revision_previous:
      {
        /* Sanity check. */
        if (local_abspath == NULL)
          return svn_error_create(SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED,
                                  NULL, NULL);

        /* The BASE, COMMITTED, and PREV revision keywords do not
           apply to URLs. */
        if (svn_path_is_url(local_abspath))
          goto invalid_rev_arg;

        SVN_ERR(svn_wc__node_get_changed_info(revnum, NULL, NULL,
                                              wc_ctx, local_abspath,
                                              scratch_pool, scratch_pool));
        if (! SVN_IS_VALID_REVNUM(*revnum))
          return svn_error_createf(SVN_ERR_CLIENT_BAD_REVISION, NULL,
                                   _("Path '%s' has no committed "
                                     "revision"),
                                   svn_dirent_local_style(local_abspath,
                                                          scratch_pool));

        if (revision->kind == svn_opt_revision_previous)
          (*revnum)--;
      }
      break;

    case svn_opt_revision_date:
      /* ### When revision->kind == svn_opt_revision_date, is there an
         ### optimization such that we can compare
         ### revision->value->date with the committed-date in the
         ### entries file (or rather, with some range of which
         ### committed-date is one endpoint), and sometimes avoid a
         ### trip over the RA layer?  The only optimizations I can
         ### think of involve examining other entries to build a
         ### timespan across which committed-revision is known to be
         ### the head, but it doesn't seem worth it.  -kff */
      if (! ra_session)
        return svn_error_create(SVN_ERR_CLIENT_RA_ACCESS_REQUIRED, NULL, NULL);
      SVN_ERR(svn_ra_get_dated_revision(ra_session, revnum,
                                        revision->value.date, scratch_pool));
      break;

    default:
      return svn_error_createf(SVN_ERR_CLIENT_BAD_REVISION, NULL,
                               _("Unrecognized revision type requested for "
                                 "'%s'"),
                               svn_dirent_local_style(local_abspath,
                                                      scratch_pool));
    }

  /* Final check -- if our caller provided a youngest revision, and
     the number we wound up with (after talking to the server) is younger
     than that revision, we need to stick to our caller's idea of "youngest".
   */
  if (youngest_rev
      && (revision->kind == svn_opt_revision_head
          || revision->kind == svn_opt_revision_date)
      && SVN_IS_VALID_REVNUM(*youngest_rev)
      && SVN_IS_VALID_REVNUM(*revnum)
      && (*revnum > *youngest_rev))
    *revnum = *youngest_rev;

  return SVN_NO_ERROR;

  invalid_rev_arg:
    return svn_error_create(
      SVN_ERR_CLIENT_BAD_REVISION, NULL,
      _("PREV, BASE, or COMMITTED revision keywords are invalid for URL"));

}
Example #6
0
svn_error_t *
svn_client__get_revision_number(svn_revnum_t *revnum,
                                svn_revnum_t *youngest_rev,
                                svn_ra_session_t *ra_session,
                                const svn_opt_revision_t *revision,
                                const char *path,
                                apr_pool_t *pool)
{
  switch (revision->kind)
    {
    case svn_opt_revision_unspecified:
      *revnum = SVN_INVALID_REVNUM;
      break;

    case svn_opt_revision_number:
      *revnum = revision->value.number;
      break;

    case svn_opt_revision_head:
      /* If our caller provided a value for HEAD that he wants us to
         use, we'll use it.  Otherwise, we have to query the
         repository (and possible return our fetched value in
         *YOUNGEST_REV, too). */
      if (youngest_rev && SVN_IS_VALID_REVNUM(*youngest_rev))
        {
          *revnum = *youngest_rev;
        }
      else
        {
          if (! ra_session)
            return svn_error_create(SVN_ERR_CLIENT_RA_ACCESS_REQUIRED,
                                    NULL, NULL);
          SVN_ERR(svn_ra_get_latest_revnum(ra_session, revnum, pool));
          if (youngest_rev)
            *youngest_rev = *revnum;
        }
      break;

    case svn_opt_revision_committed:
    case svn_opt_revision_working:
    case svn_opt_revision_base:
    case svn_opt_revision_previous:
      {
        svn_wc_adm_access_t *adm_access;
        const svn_wc_entry_t *ent;

        /* Sanity check. */
        if (path == NULL)
          return svn_error_create(SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED,
                                  NULL, NULL);

        SVN_ERR(svn_wc_adm_probe_open3(&adm_access, NULL, path, FALSE,
                                       0, NULL, NULL, pool));
        SVN_ERR(svn_wc__entry_versioned(&ent, path, adm_access, FALSE, pool));
        SVN_ERR(svn_wc_adm_close(adm_access));

        if ((revision->kind == svn_opt_revision_base)
            || (revision->kind == svn_opt_revision_working))
          {
            *revnum = ent->revision;
          }
        else
          {
            if (! SVN_IS_VALID_REVNUM(ent->cmt_rev))
              return svn_error_createf(SVN_ERR_CLIENT_BAD_REVISION, NULL,
                                       _("Path '%s' has no committed "
                                         "revision"), path);
            *revnum = ent->cmt_rev;
            if (revision->kind == svn_opt_revision_previous)
              (*revnum)--;
          }
      }
      break;

    case svn_opt_revision_date:
      /* ### When revision->kind == svn_opt_revision_date, is there an
         ### optimization such that we can compare
         ### revision->value->date with the committed-date in the
         ### entries file (or rather, with some range of which
         ### committed-date is one endpoint), and sometimes avoid a
         ### trip over the RA layer?  The only optimizations I can
         ### think of involve examining other entries to build a
         ### timespan across which committed-revision is known to be
         ### the head, but it doesn't seem worth it.  -kff */
      if (! ra_session)
        return svn_error_create(SVN_ERR_CLIENT_RA_ACCESS_REQUIRED, NULL, NULL);
      SVN_ERR(svn_ra_get_dated_revision(ra_session, revnum,
                                        revision->value.date, pool));
      break;

    default:
      return svn_error_createf(SVN_ERR_CLIENT_BAD_REVISION, NULL,
                               _("Unrecognized revision type requested for "
                                 "'%s'"),
                               svn_path_local_style(path, pool));
    }

  /* Final check -- if our caller provided a youngest revision, and
  the number we wound up with is younger than that revision, we need
  to stick to our caller's idea of "youngest". */
  if (youngest_rev
      && SVN_IS_VALID_REVNUM(*youngest_rev)
      && SVN_IS_VALID_REVNUM(*revnum)
      && (*revnum > *youngest_rev))
    *revnum = *youngest_rev;

  return SVN_NO_ERROR;
}
Example #7
0
svn_error_t *
svn_ra__location_segments_from_log(svn_ra_session_t *session,
                                   const char *path,
                                   svn_revnum_t peg_revision,
                                   svn_revnum_t start_rev,
                                   svn_revnum_t end_rev,
                                   svn_location_segment_receiver_t receiver,
                                   void *receiver_baton,
                                   apr_pool_t *pool)
{
  struct gls_log_receiver_baton lrb = { 0 };
  apr_array_header_t *targets;
  svn_node_kind_t kind;
  svn_revnum_t youngest_rev = SVN_INVALID_REVNUM;
  const char *fs_path;

  /* Fetch the absolute FS path associated with PATH. */
  SVN_ERR(get_fs_path(&fs_path, session, path, pool));

  /* If PEG_REVISION is invalid, it means HEAD.  If START_REV is
     invalid, it means HEAD.  If END_REV is SVN_INVALID_REVNUM, we'll
     use 0. */
  if (! SVN_IS_VALID_REVNUM(peg_revision))
    {
      SVN_ERR(svn_ra_get_latest_revnum(session, &youngest_rev, pool));
      peg_revision = youngest_rev;
    }
  if (! SVN_IS_VALID_REVNUM(start_rev))
    {
      if (SVN_IS_VALID_REVNUM(youngest_rev))
        start_rev = youngest_rev;
      else
        SVN_ERR(svn_ra_get_latest_revnum(session, &start_rev, pool));
    }
  if (! SVN_IS_VALID_REVNUM(end_rev))
    {
      end_rev = 0;
    }

  /* The API demands a certain ordering of our revision inputs. Enforce it. */
  SVN_ERR_ASSERT((peg_revision >= start_rev) && (start_rev >= end_rev));

  /* Sanity check: verify that the peg-object exists in repos. */
  SVN_ERR(svn_ra_check_path(session, path, peg_revision, &kind, pool));
  if (kind == svn_node_none)
    return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
                             _("Path '%s' doesn't exist in revision %ld"),
                             fs_path, start_rev);

  /* Populate most of our log receiver baton structure. */
  lrb.kind = kind;
  lrb.last_path = fs_path;
  lrb.done = FALSE;
  lrb.start_rev = start_rev;
  lrb.range_end = start_rev;
  lrb.receiver = receiver;
  lrb.receiver_baton = receiver_baton;
  lrb.pool = pool;

  /* Let the RA layer drive our log information handler, which will do
     the work of finding the actual locations for our resource.
     Notice that we always run on the youngest rev of the 3 inputs. */
  targets = apr_array_make(pool, 1, sizeof(const char *));
  APR_ARRAY_PUSH(targets, const char *) = path;
  SVN_ERR(svn_ra_get_log2(session, targets, peg_revision, end_rev, 0,
                          TRUE, FALSE, FALSE,
                          apr_array_make(pool, 0, sizeof(const char *)),
                          gls_log_receiver, &lrb, pool));

  /* If we didn't finish, we need to do so with a final segment send. */
  if (! lrb.done)
    SVN_ERR(maybe_crop_and_send_segment(lrb.last_path, start_rev,
                                        end_rev, lrb.range_end,
                                        receiver, receiver_baton, pool));

  return SVN_NO_ERROR;
}
int
main (int argc, const char **argv)
{
  apr_pool_t *pool;
  svn_error_t *err;
  const char *URL;
  svn_ra_session_t  *session;
  svn_ra_callbacks2_t *cbtable;
  svn_revnum_t rev;
  apr_hash_t *cfg_hash;
  svn_auth_baton_t *auth_baton;

  if (argc <= 1)
    {
      printf ("Usage:  %s URL\n", argv[0]);
      printf ("    Print HEAD revision of URL's repository.\n");
      return EXIT_FAILURE;
    }
  else
    URL = argv[1];

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

  /* Create top-level memory pool. Be sure to read the HACKING file to
     understand how to properly use/free subpools. */
  pool = svn_pool_create (NULL);

  /* Initialize the FS library. */
  err = svn_fs_initialize (pool);
  if (err) goto hit_error;

  /* Make sure the ~/.subversion run-time config files exist, and load. */
  err = svn_config_ensure (NULL, pool);
  if (err) goto hit_error;

  err = svn_config_get_config (&cfg_hash, NULL, pool);
  if (err) goto hit_error;

  /* Build an authentication baton. */
  {
    /* There are many different kinds of authentication back-end
       "providers".  See svn_auth.h for a full overview. */
    svn_auth_provider_object_t *provider;
    apr_array_header_t *providers
      = apr_array_make (pool, 4, sizeof (svn_auth_provider_object_t *));

    svn_client_get_simple_prompt_provider (&provider,
                                           my_simple_prompt_callback,
                                           NULL, /* baton */
                                           2, /* retry limit */ pool);
    APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;

    svn_client_get_username_prompt_provider (&provider,
                                             my_username_prompt_callback,
                                             NULL, /* baton */
                                             2, /* retry limit */ pool);
    APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;

    /* Register the auth-providers into the context's auth_baton. */
    svn_auth_open (&auth_baton, providers, pool);
  }

  /* Create a table of callbacks for the RA session, mostly nonexistent. */
  cbtable = apr_pcalloc (pool, sizeof(*cbtable));
  cbtable->auth_baton = auth_baton;
  cbtable->open_tmp_file = open_tmp_file;

  /* Now do the real work. */

  err = svn_ra_open2(&session, URL, cbtable, NULL, cfg_hash, pool);
  if (err) goto hit_error;

  err = svn_ra_get_latest_revnum(session, &rev, pool);
  if (err) goto hit_error;

  printf ("The latest revision is %ld.\n", rev);

  return EXIT_SUCCESS;

 hit_error:
  svn_handle_error2 (err, stderr, FALSE, "headrev: ");
  return EXIT_FAILURE;
}