Author: rinrab
Date: Wed May 28 19:32:09 2025
New Revision: 1925915
URL: http://svn.apache.org/viewvc?rev=1925915&view=rev
Log:
On the 'utf8-cmdline-prototype' branch: sync with trunk@r1925914.
Modified:
subversion/branches/utf8-cmdline-prototype/ (props changed)
subversion/branches/utf8-cmdline-prototype/CMakeLists.txt
subversion/branches/utf8-cmdline-prototype/build/run_tests.py
subversion/branches/utf8-cmdline-prototype/subversion/include/svn_opt.h
subversion/branches/utf8-cmdline-prototype/subversion/libsvn_subr/opt.c
subversion/branches/utf8-cmdline-prototype/subversion/svnlook/svnlook.c
subversion/branches/utf8-cmdline-prototype/subversion/svnmucc/svnmucc.c
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/prop_tests.py
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svnmucc_tests.py
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/actions.py
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/main.py
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/verify.py
Propchange: subversion/branches/utf8-cmdline-prototype/
------------------------------------------------------------------------------
Merged /subversion/trunk:r1925721-1925914
Modified: subversion/branches/utf8-cmdline-prototype/CMakeLists.txt
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/CMakeLists.txt?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
--- subversion/branches/utf8-cmdline-prototype/CMakeLists.txt (original)
+++ subversion/branches/utf8-cmdline-prototype/CMakeLists.txt Wed May 28
19:32:09 2025
@@ -83,6 +83,7 @@ cmake_dependent_option(SVN_ENABLE_TOOLS
option(SVN_ENABLE_TESTS "Build Subversion test-suite" OFF)
option(SVN_TEST_EXPAND "Expand tests; This will slow-down configuration, but
you will have an ability to run any subtest" OFF)
option(SVN_TEST_CONFIGURE_FOR_PARALLEL "Configures tests for parallel run
execution" OFF)
+set(SVN_TEST_COMMAND_ARGUMENTS "" CACHE STRING "Additional command line
options to be passed to run_tests.py")
option(SVN_ENABLE_APACHE_MODULES "Build modules for Apache HTTPD" OFF)
option(SVN_ENABLE_SWIG_PERL "Enable Subversion SWIG bindings for Perl" OFF)
@@ -778,12 +779,28 @@ if(SVN_ENABLE_TESTS)
find_package(Python3 COMPONENTS Interpreter REQUIRED)
set(run_tests_script "${CMAKE_CURRENT_SOURCE_DIR}/build/run_tests.py")
set(list_tests_script "${CMAKE_CURRENT_SOURCE_DIR}/build/list_tests.py")
+ set(test_base_dir "${CMAKE_CURRENT_BINARY_DIR}/Testing")
+
+ # Create the virtual environment for Python tests.
+ execute_process(
+ COMMAND
+ "${Python3_EXECUTABLE}" "${run_tests_script}"
+ --create-python-venv "${test_base_dir}"
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ OUTPUT_VARIABLE command_output
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ RESULT_VARIABLE command_result
+ )
+ if (command_result)
+ message(FATAL_ERROR "run_tests.py --create-python-venv failed.")
+ endif()
+ string(STRIP "${command_output}" python3_test_executable)
function(add_py_test name prog)
if(SVN_TEST_CONFIGURE_FOR_PARALLEL)
- set(test_root "${CMAKE_CURRENT_BINARY_DIR}/Testing/${name}")
+ set(test_root "${test_base_dir}/${name}")
else()
- set(test_root "${CMAKE_CURRENT_BINARY_DIR}/Testing")
+ set(test_root "${test_base_dir}")
endif()
file(MAKE_DIRECTORY "${test_root}/subversion/tests/cmdline")
@@ -792,12 +809,13 @@ if(SVN_ENABLE_TESTS)
NAME
"${name}"
COMMAND
- "${Python3_EXECUTABLE}" "${run_tests_script}"
+ "${python3_test_executable}" "${run_tests_script}"
--bin ${binary_dir}
--tools-bin ${binary_dir}
--verbose
--log-to-stdout
--set-log-level=WARNING
+ ${SVN_TEST_COMMAND_ARGUMENTS}
${CMAKE_CURRENT_SOURCE_DIR}
${test_root}
"${prog}"
Modified: subversion/branches/utf8-cmdline-prototype/build/run_tests.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/build/run_tests.py?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
--- subversion/branches/utf8-cmdline-prototype/build/run_tests.py (original)
+++ subversion/branches/utf8-cmdline-prototype/build/run_tests.py Wed May 28
19:32:09 2025
@@ -259,6 +259,8 @@ class TestHarness:
cmdline.append('--tools-bin=%s' % self.opts.tools_bin)
if self.opts.svn_bin is not None:
cmdline.append('--bin=%s' % self.opts.svn_bin)
+ if self.opts.venv_base is not None:
+ cmdline.append('--python-venv=%s' % self.opts.venv_base)
if self.opts.url is not None:
cmdline.append('--url=%s' % self.opts.url)
if self.opts.fs_type is not None:
@@ -326,16 +328,17 @@ class TestHarness:
global svntest
svntest = importlib.import_module('svntest')
- extra_packages = svntest.main.ensure_dependencies()
svntest.main.parse_options(cmdline, optparse.SUPPRESS_USAGE)
svntest.testcase.TextColors.disable()
+ dependency_path = svntest.main.ensure_dependencies()
# We have to update PYTHONPATH, otherwise the whole setting up of a
# virtualenv and installing dependencies will happen for every test case.
- python_path = os.environ.get("PYTHONPATH")
- python_path = (extra_packages if not python_path
- else "%s:%s" % (extra_packages, python_path))
- os.environ["PYTHONPATH"] = python_path
+ if dependency_path:
+ python_path = os.environ.get("PYTHONPATH")
+ python_path = (dependency_path if not python_path
+ else "%s:%s" % (dependency_path, python_path))
+ os.environ["PYTHONPATH"] = python_path
finally:
os.chdir(old_cwd)
@@ -674,6 +677,12 @@ class TestHarness:
for x in failed_list:
sys.stdout.write(x)
+ xml_error_list = [x for x in log_lines if x[:8] == 'E: XML: ']
+ if xml_error_list:
+ print('There were some XML validation errors, checking' + self.logfile)
+ for x in sorted(set(xml_error_list)):
+ sys.stdout.write(x[3:])
+
# Print summaries, from least interesting to most interesting.
if self.opts.list_tests:
print('Summary of test listing:')
@@ -1032,6 +1041,13 @@ def create_parser():
help='Use the svn binaries installed in this path')
parser.add_option('--tools-bin', action='store', dest='tools_bin',
help='Use the svn tools installed in this path')
+ parser.add_option('--create-python-venv', action='store', dest='create_venv',
+ help=('Create the Python virtual environment inside this'
+ ' path and install the dependencies used by the'
+ ' test suite, then exit. Do not run any tests.'))
+ parser.add_option('--python-venv', action='store', dest='venv_base',
+ help=('Use the virtual environment inside this path to'
+ ' find the dependencies used by the test suite.'))
parser.add_option('--fsfs-sharding', action='store', type='int',
help='Default shard size (for fsfs)')
parser.add_option('--fsfs-packing', action='store_true',
@@ -1097,12 +1113,22 @@ def create_parser():
def main():
(opts, args) = create_parser().parse_args(sys.argv[1:])
+ if opts.create_venv:
+ main_create_venv(opts, args)
+ sys.exit(0)
+
+ # Normal mode: don't create a virtual environment, run tests or whatever
+ # else was requested instead. Create the virtual environment on demand.
+ assert not opts.create_venv
if len(args) < 3:
print("{}: at least three positional arguments required; got {!r}".format(
os.path.basename(sys.argv[0]), args
))
sys.exit(2)
+ abs_srcdir = args[0]
+ abs_builddir = args[1]
+ programs = args[2:]
if opts.log_to_stdout:
logfile = None
@@ -1111,11 +1137,30 @@ def main():
logfile = os.path.abspath('tests.log')
faillogfile = os.path.abspath('fails.log')
- th = TestHarness(args[0], args[1], logfile, faillogfile, opts)
- failed = th.run(args[2:])
+ th = TestHarness(abs_srcdir, abs_builddir, logfile, faillogfile, opts)
+ failed = th.run(programs)
if failed:
sys.exit(1)
+def main_create_venv(opts, args):
+ # Environment creation mode: create the requested virtual environment,
+ # install required dependencies and exit.
+ assert opts.create_venv
+
+ if len(args) < 1:
+ print("{}: at least one positional argument required; got {!r}".format(
+ os.path.basename(sys.argv[0]), args
+ ))
+ sys.exit(2)
+ abs_srcdir = args[0]
+
+ sys.path.insert(0, os.path.join(abs_srcdir, "subversion", "tests",
"cmdline"))
+ svntest = importlib.import_module("svntest")
+ svntest.main.venv_base = opts.create_venv
+ venv_dir = svntest.main.venv_path()
+ python_prog, _ = svntest.main.create_python_venv(venv_dir, quiet=True)
+ print(python_prog)
+
# Run main if not imported as a module
if __name__ == '__main__':
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/include/svn_opt.h
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/include/svn_opt.h?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
--- subversion/branches/utf8-cmdline-prototype/subversion/include/svn_opt.h
(original)
+++ subversion/branches/utf8-cmdline-prototype/subversion/include/svn_opt.h Wed
May 28 19:32:09 2025
@@ -482,6 +482,24 @@ typedef struct svn_opt_revision_range_t
svn_opt_revision_t end;
} svn_opt_revision_range_t;
+
+/**
+ * Parse NULL-terminated C string @a str as a revision number and
+ * store its value in @a rev.
+ *
+ * If @a str is not a valid revision number, then the error
+ * #SVN_ERR_REVNUM_PARSE_FAILURE error is returned. Negative numbers
+ * parsed from @a str are considered invalid, and result in the same error.
+ *
+ * Unlike svn_revnum_parse(), this function support our cmdline revision
+ * number format, whereas the revnum may be prefixed with an 'r' symbol.
+ *
+ * @since New in 1.15
+ * @see svn_revnum_parse()
+ */
+svn_error_t *
+svn_opt_parse_revnum(svn_revnum_t *rev, const char *str);
+
/**
* Set @a *start_revision and/or @a *end_revision according to @a arg,
* where @a arg is "N" or "N:M", like so:
@@ -553,9 +571,10 @@ svn_opt_parse_revision_to_range(apr_arra
*
* @since New in 1.15.
*/
-int svn_opt_parse_change_to_range(apr_array_header_t *opt_ranges,
- const char *arg,
- apr_pool_t *result_pool);
+int
+svn_opt_parse_change_to_range(apr_array_header_t *opt_ranges,
+ const char *arg,
+ apr_pool_t *result_pool);
/**
* Resolve peg revisions and operational revisions in the following way:
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/libsvn_subr/opt.c
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/libsvn_subr/opt.c?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
--- subversion/branches/utf8-cmdline-prototype/subversion/libsvn_subr/opt.c
(original)
+++ subversion/branches/utf8-cmdline-prototype/subversion/libsvn_subr/opt.c Wed
May 28 19:32:09 2025
@@ -710,6 +710,16 @@ int svn_opt_parse_change_to_range(apr_ar
}
svn_error_t *
+svn_opt_parse_revnum(svn_revnum_t *rev, const char *str)
+{
+ /* Allow any number of 'r's to prefix a revision number. */
+ while (*str == 'r')
+ str++;
+
+ return svn_error_trace(svn_revnum_parse(rev, str, NULL));
+}
+
+svn_error_t *
svn_opt_resolve_revisions(svn_opt_revision_t *peg_rev,
svn_opt_revision_t *op_rev,
svn_boolean_t is_url,
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/svnlook/svnlook.c
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/svnlook/svnlook.c?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
--- subversion/branches/utf8-cmdline-prototype/subversion/svnlook/svnlook.c
(original)
+++ subversion/branches/utf8-cmdline-prototype/subversion/svnlook/svnlook.c Wed
May 28 19:32:09 2025
@@ -2528,7 +2528,7 @@ sub_main(int *exit_code,
switch (opt_id)
{
case 'r':
- SVN_ERR(svn_revnum_parse(&opt_state.rev, utf8_opt_arg, NULL));
+ SVN_ERR(svn_opt_parse_revnum(&opt_state.rev, utf8_opt_arg));
break;
case 't':
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/svnmucc/svnmucc.c
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/svnmucc/svnmucc.c?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
--- subversion/branches/utf8-cmdline-prototype/subversion/svnmucc/svnmucc.c
(original)
+++ subversion/branches/utf8-cmdline-prototype/subversion/svnmucc/svnmucc.c Wed
May 28 19:32:09 2025
@@ -429,7 +429,7 @@ log_message_func(const char **log_msg,
svn_string_t *message = svn_string_create(lmb->log_message, pool);
SVN_ERR_W(svn_subst_translate_string2(&message, NULL, NULL,
- message, NULL, FALSE,
+ message, "UTF-8", FALSE,
pool, pool),
_("Error normalizing log message to internal format"));
@@ -576,6 +576,7 @@ sub_main(int *exit_code,
const char *filename;
SVN_ERR(svn_utf_cstring_to_utf8(&filename, arg, pool));
SVN_ERR(svn_stringbuf_from_file2(&filedata, filename, pool));
+ SVN_ERR(svn_utf_stringbuf_to_utf8(&filedata, filedata, pool));
}
break;
case 'u':
@@ -595,19 +596,7 @@ sub_main(int *exit_code,
root_url = sanitize_url(root_url, pool);
break;
case 'r':
- {
- const char *saved_arg = arg;
- char *digits_end = NULL;
- while (*arg == 'r')
- arg++;
- base_revision = strtol(arg, &digits_end, 10);
- if ((! SVN_IS_VALID_REVNUM(base_revision))
- || (! digits_end)
- || *digits_end)
- return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Invalid revision number '%s'"),
- saved_arg);
- }
+ SVN_ERR(svn_opt_parse_revnum(&base_revision, arg));
break;
case with_revprop_opt:
SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, arg, pool));
@@ -774,7 +763,7 @@ sub_main(int *exit_code,
lmb.non_interactive = non_interactive;
lmb.ctx = ctx;
- /* Make sure we have a log message to use. */
+ /* Make sure we have a log message to use. */
SVN_ERR(sanitize_log_sources(&lmb.log_message, message, revprops, filedata,
pool, pool));
@@ -822,23 +811,11 @@ sub_main(int *exit_code,
if (action->action == ACTION_CP)
{
const char *rev_str = APR_ARRAY_IDX(action_args, i, const char *);
- if (strcmp(rev_str, "head") == 0)
- action->rev = SVN_INVALID_REVNUM;
- else if (strcmp(rev_str, "HEAD") == 0)
+ if (svn_cstring_casecmp(rev_str, "head") == 0)
action->rev = SVN_INVALID_REVNUM;
else
- {
- char *end;
-
- while (*rev_str == 'r')
- ++rev_str;
+ SVN_ERR(svn_opt_parse_revnum(&action->rev, rev_str));
- action->rev = strtol(rev_str, &end, 0);
- if (*end)
- return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
- "'%s' is not a revision\n",
- rev_str);
- }
if (++i == action_args->nelts)
return insufficient();
}
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/prop_tests.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/prop_tests.py?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
---
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/prop_tests.py
(original)
+++
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/prop_tests.py
Wed May 28 19:32:09 2025
@@ -2640,6 +2640,9 @@ def xml_unsafe_author(sbox):
wc_dir)
@Issue(4415)
+@Issue(4919)
+@XFail(lambda: (svntest.main.is_bad_xml_fatal()
+ and not svntest.main.is_ra_type_dav()))
def xml_unsafe_author2(sbox):
"svn:author with XML unsafe chars 2"
@@ -2666,6 +2669,13 @@ def xml_unsafe_author2(sbox):
expected_author = 'foo\bbar'
# Use svn ls in --xml mode to test locale independent output.
+ # FIXME: Theat literal \b in the author field is invalid XML.
+ # Should be encoded as a character entity and enclosed
+ # in a CDATA section, like this:
+ #
+ # <[CDATA[foo@#08;bar]]>
+ # or
+ # foo<[CDATA[@#08;]]>bar
expected_output = [
'<?xml version="1.0" encoding="UTF-8"?>\n',
'<lists>\n',
@@ -2694,8 +2704,8 @@ def xml_unsafe_author2(sbox):
'</lists>\n'
]
- svntest.actions.run_and_verify_svn(expected_output, [],
- 'ls', '--xml', repo_url)
+ svntest.actions.run_and_verify_svn_xml(expected_output, [],
+ 'list', '--xml', repo_url)
expected_info = [{
'Repository Root' : sbox.repo_url,
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svnmucc_tests.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svnmucc_tests.py?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
---
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svnmucc_tests.py
(original)
+++
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svnmucc_tests.py
Wed May 28 19:32:09 2025
@@ -313,7 +313,7 @@ def basic_svnmucc(sbox):
# Expected missing revision error
xtest_svnmucc(sbox.repo_url,
- ["svnmucc: E200004: 'a' is not a revision"
+ ["svnmucc: E200022: Invalid revision number found parsing 'a'"
], #---------
'-m', 'log msg',
'cp', 'a', 'b')
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/actions.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/actions.py?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
---
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/actions.py
(original)
+++
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/actions.py
Wed May 28 19:32:09 2025
@@ -797,11 +797,11 @@ def run_and_verify_log_xml(expected_log_
# We'll parse the output unless the caller specifies expected_stderr or
# expected_stdout for run_and_verify_svn.
parse = True
- if expected_stderr == None:
+ if expected_stderr is None:
expected_stderr = []
else:
parse = False
- if expected_stdout != None:
+ if expected_stdout is not None:
parse = False
log_args = list(args)
@@ -813,6 +813,7 @@ def run_and_verify_log_xml(expected_log_
'log', '--xml', *log_args)
if not parse:
return
+ verify.validate_xml_schema('log', stdout)
entries = LogParser().parse(stdout)
for index in range(len(entries)):
@@ -1647,9 +1648,9 @@ def run_and_verify_status_xml(expected_e
exit_code, output, errput = run_and_verify_svn(None, [],
'status', '--xml', *args)
-
if len(errput) > 0:
raise Failure
+ verify.validate_xml_schema('status', output)
doc = parseString(''.join(output))
entries = doc.getElementsByTagName('entry')
@@ -1726,6 +1727,7 @@ def run_and_verify_inherited_prop_xml(pa
if len(errput) > 0:
raise Failure
+ ## FIXME: Need XML schema: verify.validate_xml_schema('props', output)
# Props inherited from within the WC are keyed on absolute paths.
expected_iprops = {}
@@ -1798,10 +1800,10 @@ def run_and_verify_diff_summarize_xml(er
'diff', '--summarize',
'--xml', *args)
-
# Return if errors are present since they were expected
if len(errput) > 0:
return
+ verify.validate_xml_schema('diff', output)
doc = parseString(''.join(output))
paths = doc.getElementsByTagName("path")
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/main.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/main.py?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
---
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/main.py
(original)
+++
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/main.py
Wed May 28 19:32:09 2025
@@ -36,6 +36,7 @@ import xml
import urllib
import logging
import hashlib
+import importlib
import zipfile
import codecs
import queue
@@ -222,11 +223,13 @@ work_dir = "svn-test-work"
# Directory for the Python virtual environment where we install
# external dependencies of the test environment
-venv_dir = os.path.join(work_dir, "__venv__")
+venv_base = work_dir
+venv_path = lambda: os.path.join(venv_base, "__venv__")
+venv_create = True
# List of dependencies
+found_dependencies = set()
SVN_TESTS_REQUIRE = ["lxml", "rnc2rng"]
-dependencies_ensured = False
# Constant for the merge info property.
SVN_PROP_MERGEINFO = "svn:mergeinfo"
@@ -1753,6 +1756,13 @@ def is_httpd_authz_provider_enabled():
def is_remote_http_connection_allowed():
return options.allow_remote_http_connection
+# XML schema validation
+def is_bad_xml_fatal():
+ """Are we treating invalid XML output as a fatal error?"""
+ # Only if we have all the necessary dependencies.
+ return {'lxml', 'rnc2rnd'} & found_dependencies
+
+
def wc_format(ver=None):
"""Return the WC format number used by Subversion version VER.
@@ -1856,6 +1866,8 @@ class TestSpawningThread(threading.Threa
args.append('--allow-remote-http-connection')
if options.svn_bin:
args.append('--bin=' + options.svn_bin)
+ if options.venv_base:
+ args.append('--python-venv=' + options.venv_base)
if options.store_pristine:
args.append('--store-pristine=' + options.store_pristine)
if options.valgrind:
@@ -2230,6 +2242,9 @@ def _create_parser(usage=None):
help='Whether to clean up')
parser.add_option('--enable-sasl', action='store_true',
help='Whether to enable SASL authentication')
+ parser.add_option('--python-venv', action='store', dest='venv_base',
+ help=('Use the virtual environment inside this path to'
+ ' find the dependencies used by the test suite.'))
parser.add_option('--bin', action='store', dest='svn_bin',
help='Use the svn binaries installed in this path')
parser.add_option('--use-jsvn', action='store_true',
@@ -2336,6 +2351,8 @@ def parse_options(arglist=sys.argv[1:],
"""Parse the arguments in arg_list, and set the global options object with
the results"""
+ global venv_base
+ global venv_create
global options
parser = _create_parser(usage)
@@ -2385,7 +2402,9 @@ def parse_options(arglist=sys.argv[1:],
svn_wc__max_supported_format_version(),
options.wc_format_version))
- pass
+ if options.venv_base:
+ venv_base = options.venv_base
+ venv_create = False
return (parser, args)
@@ -2417,7 +2436,6 @@ def run_tests(test_list, serial_only = F
appropriate exit code.
"""
- ensure_dependencies()
sys.exit(execute_tests(test_list, serial_only))
def ensure_dependencies():
@@ -2428,18 +2446,42 @@ def ensure_dependencies():
upgrade the venv in that case. In practice, we won't.
"""
- global dependencies_ensured
- if dependencies_ensured:
- return
-
+ venv_dir = os.path.abspath(venv_path())
package_path = os.path.join(venv_dir, "lib",
"python%d.%d" % sys.version_info[:2],
"site-packages")
- package_path = os.path.abspath(package_path)
- if package_path in sys.path:
- dependencies_ensured = True
- return
+ # Check if all our dependencies are installed. It doesn't matter if
+ # they're installed in our venv, as long as they're available.
+ found_dependencies.clear()
+ saved_sys_path = sys.path[:]
+ try:
+ sys.path.insert(0, package_path)
+ for package in SVN_TESTS_REQUIRE:
+ importlib.import_module(package)
+ found_dependencies.add(package)
+ have_required = True
+ except ImportError:
+ have_required = False
+ finally:
+ sys.path[:] = saved_sys_path
+
+ if have_required:
+ if package_path not in sys.path:
+ sys.path.append(package_path)
+ return package_path
+
+ if venv_create:
+ python_prog, python_path = create_python_venv(venv_dir)
+ if python_prog is not None:
+ assert python_path == package_path
+ if package_path not in sys.path:
+ sys.path.append(package_path)
+ found_dependencies.update(set(SVN_TESTS_REQUIRE))
+ return package_path
+ return None
+
+def create_python_venv(venv_dir, quiet=False):
try:
# Create the virtual environment
if not os.path.isdir(venv_dir):
@@ -2447,19 +2489,22 @@ def ensure_dependencies():
safe_rmtree(venv_dir)
venv.create(venv_dir, with_pip=True)
- # Install any (new) dependencies
- pip = os.path.join(venv_dir, venv_bin, "pip"+_exe)
+ # Install the dependencies
+ pip = os.path.join(venv_dir, venv_bin, "pip" + _exe)
pip_options = ("--disable-pip-version-check", "--require-virtualenv")
subprocess.run([pip, *pip_options, "install", *SVN_TESTS_REQUIRE],
- check=True)
+ check=True, stdout=subprocess.PIPE if quiet else None)
+ importlib.invalidate_caches()
- sys.path.append(package_path)
- dependencies_ensured = True
- return package_path
- except Exception as ex:
- print("WARNING: Could not install test dependencies,"
- " some tests will be skipped", file=sys.stderr)
- print(ex, file=sys.stderr)
+ python_prog = os.path.join(venv_dir, venv_bin, "python" + _exe)
+ python_path = os.path.join(venv_dir, "lib",
+ "python%d.%d" % sys.version_info[:2],
+ "site-packages")
+ return python_prog, python_path
+ except Exception:
+ if logger:
+ logger.warning('Could not install test dependencies', exc_info=True)
+ return None, None
def get_issue_details(issue_numbers):
"""For each issue number in ISSUE_NUMBERS query the issue
@@ -2659,6 +2704,10 @@ def execute_tests(test_list, serial_only
wc_incomplete_tester_binary = os.path.join(options.tools_bin,
'wc-incomplete-tester' + _exe)
+ assert options.venv_base is None or venv_base == options.venv_base, \
+ 'venv_base=%s options.venv_base=%s' % (venv_base, options.venv_base)
+ ensure_dependencies()
+
######################################################################
# Cleanup: if a previous run crashed or interrupted the python
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/verify.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/verify.py?rev=1925915&r1=1925914&r2=1925915&view=diff
==============================================================================
---
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/verify.py
(original)
+++
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/verify.py
Wed May 28 19:32:09 2025
@@ -1062,8 +1062,14 @@ def validate_xml_schema(name: str, lines
source = ''.join(lines)
document = etree.parse(BytesIO(source.encode("utf-8")))
if not schema.validate(document):
- raise SVNXMLSchemaValidationError("schema %s" % schema_name)
- except Exception:
- print("ERROR: XML output does not conform to schema", schema_name)
- print(source)
- raise
+ raise SVNXMLSchemaValidationError(schema.error_log)
+ except ImportError:
+ logger.error("XML: Module lxml.etree not found")
+ return
+ except Exception as ex:
+ logger.error("XML: " + str(ex))
+ logger.warning("XML:\n" + "\n".join(repr(line) for line in lines))
+ if svntest.main.is_bad_xml_fatal():
+ raise
+ else:
+ logger.warning("XML:", exc_info=True)