blob: 967ce5be74d7e0c6accdf316d4028a41e95e2634 [file] [log] [blame]
/*
* minimal_client.c - a minimal Subversion client application ("hello world")
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This app demonstrates how to use the svn_client.h API.
*
* It reads a directory URL from the commandline, runs
* svn_client_list() and prints the list of directory-entries. It
* also knows how to deal with basic username/password authentication
* challenges.
*
* For a much more complex example, the svn cmdline client might be
* considered the 'reference implementation'.
*
* From a Linux system, a typical commandline compile might look like:
*
* cc minimal_client.c -o minimal_client \
* -I/usr/local/include/subversion-1 -I/usr/local/apache2/include \
* -L/usr/local/apache2/lib -L/usr/local/lib \
* -lsvn_client-1 -lapr-0 -laprutil-0
*
*/
#include "svn_client.h"
#include "svn_cmdline.h"
#include "svn_pools.h"
#include "svn_config.h"
#include "svn_fs.h"
/* Display a prompt and read a one-line response into the provided buffer,
removing a trailing newline if present. */
static svn_error_t *
prompt_and_read_line(const char *prompt,
char *buffer,
size_t max)
{
int len;
printf("%s: ", prompt);
if (fgets(buffer, max, stdin) == NULL)
return svn_error_create(0, NULL, "error reading stdin");
len = strlen(buffer);
if (len > 0 && buffer[len-1] == '\n')
buffer[len-1] = 0;
return SVN_NO_ERROR;
}
/* A tiny callback function of type 'svn_auth_simple_prompt_func_t'. For
a much better example, see svn_cl__auth_simple_prompt in the official
svn cmdline client. */
static svn_error_t *
my_simple_prompt_callback (svn_auth_cred_simple_t **cred,
void *baton,
const char *realm,
const char *username,
svn_boolean_t may_save,
apr_pool_t *pool)
{
svn_auth_cred_simple_t *ret = apr_pcalloc (pool, sizeof (*ret));
char answerbuf[100];
if (realm)
{
printf ("Authentication realm: %s\n", realm);
}
if (username)
ret->username = apr_pstrdup (pool, username);
else
{
SVN_ERR (prompt_and_read_line("Username", answerbuf, sizeof(answerbuf)));
ret->username = apr_pstrdup (pool, answerbuf);
}
SVN_ERR (prompt_and_read_line("Password", answerbuf, sizeof(answerbuf)));
ret->password = apr_pstrdup (pool, answerbuf);
*cred = ret;
return SVN_NO_ERROR;
}
/* A tiny callback function of type 'svn_auth_username_prompt_func_t'. For
a much better example, see svn_cl__auth_username_prompt in the official
svn cmdline client. */
static svn_error_t *
my_username_prompt_callback (svn_auth_cred_username_t **cred,
void *baton,
const char *realm,
svn_boolean_t may_save,
apr_pool_t *pool)
{
svn_auth_cred_username_t *ret = apr_pcalloc (pool, sizeof (*ret));
char answerbuf[100];
if (realm)
{
printf ("Authentication realm: %s\n", realm);
}
SVN_ERR (prompt_and_read_line("Username", answerbuf, sizeof(answerbuf)));
ret->username = apr_pstrdup (pool, answerbuf);
*cred = ret;
return SVN_NO_ERROR;
}
int
main (int argc, const char **argv)
{
apr_pool_t *pool;
svn_error_t *err;
svn_opt_revision_t revision;
apr_hash_t *dirents;
apr_hash_index_t *hi;
svn_client_ctx_t *ctx;
const char *URL;
if (argc <= 1)
{
printf ("Usage: %s URL\n", argv[0]);
return EXIT_FAILURE;
}
else
URL = argv[1];
/* Initialize the app. Send all error messages to 'stderr'. */
if (svn_cmdline_init ("minimal_client", 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)
{
/* For functions deeper in the stack, we usually use the
SVN_ERR() exception-throwing macro (see svn_error.h). At the
top level, we catch & print the error with svn_handle_error2(). */
svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
return EXIT_FAILURE;
}
/* Make sure the ~/.subversion run-time config files exist */
err = svn_config_ensure (NULL, pool);
if (err)
{
svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
return EXIT_FAILURE;
}
/* All clients need to fill out a client_ctx object. */
{
/* Initialize and allocate the client_ctx object. */
if ((err = svn_client_create_context (&ctx, pool)))
{
svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
return EXIT_FAILURE;
}
/* Load the run-time config file into a hash */
if ((err = svn_config_get_config (&(ctx->config), NULL, pool)))
{
svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
return EXIT_FAILURE;
}
#ifdef WIN32
/* Set the working copy administrative directory name. */
if (getenv ("SVN_ASP_DOT_NET_HACK"))
{
err = svn_wc_set_adm_dir ("_svn", pool);
if (err)
{
svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
return EXIT_FAILURE;
}
}
#endif
/* Depending on what your client does, you'll want to read about
(and implement) the various callback function types below. */
/* A func (& context) which receives event signals during
checkouts, updates, commits, etc. */
/* ctx->notify_func = my_notification_func;
ctx->notify_baton = NULL; */
/* A func (& context) which can receive log messages */
/* ctx->log_msg_func = my_log_msg_receiver_func;
ctx->log_msg_baton = NULL; */
/* A func (& context) which checks whether the user cancelled */
/* ctx->cancel_func = my_cancel_checking_func;
ctx->cancel_baton = NULL; */
/* Make the client_ctx capable of authenticating users */
{
/* There are many different kinds of authentication back-end
"providers". See svn_auth.h for a full overview.
If you want to get the auth behavior of the 'svn' program,
you can use svn_cmdline_setup_auth_baton, which will give
you the exact set of auth providers it uses. This program
doesn't use it because it's only appropriate for a command
line program, and this is supposed to be a general purpose
example. */
svn_auth_provider_object_t *provider;
apr_array_header_t *providers
= apr_array_make (pool, 4, sizeof (svn_auth_provider_object_t *));
svn_auth_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_auth_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 (&ctx->auth_baton, providers, pool);
}
} /* end of client_ctx setup */
/* Now do the real work. */
/* Set revision to always be the HEAD revision. It could, however,
be set to a specific revision number, date, or other values. */
revision.kind = svn_opt_revision_head;
/* Main call into libsvn_client does all the work. */
err = svn_client_ls (&dirents,
URL, &revision,
FALSE, /* no recursion */
ctx, pool);
if (err)
{
svn_handle_error2 (err, stderr, FALSE, "minimal_client: ");
return EXIT_FAILURE;
}
/* Print the dir entries in the hash. */
for (hi = apr_hash_first (pool, dirents); hi; hi = apr_hash_next (hi))
{
const char *entryname;
svn_dirent_t *val;
apr_hash_this (hi, (void *) &entryname, NULL, (void *) &val);
printf (" %s\n", entryname);
/* 'val' is actually an svn_dirent_t structure; a more complex
program would mine it for extra printable information. */
}
return EXIT_SUCCESS;
}