You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/10/15 10:52:18 UTC
svn commit: r1532250 [32/37] - in /subversion/branches/cache-server: ./
build/ build/ac-macros/ build/generator/ build/generator/swig/
build/generator/templates/ contrib/client-side/emacs/ contrib/hook-scripts/
contrib/server-side/fsfsfixer/ contrib/se...
Modified: subversion/branches/cache-server/subversion/svnserve/server.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/svnserve/server.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/svnserve/server.h (original)
+++ subversion/branches/cache-server/subversion/svnserve/server.h Tue Oct 15 08:52:06 2013
@@ -36,14 +36,18 @@ extern "C" {
#include "svn_repos.h"
#include "svn_ra_svn.h"
+#include "private/svn_mutex.h"
+
enum username_case_type { CASE_FORCE_UPPER, CASE_FORCE_LOWER, CASE_ASIS };
-typedef struct server_baton_t {
+enum authn_type { UNAUTHENTICATED, AUTHENTICATED };
+enum access_type { NO_ACCESS, READ_ACCESS, WRITE_ACCESS };
+
+typedef struct repository_t {
svn_repos_t *repos;
const char *repos_name; /* URI-encoded name of repository (not for authz) */
svn_fs_t *fs; /* For convenience; same as svn_repos_fs(repos) */
const char *base; /* Base directory for config files */
- svn_config_t *cfg; /* Parsed repository svnserve.conf */
svn_config_t *pwdb; /* Parsed password database */
svn_authz_t *authzdb; /* Parsed authz rules */
const char *authz_repos_name; /* The name of the repository for authz */
@@ -51,24 +55,35 @@ typedef struct server_baton_t {
const char *repos_url; /* URL to base of repository */
svn_stringbuf_t *fs_path;/* Decoded base in-repos path (w/ leading slash) */
apr_hash_t *fs_config; /* Additional FS configuration parameters */
- const char *user; /* Authenticated username of the user */
enum username_case_type username_case; /* Case-normalize the username? */
+ svn_boolean_t use_sasl; /* Use Cyrus SASL for authentication;
+ always false if SVN_HAVE_SASL not defined */
+ unsigned min_ssf; /* min-encryption SASL parameter */
+ unsigned max_ssf; /* max-encryption SASL parameter */
+
+ enum access_type auth_access; /* access granted to authenticated users */
+ enum access_type anon_access; /* access granted to annonymous users */
+
+} repository_t;
+
+typedef struct client_info_t {
+ const char *user; /* Authenticated username of the user */
+ const char *remote_host; /* IP of the client that contacted the server */
const char *authz_user; /* Username for authz ('user' + 'username_case') */
svn_boolean_t tunnel; /* Tunneled through login agent */
const char *tunnel_user; /* Allow EXTERNAL to authenticate as this */
+} client_info_t;
+
+typedef struct server_baton_t {
+ repository_t *repository; /* repository-specific data to use */
+ client_info_t *client_info; /* client-specific data to use */
+ struct logger_t *logger; /* Log file data structure.
+ May be NULL even if log_file is not. */
svn_boolean_t read_only; /* Disallow write access (global flag) */
- svn_boolean_t use_sasl; /* Use Cyrus SASL for authentication;
- always false if SVN_HAVE_SASL not defined */
- apr_file_t *log_file; /* Log filehandle. */
svn_boolean_t vhost; /* Use virtual-host-based path to repo. */
apr_pool_t *pool;
} server_baton_t;
-enum authn_type { UNAUTHENTICATED, AUTHENTICATED };
-enum access_type { NO_ACCESS, READ_ACCESS, WRITE_ACCESS };
-
-enum access_type get_access(server_baton_t *b, enum authn_type auth);
-
typedef struct serve_params_t {
/* The virtual root of the repositories to serve. The client URL
path is interpreted relative to this root and is not allowed to
@@ -97,8 +112,8 @@ typedef struct serve_params_t {
per-repository svnserve.conf are not read. */
svn_config_t *cfg;
- /* A filehandle open for writing logs to; possibly NULL. */
- apr_file_t *log_file;
+ /* logging data structure; possibly NULL. */
+ struct logger_t *logger;
/* Username case normalization style. */
enum username_case_type username_case;
@@ -133,29 +148,16 @@ typedef struct serve_params_t {
svn_boolean_t vhost;
} serve_params_t;
+/* Return a client_info_t structure allocated in POOL and initialize it
+ * with data from CONN. */
+client_info_t * get_client_info(svn_ra_svn_conn_t *conn,
+ serve_params_t *params,
+ apr_pool_t *pool);
+
/* Serve the connection CONN according to the parameters PARAMS. */
svn_error_t *serve(svn_ra_svn_conn_t *conn, serve_params_t *params,
apr_pool_t *pool);
-/* Load the password database for the listening server based on the
- entries in the SERVER struct.
-
- SERVER and CONN must not be NULL. The real errors will be logged with
- SERVER and CONN but return generic errors to the client. */
-svn_error_t *load_pwdb_config(server_baton_t *server,
- svn_ra_svn_conn_t *conn,
- apr_pool_t *pool);
-
-/* Load the authz database for the listening server based on the
- entries in the SERVER struct.
-
- SERVER and CONN must not be NULL. The real errors will be logged with
- SERVER and CONN but return generic errors to the client. */
-svn_error_t *load_authz_config(server_baton_t *server,
- svn_ra_svn_conn_t *conn,
- const char *repos_root,
- apr_pool_t *pool);
-
/* Initialize the Cyrus SASL library. POOL is used for allocations. */
svn_error_t *cyrus_init(apr_pool_t *pool);
@@ -172,13 +174,6 @@ svn_error_t *cyrus_auth_request(svn_ra_s
apr_size_t escape_errorlog_item(char *dest, const char *source,
apr_size_t buflen);
-/* Log ERR to LOG_FILE if LOG_FILE is not NULL. Include REMOTE_HOST,
- USER, and REPOS in the log if they are not NULL. Allocate temporary
- char buffers in POOL (which caller can then clear or dispose of). */
-void
-log_error(svn_error_t *err, apr_file_t *log_file, const char *remote_host,
- const char *user, const char *repos, apr_pool_t *pool);
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
Modified: subversion/branches/cache-server/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/svnserve/svnserve.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/cache-server/subversion/svnserve/svnserve.c Tue Oct 15 08:52:06 2013
@@ -53,6 +53,23 @@
#include "private/svn_dep_compat.h"
#include "private/svn_cmdline_private.h"
+#include "private/svn_atomic.h"
+#include "private/svn_mutex.h"
+#include "private/svn_subr_private.h"
+
+/* Alas! old APR-Utils don't provide thread pools */
+#if APR_HAS_THREADS
+# if APR_VERSION_AT_LEAST(1,3,0)
+# include <apr_thread_pool.h>
+# define HAVE_THREADPOOLS 1
+# define THREAD_ERROR_MSG _("Can't push task")
+# else
+# define HAVE_THREADPOOLS 0
+# define THREAD_ERROR_MSG _("Can't create thread")
+# endif
+#else
+# define HAVE_THREADPOOLS 0
+#endif
#include "winservice.h"
@@ -61,6 +78,7 @@
#endif
#include "server.h"
+#include "logger.h"
/* The strategy for handling incoming connections. Some of these may be
unavailable due to platform limitations. */
@@ -101,6 +119,50 @@ enum run_mode {
#endif
+/* Parameters for the worker thread pool used in threaded mode. */
+
+/* Have at least this many worker threads (even if there are no requests
+ * to handle).
+ *
+ * A 0 value is legal but increases the latency for the next incoming
+ * request. Higher values may be useful for servers that experience short
+ * bursts of concurrent requests followed by longer idle periods.
+ */
+#define THREADPOOL_MIN_SIZE 1
+
+/* Maximum number of worker threads. If there are more concurrent requests
+ * than worker threads, the extra requests get queued.
+ *
+ * Since very slow connections will hog a full thread for a potentially
+ * long time before timing out, be sure to not set this limit too low.
+ *
+ * On the other hand, keep in mind that every thread will allocate up to
+ * 4MB of unused RAM in the APR allocator of its root pool. 32 bit servers
+ * must hence do with fewer threads.
+ */
+#if (APR_SIZEOF_VOIDP <= 4)
+#define THREADPOOL_MAX_SIZE 64
+#else
+#define THREADPOOL_MAX_SIZE 256
+#endif
+
+/* Number of microseconds that an unused thread remains in the pool before
+ * being terminated.
+ *
+ * Higher values are useful if clients frequently send small requests and
+ * you want to minimize the latency for those.
+ */
+#define THREADPOOL_THREAD_IDLE_LIMIT 1000000
+
+/* Number of client to server connections that may concurrently in the
+ * TCP 3-way handshake state, i.e. are in the process of being created.
+ *
+ * Larger values improve scalability with lots of small requests comming
+ * on over long latency networks.
+ *
+ * The OS may actually use a lower limit than specified here.
+ */
+#define ACCEPT_BACKLOG 128
#ifdef WIN32
static apr_os_sock_t winservice_svnserve_accept_socket = INVALID_SOCKET;
@@ -223,7 +285,7 @@ static const apr_getopt_option_t svnserv
" "
"revisions.\n"
" "
- "Default is no.\n"
+ "Default is yes.\n"
" "
"[used for FSFS repositories only]")},
{"cache-fulltexts", SVNSERVE_OPT_CACHE_FULLTEXTS, 1,
@@ -290,7 +352,6 @@ static const apr_getopt_option_t svnserv
{0, 0, 0, 0}
};
-
static void usage(const char *progname, apr_pool_t *pool)
{
if (!progname)
@@ -309,15 +370,21 @@ static void help(apr_pool_t *pool)
#ifdef WIN32
svn_error_clear(svn_cmdline_fputs(_("usage: svnserve [-d | -i | -t | -X "
"| --service] [options]\n"
+ "Subversion repository server.\n"
+ "Type 'svnserve --version' to see the "
+ "program version.\n"
"\n"
"Valid options:\n"),
- stdout, pool));
+ stdout, pool));
#else
svn_error_clear(svn_cmdline_fputs(_("usage: svnserve [-d | -i | -t | -X] "
"[options]\n"
+ "Subversion repository server.\n"
+ "Type 'svnserve --version' to see the "
+ "program version.\n"
"\n"
"Valid options:\n"),
- stdout, pool));
+ stdout, pool));
#endif
for (i = 0; svnserve__options[i].name && svnserve__options[i].optch; i++)
{
@@ -378,20 +445,108 @@ static apr_status_t redirect_stdout(void
return apr_file_dup2(out_file, err_file, pool);
}
+#if APR_HAS_THREADS
+/* The pool passed to apr_thread_create can only be released when both
+
+ A: the call to apr_thread_create has returned to the calling thread
+ B: the new thread has started running and reached apr_thread_start_t
+
+ So we set the atomic counter to 2 then both the calling thread and
+ the new thread decrease it and when it reaches 0 the pool can be
+ released. */
+typedef struct shared_pool_t {
+ svn_atomic_t count;
+ apr_pool_t *pool; /* root pool used to allocate the socket */
+ svn_root_pools__t *root_pools; /* put it back into this after use */
+} shared_pool_t;
+
+static shared_pool_t *
+attach_shared_pool(apr_pool_t *pool,
+ svn_root_pools__t *root_pools)
+{
+ shared_pool_t *shared = apr_palloc(pool, sizeof(*shared));
+
+ shared->pool = pool;
+ shared->root_pools = root_pools;
+ svn_atomic_set(&shared->count, 2);
+
+ return shared;
+}
+
+static void
+release_shared_pool(struct shared_pool_t *shared)
+{
+ if (svn_atomic_dec(&shared->count) == 0)
+ svn_root_pools__release_pool(shared->pool, shared->root_pools);
+}
+#endif
+
+/* Wrapper around serve() that takes a socket instead of a connection.
+ * This is to off-load work from the main thread in threaded and fork modes.
+ */
+static svn_error_t *
+serve_socket(apr_socket_t *usock,
+ serve_params_t *params,
+ apr_pool_t *pool)
+{
+ apr_status_t status;
+ svn_ra_svn_conn_t *conn;
+ svn_error_t *err;
+
+ /* Enable TCP keep-alives on the socket so we time out when
+ * the connection breaks due to network-layer problems.
+ * If the peer has dropped the connection due to a network partition
+ * or a crash, or if the peer no longer considers the connection
+ * valid because we are behind a NAT and our public IP has changed,
+ * it will respond to the keep-alive probe with a RST instead of an
+ * acknowledgment segment, which will cause svn to abort the session
+ * even while it is currently blocked waiting for data from the peer. */
+ status = apr_socket_opt_set(usock, APR_SO_KEEPALIVE, 1);
+ if (status)
+ {
+ /* It's not a fatal error if we cannot enable keep-alives. */
+ }
+
+ /* create the connection, configure ports etc. */
+ conn = svn_ra_svn_create_conn3(usock, NULL, NULL,
+ params->compression_level,
+ params->zero_copy_limit,
+ params->error_check_interval,
+ pool);
+
+ /* process the actual request and log errors */
+ err = serve(conn, params, pool);
+ if (err)
+ logger__log_error(params->logger, err, NULL,
+ get_client_info(conn, params, pool));
+
+ return svn_error_trace(err);
+}
+
/* "Arguments" passed from the main thread to the connection thread */
struct serve_thread_t {
- svn_ra_svn_conn_t *conn;
+ apr_socket_t *usock;
serve_params_t *params;
- apr_pool_t *pool;
+#if APR_HAS_THREADS
+ shared_pool_t *shared_pool;
+#endif
};
#if APR_HAS_THREADS
+
+/* allocate and recycle root pools for connection objects.
+ There should be at most THREADPOOL_MAX_SIZE such pools. */
+svn_root_pools__t *connection_pools;
+
static void * APR_THREAD_FUNC serve_thread(apr_thread_t *tid, void *data)
{
struct serve_thread_t *d = data;
- svn_error_clear(serve(d->conn, d->params, d->pool));
- svn_pool_destroy(d->pool);
+ apr_pool_t *pool = svn_root_pools__acquire_pool(connection_pools);
+ svn_error_clear(serve_socket(d->usock, d->params, pool));
+ svn_root_pools__release_pool(pool, connection_pools);
+
+ release_shared_pool(d->shared_pool);
return NULL;
}
@@ -405,8 +560,9 @@ static svn_error_t *write_pid_file(const
const char *contents = apr_psprintf(pool, "%" APR_PID_T_FMT "\n",
getpid());
+ SVN_ERR(svn_io_remove_file2(filename, TRUE, pool));
SVN_ERR(svn_io_file_open(&file, filename,
- APR_WRITE | APR_CREATE | APR_TRUNCATE,
+ APR_WRITE | APR_CREATE | APR_EXCL,
APR_OS_DEFAULT, pool));
SVN_ERR(svn_io_file_write_full(file, contents, strlen(contents), NULL,
pool));
@@ -431,7 +587,7 @@ check_lib_versions(void)
};
SVN_VERSION_DEFINE(my_version);
- return svn_ver_check_list(&my_version, checklist);
+ return svn_ver_check_list2(&my_version, checklist, svn_ver_equal);
}
@@ -443,20 +599,22 @@ int main(int argc, const char *argv[])
apr_file_t *in_file, *out_file;
apr_sockaddr_t *sa;
apr_pool_t *pool;
- apr_pool_t *connection_pool;
svn_error_t *err;
apr_getopt_t *os;
int opt;
serve_params_t params;
const char *arg;
apr_status_t status;
- svn_ra_svn_conn_t *conn;
apr_proc_t proc;
#if APR_HAS_THREADS
+ shared_pool_t *shared_pool;
+ struct serve_thread_t *thread_data;
+#if HAVE_THREADPOOLS
+ apr_thread_pool_t *threads;
+#else
apr_threadattr_t *tattr;
apr_thread_t *tid;
-
- struct serve_thread_t *thread_data;
+#endif
#endif
enum connection_handling_mode handling_mode = CONNECTION_DEFAULT;
apr_uint16_t port = SVN_RA_SVN_PORT;
@@ -474,6 +632,7 @@ int main(int argc, const char *argv[])
const char *pid_filename = NULL;
const char *log_filename = NULL;
svn_node_kind_t kind;
+ svn_root_pools__t *socket_pools;
/* Initialize the app. */
if (svn_cmdline_init("svnserve", stderr) != EXIT_SUCCESS)
@@ -507,12 +666,12 @@ int main(int argc, const char *argv[])
params.base = NULL;
params.cfg = NULL;
params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
- params.log_file = NULL;
+ params.logger = NULL;
params.vhost = FALSE;
params.username_case = CASE_ASIS;
params.memory_cache_size = (apr_uint64_t)-1;
params.cache_fulltexts = TRUE;
- params.cache_txdeltas = FALSE;
+ params.cache_txdeltas = TRUE;
params.cache_revprops = FALSE;
params.zero_copy_limit = 0;
params.error_check_interval = 4096;
@@ -763,9 +922,7 @@ int main(int argc, const char *argv[])
}
if (log_filename)
- SVN_INT_ERR(svn_io_file_open(¶ms.log_file, log_filename,
- APR_WRITE | APR_CREATE | APR_APPEND,
- APR_OS_DEFAULT, pool));
+ SVN_INT_ERR(logger__create(¶ms.logger, log_filename, pool));
if (params.tunnel_user && run_mode != run_mode_tunnel)
{
@@ -778,6 +935,9 @@ int main(int argc, const char *argv[])
if (run_mode == run_mode_inetd || run_mode == run_mode_tunnel)
{
+ apr_pool_t *connection_pool;
+ svn_ra_svn_conn_t *conn;
+
params.tunnel = (run_mode == run_mode_tunnel);
apr_pool_cleanup_register(pool, pool, apr_pool_cleanup_null,
redirect_stdout);
@@ -924,7 +1084,7 @@ int main(int argc, const char *argv[])
return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
}
- apr_socket_listen(sock, 7);
+ apr_socket_listen(sock, ACCEPT_BACKLOG);
#if APR_HAS_FORK
if (run_mode != run_mode_listen_once && !foreground)
@@ -986,8 +1146,45 @@ int main(int argc, const char *argv[])
svn_cache_config_set(&settings);
}
+ /* we use (and recycle) separate pools for sockets (many small ones)
+ and connections (fewer but larger ones) */
+ err = svn_root_pools__create(&socket_pools);
+ if (err)
+ return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+
+#if APR_HAS_THREADS
+ err = svn_root_pools__create(&connection_pools);
+ if (err)
+ return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+#endif
+
+#if HAVE_THREADPOOLS
+ if (handling_mode == connection_mode_thread)
+ {
+ /* create the thread pool */
+ status = apr_thread_pool_create(&threads,
+ THREADPOOL_MIN_SIZE,
+ THREADPOOL_MAX_SIZE,
+ pool);
+ if (status)
+ {
+ err = svn_error_wrap_apr (status, _("Can't create thread pool"));
+ return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
+ }
+
+ /* let idle threads linger for a while in case more requests are
+ coming in */
+ apr_thread_pool_idle_wait_set(threads, THREADPOOL_THREAD_IDLE_LIMIT);
+
+ /* don't queue requests unless we reached the worker thread limit */
+ apr_thread_pool_threshold_set(threads, 0);
+ }
+#endif
+
while (1)
{
+ apr_pool_t *socket_pool;
+
#ifdef WIN32
if (winservice_is_stopping())
return ERROR_SUCCESS;
@@ -997,20 +1194,21 @@ int main(int argc, const char *argv[])
the connection threads so it cannot clean up after each one. So
separate pools that can be cleared at thread exit are used. */
- connection_pool
- = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+ socket_pool = svn_root_pools__acquire_pool(socket_pools);
- status = apr_socket_accept(&usock, sock, connection_pool);
+ status = apr_socket_accept(&usock, sock, socket_pool);
if (handling_mode == connection_mode_fork)
{
/* Collect any zombie child processes. */
while (apr_proc_wait_all_procs(&proc, NULL, NULL, APR_NOWAIT,
- connection_pool) == APR_CHILD_DONE)
+ socket_pool) == APR_CHILD_DONE)
;
}
- if (APR_STATUS_IS_EINTR(status))
+ if (APR_STATUS_IS_EINTR(status)
+ || APR_STATUS_IS_ECONNABORTED(status)
+ || APR_STATUS_IS_ECONNRESET(status))
{
- svn_pool_destroy(connection_pool);
+ svn_root_pools__release_pool(socket_pool, socket_pools);
continue;
}
if (status)
@@ -1020,29 +1218,9 @@ int main(int argc, const char *argv[])
return svn_cmdline_handle_exit_error(err, pool, "svnserve: ");
}
- /* Enable TCP keep-alives on the socket so we time out when
- * the connection breaks due to network-layer problems.
- * If the peer has dropped the connection due to a network partition
- * or a crash, or if the peer no longer considers the connection
- * valid because we are behind a NAT and our public IP has changed,
- * it will respond to the keep-alive probe with a RST instead of an
- * acknowledgment segment, which will cause svn to abort the session
- * even while it is currently blocked waiting for data from the peer. */
- status = apr_socket_opt_set(usock, APR_SO_KEEPALIVE, 1);
- if (status)
- {
- /* It's not a fatal error if we cannot enable keep-alives. */
- }
-
- conn = svn_ra_svn_create_conn3(usock, NULL, NULL,
- params.compression_level,
- params.zero_copy_limit,
- params.error_check_interval,
- connection_pool);
-
if (run_mode == run_mode_listen_once)
{
- err = serve(conn, ¶ms, connection_pool);
+ err = serve_socket(usock, ¶ms, socket_pool);
if (err)
svn_handle_error2(err, stdout, FALSE, "svnserve: ");
@@ -1057,16 +1235,11 @@ int main(int argc, const char *argv[])
{
case connection_mode_fork:
#if APR_HAS_FORK
- status = apr_proc_fork(&proc, connection_pool);
+ status = apr_proc_fork(&proc, socket_pool);
if (status == APR_INCHILD)
{
apr_socket_close(sock);
- err = serve(conn, ¶ms, connection_pool);
- log_error(err, params.log_file,
- svn_ra_svn_conn_remote_host(conn),
- NULL, NULL, /* user, repos */
- connection_pool);
- svn_error_clear(err);
+ svn_error_clear(serve_socket(usock, ¶ms, socket_pool));
apr_socket_close(usock);
exit(0);
}
@@ -1077,14 +1250,11 @@ int main(int argc, const char *argv[])
else
{
err = svn_error_wrap_apr(status, "apr_proc_fork");
- log_error(err, params.log_file,
- svn_ra_svn_conn_remote_host(conn),
- NULL, NULL, /* user, repos */
- connection_pool);
+ logger__log_error(params.logger, err, NULL, NULL);
svn_error_clear(err);
apr_socket_close(usock);
}
- svn_pool_destroy(connection_pool);
+ svn_root_pools__release_pool(socket_pool, socket_pools);
#endif
break;
@@ -1093,7 +1263,17 @@ int main(int argc, const char *argv[])
particularly sophisticated strategy for a threaded server, it's
little different from forking one process per connection. */
#if APR_HAS_THREADS
- status = apr_threadattr_create(&tattr, connection_pool);
+ shared_pool = attach_shared_pool(socket_pool, socket_pools);
+
+ thread_data = apr_palloc(socket_pool, sizeof(*thread_data));
+ thread_data->usock = usock;
+ thread_data->params = ¶ms;
+ thread_data->shared_pool = shared_pool;
+#if HAVE_THREADPOOLS
+ status = apr_thread_pool_push(threads, serve_thread, thread_data,
+ 0, NULL);
+#else
+ status = apr_threadattr_create(&tattr, socket_pool);
if (status)
{
err = svn_error_wrap_apr(status, _("Can't create threadattr"));
@@ -1109,26 +1289,24 @@ int main(int argc, const char *argv[])
svn_error_clear(err);
exit(1);
}
- thread_data = apr_palloc(connection_pool, sizeof(*thread_data));
- thread_data->conn = conn;
- thread_data->params = ¶ms;
- thread_data->pool = connection_pool;
status = apr_thread_create(&tid, tattr, serve_thread, thread_data,
- connection_pool);
+ shared_pool->pool);
+#endif
if (status)
{
- err = svn_error_wrap_apr(status, _("Can't create thread"));
+ err = svn_error_wrap_apr(status, THREAD_ERROR_MSG);
svn_handle_error2(err, stderr, FALSE, "svnserve: ");
svn_error_clear(err);
exit(1);
}
+ release_shared_pool(shared_pool);
#endif
break;
case connection_mode_single:
/* Serve one connection at a time. */
- svn_error_clear(serve(conn, ¶ms, connection_pool));
- svn_pool_destroy(connection_pool);
+ svn_error_clear(serve_socket(usock, ¶ms, socket_pool));
+ svn_root_pools__release_pool(socket_pool, socket_pools);
}
}
Modified: subversion/branches/cache-server/subversion/svnsync/svnsync.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/svnsync/svnsync.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/svnsync/svnsync.c (original)
+++ subversion/branches/cache-server/subversion/svnsync/svnsync.c Tue Oct 15 08:52:06 2013
@@ -19,6 +19,7 @@
* ====================================================================
*/
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_cmdline.h"
#include "svn_config.h"
@@ -41,8 +42,6 @@
#include "sync.h"
-#include "svn_private_config.h"
-
#include <apr_signal.h>
#include <apr_uuid.h>
@@ -312,7 +311,7 @@ check_lib_versions(void)
};
SVN_VERSION_DEFINE(my_version);
- return svn_ver_check_list(&my_version, checklist);
+ return svn_ver_check_list2(&my_version, checklist, svn_ver_equal);
}
@@ -1297,7 +1296,7 @@ replay_rev_finished(svn_revnum_t revisio
if (rb->sb->committed_rev != revision)
return svn_error_createf
(APR_EINVAL, NULL,
- _("Commit created rev %ld but should have created %ld"),
+ _("Commit created r%ld but should have created r%ld"),
rb->sb->committed_rev, revision);
SVN_ERR(svn_ra_rev_proplist(rb->to_session, revision, &existing_props,
@@ -1847,6 +1846,7 @@ help_cmd(apr_getopt_t *os, void *baton,
const char *header =
_("general usage: svnsync SUBCOMMAND DEST_URL [ARGS & OPTIONS ...]\n"
+ "Subversion repository replication tool.\n"
"Type 'svnsync help <subcommand>' for help on a specific subcommand.\n"
"Type 'svnsync --version' to see the program version and RA modules.\n"
"\n"
Modified: subversion/branches/cache-server/subversion/svnsync/sync.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/svnsync/sync.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/svnsync/sync.c (original)
+++ subversion/branches/cache-server/subversion/svnsync/sync.c Tue Oct 15 08:52:06 2013
@@ -19,6 +19,7 @@
* ====================================================================
*/
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_cmdline.h"
#include "svn_config.h"
@@ -36,8 +37,6 @@
#include "sync.h"
-#include "svn_private_config.h"
-
#include <apr_network_io.h>
#include <apr_signal.h>
#include <apr_uuid.h>
Modified: subversion/branches/cache-server/subversion/svnversion/svnversion.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/svnversion/svnversion.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/svnversion/svnversion.c (original)
+++ subversion/branches/cache-server/subversion/svnversion/svnversion.c Tue Oct 15 08:52:06 2013
@@ -57,7 +57,10 @@ help(const apr_getopt_option_t *options,
svn_error_clear
(svn_cmdline_fprintf
(stdout, pool,
- _("usage: svnversion [OPTIONS] [WC_PATH [TRAIL_URL]]\n\n"
+ _("usage: svnversion [OPTIONS] [WC_PATH [TRAIL_URL]]\n"
+ "Subversion working copy identification tool.\n"
+ "Type 'svnversion --version' to see the program version.\n"
+ "\n"
" Produce a compact version identifier for the working copy path\n"
" WC_PATH. TRAIL_URL is the trailing portion of the URL used to\n"
" determine if WC_PATH itself is switched (detection of switches\n"
@@ -110,7 +113,7 @@ check_lib_versions(void)
};
SVN_VERSION_DEFINE(my_version);
- return svn_ver_check_list(&my_version, checklist);
+ return svn_ver_check_list2(&my_version, checklist, svn_ver_equal);
}
/*
Propchange: subversion/branches/cache-server/subversion/tests/cmdline/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Oct 15 08:52:06 2013
@@ -8,3 +8,4 @@ httpd-*
entries-dump
atomic-ra-revprop-change
.libs
+.davautocheck.sh.stop
Modified: subversion/branches/cache-server/subversion/tests/cmdline/README
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/README?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/README (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/README Tue Oct 15 08:52:06 2013
@@ -245,9 +245,25 @@ Directory Contents
/verify.py: Verifies output from Subversion.
- /entry.py: Parse an `entries' file (### not used yet)
-
-
+ /testcase.py: Control of test case execution - contains
+ decorators for expected failures and conditionally
+ executed tests.
+
+ /sandbox.py: Tools for manipulating a test's working area
+ ("a sandbox"), those are handy for most simple
+ actions a test might want to perform on a wc.
+
+ /objects.py: Objects that keep track of state during a test.
+ (not directly used by the test scripts.)
+
+ /mergetrees.py: Routines that create merge scenarios.
+
+ /factory.py: Automatically generate a (near-)complete new
+ cmdline test from a series of shell commands.
+
+ /error.py: Error codes as constants, for convenience.
+ (auto-generated by tools/dev/gen-py-error.py)
+
What the Python Tests are Doing
===============================
Modified: subversion/branches/cache-server/subversion/tests/cmdline/authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/authz_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/authz_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/authz_tests.py Tue Oct 15 08:52:06 2013
@@ -576,7 +576,8 @@ def authz_log_and_tracing_test(sbox):
if sbox.repo_url.startswith('http'):
expected_err2 = expected_err
else:
- expected_err2 = ".*svn: E220001: Item is not readable.*"
+ expected_err2 = ".*svn: E220001: Unreadable path encountered; " \
+ "access denied.*"
# if we do the same thing directly on the unreadable file, we get:
# svn: Item is not readable
@@ -1550,6 +1551,44 @@ def log_diff_dontdothat(sbox):
'log', ddt_url,
'-c', 1, '--diff')
+@Issue(4422)
+@Skip(svntest.main.is_ra_type_file)
+def authz_file_external_to_authz(sbox):
+ "replace file external with authz node"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+
+ write_authz_file(sbox, {"/": "* = rw"})
+ write_restrictive_svnserve_conf(sbox.repo_dir)
+
+ sbox.simple_propset('svn:externals', 'Z ' + repo_url + '/iota', '')
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('', status=' M')
+ expected_status.add({
+ 'Z' : Item(status=' ', wc_rev='1', switched='X'),
+ })
+ svntest.actions.run_and_verify_update(wc_dir,
+ None, None, expected_status)
+
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'cp', repo_url + '/A',
+ repo_url + '/Z',
+ '-m', 'Add Z')
+
+ write_authz_file(sbox, {"/": "* = rw", "/Z": "* = "})
+
+ expected_status.tweak(wc_rev=2)
+
+ # ### This used to assert with
+ # ### svn: E235000: In file 'update_editor.c' line 3043: assertion failed
+ # ### (status != svn_wc__db_status_normal)
+
+ svntest.actions.run_and_verify_update(wc_dir,
+ None, None, expected_status)
+
########################################################################
# Run the tests
@@ -1584,6 +1623,7 @@ test_list = [ None,
authz_svnserve_groups,
authz_del_from_subdir,
log_diff_dontdothat,
+ authz_file_external_to_authz,
]
serial_only = True
Modified: subversion/branches/cache-server/subversion/tests/cmdline/autoprop_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/autoprop_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/autoprop_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/autoprop_tests.py Tue Oct 15 08:52:06 2013
@@ -695,8 +695,7 @@ def svn_prop_inheritable_autoprops_unver
'*.c=svn:eol-style=CR', sbox.ospath('A/B'))
svntest.main.run_svn(None, 'ps', SVN_PROP_INHERITABLE_AUTOPROPS,
'*.c=svn:eol-style=native', sbox.ospath('A/D'))
- svntest.main.run_svn(None, 'ci', '-m', 'Add inheritable autoprops',
- sbox.wc_dir)
+ sbox.simple_commit(message='Add inheritable autoprops')
# Create two subtrees, each with one new file.
os.mkdir(Z_path)
Modified: subversion/branches/cache-server/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/basic_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/basic_tests.py Tue Oct 15 08:52:06 2013
@@ -3049,6 +3049,34 @@ def peg_rev_on_non_existent_wc_path(sbox
svntest.actions.run_and_verify_svn(None, ['r2\n'], [],
'cat', '-r2', sbox.ospath('mu3') + '@3')
+
+@Issue(4299)
+def basic_youngest(sbox):
+ 'basic youngest'
+
+ sbox.build(read_only=True)
+
+ repos_url = sbox.repo_url
+ deep_repos_url = repos_url + '/A/D/G'
+
+ wc_dir = sbox.wc_dir
+ deep_wc_dir = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
+ bad_wc_dir = os.path.join(wc_dir, 'Z')
+
+ svntest.actions.run_and_verify_svn("'svn youngest' on bad WC path",
+ None, svntest.verify.AnyOutput,
+ 'youngest', bad_wc_dir)
+
+ for flag, output in [(False, "1\n"), (True, "1")]:
+ for path in [repos_url, deep_repos_url, wc_dir, deep_wc_dir]:
+ if flag:
+ svntest.actions.run_and_verify_svn("svn youngest", [output], [],
+ 'youngest', '--no-newline', path)
+ else:
+ svntest.actions.run_and_verify_svn("svn youngest", [output], [],
+ 'youngest', path)
+
+
########################################################################
# Run the tests
@@ -3117,6 +3145,7 @@ test_list = [ None,
rm_missing_with_case_clashing_ondisk_item,
delete_conflicts_one_of_many,
peg_rev_on_non_existent_wc_path,
+ basic_youngest,
]
if __name__ == '__main__':
Modified: subversion/branches/cache-server/subversion/tests/cmdline/blame_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/blame_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/blame_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/blame_tests.py Tue Oct 15 08:52:06 2013
@@ -34,7 +34,7 @@ from svntest.main import server_has_merg
from prop_tests import binary_mime_type_on_text_file_warning
# For some basic merge setup used by blame -g tests.
-from merge_tests import set_up_branch
+from svntest.mergetrees import set_up_branch
# (abbreviation)
Skip = svntest.testcase.Skip_deco
@@ -772,7 +772,7 @@ def merge_sensitive_blame_and_empty_merg
# Make an edit to A/D/H/psi in r3.
svntest.main.file_append(psi_path, "trunk edit in revision three.\n")
- svntest.main.run_svn(None, 'ci', '-m', 'trunk edit', wc_dir)
+ sbox.simple_commit(message='trunk edit')
# Merge r3 from A to A_COPY, reverse merge r3 from A/D/H/psi
# to A_COPY/D/H/psi, and commit as r4. This results in empty
@@ -782,21 +782,18 @@ def merge_sensitive_blame_and_empty_merg
sbox.repo_url + '/A', A_COPY_path)
svntest.main.run_svn(None, 'merge', '-c-3',
sbox.repo_url + '/A/D/H/psi', psi_COPY_path)
- svntest.main.run_svn(None, 'ci', '-m',
- 'Sync merge A to A_COPY excepting A_COPY/D/H/psi',
- wc_dir)
+ sbox.simple_commit(message='Sync merge A to A_COPY excepting A_COPY/D/H/psi')
# Make an edit to A/D/H/psi in r5.
svntest.main.file_append(psi_path, "trunk edit in revision five.\n")
- svntest.main.run_svn(None, 'ci', '-m', 'trunk edit', wc_dir)
+ sbox.simple_commit(message='trunk edit')
# Sync merge A/D/H/psi to A_COPY/D/H/psi and commit as r6. This replaces
# the empty mergeinfo on A_COPY/D/H/psi with '/A/D/H/psi:2-5'.
svntest.main.run_svn(None, 'up', wc_dir)
svntest.main.run_svn(None, 'merge', sbox.repo_url + '/A/D/H/psi',
psi_COPY_path)
- svntest.main.run_svn(None, 'ci', '-m',
- 'Sync merge A/D/H/psi to A_COPY/D/H/psi', wc_dir)
+ sbox.simple_commit(message='Sync merge A/D/H/psi to A_COPY/D/H/psi')
# Check the blame -g output:
# Currently this test fails because the trunk edit done in r3 is
@@ -959,6 +956,34 @@ def blame_eol_handling(sbox):
'blame', f2)
+@SkipUnless(svntest.main.server_has_reverse_get_file_revs)
+def blame_youngest_to_oldest(sbox):
+ "blame_youngest_to_oldest"
+
+ sbox.build()
+
+ # First, make a new revision of iota.
+ iota = sbox.ospath('iota')
+ orig_line = open(iota).read()
+ line = "New contents for iota\n"
+ svntest.main.file_append(iota, line)
+ sbox.simple_commit()
+
+ # Move the file, to check that the operation will peg correctly.
+ iota_moved = sbox.ospath('iota_moved')
+ sbox.simple_move('iota', 'iota_moved')
+ sbox.simple_commit()
+
+ # Delete a line.
+ open(iota_moved, 'w').write(line)
+ sbox.simple_commit()
+
+ expected_output = [
+ ' %d jrandom %s\n' % (3, orig_line[:-1]),
+ ]
+ svntest.actions.run_and_verify_svn(None, expected_output, [],
+ 'blame', '-r4:1', iota_moved)
+
########################################################################
# Run the tests
@@ -982,6 +1007,7 @@ test_list = [ None,
merge_sensitive_blame_and_empty_mergeinfo,
blame_multiple_targets,
blame_eol_handling,
+ blame_youngest_to_oldest,
]
if __name__ == '__main__':
Modified: subversion/branches/cache-server/subversion/tests/cmdline/checkout_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/checkout_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/checkout_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/checkout_tests.py Tue Oct 15 08:52:06 2013
@@ -660,8 +660,13 @@ def checkout_peg_rev_date(sbox):
sbox.build()
wc_dir = sbox.wc_dir
- # note the current time to use it as peg revision date.
- current_time = time.strftime("%Y-%m-%dT%H:%M:%S")
+ exit_code, output, errput = svntest.main.run_svn(None, 'propget', 'svn:date',
+ '--revprop', '-r1',
+ '--strict',
+ sbox.repo_url)
+ if exit_code or errput != [] or len(output) != 1:
+ raise svntest.Failure("svn:date propget failed")
+ r1_time = output[0]
# sleep till the next second.
time.sleep(1.1)
@@ -686,7 +691,7 @@ def checkout_peg_rev_date(sbox):
# use an old date to checkout, that way we're sure we get the first revision
svntest.actions.run_and_verify_checkout(sbox.repo_url +
- '@{' + current_time + '}',
+ '@{' + r1_time + '}',
checkout_target,
expected_output,
expected_wc)
@@ -1052,7 +1057,7 @@ def checkout_wc_from_drive(sbox):
svntest.main.safe_rmtree(sbox.wc_dir)
os.mkdir(sbox.wc_dir)
- # create a virtual drive to the working copy folder
+ # create a virtual drive to the repository folder
drive = find_the_next_available_drive_letter()
if drive is None:
raise svntest.Skip
@@ -1088,8 +1093,49 @@ def checkout_wc_from_drive(sbox):
})
svntest.actions.run_and_verify_checkout(repo_url, wc_dir,
expected_output, expected_wc,
- None, None, None, None,
- '--force')
+ None, None, None, None)
+
+ wc2_dir = sbox.add_wc_path('2')
+ expected_output = wc.State(wc2_dir, {
+ 'D' : Item(status='A '),
+ 'D/H' : Item(status='A '),
+ 'D/H/psi' : Item(status='A '),
+ 'D/H/chi' : Item(status='A '),
+ 'D/H/omega' : Item(status='A '),
+ 'D/G' : Item(status='A '),
+ 'D/G/tau' : Item(status='A '),
+ 'D/G/pi' : Item(status='A '),
+ 'D/G/rho' : Item(status='A '),
+ 'D/gamma' : Item(status='A '),
+ 'C' : Item(status='A '),
+ 'mu' : Item(status='A '),
+ 'B' : Item(status='A '),
+ 'B/E' : Item(status='A '),
+ 'B/E/alpha' : Item(status='A '),
+ 'B/E/beta' : Item(status='A '),
+ 'B/F' : Item(status='A '),
+ 'B/lambda' : Item(status='A '),
+ })
+ svntest.actions.run_and_verify_checkout(repo_url + '/A', wc2_dir,
+ expected_output, None,
+ None, None, None, None)
+
+ wc3_dir = sbox.add_wc_path('3')
+ expected_output = wc.State(wc3_dir, {
+ 'H' : Item(status='A '),
+ 'H/psi' : Item(status='A '),
+ 'H/chi' : Item(status='A '),
+ 'H/omega' : Item(status='A '),
+ 'G' : Item(status='A '),
+ 'G/tau' : Item(status='A '),
+ 'G/pi' : Item(status='A '),
+ 'G/rho' : Item(status='A '),
+ 'gamma' : Item(status='A '),
+ })
+
+ svntest.actions.run_and_verify_checkout(repo_url + '/A/D', wc3_dir,
+ expected_output, None,
+ None, None, None, None)
finally:
os.chdir(was_cwd)
Modified: subversion/branches/cache-server/subversion/tests/cmdline/commit_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/commit_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/commit_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/commit_tests.py Tue Oct 15 08:52:06 2013
@@ -1250,7 +1250,7 @@ def commit_add_file_twice(sbox):
svntest.actions.run_and_verify_commit(wc_dir,
None,
None,
- "already exists",
+ "E160020: File.*already exists",
wc_dir)
#----------------------------------------------------------------------
@@ -1797,7 +1797,7 @@ def commit_out_of_date_deletions(sbox):
I_path = sbox.ospath('A/I')
os.mkdir(I_path)
svntest.main.run_svn(None, 'add', I_path)
- svntest.main.run_svn(None, 'ci', '-m', 'prep', wc_dir)
+ sbox.simple_commit(message='prep')
svntest.main.run_svn(None, 'up', wc_dir)
# Make a backup copy of the working copy
@@ -2945,6 +2945,77 @@ def last_changed_of_copied_subdir(sbox):
}
svntest.actions.run_and_verify_info([expected], E_copied)
+@XFail()
+def commit_unversioned(sbox):
+ "verify behavior on unversioned targets"
+
+ sbox.build(read_only=True)
+ wc_dir = sbox.wc_dir
+
+ expected_err = 'E200009: .*existing.*\' is not under version control'
+
+ # Unversioned, but existing file
+ svntest.main.file_write(sbox.ospath('existing'), "xxxx")
+ svntest.actions.run_and_verify_commit(wc_dir, None, None, expected_err,
+ sbox.ospath('existing'))
+
+ # Unversioned, not existing
+ svntest.actions.run_and_verify_commit(wc_dir, None, None, expected_err,
+ sbox.ospath('not-existing'))
+
+@Issue(4400)
+def commit_cp_with_deep_delete(sbox):
+ "verify behavior of a copy with a deep (>=3) delete"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Prep by adding a tree deep enough to exercise the issue.
+ sbox.simple_mkdir('A/B/E/I')
+ sbox.simple_commit(message='prep')
+ svntest.main.run_svn(None, 'up', wc_dir)
+
+ # copy the deep tree and then delete a dir 3 deep.
+ sbox.simple_copy('A','A2')
+ sbox.simple_rm('A2/B/E/I')
+
+ # come up with the expected output and status
+ expected_output = svntest.wc.State(wc_dir, {
+ 'A2' : Item(verb='Adding'),
+ 'A2/B/E/I' : Item(verb='Deleting'),
+ })
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+ expected_status.add({
+ 'A/B/E/I' : Item(status=' ', wc_rev='2'),
+ 'A2' : Item(status=' ', wc_rev='3'),
+ 'A2/B' : Item(status=' ', wc_rev='3'),
+ 'A2/B/lambda' : Item(status=' ', wc_rev='3'),
+ 'A2/B/F' : Item(status=' ', wc_rev='3'),
+ 'A2/B/E' : Item(status=' ', wc_rev='3'),
+ 'A2/B/E/alpha' : Item(status=' ', wc_rev='3'),
+ 'A2/B/E/beta' : Item(status=' ', wc_rev='3'),
+ 'A2/D' : Item(status=' ', wc_rev='3'),
+ 'A2/D/gamma' : Item(status=' ', wc_rev='3'),
+ 'A2/D/H' : Item(status=' ', wc_rev='3'),
+ 'A2/D/H/psi' : Item(status=' ', wc_rev='3'),
+ 'A2/D/H/omega' : Item(status=' ', wc_rev='3'),
+ 'A2/D/H/chi' : Item(status=' ', wc_rev='3'),
+ 'A2/D/G' : Item(status=' ', wc_rev='3'),
+ 'A2/D/G/tau' : Item(status=' ', wc_rev='3'),
+ 'A2/D/G/rho' : Item(status=' ', wc_rev='3'),
+ 'A2/D/G/pi' : Item(status=' ', wc_rev='3'),
+ 'A2/C' : Item(status=' ', wc_rev='3'),
+ 'A2/mu' : Item(status=' ', wc_rev='3'),
+ })
+
+ # Commit the copy without the one dir.
+ svntest.actions.run_and_verify_commit(wc_dir,
+ expected_output,
+ expected_status,
+ None,
+ wc_dir)
+
+
########################################################################
# Run the tests
@@ -3017,6 +3088,8 @@ test_list = [ None,
commit_add_subadd,
commit_danglers,
last_changed_of_copied_subdir,
+ commit_unversioned,
+ commit_cp_with_deep_delete,
]
if __name__ == '__main__':
Modified: subversion/branches/cache-server/subversion/tests/cmdline/davautocheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/davautocheck.sh?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/davautocheck.sh (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/davautocheck.sh Tue Oct 15 08:52:06 2013
@@ -27,7 +27,7 @@
# testing are:
# - Subversion built using --enable-shared --enable-dso --with-apxs options,
# - Working Apache 2 HTTPD Server with the apxs program reachable through
-# PATH or specified via the APXS environment variable,
+# PATH or specified via the APXS Makefile variable or environment variable,
# - Modules dav_module and log_config_module compiled as DSO or built into
# Apache HTTPD Server executable.
# The basic intension of this script is to be able to perform "make check"
@@ -79,12 +79,14 @@
# environment.
#
# Passing --no-tests as argv[1] will have the script start a server
-# but not run any tests.
+# but not run any tests. Passing --gdb will do the same, and in addition
+# spawn gdb in the foreground attached to the running server.
PYTHON=${PYTHON:-python}
SCRIPTDIR=$(dirname $0)
SCRIPT=$(basename $0)
+STOPSCRIPT=$SCRIPTDIR/.$SCRIPT.stop
trap stop_httpd_and_die HUP TERM INT
@@ -113,13 +115,17 @@ query() {
read -n 1 -t 32
else
#
- prog=$(cat) <<'EOF'
+ prog="
import select as s
import sys
+import tty, termios
+tty.setcbreak(sys.stdin.fileno(), termios.TCSANOW)
if s.select([sys.stdin.fileno()], [], [], 32)[0]:
sys.stdout.write(sys.stdin.read(1))
-EOF
- REPLY=`stty cbreak; $PYTHON -c "$prog" "$@"; stty -cbreak`
+"
+ stty_state=`stty -g`
+ REPLY=`$PYTHON -u -c "$prog" "$@"`
+ stty $stty_state
fi
echo
[ "${REPLY:-$2}" = 'y' ]
@@ -157,8 +163,20 @@ get_prog_name() {
}
# Don't assume sbin is in the PATH.
+# ### Presumably this is used to locate /usr/sbin/apxs or /usr/sbin/apache2
PATH="$PATH:/usr/sbin:/usr/local/sbin"
+# Find the source and build directories. The build dir can be found if it is
+# the current working dir or the source dir.
+ABS_SRCDIR=$(cd ${SCRIPTDIR}/../../../; pwd)
+if [ -x subversion/svn/svn ]; then
+ ABS_BUILDDIR=$(pwd)
+elif [ -x $ABS_SRCDIR/subversion/svn/svn ]; then
+ ABS_BUILDDIR=$ABS_SRCDIR
+else
+ fail "Run this script from the root of Subversion's build tree!"
+fi
+
# Remove any proxy environmental variables that affect wget or curl.
# We don't need a proxy to connect to localhost and having the proxy
# environmental variables set breaks the Apache configuration file
@@ -169,10 +187,18 @@ unset http_proxy
unset HTTPS_PROXY
# Pick up value from environment or PATH (also try apxs2 - for Debian)
-[ ${APXS:+set} ] \
- || APXS=$(which apxs) \
- || APXS=$(which apxs2) \
- || fail "neither apxs or apxs2 found - required to run davautocheck"
+if [ ${APXS:+set} ]; then
+ :
+elif APXS=$(grep '^APXS' $ABS_BUILDDIR/Makefile | sed 's/^APXS *= *//') && \
+ [ -n "$APXS" ]; then
+ :
+elif APXS=$(which apxs); then
+ :
+elif APXS=$(which apxs2); then
+ :
+else
+ fail "neither apxs or apxs2 found - required to run davautocheck"
+fi
[ -x $APXS ] || fail "Can't execute apxs executable $APXS"
@@ -195,17 +221,6 @@ if [ ${CACHE_REVPROPS:+set} ]; then
CACHE_REVPROPS_SETTING=on
fi
-# Find the source and build directories. The build dir can be found if it is
-# the current working dir or the source dir.
-ABS_SRCDIR=$(cd ${SCRIPTDIR}/../../../; pwd)
-if [ -x subversion/svn/svn ]; then
- ABS_BUILDDIR=$(pwd)
-elif [ -x $ABS_SRCDIR/subversion/svn/svn ]; then
- ABS_BUILDDIR=$ABS_SRCDIR
-else
- fail "Run this script from the root of Subversion's build tree!"
-fi
-
if [ ${MODULE_PATH:+set} ]; then
MOD_DAV_SVN="$MODULE_PATH/mod_dav_svn.so"
MOD_AUTHZ_SVN="$MODULE_PATH/mod_authz_svn.so"
@@ -300,17 +315,16 @@ if [ ${USE_SSL:+set} ]; then
|| fail "SSL module not found"
fi
-random_port() {
- if [ -n "$BASH_VERSION" ]; then
- echo $(($RANDOM+1024))
- else
- $PYTHON -c 'import random; print random.randint(1024, 2**16-1)'
- fi
-}
+# Stop any previous instances, os we can re-use the port.
+if [ -x $STOPSCRIPT ]; then $STOPSCRIPT ; sleep 1; fi
-HTTPD_PORT=$(random_port)
-while netstat -an | grep $HTTPD_PORT | grep 'LISTEN'; do
- HTTPD_PORT=$(random_port)
+HTTPD_PORT=3691
+while netstat -an | grep $HTTPD_PORT | grep 'LISTEN' >/dev/null; do
+ HTTPD_PORT=$(( HTTPD_PORT + 1 ))
+ if [ $HTTPD_PORT -eq 65536 ]; then
+ # Most likely the loop condition is true regardless of $HTTPD_PORT
+ fail "netstat claims you have no free ports for httpd to listen on."
+ fi
done
HTTPD_ROOT="$ABS_BUILDDIR/subversion/tests/cmdline/httpd-$(date '+%Y%m%d-%H%M%S')"
HTTPD_CFG="$HTTPD_ROOT/cfg"
@@ -318,7 +332,13 @@ HTTPD_PID="$HTTPD_ROOT/pid"
HTTPD_ACCESS_LOG="$HTTPD_ROOT/access_log"
HTTPD_ERROR_LOG="$HTTPD_ROOT/error_log"
HTTPD_MIME_TYPES="$HTTPD_ROOT/mime.types"
-BASE_URL="http://localhost:$HTTPD_PORT"
+if [ -z "$BASE_URL" ]; then
+ BASE_URL="http://localhost:$HTTPD_PORT"
+else
+ # Specify the public name of the host when using a proxy on another host, the
+ # port number will be appended.
+ BASE_URL="$BASE_URL:$HTTPD_PORT"
+fi
HTTPD_USERS="$HTTPD_ROOT/users"
mkdir "$HTTPD_ROOT" \
@@ -430,7 +450,7 @@ PidFile "$HTTPD_PID"
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog "$HTTPD_ACCESS_LOG" common
ErrorLog "$HTTPD_ERROR_LOG"
-LogLevel Debug
+LogLevel debug
ServerRoot "$HTTPD_ROOT"
DocumentRoot "$HTTPD_ROOT"
ScoreBoardFile "$HTTPD_ROOT/run"
@@ -486,6 +506,20 @@ RedirectMatch ^/svn-test-work/
__EOF__
START="$HTTPD -f $HTTPD_CFG"
+printf \
+'#!/bin/sh
+if [ -d "%s" ]; then
+ printf "Stopping previous HTTPD instance..."
+ if %s -k stop; then
+ # httpd had no output; echo a newline.
+ echo ""
+ elif [ -s "%s" ]; then
+ # httpd would have printed an error terminated by a newline.
+ kill -9 "`cat %s`"
+ fi
+fi
+' >$STOPSCRIPT "$HTTPD_ROOT" "$START" "$HTTPD_PID" "$HTTPD_PID"
+chmod +x $STOPSCRIPT
$START -t \
|| fail "Configuration file didn't pass the check, most likely modules couldn't be loaded"
@@ -522,10 +556,17 @@ rm "$HTTPD_CFG-copy"
say "HTTPD is good"
if [ $# -eq 1 ] && [ "x$1" = 'x--no-tests' ]; then
- echo "http://localhost:$HTTPD_PORT"
+ echo "http://localhost:$HTTPD_PORT/svn-test-work/repositories"
exit
fi
+if [ $# -eq 1 ] && [ "x$1" = 'x--gdb' ]; then
+ echo "http://localhost:$HTTPD_PORT/svn-test-work/repositories"
+ $STOPSCRIPT && gdb -silent -ex r -args $START -X
+ exit
+fi
+
+
if type time > /dev/null; then
TIME_CMD=time
else
Modified: subversion/branches/cache-server/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/diff_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/diff_tests.py Tue Oct 15 08:52:06 2013
@@ -32,7 +32,7 @@ logger = logging.getLogger()
# Our testing module
import svntest
-from svntest import err
+from svntest import err, wc
from prop_tests import binary_mime_type_on_text_file_warning
@@ -1899,7 +1899,7 @@ def diff_keywords(sbox):
def diff_force(sbox):
- "show diffs for binary files with --force"
+ "show diffs for binary files"
sbox.build()
wc_dir = sbox.wc_dir
@@ -1943,34 +1943,20 @@ def diff_force(sbox):
svntest.actions.run_and_verify_commit(wc_dir, expected_output,
expected_status, None, wc_dir)
- # Check that we get diff when the first, the second and both files are
- # marked as binary.
+ # Check that we get diff when the first, the second and both files
+ # are marked as binary. First we'll use --force. Then we'll use
+ # the configuration option 'diff-ignore-content-type'.
re_nodisplay = re.compile('^Cannot display:')
- exit_code, stdout, stderr = svntest.main.run_svn(None,
- 'diff', '-r1:2', iota_path,
- '--force')
-
- for line in stdout:
- if (re_nodisplay.match(line)):
- raise svntest.Failure
-
- exit_code, stdout, stderr = svntest.main.run_svn(None,
- 'diff', '-r2:1', iota_path,
- '--force')
-
- for line in stdout:
- if (re_nodisplay.match(line)):
- raise svntest.Failure
-
- exit_code, stdout, stderr = svntest.main.run_svn(None,
- 'diff', '-r2:3', iota_path,
- '--force')
-
- for line in stdout:
- if (re_nodisplay.match(line)):
- raise svntest.Failure
+ for opt in ['--force',
+ '--config-option=config:miscellany:diff-ignore-content-type=yes']:
+ for range in ['-r1:2', '-r2:1', '-r2:3']:
+ exit_code, stdout, stderr = svntest.main.run_svn(None, 'diff', range,
+ iota_path, opt)
+ for line in stdout:
+ if (re_nodisplay.match(line)):
+ raise svntest.Failure
#----------------------------------------------------------------------
# Regression test for issue #2333: Renaming a directory should produce
@@ -4520,6 +4506,134 @@ def diff_dir_replaced_by_dir(sbox):
svntest.actions.run_and_verify_svn(None, expected_output, [],
'diff', '--summarize', wc_dir)
+
+@Issue(4366)
+def diff_repos_empty_file_addition(sbox):
+ "repos diff of rev which adds empty file"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Add and commit an empty file.
+ svntest.main.file_append(sbox.ospath('newfile'), "")
+ svntest.main.run_svn(None, 'add', sbox.ospath('newfile'))
+ expected_output = svntest.wc.State(sbox.wc_dir, {
+ 'newfile': Item(verb='Adding'),
+ })
+ expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+ expected_status.add({
+ 'newfile' : Item(status=' ', wc_rev=2),
+ })
+ svntest.actions.run_and_verify_commit(sbox.wc_dir, expected_output,
+ expected_status, None, sbox.wc_dir)
+
+ # Now diff the revision that added the empty file.
+ expected_output = [
+ 'Index: newfile\n',
+ '===================================================================\n',
+ ]
+ svntest.actions.run_and_verify_svn(None, expected_output, [],
+ 'diff', '-c', '2', sbox.repo_url)
+
+def diff_missing_tree_conflict_victim(sbox):
+ "diff with missing tree-conflict victim in wc"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Produce an 'incoming edit vs. local missing' tree conflict:
+ # r2: edit iota and commit the change
+ svntest.main.file_append(sbox.ospath('iota'), "This is a change to iota.\n")
+ sbox.simple_propset('k', 'v', 'A/C')
+ sbox.simple_commit()
+ # now remove iota
+ sbox.simple_rm('iota', 'A/C')
+ sbox.simple_commit()
+ # update to avoid mixed-rev wc warning
+ sbox.simple_update()
+ # merge r2 into wc and verify that a tree conflict is flagged on iota
+ expected_output = wc.State(wc_dir, {
+ 'iota' : Item(status=' ', treeconflict='C'),
+ 'A/C' : Item(status=' ', treeconflict='C')
+ })
+ expected_mergeinfo_output = wc.State(wc_dir, {})
+ expected_elision_output = wc.State(wc_dir, {})
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.remove('iota','A/C')
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
+ expected_status.tweak('iota', 'A/C',
+ status='! ', treeconflict='C', wc_rev=None)
+ expected_skip = wc.State('', { })
+ svntest.actions.run_and_verify_merge(wc_dir, '1', '2',
+ sbox.repo_url, None,
+ expected_output,
+ expected_mergeinfo_output,
+ expected_elision_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, None, None, None, None, None,
+ False, '--ignore-ancestry', wc_dir)
+
+ # 'svn diff' should show no change for the working copy
+ # This currently fails because svn errors out with a 'node not found' error
+ expected_output = [ ]
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff', wc_dir)
+
+@Issue(4396)
+def diff_local_missing_obstruction(sbox):
+ "diff local missing and obstructed files"
+
+ sbox.build(read_only=True)
+ wc_dir = sbox.wc_dir
+
+ os.unlink(sbox.ospath('iota'))
+ os.unlink(sbox.ospath('A/mu'))
+ os.mkdir(sbox.ospath('A/mu'))
+
+ # Expect no output for missing and obstructed files
+ expected_output = [
+ ]
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff', wc_dir)
+
+ sbox.simple_propset('K', 'V', 'iota', 'A/mu')
+ sbox.simple_append('IotA', 'Content')
+
+ # But do expect a proper property diff
+ expected_output = [
+ 'Index: %s\n' % (sbox.path('A/mu'),),
+ '===================================================================\n',
+ '--- %s\t(revision 1)\n' % (sbox.path('A/mu'),),
+ '+++ %s\t(working copy)\n' % (sbox.path('A/mu'),),
+ '\n',
+ 'Property changes on: %s\n' % (sbox.path('A/mu'),),
+ '___________________________________________________________________\n',
+ 'Added: K\n',
+ '## -0,0 +1 ##\n',
+ '+V\n',
+ '\ No newline at end of property\n',
+ 'Index: %s\n' % (sbox.path('iota'),),
+ '===================================================================\n',
+ '--- %s\t(revision 1)\n' % (sbox.path('iota'),),
+ '+++ %s\t(working copy)\n' % (sbox.path('iota'),),
+ '\n',
+ 'Property changes on: %s\n' % (sbox.path('iota'),),
+ '___________________________________________________________________\n',
+ 'Added: K\n',
+ '## -0,0 +1 ##\n',
+ '+V\n',
+ '\ No newline at end of property\n',
+ ]
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff', wc_dir)
+
+ # Create an external. This produces an error in 1.8.0.
+ sbox.simple_propset('svn:externals', 'AA/BB ' + sbox.repo_url + '/A', '.')
+ sbox.simple_update()
+
+ svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
+ 'diff', wc_dir)
+
+
########################################################################
#Run the tests
@@ -4598,6 +4712,9 @@ test_list = [ None,
local_tree_replace,
diff_dir_replaced_by_file,
diff_dir_replaced_by_dir,
+ diff_repos_empty_file_addition,
+ diff_missing_tree_conflict_victim,
+ diff_local_missing_obstruction,
]
if __name__ == '__main__':
Modified: subversion/branches/cache-server/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/externals_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/externals_tests.py Tue Oct 15 08:52:06 2013
@@ -3226,6 +3226,126 @@ def update_dir_external_shallow(sbox):
'--set-depth=infinity',
sbox.ospath('A/B/E'))
+@Issue(4411)
+@XFail()
+def switch_parent_relative_file_external(sbox):
+ "switch parent-relative file external"
+
+ sbox.build()
+
+ # Create a parent-relative file external in r2
+ sbox.simple_propset('svn:externals', '../D/gamma gamma-ext', 'A/B')
+ sbox.simple_commit()
+ sbox.simple_update()
+
+ # Create a branch that contains the file external
+ sbox.simple_copy('A', 'A_copy')
+ sbox.simple_commit()
+ sbox.simple_update()
+
+ # Check out A/B_copy to a new working copy
+ branch_wc = sbox.add_wc_path("branch")
+ branch_url = sbox.repo_url + '/A_copy'
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'checkout', branch_url,
+ branch_wc)
+
+ # Rename the branch
+ sbox.simple_move('A_copy', 'A_copy2')
+ sbox.simple_commit()
+
+ # Switch the branch working copy to the new branch URL
+ new_branch_url = sbox.repo_url + '/A_copy2'
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'switch', new_branch_url,
+ branch_wc)
+
+ # Bug: The branch working copy can no longer be updated.
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'update', branch_wc)
+
+@Issue(4420)
+def file_external_unversioned_obstruction(sbox):
+ """file externals unversioned obstruction"""
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ expected_output = verify.RegexOutput('r2 committed .*')
+ svntest.actions.run_and_verify_svnmucc(None, expected_output, [],
+ '-U', sbox.repo_url, '-m', 'r2: set external',
+ 'propset', 'svn:externals', '^/A/mu mu-ext', 'A')
+
+ sbox.simple_append('A/mu-ext', 'unversioned obstruction')
+
+ # Update reports a tree-conflict but status doesn't show any such
+ # conflict. I'm no sure whether this is correct.
+ expected_output = svntest.wc.State(wc_dir, {
+ 'A' : Item(status=' U'),
+ 'A/mu-ext' : Item(status=' ', treeconflict='A'),
+ })
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.add({
+ 'A/mu-ext' : Item('unversioned obstruction'),
+ })
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+ expected_status.add({
+ 'A/mu-ext' : Item(status='M ', wc_rev='2', switched='X'),
+ })
+ svntest.actions.run_and_verify_update(wc_dir,
+ expected_output, expected_disk,
+ expected_status)
+
+@Issue(4001)
+@XFail()
+def file_external_versioned_obstruction(sbox):
+ """file externals versioned obstruction"""
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ expected_output = verify.RegexOutput('r2 committed .*')
+ svntest.actions.run_and_verify_svnmucc(None, expected_output, [],
+ '-U', sbox.repo_url, '-m', 'r2: set external',
+ 'propset', 'svn:externals', '^/A/mu mu-ext', 'A')
+
+ expected_output = svntest.wc.State(wc_dir, {
+ 'A' : Item(status=' U'),
+ 'A/mu-ext' : Item(status='A '),
+ })
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.add({
+ 'A/mu-ext' : Item('This is the file \'mu\'.\n'),
+ })
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+ expected_status.add({
+ 'A/mu-ext' : Item(status=' ', wc_rev='2', switched='X'),
+ })
+ svntest.actions.run_and_verify_update(wc_dir,
+ expected_output, expected_disk,
+ expected_status)
+
+ # Update skips adding the versioned node because of the file
+ # external obstruction then when the external is deleted the
+ # versioned node is missing from disk and wc.db. Not really sure
+ # what should happen, perhaps a not-present node?
+ expected_output = verify.RegexOutput('r3 committed .*')
+ svntest.actions.run_and_verify_svnmucc(None, expected_output, [],
+ '-U', sbox.repo_url, '-m', 'r3: copy file',
+ 'cp', 'head', 'A/mu', 'A/mu-ext',
+ 'propdel', 'svn:externals', 'A')
+
+ expected_output = svntest.wc.State(wc_dir, {
+ 'A' : Item(status=' U'),
+ 'A/mu-ext' : Item(verb='Removed external', prev_verb='Skipped'),
+ })
+ expected_disk.tweak('A/mu-ext', content='This is the file \'mu\'.\n')
+ expected_status.tweak(wc_rev=3)
+ expected_status.tweak('A/mu-ext', switched=None)
+ svntest.actions.run_and_verify_update(wc_dir,
+ expected_output, expected_disk,
+ expected_status)
+
########################################################################
# Run the tests
@@ -3279,6 +3399,9 @@ test_list = [ None,
move_with_file_externals,
pinned_externals,
update_dir_external_shallow,
+ switch_parent_relative_file_external,
+ file_external_unversioned_obstruction,
+ file_external_versioned_obstruction,
]
if __name__ == '__main__':
Modified: subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests.py Tue Oct 15 08:52:06 2013
@@ -72,6 +72,7 @@ del_lines_res = [
re.compile(r"\* ra_(neon|local|svn|serf) :"),
re.compile(r" - handles '(https?|file|svn)' scheme"),
re.compile(r" - with Cyrus SASL authentication"),
+ re.compile(r" - using serf \d+\.\d+\.\d+"),
re.compile(r"\* fs_(base|fs) :"),
]
@@ -89,13 +90,6 @@ rep_lines_res = [
# In 'svn --version --quiet', we print only the version
# number in a single line.
(re.compile(r'^\d+\.\d+\.\d+(-[a-zA-Z0-9]+)?$'), 'X.Y.Z\n'),
- # 'svn --help' has a line with the version number.
- # It can vary, for example:
- # "Subversion command-line client, version 1.1.0."
- # "Subversion command-line client, version 1.1.0-dev."
- (re.compile(r'Subversion command-line client, '
- 'version \d+\.\d+\.\d+(.|-[a-zA-Z0-9]+\.)$'),
- 'Subversion command-line client, version X.Y.Z.'),
]
# This is a trigger pattern that selects the secondary set of
Modified: subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout Tue Oct 15 08:52:06 2013
@@ -1,5 +1,5 @@
usage: svn <subcommand> [options] [args]
-Subversion command-line client, version X.Y.Z.
+Subversion command-line client.
Type 'svn help <subcommand>' for help on a specific subcommand.
Type 'svn --version' to see the program version and RA modules
or 'svn --version --quiet' to see just the version number.
@@ -45,6 +45,7 @@ Available subcommands:
unlock
update (up)
upgrade
+ youngest
Subversion is a tool for version control.
For additional information, see http://subversion.apache.org/
Modified: subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout Tue Oct 15 08:52:06 2013
@@ -95,6 +95,8 @@ Valid options:
--with-all-revprops : retrieve all revision properties
--with-no-revprops : retrieve no revision properties
--with-revprop ARG : retrieve revision property ARG
+ --auto-moves : attempt to interpret matching unique DEL+ADD
+ pairs as moves
--depth ARG : limit operation by depth ARG ('empty', 'files',
'immediates', or 'infinity')
--diff : produce diff output
Modified: subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout Tue Oct 15 08:52:06 2013
@@ -1,5 +1,5 @@
usage: svn <subcommand> [options] [args]
-Subversion command-line client, version X.Y.Z.
+Subversion command-line client.
Type 'svn help <subcommand>' for help on a specific subcommand.
Type 'svn --version' to see the program version and RA modules
or 'svn --version --quiet' to see just the version number.
@@ -45,6 +45,7 @@ Available subcommands:
unlock
update (up)
upgrade
+ youngest
Subversion is a tool for version control.
For additional information, see http://subversion.apache.org/
Modified: subversion/branches/cache-server/subversion/tests/cmdline/history_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/history_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/history_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/history_tests.py Tue Oct 15 08:52:06 2013
@@ -189,20 +189,17 @@ def cat_avoids_false_identities(sbox):
svntest.main.run_svn(None, 'del', iota_path)
svntest.main.file_append(iota_path, "YOU SHOULD NOT SEE THIS\n")
svntest.main.run_svn(None, 'add', iota_path)
- svntest.main.run_svn(None, 'ci', '-m', 'log msg',
- wc_dir)
+ sbox.simple_commit(message='log msg')
svntest.main.run_svn(None, 'up', wc_dir)
# r3
svntest.main.run_svn(None, 'del', iota_path)
- svntest.main.run_svn(None, 'ci', '-m', 'log msg',
- wc_dir)
+ sbox.simple_commit(message='log msg')
svntest.main.run_svn(None, 'up', wc_dir)
# r4
svntest.main.run_svn(None, 'cp', iota_url + '@1', wc_dir)
- svntest.main.run_svn(None, 'ci', '-m', 'log msg',
- wc_dir)
+ sbox.simple_commit(message='log msg')
svntest.main.run_svn(None, 'up', wc_dir)
# 'svn cat -r2 iota' should error, because the line of history
Modified: subversion/branches/cache-server/subversion/tests/cmdline/info_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/info_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/info_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/info_tests.py Tue Oct 15 08:52:06 2013
@@ -526,6 +526,11 @@ def binary_tree_conflict(sbox):
}]
svntest.actions.run_and_verify_info(expected_info, iota)
+ expected_info = [{
+ 'Path' : '%s' % re.escape(wc_dir),
+ }]
+ svntest.actions.run_and_verify_info(expected_info, wc_dir)
+
def relpath_escaping(sbox):
"relpath escaping should be usable as-is"
Modified: subversion/branches/cache-server/subversion/tests/cmdline/lock_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/tests/cmdline/lock_tests.py?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/tests/cmdline/lock_tests.py (original)
+++ subversion/branches/cache-server/subversion/tests/cmdline/lock_tests.py Tue Oct 15 08:52:06 2013
@@ -1500,7 +1500,7 @@ def verify_path_escaping(sbox):
svntest.main.run_svn(None, 'add', file1, file2, file3)
- svntest.main.run_svn(None, 'ci', '-m', 'commit', wc_dir)
+ sbox.simple_commit(message='commit')
svntest.main.run_svn(None, 'lock', '-m', 'lock 1', file1)
svntest.main.run_svn(None, 'lock', '-m', 'lock 2', sbox.repo_url + '/file%20%232')
@@ -1815,6 +1815,111 @@ def lock_unlock_deleted(sbox):
expected_status.tweak('A/mu', writelocked=None)
svntest.actions.run_and_verify_status(wc_dir, expected_status)
+@Issue(4369)
+def commit_stolen_lock(sbox):
+ "commit with a stolen lock"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ sbox.simple_append('A/mu', 'zig-zag')
+ sbox.simple_lock('A/mu')
+
+ expected_output = '\'mu\' locked by user \'jrandom\'.'
+ svntest.actions.run_and_verify_svn(None, expected_output, [],
+ 'lock', '--force',
+ sbox.repo_url + '/A/mu')
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('A/mu', status='M ', writelocked='T')
+ err_re = "(.*E160037: Cannot verify lock on path '/A/mu')|" + \
+ "(.*E160038: '/.*/A/mu': no lock token available)"
+ svntest.actions.run_and_verify_commit(wc_dir,
+ [],
+ expected_status,
+ err_re,
+ wc_dir)
+
+# When removing directories, the locks of contained files were not
+# correctly removed from the working copy database, thus they later
+# magically reappeared when new files or directories with the same
+# pathes were added.
+@Issue(4364)
+def drop_locks_on_parent_deletion(sbox):
+ "drop locks when the parent is deleted"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # lock some files, and remove them.
+ sbox.simple_lock('A/B/lambda')
+ sbox.simple_lock('A/B/E/alpha')
+ sbox.simple_lock('A/B/E/beta')
+ sbox.simple_rm('A/B')
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.remove_subtree('A/B')
+
+ svntest.actions.run_and_verify_commit(wc_dir,
+ [],
+ expected_status,
+ None,
+ wc_dir)
+
+ # now re-add entities to the deleted pathes.
+ sbox.simple_mkdir('A/B')
+ sbox.simple_add_text('new file replacing old file', 'A/B/lambda')
+ sbox.simple_add_text('file replacing former dir', 'A/B/F')
+ # The bug also resurrected locks on directories when their path
+ # matched a former file.
+ sbox.simple_mkdir('A/B/E', 'A/B/E/alpha')
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('A/B',
+ 'A/B/E',
+ 'A/B/E/alpha',
+ 'A/B/F',
+ 'A/B/lambda',
+ wc_rev='3')
+ expected_status.remove('A/B/E/beta')
+
+ svntest.actions.run_and_verify_commit(wc_dir,
+ [],
+ expected_status,
+ None,
+ wc_dir)
+
+
+def copy_with_lock(sbox):
+ """copy with lock on source"""
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ lock_url = sbox.repo_url + '/A/B/E/alpha'
+
+ svntest.actions.run_and_validate_lock(lock_url, svntest.main.wc_author)
+ sbox.simple_copy('A/B/E', 'A/B/E2')
+
+ expected_output = svntest.wc.State(wc_dir, {
+ 'A/B/E2' : Item(verb='Adding'),
+ })
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('A/B/E/alpha', writelocked='O')
+ expected_status.add({
+ 'A/B/E2' : Item(status=' ', wc_rev=2),
+ 'A/B/E2/alpha' : Item(status=' ', wc_rev=2),
+ 'A/B/E2/beta' : Item(status=' ', wc_rev=2),
+ })
+
+ # This is really a regression test for httpd: 2.2.25 and 2.4.6 have
+ # a bug that causes mod_dav to check for locks on the copy source
+ # and so the commit fails.
+ svntest.actions.run_and_verify_commit(wc_dir,
+ expected_output,
+ expected_status,
+ None,
+ wc_dir)
+
########################################################################
# Run the tests
@@ -1866,6 +1971,9 @@ test_list = [ None,
lock_multi_wc,
locks_stick_over_switch,
lock_unlock_deleted,
+ commit_stolen_lock,
+ drop_locks_on_parent_deletion,
+ copy_with_lock,
]
if __name__ == '__main__':