Modified: subversion/branches/swig-py3/subversion/tests/cmdline/svnadmin_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/svnadmin_tests.py?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/svnadmin_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/svnadmin_tests.py Sun Dec 24 05:23:08 2017 @@ -129,6 +129,15 @@ def check_hotcopy_fsfs_fsx(src, dst): if src_file == 'rep-cache.db': db1 = svntest.sqlite3.connect(src_path) db2 = svntest.sqlite3.connect(dst_path) + schema1 = db1.execute("pragma user_version").fetchone()[0] + schema2 = db2.execute("pragma user_version").fetchone()[0] + if schema1 != schema2: + raise svntest.Failure("rep-cache schema differs: '%s' vs. '%s'" + % (schema1, schema2)) + # Can't test newer rep-cache schemas with an old built-in SQLite. + if schema1 >= 2 and svntest.sqlite3.sqlite_version_info < (3, 8, 2): + continue + rows1 = [] rows2 = [] for row in db1.execute("select * from rep_cache order by hash"): @@ -746,7 +755,7 @@ def verify_windows_paths_in_repos(sbox): "* Verified revision 0.\n", "* Verified revision 1.\n", "* Verified revision 2.\n"], output) - elif svntest.main.fs_has_rep_sharing(): + elif svntest.main.fs_has_rep_sharing() and not svntest.main.is_fs_type_bdb(): svntest.verify.compare_and_display_lines( "Error while running 'svnadmin verify'.", 'STDOUT', ["* Verifying repository metadata ...\n", @@ -790,6 +799,10 @@ def fsfs_file(repo_dir, kind, rev): def verify_incremental_fsfs(sbox): """svnadmin verify detects corruption dump can't""" + if svntest.main.options.fsfs_version is not None and \ + svntest.main.options.fsfs_version not in [4, 6]: + raise svntest.Skip("Unsupported prepackaged repository version") + # setup a repo with a directory 'c:hi' # use physical addressing as this is hard to provoke with logical addressing sbox.build(create_wc = False, @@ -807,7 +820,7 @@ def verify_incremental_fsfs(sbox): # the listing itself is valid. r2 = fsfs_file(sbox.repo_dir, 'revs', '2') if r2.endswith('pack'): - raise svntest.Skip('Test doesn\'t handle packed revisions') + raise svntest.Skip("Test doesn't handle packed revisions") fp = open(r2, 'wb') fp.write(b"""id: 0-2.0.r2/0 @@ -1654,6 +1667,10 @@ text def verify_non_utf8_paths(sbox): "svnadmin verify with non-UTF-8 paths" + if svntest.main.options.fsfs_version is not None and \ + svntest.main.options.fsfs_version not in [4, 6]: + raise svntest.Skip("Unsupported prepackaged repository version") + dumpfile = clean_dumpfile() # Corruption only possible in physically addressed revisions created @@ -1676,15 +1693,12 @@ def verify_non_utf8_paths(sbox): if line == b"A\n": # replace 'A' with a latin1 character -- the new path is not valid UTF-8 fp_new.write(b"\xE6\n") - elif line == b"text: 1 279 32 32 d63ecce65d8c428b86f4f8b0920921fe\n": + elif line == b"text: 1 340 32 32 a6be7b4cf075fd39e6a99eb69a31232b\n": # phys, PLAIN directories: fix up the representation checksum - fp_new.write(b"text: 1 279 32 32 b50b1d5ed64075b5f632f3b8c30cd6b2\n") - elif line == b"text: 1 292 44 32 a6be7b4cf075fd39e6a99eb69a31232b\n": + fp_new.write(b"text: 1 340 32 32 f2e93e73272cac0f18fccf16f224eb93\n") + elif line == b"text: 1 340 44 32 a6be7b4cf075fd39e6a99eb69a31232b\n": # phys, deltified directories: fix up the representation checksum - fp_new.write(b"text: 1 292 44 32 f2e93e73272cac0f18fccf16f224eb93\n") - elif line == b"text: 1 6 31 31 90f306aa9bfd72f456072076a2bd94f7\n": - # log addressing: fix up the representation checksum - fp_new.write(b"text: 1 6 31 31 db2d4a0bad5dff0aea9a288dec02f1fb\n") + fp_new.write(b"text: 1 340 44 32 f2e93e73272cac0f18fccf16f224eb93\n") elif line == b"cpath: /A\n": # also fix up the 'created path' field fp_new.write(b"cpath: /\xE6\n") @@ -2520,7 +2534,7 @@ def verify_denormalized_names(sbox): ".*Verified revision 7."] # The BDB backend doesn't do global metadata verification. - if (svntest.main.fs_has_rep_sharing()): + if (svntest.main.fs_has_rep_sharing() and not svntest.main.is_fs_type_bdb()): expected_output_regex_list.insert(0, ".*Verifying repository metadata.*") if svntest.main.options.fsfs_sharding is not None: @@ -3350,7 +3364,8 @@ def dump_no_op_change(sbox): svntest.actions.run_and_verify_svn(expected, [], 'log', '-v', sbox2.repo_url + '/bar') -@XFail() # This test will XPASS on FSFS if rep-caching is disabled. +@XFail(svntest.main.is_fs_type_bdb) +@XFail(svntest.main.is_fs_type_fsx) @Issue(4623) def dump_no_op_prop_change(sbox): "svnadmin dump with no-op property change"
Modified: subversion/branches/swig-py3/subversion/tests/cmdline/svntest/__init__.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/svntest/__init__.py?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/svntest/__init__.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/svntest/__init__.py Sun Dec 24 05:23:08 2017 @@ -35,11 +35,8 @@ if sys.hexversion < 0x2070000: try: import sqlite3 except ImportError: - try: - from pysqlite2 import dbapi2 as sqlite3 - except ImportError: - sys.stderr.write('[SKIPPED] Python sqlite3 module required\n') - sys.exit(0) + sys.stderr.write('[SKIPPED] Python sqlite3 module required\n') + sys.exit(0) # don't export this name del sys Modified: subversion/branches/swig-py3/subversion/tests/cmdline/svntest/main.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/svntest/main.py?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/svntest/main.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/svntest/main.py Sun Dec 24 05:23:08 2017 @@ -56,7 +56,7 @@ import svntest from svntest import Failure from svntest import Skip -SVN_VER_MINOR = 10 +SVN_VER_MINOR = 11 ###################################################################### # @@ -1043,7 +1043,8 @@ def _post_create_repos(path, minor_versi shutil.copy(options.config_file, confpath) if options.memcached_server is not None or \ - options.fsfs_compression is not None and \ + options.fsfs_compression is not None or \ + options.fsfs_dir_deltification is not None and \ os.path.exists(confpath): with open(confpath, 'r') as conffile: newlines = [] @@ -1051,6 +1052,10 @@ def _post_create_repos(path, minor_versi if line.startswith('# compression ') and \ options.fsfs_compression is not None: line = 'compression = %s\n' % options.fsfs_compression + if line.startswith('# enable-dir-deltification ') and \ + options.fsfs_dir_deltification is not None: + line = 'enable-dir-deltification = %s\n' % \ + options.fsfs_dir_deltification newlines += line if options.memcached_server is not None and \ line == '[memcached-servers]\n': @@ -1569,9 +1574,11 @@ def is_fs_log_addressing(): return is_fs_type_fsx() or \ (is_fs_type_fsfs() and options.server_minor_version >= 9) +def fs_has_sha1(): + return fs_has_rep_sharing() + def fs_has_rep_sharing(): - return is_fs_type_fsx() or \ - (is_fs_type_fsfs() and options.server_minor_version >= 6) + return options.server_minor_version >= 6 def fs_has_pack(): return is_fs_type_fsx() or \ @@ -1603,28 +1610,28 @@ def server_has_mergeinfo(): return options.server_minor_version >= 5 def server_has_revprop_commit(): - return options.server_minor_version >= 5 + return options.server_caps.has_revprop_commit def server_authz_has_aliases(): - return options.server_minor_version >= 5 + return options.server_caps.authz_has_aliases def server_gets_client_capabilities(): - return options.server_minor_version >= 5 + return options.server_caps.gets_client_capabilities def server_has_partial_replay(): - return options.server_minor_version >= 5 + return options.server_caps.has_partial_replay def server_enforces_UTF8_fspaths_in_verify(): - return options.server_minor_version >= 6 + return options.server_caps.enforces_UTF8_fspaths_in_verify def server_enforces_date_syntax(): - return options.server_minor_version >= 5 + return options.server_caps.enforces_date_syntax def server_has_atomic_revprop(): - return options.server_minor_version >= 7 + return options.server_caps.has_atomic_revprop def server_has_reverse_get_file_revs(): - return options.server_minor_version >= 8 + return options.server_caps.has_reverse_get_file_revs def is_plaintext_password_storage_disabled(): try: @@ -1739,6 +1746,8 @@ class TestSpawningThread(threading.Threa args.append('--dump-load-cross-check') if options.fsfs_compression: args.append('--fsfs-compression=' + options.fsfs_compression) + if options.fsfs_dir_deltification: + args.append('--fsfs-dir-deltification=' + options.fsfs_dir_deltification) result, stdout_lines, stderr_lines = spawn_process(command, 0, False, None, *args) @@ -2153,6 +2162,8 @@ def _create_parser(usage=None): help='Use memcached server at specified URL (FSFS only)') parser.add_option('--fsfs-compression', action='store', type='str', help='Set compression type (for fsfs)') + parser.add_option('--fsfs-dir-deltification', action='store', type='str', + help='Set directory deltification option (for fsfs)') # most of the defaults are None, but some are other values, set them here parser.set_defaults( @@ -2165,6 +2176,19 @@ def _create_parser(usage=None): return parser +class ServerCaps(): + """A simple struct that contains the actual server capabilities that don't + depend on other settings like FS versions.""" + + def __init__(self, options): + self.has_revprop_commit = options.server_minor_version >= 5 + self.authz_has_aliases = options.server_minor_version >= 5 + self.gets_client_capabilities = options.server_minor_version >= 5 + self.has_partial_replay = options.server_minor_version >= 5 + self.enforces_UTF8_fspaths_in_verify = options.server_minor_version >= 6 + self.enforces_date_syntax = options.server_minor_version >= 5 + self.has_atomic_revprop = options.server_minor_version >= 7 + self.has_reverse_get_file_revs = options.server_minor_version >= 8 def parse_options(arglist=sys.argv[1:], usage=None): """Parse the arguments in arg_list, and set the global options object with @@ -2175,6 +2199,12 @@ def parse_options(arglist=sys.argv[1:], parser = _create_parser(usage) (options, args) = parser.parse_args(arglist) + # Peg the actual server capabilities. + # We tweak the server_minor_version later to accommodate FS restrictions, + # but we don't want them to interfere with expectations towards the "pure" + # server code. + options.server_caps = ServerCaps(options) + # If there are no logging handlers registered yet, then install our # own with our custom formatter. (anything currently installed *is* # our handler as tested above, in _create_parser) @@ -2206,26 +2236,29 @@ def parse_options(arglist=sys.argv[1:], parser.error("test harness only supports server minor versions 3-%d" % SVN_VER_MINOR) - # Make sure the server-minor-version matches the fsfs-version parameter. + pass + + return (parser, args) + +def tweak_options_for_precooked_repos(): + """Make sure the server-minor-version matches the fsfs-version parameter + for pre-cooked repositories.""" + + global options + + # Server versions that introduced the respective FSFS formats: + introducing_version = { 1:1, 2:4, 3:5, 4:6, 6:8, 7:9 } if options.fsfs_version: - if options.fsfs_version == 6: + if options.fsfs_version in introducing_version: + introduced_in = introducing_version[options.fsfs_version] if options.server_minor_version \ - and options.server_minor_version != 8 \ + and options.server_minor_version != introduced_in \ and options.server_minor_version != SVN_VER_MINOR: - parser.error("--fsfs-version=6 requires --server-minor-version=8") - options.server_minor_version = 8 - if options.fsfs_version == 4: - if options.server_minor_version \ - and options.server_minor_version != 7 \ - and options.server_minor_version != SVN_VER_MINOR: - parser.error("--fsfs-version=4 requires --server-minor-version=7") - options.server_minor_version = 7 - pass + parser.error("--fsfs-version=%d requires --server-minor-version=%d" \ + % (options.fsfs_version, introduced_in)) + options.server_minor_version = introduced_in # ### Add more tweaks here if and when we support pre-cooked versions # ### of FSFS repositories. - pass - - return (parser, args) def run_tests(test_list, serial_only = False): @@ -2321,6 +2354,7 @@ def execute_tests(test_list, serial_only if not options: # Override which tests to run from the commandline (parser, args) = parse_options() + tweak_options_for_precooked_repos() test_selection = args else: parser = _create_parser() Modified: subversion/branches/swig-py3/subversion/tests/cmdline/svntest/verify.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/svntest/verify.py?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/svntest/verify.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/svntest/verify.py Sun Dec 24 05:23:08 2017 @@ -467,10 +467,11 @@ def verify_exit_code(message, actual, ex # A simple dump file parser. While sufficient for the current # testsuite it doesn't cope with all valid dump files. class DumpParser: - def __init__(self, lines): + def __init__(self, lines, ignore_sha1=False): self.current = 0 self.lines = lines self.parsed = {} + self.ignore_sha1 = ignore_sha1 def parse_line(self, regex, required=True): m = re.match(regex, self.lines[self.current]) @@ -660,6 +661,9 @@ class DumpParser: if not header in headers: node[key] = None continue + if self.ignore_sha1 and (key in ['copy_sha1', 'text_sha1']): + node[key] = None + continue m = re.match(regex, headers[header]) if not m: raise SVNDumpParseError("expected '%s' at line %d\n%s" @@ -735,8 +739,7 @@ def compare_dump_files(message, label, e of lines as returned by run_and_verify_dump, and check that the same revisions, nodes, properties, etc. are present in both dumps. """ - - parsed_expected = DumpParser(expected).parse() + parsed_expected = DumpParser(expected, not svntest.main.fs_has_sha1()).parse() parsed_actual = DumpParser(actual).parse() if ignore_uuid: Modified: subversion/branches/swig-py3/subversion/tests/cmdline/svntest/wc.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/svntest/wc.py?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/svntest/wc.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/svntest/wc.py Sun Dec 24 05:23:08 2017 @@ -1092,17 +1092,8 @@ def svn_uri_quote(url): def python_sqlite_can_read_wc(): """Check if the Python builtin is capable enough to peek into wc.db""" - - try: - db = svntest.sqlite3.connect('') - - c = db.cursor() - c.execute('select sqlite_version()') - ver = tuple(map(int, c.fetchall()[0][0].split('.'))) - - return ver >= (3, 6, 18) # Currently enough (1.7-1.9) - except: - return False + # Currently enough (1.7-1.9) + return svntest.sqlite3.sqlite_version_info >= (3, 6, 18) def open_wc_db(local_path): """Open the SQLite DB for the WC path LOCAL_PATH. Modified: subversion/branches/swig-py3/subversion/tests/cmdline/update_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/update_tests.py?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/update_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/update_tests.py Sun Dec 24 05:23:08 2017 @@ -6840,6 +6840,21 @@ def update_delete_switched(sbox): svntest.actions.run_and_verify_update(wc_dir, None, None, expected_status, [], False, sbox.ospath('A'), '-r', 0) +@XFail() +def update_add_missing_local_add(sbox): + "update adds missing local addition" + + sbox.build(read_only=True) + + # Note that updating 'A' to r0 doesn't reproduce this issue... + sbox.simple_update('', revision='0') + sbox.simple_mkdir('A') + sbox.simple_add_text('mumumu', 'A/mu') + os.unlink(sbox.ospath('A/mu')) + os.rmdir(sbox.ospath('A')) + + sbox.simple_update() + ####################################################################### # Run the tests @@ -6930,6 +6945,7 @@ test_list = [ None, update_add_conflicted_deep, missing_tmp_update, update_delete_switched, + update_add_missing_local_add, ] if __name__ == '__main__': Modified: subversion/branches/swig-py3/subversion/tests/libsvn_client/conflicts-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_client/conflicts-test.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_client/conflicts-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_client/conflicts-test.c Sun Dec 24 05:23:08 2017 @@ -540,7 +540,7 @@ create_wc_with_dir_add_vs_dir_add_merge_ /* Now move the new directory to the colliding path. */ new_dir_path = svn_relpath_join(trunk_path, new_dir_name, b->pool); SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM)); - sbox_wc_move(b, move_src_path, new_dir_path); + SVN_ERR(sbox_wc_move(b, move_src_path, new_dir_path)); SVN_ERR(sbox_wc_commit(b, "")); } new_dir_path = svn_relpath_join(branch_path, new_dir_name, b->pool); Modified: subversion/branches/swig-py3/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c Sun Dec 24 05:23:08 2017 @@ -1631,8 +1631,8 @@ delta_chain_with_plain(const svn_test_op svn_hash_sets(props, "p", svn_string_create(prop_value->data, pool)); hash_rep = svn_stringbuf_create_empty(pool); - svn_hash_write2(props, svn_stream_from_stringbuf(hash_rep, pool), "END", - pool); + SVN_ERR(svn_hash_write2(props, svn_stream_from_stringbuf(hash_rep, pool), + "END", pool)); SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool)); SVN_ERR(svn_fs_txn_root(&root, txn, pool)); Modified: subversion/branches/swig-py3/subversion/tests/libsvn_ra/ra-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_ra/ra-test.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_ra/ra-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_ra/ra-test.c Sun Dec 24 05:23:08 2017 @@ -427,17 +427,7 @@ lock_cb(void *baton, struct lock_result_t *result = apr_palloc(b->pool, sizeof(struct lock_result_t)); - if (lock) - { - result->lock = apr_palloc(b->pool, sizeof(svn_lock_t)); - *result->lock = *lock; - result->lock->path = apr_pstrdup(b->pool, lock->path); - result->lock->token = apr_pstrdup(b->pool, lock->token); - result->lock->owner = apr_pstrdup(b->pool, lock->owner); - result->lock->comment = apr_pstrdup(b->pool, lock->comment); - } - else - result->lock = NULL; + result->lock = svn_lock_dup(lock, b->pool); result->err = ra_err; svn_hash_sets(b->results, apr_pstrdup(b->pool, path), result); @@ -1682,6 +1672,118 @@ commit_empty_last_change(const svn_test_ return SVN_NO_ERROR; } +static svn_error_t * +commit_locked_file(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + const char *url; + svn_ra_callbacks2_t *cbtable; + svn_ra_session_t *session; + const svn_delta_editor_t *editor; + void *edit_baton; + void *root_baton; + void *file_baton; + struct lock_result_t *lock_result; + apr_hash_t *lock_tokens; + svn_txdelta_window_handler_t handler; + void *handler_baton; + svn_revnum_t fetched_rev; + apr_hash_t *fetched_props; + const svn_string_t *propval; + + SVN_ERR(svn_test__create_repos2(NULL, &url, NULL, + "test-repo-commit-locked-file-test", + opts, pool, pool)); + + SVN_ERR(svn_ra_initialize(pool)); + SVN_ERR(svn_ra_create_callbacks(&cbtable, pool)); + SVN_ERR(svn_test__init_auth_baton(&cbtable->auth_baton, pool)); + + SVN_ERR(svn_ra_open4(&session, NULL, url, NULL, cbtable, + NULL, NULL, pool)); + SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton, + apr_hash_make(pool), + NULL, NULL, NULL, TRUE, pool)); + /* Add a file. */ + SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, + pool, &root_baton)); + SVN_ERR(editor->add_file("file", root_baton, NULL, SVN_INVALID_REVNUM, + pool, &file_baton)); + SVN_ERR(editor->close_file(file_baton, NULL, pool)); + SVN_ERR(editor->close_directory(root_baton, pool)); + SVN_ERR(editor->close_edit(edit_baton, pool)); + + /* Acquire a lock on this file. */ + { + struct lock_baton_t baton = {0}; + svn_revnum_t rev = 1; + apr_hash_t *lock_targets; + + baton.results = apr_hash_make(pool); + baton.pool = pool; + + lock_targets = apr_hash_make(pool); + svn_hash_sets(lock_targets, "file", &rev); + SVN_ERR(svn_ra_lock(session, lock_targets, "comment", FALSE, + lock_cb, &baton, pool)); + + SVN_ERR(expect_lock("file", baton.results, session, pool)); + lock_result = svn_hash_gets(baton.results, "file"); + } + + /* Open a new session using the file parent's URL. */ + SVN_ERR(svn_ra_open4(&session, NULL, url, NULL, cbtable, + NULL, NULL, pool)); + + /* Create a new commit editor supplying our lock token. */ + lock_tokens = apr_hash_make(pool); + svn_hash_sets(lock_tokens, "file", lock_result->lock->token); + SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton, + apr_hash_make(pool), NULL, NULL, + lock_tokens, TRUE, pool)); + /* Edit the locked file. */ + SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, + pool, &root_baton)); + SVN_ERR(editor->open_file("file", root_baton, SVN_INVALID_REVNUM, pool, + &file_baton)); + SVN_ERR(editor->apply_textdelta(file_baton, NULL, pool, &handler, + &handler_baton)); + SVN_ERR(svn_txdelta_send_string(svn_string_create("A", pool), + handler, handler_baton, pool)); + SVN_ERR(editor->close_file(file_baton, NULL, pool)); + SVN_ERR(editor->close_directory(root_baton, pool)); + SVN_ERR(editor->close_edit(edit_baton, pool)); + + /* Check the result. */ + SVN_ERR(svn_ra_get_file(session, "file", SVN_INVALID_REVNUM, NULL, + &fetched_rev, NULL, pool)); + SVN_TEST_INT_ASSERT((int) fetched_rev, 2); + + /* Change property of the locked file. */ + SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton, + apr_hash_make(pool), NULL, NULL, + lock_tokens, TRUE, pool)); + SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, + pool, &root_baton)); + SVN_ERR(editor->open_file("file", root_baton, SVN_INVALID_REVNUM, pool, + &file_baton)); + SVN_ERR(editor->change_file_prop(file_baton, "propname", + svn_string_create("propval", pool), + pool)); + SVN_ERR(editor->close_file(file_baton, NULL, pool)); + SVN_ERR(editor->close_directory(root_baton, pool)); + SVN_ERR(editor->close_edit(edit_baton, pool)); + + /* Check the result. */ + SVN_ERR(svn_ra_get_file(session, "file", SVN_INVALID_REVNUM, NULL, + &fetched_rev, &fetched_props, pool)); + SVN_TEST_INT_ASSERT((int) fetched_rev, 3); + propval = svn_hash_gets(fetched_props, "propname"); + SVN_TEST_ASSERT(propval); + SVN_TEST_STRING_ASSERT(propval->data, "propval"); + + return SVN_NO_ERROR; +} + /* The test table. */ @@ -1716,6 +1818,8 @@ static struct svn_test_descriptor_t test "verify checkout over a tunnel"), SVN_TEST_OPTS_PASS(commit_empty_last_change, "check how last change applies to empty commit"), + SVN_TEST_OPTS_PASS(commit_locked_file, + "check commit editor for a locked file"), SVN_TEST_NULL }; Modified: subversion/branches/swig-py3/subversion/tests/libsvn_repos/authz-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_repos/authz-test.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_repos/authz-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_repos/authz-test.c Sun Dec 24 05:23:08 2017 @@ -277,9 +277,9 @@ test_authz_parse(const svn_test_opts_t * printf("[users]\n"); if (authz->has_anon_rights) - print_user_rights(NULL, NULL, 0, &authz->anon_rights, pool); + SVN_ERR(print_user_rights(NULL, NULL, 0, &authz->anon_rights, pool)); if (authz->has_authn_rights) - print_user_rights(NULL, NULL, 0, &authz->authn_rights, pool); + SVN_ERR(print_user_rights(NULL, NULL, 0, &authz->authn_rights, pool)); SVN_ERR(svn_iter_apr_hash(NULL, authz->user_rights, print_user_rights, NULL, pool)); printf("\n\n"); Modified: subversion/branches/swig-py3/subversion/tests/libsvn_repos/dump-load-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_repos/dump-load-test.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_repos/dump-load-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_repos/dump-load-test.c Sun Dec 24 05:23:08 2017 @@ -81,7 +81,7 @@ test_dump_bad_props(svn_stringbuf_t **du notify_func, notify_baton, NULL, NULL, NULL, NULL, pool)); - svn_stream_close(stream); + SVN_ERR(svn_stream_close(stream)); /* Check that the property appears in the dump data */ expected_str = apr_psprintf(pool, "K %d\n%s\n" @@ -131,7 +131,7 @@ test_load_bad_props(svn_stringbuf_t *dum notify_func, notify_baton, NULL, NULL, /*cancellation*/ pool)); - svn_stream_close(stream); + SVN_ERR(svn_stream_close(stream)); /* Check the loaded property */ fs = svn_repos_fs(repos); Modified: subversion/branches/swig-py3/subversion/tests/libsvn_subr/mergeinfo-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_subr/mergeinfo-test.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_subr/mergeinfo-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_subr/mergeinfo-test.c Sun Dec 24 05:23:08 2017 @@ -1762,7 +1762,7 @@ test_rangelist_merge_overlap(apr_pool_t svn_string_t * tmp_string; svn_rangelist_t *range_list; - svn_rangelist_to_string(&tmp_string, rangelist, pool); + SVN_ERR(svn_rangelist_to_string(&tmp_string, rangelist, pool)); SVN_ERR(svn_rangelist__parse(&range_list, tmp_string->data, pool)); } Modified: subversion/branches/swig-py3/subversion/tests/libsvn_subr/priority-queue-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_subr/priority-queue-test.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_subr/priority-queue-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_subr/priority-queue-test.c Sun Dec 24 05:23:08 2017 @@ -125,7 +125,7 @@ verify_queue_order(svn_priority_queue__t } /* the queue should now be empty */ - verify_empty_queue(queue); + SVN_ERR(verify_empty_queue(queue)); return SVN_NO_ERROR; } @@ -154,7 +154,7 @@ test_empty_queue(apr_pool_t *pool) svn_priority_queue__t *queue = svn_priority_queue__create(elements, compare_func); - verify_empty_queue(queue); + SVN_ERR(verify_empty_queue(queue)); return SVN_NO_ERROR; } @@ -214,7 +214,7 @@ test_update(apr_pool_t *pool) } /* the queue should now be empty */ - verify_empty_queue(queue); + SVN_ERR(verify_empty_queue(queue)); return SVN_NO_ERROR; } Modified: subversion/branches/swig-py3/subversion/tests/libsvn_subr/subst_translate-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_subr/subst_translate-test.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_subr/subst_translate-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_subr/subst_translate-test.c Sun Dec 24 05:23:08 2017 @@ -158,7 +158,7 @@ test_svn_subst_translate_string2_null_en }; const char **other_locale; - strncpy(orig_lc_all, setlocale(LC_ALL, NULL), sizeof (orig_lc_all)); + strncpy(orig_lc_all, setlocale(LC_ALL, NULL), sizeof (orig_lc_all) - 1); for (other_locale = other_locales; *other_locale != NULL; ++other_locale) { Modified: subversion/branches/swig-py3/tools/client-side/bash_completion URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/client-side/bash_completion?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/tools/client-side/bash_completion (original) +++ subversion/branches/swig-py3/tools/client-side/bash_completion Sun Dec 24 05:23:08 2017 @@ -128,7 +128,7 @@ function _svn_complete_target() { COMPREPLY=( $(compgen -d -S '/' -X '*/.*' -- $cur ) ) return elif [[ ( $1 == "all" && $cur == ^/* ) || ( "$colon" == ":" && $cur == //*/* ) ]] - then # we already hava a protocoll and host: autocomplete for svn ls ^/bla | svn ls remote_url | svn checkout remote_url + then # we already have a protocol and host: autocomplete for svn ls ^/bla | svn ls remote_url | svn checkout remote_url local p if [ "$colon" == ":" ] ; then p="$prefix$colon" @@ -248,6 +248,7 @@ _svn() cmds="$cmds patch propdel pdel propedit pedit propget pget proplist" cmds="$cmds plist propset pset relocate resolve resolved revert status" cmds="$cmds switch unlock update upgrade" + cmds="$cmds shelve shelves unshelve" # help options have a strange command status... local helpOpts='--help -h' @@ -445,7 +446,7 @@ _svn() # then we have an argument if [[ $cmd = 'merge' && ! $URL ]] ; then - # fist argument is the source URL for the merge + # first argument is the source URL for the merge URL=$opt fi @@ -881,8 +882,8 @@ _svn() --force" ;; cleanup) - cmdOpts="--diff3-cmd $pOpts --include-externals -q --quiet\ - --remove-ignored --remove-unversioned" + cmdOpts="$pOpts --include-externals -q --quiet\ + --remove-ignored --remove-unversioned --vacuum-pristines" ;; commit|ci) cmdOpts="$mOpts $qOpts $nOpts --targets --editor-cmd $pOpts \ @@ -951,7 +952,7 @@ _svn() cmdOpts="$mOpts $qOpts --editor-cmd $pOpts --parents" ;; move|mv|rename|ren) - cmdOpts="$mOpts $rOpts $qOpts --force --editor-cmd $pOpts \ + cmdOpts="$mOpts $qOpts --force --editor-cmd $pOpts \ --parents --allow-mixed-revisions" ;; patch) @@ -1004,7 +1005,7 @@ _svn() $rOpts $cOpts" ;; switch|sw) - cmdOpts="--relocate $rOpts $nOpts $qOpts $pOpts --diff3-cmd \ + cmdOpts="$rOpts $nOpts $qOpts $pOpts --diff3-cmd \ --force --accept --ignore-externals --set-depth \ --ignore-ancestry" ;; @@ -1020,6 +1021,15 @@ _svn() upgrade) cmdOpts="$qOpts $pOpts" ;; + shelve) + cmdOpts="$qOpts --keep-local --delete --list -m --message -F --file --encoding --force-log --editor-cmd --dry-run --depth --targets $cOpts $pOpts" + ;; + unshelve) + cmdOpts="$qOpts --keep-shelved --list --dry-run $pOpts" + ;; + shelves) + cmdOpts="$pOpts" + ;; *) ;; esac @@ -1130,17 +1140,19 @@ _svnadmin () case ${COMP_WORDS[1]} in create) cmdOpts="--bdb-txn-nosync --bdb-log-keep --config-dir \ - --fs-type --pre-1.4-compatible --pre-1.5-compatible \ - --pre-1.6-compatible --compatible-version" + --fs-type --compatible-version" ;; deltify) - cmdOpts="-r --revision -q --quiet" + cmdOpts="-r --revision -q --quiet -M --memory-cache-size" ;; dump) cmdOpts="-r --revision --incremental -q --quiet --deltas \ -M --memory-cache-size -F --file \ --exclude --include --pattern" ;; + dump-revprops) + cmdOpts="-r --revision -q --quiet -F --file" + ;; freeze) cmdOpts="-F --file" ;; @@ -1148,23 +1160,35 @@ _svnadmin () cmdOpts="$cmds" ;; hotcopy) - cmdOpts="--clean-logs" + cmdOpts="--clean-logs --incremental -q --quiet" ;; load) cmdOpts="--ignore-uuid --force-uuid --parent-dir -q --quiet \ --use-pre-commit-hook --use-post-commit-hook \ --bypass-prop-validation -M --memory-cache-size \ - --no-flush-to-disk --normalize-props -F --file" + --no-flush-to-disk --normalize-props -F --file \ + --ignore-dates -r --revision" + ;; + load-revprops) + cmdOpts="-r --revision -q --quiet -F --file \ + --bypass-prop-validation --normalize-props \ + --force-uuid --no-flush-to-disk" ;; lstxns) cmdOpts="-r --revision" ;; lock|unlock) - cmdOpts="--bypass-hooks" + cmdOpts="--bypass-hooks -q --quiet" + ;; + pack) + cmdOpts="-M --memory-cache-size -q --quiet" ;; recover) cmdOpts="--wait" ;; + rmlocks) + cmdOpts="-q --quiet" + ;; rmtxns) cmdOpts="-q --quiet" ;; @@ -1177,7 +1201,9 @@ _svnadmin () --use-post-revprop-change-hook" ;; verify) - cmdOpts="-r --revision -q --quiet" + cmdOpts="-r --revision -t --transaction -q --quiet \ + --check-normalization --keep-going \ + -M --memory-cache-size --metadata-only" ;; *) ;; Modified: subversion/branches/swig-py3/tools/client-side/bash_completion_test URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/client-side/bash_completion_test?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/tools/client-side/bash_completion_test (original) +++ subversion/branches/swig-py3/tools/client-side/bash_completion_test Sun Dec 24 05:23:08 2017 @@ -20,9 +20,16 @@ # script produces appropriate lists of completions for various incomplete svn # command lines. -if [ ! -f "$1" ] || [ "$2" ]; then - echo "Usage: bash_completion_test BASH_COMPLETION_PATHNAME" +THIS_DIR=`dirname "$0"` +SCRIPT="$1" +if [ -z "$SCRIPT" ]; then + SCRIPT="$THIS_DIR/bash_completion" +fi + +if [ ! -r "$SCRIPT" ] || [ "$2" ]; then + echo "Usage: bash_completion_test [BASH_COMPLETION_PATHNAME]" echo "Tests the specified \"bash_completion\" script," + echo "defaulting to the one in the same directory as this test," echo "including checking it against the \"svn\" program found in the current PATH." exit 1 fi @@ -32,20 +39,26 @@ shopt -s extglob export LC_ALL=C # Execute the script which is to be tested. -. "$1" +. "$SCRIPT" -# From the given incomplete svn command, print a space-separated list of +# From the given incomplete command, print a space-separated list of # possible completions of the last argument (or of an empty first argument # if no subcommand is given). -# Usage: get_svn_completions [SVN-SUBCOMMAND [SVN-OPTION...]] -get_svn_completions() { - COMP_WORDS=(svn "$@") - if [ $# == 0 ]; then +# +# Usage: get_completions SVN-CMD [SVN-SUBCOMMAND [SVN-OPTION...]] +# where SVN-CMD is "svn", "svnadmin", etc.; such that when a leading +# underscore is added, it must name one of the completion functions in +# "bash_completion". +get_completions() { + SVN_CMD="$1" + COMP_WORDS=("$@") + if [ $# == 1 ]; then COMP_CWORD=1 else - COMP_CWORD=$# + COMP_CWORD=$(($#-1)) fi - _svn + # Call the appropriate completion function (e.g. "_svn") with no arguments. + "_$SVN_CMD" echo -n "${COMPREPLY[*]}" } @@ -62,30 +75,38 @@ fail() { } # Check that EXPECTED-WORD is among the completions of the last word in -# SVN-COMMAND. SVN-COMMAND is a single argument to this function, split -# into multiple arguments when passed to "get_svn_completions()". -# Usage: includes SVN-COMMAND EXPECTED-WORD +# SVN-ARGS. SVN-ARGS is a single argument to this function, split +# into multiple arguments when passed to "get_completions()". +# Usage: includes SVN-CMD SVN-ARGS EXPECTED-WORD includes() { - COMPLETIONS=`get_svn_completions $1` - if [[ "$2" != @(${COMPLETIONS// /|}) ]]; then - fail "completions of \"svn $1\" should include \"$2\"" \ + SVN_CMD="$1" + SVN_ARGS="$2" + EXPECTED_WORD="$3" + COMPLETIONS=`get_completions "$SVN_CMD" $SVN_ARGS` + if [[ "$EXPECTED_WORD" != @(${COMPLETIONS// /|}) ]]; then + fail "completions of \"$SVN_CMD $SVN_ARGS\" should include \"$EXPECTED_WORD\"" \ "(completions: $COMPLETIONS)" fi } excludes() { - COMPLETIONS=`get_svn_completions $1` - if [[ "$2" == @(${COMPLETIONS// /|}) ]]; then - fail "completions of \"svn $1\" should exclude \"$2\"" \ + SVN_CMD="$1" + SVN_ARGS="$2" + EXPECTED_WORD="$3" + COMPLETIONS=`get_completions "$SVN_CMD" $SVN_ARGS` + if [[ "$EXPECTED_WORD" == @(${COMPLETIONS// /|}) ]]; then + fail "completions of \"$SVN_CMD $SVN_ARGS\" should exclude \"$EXPECTED_WORD\"" \ "(completions: $COMPLETIONS)" fi } -# Print the valid subcommands for "svn", one per line, sorted. +# Print the valid subcommands for an "svn"-like program, one per line, sorted. # Exclude any synonym that is just a truncation of its full name. -# Usage: get_svn_subcommands +# Usage: get_svn_subcommands SVN-CMD +# where SVN-CMD is "svn" or another program that outputs similar help. get_svn_subcommands() { - svn help | + SVN_CMD="$1" + "$SVN_CMD" help | # Find the relevant lines. sed -n -e '1,/^Available subcommands:$/d;/^$/q;p' | # Remove brackets and commas @@ -111,18 +132,21 @@ get_svn_subcommands() { } # Print the valid option switches for "svn SUBCMD", one per line, sorted. -# Usage: get_svn_options SUBCMD +# Usage: get_svn_options SVN-CMD SUBCMD +# where SVN-CMD is "svn" or another program that outputs similar help. get_svn_options() { - { svn help "$1" | + SVN_CMD="$1" + SUBCMD="$2" + { "$SVN_CMD" help "$SUBCMD" | # Remove deprecated options grep -v deprecated | # Find the relevant lines; remove "arg" and description. - sed -n -e '1,/^Valid options:$/d;/^ -/!d' \ + sed -n -e '1,/^\(Valid\|Global\) options:$/d;/^ -/!d' \ -e 's/\( ARG\)* * : .*//;p' | # Remove brackets; put each word on its own line. tr -d '] ' | tr '[' '\n' # The following options are always accepted but not listed in the help - if [ "$1" != "help" ] ; then + if [ "$SUBCMD" != "help" ] ; then echo "-h" echo "--help" fi @@ -136,36 +160,38 @@ set +e # Do not exit on error TESTS_FAILED= echo "Checking general completion" -includes "he" "help" -includes "" "help" -includes "" "--version" - -echo "Checking list of subcommands" -HELP_SUBCMDS=`get_svn_subcommands | tr "\n" " "` -COMPLETION_SUBCMDS=`get_svn_completions | tr " " "\n" | grep -v "^-" | sort | tr "\n" " "` -if [ "$HELP_SUBCMDS" != "$COMPLETION_SUBCMDS" ]; then - fail "non-option completions for \"svn \" != subcommands accepted" \ - " (non-o. cmpl.: $COMPLETION_SUBCMDS)" \ - " (svn accepts: $HELP_SUBCMDS)" -fi - -echo "Checking list of options for each subcommand" -for SUBCMD in $HELP_SUBCMDS; do - HELP_OPTIONS=`get_svn_options $SUBCMD | tr "\n" " "` - COMPLETION_OPTIONS=`get_svn_completions $SUBCMD - | tr " " "\n" | sort | tr "\n" " "` - if [ "$HELP_OPTIONS" != "$COMPLETION_OPTIONS" ]; then - fail "completions for \"svn $SUBCMD -\" != options accepted" \ - " (completions: $COMPLETION_OPTIONS)" \ - " (svn accepts: $HELP_OPTIONS)" +includes svn "he" "help" +includes svn "" "help" +includes svn "" "--version" + +for SVN_CMD in svn svnadmin svndumpfilter svnlook svnrdump svnsync; do + echo "Checking list of subcommands: $SVN_CMD" + HELP_SUBCMDS=`get_svn_subcommands "$SVN_CMD" | tr "\n" " "` + COMPLETION_SUBCMDS=`get_completions "$SVN_CMD" | tr " " "\n" | grep -v "^-" | sort | tr "\n" " "` + if [ "$HELP_SUBCMDS" != "$COMPLETION_SUBCMDS" ]; then + fail "non-option completions for \"$SVN_CMD\" != subcommands accepted" \ + " (non-o. cmpl.: $COMPLETION_SUBCMDS)" \ + " (help says: $HELP_SUBCMDS)" fi + + echo "Checking list of options for each subcommand" + for SUBCMD in $HELP_SUBCMDS; do + HELP_OPTIONS=`get_svn_options $SVN_CMD $SUBCMD | tr "\n" " "` + COMPLETION_OPTIONS=`get_completions $SVN_CMD $SUBCMD - | tr " " "\n" | sort | tr "\n" " "` + if [ "$HELP_OPTIONS" != "$COMPLETION_OPTIONS" ]; then + fail "completions for \"$SVN_CMD $SUBCMD -\" != options accepted" \ + " (completions: $COMPLETION_OPTIONS)" \ + " (help says: $HELP_OPTIONS)" + fi + done done echo "Checking rejection of synonyms" -excludes "diff -x -u -" "-x" -excludes "diff -x -u --e" "--extensions" -excludes "diff --extensions -u -" "--extensions" -excludes "diff --extensions -u -" "-x" -excludes "diff --extensions=-u -" "-x" +excludes svn "diff -x -u -" "-x" +excludes svn "diff -x -u --e" "--extensions" +excludes svn "diff --extensions -u -" "--extensions" +excludes svn "diff --extensions -u -" "-x" +excludes svn "diff --extensions=-u -" "-x" if [ $TESTS_FAILED ]; then echo "FAILURE: at least one bash_completion test failed." Modified: subversion/branches/swig-py3/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c (original) +++ subversion/branches/swig-py3/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c Sun Dec 24 05:23:08 2017 @@ -68,6 +68,7 @@ use the short option letter as identifier. */ typedef enum svn_min__longopt_t { opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID, + opt_auth_password_from_stdin, opt_auth_username, opt_config_dir, opt_config_options, @@ -113,6 +114,9 @@ const apr_getopt_option_t svn_min__optio N_("specify a password ARG (caution: on many operating\n" " " "systems, other users will be able to see this)")}, + {"password-from-stdin", + opt_auth_password_from_stdin, 0, + N_("read password from stdin")}, {"targets", opt_targets, 1, N_("pass contents of file ARG as additional args")}, {"depth", opt_depth, 1, @@ -209,11 +213,11 @@ const apr_getopt_option_t svn_min__optio command to take these arguments allows scripts to just pass them willy-nilly to every invocation of 'svn') . */ const int svn_min__global_options[] = -{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive, - opt_force_interactive, opt_trust_server_cert, - opt_trust_server_cert_unknown_ca, opt_trust_server_cert_cn_mismatch, - opt_trust_server_cert_expired, opt_trust_server_cert_not_yet_valid, - opt_trust_server_cert_other_failure, +{ opt_auth_username, opt_auth_password, opt_auth_password_from_stdin, + opt_no_auth_cache, opt_non_interactive, opt_force_interactive, + opt_trust_server_cert, opt_trust_server_cert_unknown_ca, + opt_trust_server_cert_cn_mismatch, opt_trust_server_cert_expired, + opt_trust_server_cert_not_yet_valid, opt_trust_server_cert_other_failure, opt_config_dir, opt_config_options, 0 }; @@ -417,6 +421,7 @@ sub_main(int *exit_code, int argc, const svn_boolean_t interactive_conflicts = FALSE; svn_boolean_t force_interactive = FALSE; apr_hash_t *cfg_hash; + svn_boolean_t read_pass_from_stdin = FALSE; received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int)); @@ -528,6 +533,9 @@ sub_main(int *exit_code, int argc, const SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password, opt_arg, pool)); break; + case opt_auth_password_from_stdin: + read_pass_from_stdin = TRUE; + break; case opt_no_auth_cache: opt_state.no_auth_cache = TRUE; break; @@ -606,6 +614,14 @@ sub_main(int *exit_code, int argc, const opt_state.non_interactive, force_interactive); + /* --password-from-stdin can only be used with --non-interactive */ + if (read_pass_from_stdin && !opt_state.non_interactive) + { + return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--password-from-stdin requires " + "--non-interactive")); + } + /* ### This really belongs in libsvn_client. The trouble is, there's no one place there to run it from, no svn_client_init(). We'd have to add it to all the public @@ -788,6 +804,12 @@ sub_main(int *exit_code, int argc, const } #endif + /* Get password from stdin if necessary */ + if (read_pass_from_stdin) + { + SVN_ERR(svn_io_stdin_readline(&opt_state.auth_password, pool, pool)); + } + /* Create a client context object. */ command_baton.opt_state = &opt_state; SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool)); Modified: subversion/branches/swig-py3/tools/client-side/svnconflict/svnconflict.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/client-side/svnconflict/svnconflict.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/tools/client-side/svnconflict/svnconflict.c (original) +++ subversion/branches/swig-py3/tools/client-side/svnconflict/svnconflict.c Sun Dec 24 05:23:08 2017 @@ -78,6 +78,7 @@ typedef struct svnconflict_cmd_baton_t use the short option letter as identifier. */ typedef enum svnconflict_longopt_t { opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID, + opt_auth_password_from_stdin, opt_auth_username, opt_config_dir, opt_config_options, @@ -96,6 +97,9 @@ static const apr_getopt_option_t svnconf N_("specify a password ARG (caution: on many operating\n" " " "systems, other users will be able to see this)")}, + {"password-from-stdin", + opt_auth_password_from_stdin, 0, + N_("read password from stdin")}, {"config-dir", opt_config_dir, 1, N_("read user configuration files from directory ARG")}, {"config-option", opt_config_options, 1, @@ -141,7 +145,8 @@ static svn_error_t * svnconflict_resolve /* Options that apply to all commands. */ static const int svnconflict_global_options[] = -{ opt_auth_username, opt_auth_password, opt_config_dir, opt_config_options, 0 }; +{ opt_auth_username, opt_auth_password, opt_auth_password_from_stdin, + opt_config_dir, opt_config_options, 0 }; static const svn_opt_subcommand_desc2_t svnconflict_cmd_table[] = { @@ -363,12 +368,12 @@ svnconflict_list(apr_getopt_t *os, void &conflict, local_abspath, ctx, pool)); if (text_conflicted) - svn_cmdline_printf(pool, "text-conflict\n"); + SVN_ERR(svn_cmdline_printf(pool, "text-conflict\n")); for (i = 0; i < props_conflicted->nelts; i++) { const char *propname = APR_ARRAY_IDX(props_conflicted, i, const char *); - svn_cmdline_printf(pool, "prop-conflict: %s\n", propname); + SVN_ERR(svn_cmdline_printf(pool, "prop-conflict: %s\n", propname)); } if (tree_conflicted) @@ -380,14 +385,14 @@ svnconflict_list(apr_getopt_t *os, void &local_change, conflict, ctx, pool, pool)); - svn_cmdline_printf(pool, "tree-conflict: %s %s\n", - incoming_change, local_change); + SVN_ERR(svn_cmdline_printf(pool, "tree-conflict: %s %s\n", + incoming_change, local_change)); } return SVN_NO_ERROR; } -static void +static svn_error_t * print_conflict_options(apr_array_header_t *options, apr_pool_t *pool) { int i; @@ -401,8 +406,9 @@ print_conflict_options(apr_array_header_ option = APR_ARRAY_IDX(options, i, svn_client_conflict_option_t *); id = svn_client_conflict_option_get_id(option); label = svn_client_conflict_option_get_label(option, pool); - svn_cmdline_printf(pool, "%d: %s\n", id, label); + SVN_ERR(svn_cmdline_printf(pool, "%d: %s\n", id, label)); } + return SVN_NO_ERROR; } /* This implements the `svn_opt_subcommand_t' interface. */ @@ -433,7 +439,7 @@ svnconflict_options_text(apr_getopt_t *o SVN_ERR(svn_client_conflict_text_get_resolution_options(&options, conflict, ctx, pool, pool)); - print_conflict_options(options, pool); + SVN_ERR(print_conflict_options(options, pool)); return SVN_NO_ERROR; } @@ -466,7 +472,7 @@ svnconflict_options_prop(apr_getopt_t *o SVN_ERR(svn_client_conflict_prop_get_resolution_options(&options, conflict, ctx, pool, pool)); - print_conflict_options(options, pool); + SVN_ERR(print_conflict_options(options, pool)); return SVN_NO_ERROR; } @@ -500,7 +506,7 @@ svnconflict_options_tree(apr_getopt_t *o SVN_ERR(svn_client_conflict_tree_get_resolution_options(&options, conflict, ctx, pool, pool)); - print_conflict_options(options, pool); + SVN_ERR(print_conflict_options(options, pool)); return SVN_NO_ERROR; } @@ -639,6 +645,7 @@ sub_main(int *exit_code, int argc, const svn_auth_baton_t *ab; svn_config_t *cfg_config; apr_hash_t *cfg_hash; + svn_boolean_t read_pass_from_stdin = FALSE; received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int)); @@ -704,6 +711,9 @@ sub_main(int *exit_code, int argc, const SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password, opt_arg, pool)); break; + case opt_auth_password_from_stdin: + read_pass_from_stdin = TRUE; + break; case opt_config_dir: SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); opt_state.config_dir = svn_dirent_internal_style(utf8_opt_arg, pool); @@ -845,6 +855,13 @@ sub_main(int *exit_code, int argc, const cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG); + /* Get password from stdin if necessary */ + if (read_pass_from_stdin) + { + SVN_ERR(svn_io_stdin_readline(&opt_state.auth_password, pool, pool)); + } + + /* Create a client context object. */ command_baton.opt_state = &opt_state; SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool)); Modified: subversion/branches/swig-py3/tools/dev/svnmover/svnmover.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dev/svnmover/svnmover.c?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/tools/dev/svnmover/svnmover.c (original) +++ subversion/branches/swig-py3/tools/dev/svnmover/svnmover.c Sun Dec 24 05:23:08 2017 @@ -2436,7 +2436,7 @@ do_put_file(svn_branch__txn_t *txn, else SVN_ERR(svn_stream_for_stdin2(&src, FALSE, scratch_pool)); - svn_stringbuf_from_stream(&text, src, 0, scratch_pool); + SVN_ERR(svn_stringbuf_from_stream(&text, src, 0, scratch_pool)); } payload = svn_element__payload_create_file(props, text, scratch_pool); @@ -4332,7 +4332,8 @@ sub_main(int *exit_code, int argc, const trust_server_cert_opt, trust_server_cert_failures_opt, ui_opt, - colour_opt + colour_opt, + auth_password_from_stdin_opt }; static const apr_getopt_option_t options[] = { {"verbose", 'v', 0, ""}, @@ -4341,6 +4342,7 @@ sub_main(int *exit_code, int argc, const {"file", 'F', 1, ""}, {"username", 'u', 1, ""}, {"password", 'p', 1, ""}, + {"password-from-stdin", auth_password_from_stdin_opt, 1, ""}, {"root-url", 'U', 1, ""}, {"revision", 'r', 1, ""}, {"branch-id", 'B', 1, ""}, @@ -4387,6 +4389,7 @@ sub_main(int *exit_code, int argc, const const char *log_msg; svn_tristate_t coloured_output = svn_tristate_false; svnmover_wc_t *wc; + svn_boolean_t read_pass_from_stdin = FALSE; /* Check library versions */ SVN_ERR(check_lib_versions()); @@ -4431,6 +4434,9 @@ sub_main(int *exit_code, int argc, const case 'p': password = apr_pstrdup(pool, arg); break; + case auth_password_from_stdin_opt: + read_pass_from_stdin = TRUE; + break; case 'U': SVN_ERR(svn_utf_cstring_to_utf8(&anchor_url, arg, pool)); if (! svn_path_is_url(anchor_url)) @@ -4553,6 +4559,13 @@ sub_main(int *exit_code, int argc, const "--non-interactive")); } + /* --password-from-stdin can only be used with --non-interactive */ + if (read_pass_from_stdin && !non_interactive) + { + return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("--password-from-stdin requires " + "--non-interactive")); + } /* Now initialize the client context */ @@ -4580,6 +4593,12 @@ sub_main(int *exit_code, int argc, const "svnmover: ", "--config-option")); } + /* Get password from stdin if necessary */ + if (read_pass_from_stdin) + { + SVN_ERR(svn_io_stdin_readline(&password, pool, pool)); + } + SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool)); cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG); Modified: subversion/branches/swig-py3/tools/dev/unix-build/Makefile.svn URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dev/unix-build/Makefile.svn?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/tools/dev/unix-build/Makefile.svn (original) +++ subversion/branches/swig-py3/tools/dev/unix-build/Makefile.svn Sun Dec 24 05:23:08 2017 @@ -1467,6 +1467,7 @@ SERF_FLAG=--with-serf="$(PREFIX)/serf" # serf >= 1.3.0 is built with scons and no longer sets up rpath linker flags, # so we have to do that ourselves :( SERF_LDFLAG=-Wl,-rpath,$(PREFIX)/serf/lib -Wl,-rpath,$(PREFIX)/bdb/lib +LZ4_LDFLAG=-Wl,-rpath,$(PREFIX)/lz4/lib MOD_DAV_SVN=modules/svn-$(WC)/mod_dav_svn.so MOD_AUTHZ_SVN=modules/svn-$(WC)/mod_authz_svn.so MOD_DONTDOTHAT=modules/svn-$(WC)/mod_dontdothat.so @@ -1501,7 +1502,7 @@ $(SVN_OBJDIR)/.configured: $(SVN_OBJDIR) $(RUBY_OBJDIR)/.installed $(PYTHON_OBJDIR)/.installed cd $(SVN_SRCDIR) && ./autogen.sh cd $(svn_builddir) && \ - env LDFLAGS="-L$(PREFIX)/neon/lib -L$(PREFIX)/apr/lib $(SERF_LDFLAG) -L$(PREFIX)/gettext/lib -L$(PREFIX)/iconv/lib" \ + env LDFLAGS="-L$(PREFIX)/neon/lib -L$(PREFIX)/apr/lib $(SERF_LDFLAG) $(LZ4_LDFLAG) -L$(PREFIX)/gettext/lib -L$(PREFIX)/iconv/lib" \ CFLAGS="-I$(PREFIX)/gettext/include -DAPR_POOL_DEBUG" \ CXXFLAGS="-I$(PREFIX)/gettext/include -DAPR_POOL_DEBUG" \ LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):$$LD_LIBRARY_PATH" \ Modified: subversion/branches/swig-py3/tools/dist/release.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/release.py?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/tools/dist/release.py (original) +++ subversion/branches/swig-py3/tools/dist/release.py Sun Dec 24 05:23:08 2017 @@ -174,7 +174,7 @@ class Version(object): ver_tag = '" (Alpha %d)"' % self.pre_num ver_numtag = '"-alpha%d"' % self.pre_num elif self.pre == 'beta': - ver_tag = '" (Beta %d)"' % args.version.pre_num + ver_tag = '" (Beta %d)"' % self.pre_num ver_numtag = '"-beta%d"' % self.pre_num elif self.pre == 'rc': ver_tag = '" (Release Candidate %d)"' % self.pre_num @@ -1174,6 +1174,173 @@ def get_keys(args): fd.seek(0) subprocess.check_call(['gpg', '--import'], stdin=fd) +def add_to_changes_dict(changes_dict, audience, section, change, revision): + # Normalize arguments + if audience: + audience = audience.upper() + if section: + section = section.lower() + change = change.strip() + + if not audience in changes_dict: + changes_dict[audience] = dict() + if not section in changes_dict[audience]: + changes_dict[audience][section] = dict() + + changes = changes_dict[audience][section] + if change in changes: + changes[change].add(revision) + else: + changes[change] = set([revision]) + +def print_section(changes_dict, audience, section, title, mandatory=False): + if audience in changes_dict: + audience_changes = changes_dict[audience] + if mandatory or (section in audience_changes): + if title: + print(' - %s:' % title) + if section in audience_changes: + print_changes(audience_changes[section]) + elif mandatory: + print(' (none)') + +def print_changes(changes): + # Print in alphabetical order, so entries with the same prefix are together + for change in sorted(changes): + revs = changes[change] + rev_string = 'r' + str(min(revs)) + (' et al' if len(revs) > 1 else '') + print(' * %s (%s)' % (change, rev_string)) + +def write_changelog(args): + 'Write changelog, parsed from commit messages' + # Changelog lines are lines with the following format: + # '['[audience[:section]]']' <message> + # or: + # <message> '['[audience[:section]]']' + # where audience = U (User-visible) or D (Developer-visible) + # section = general|major|minor|client|server|clientserver|other|api|bindings + # (section is optional and is treated case-insensitively) + # message = the actual text for CHANGES + # + # This means the "changes label" can be used as prefix or suffix, and it + # can also be left empty (which results in an uncategorized changes entry), + # if the committer isn't sure where the changelog entry belongs. + # + # Putting [skip], [ignore], [c:skip] or [c:ignore] somewhere in the + # log message means this commit must be ignored for Changelog processing + # (ignored even with the --include-unlabeled-summaries option). + # + # If there is no changes label anywhere in the commit message, and the + # --include-unlabeled-summaries option is used, we'll consider the summary + # line of the commit message (= first line except if it starts with a *) + # as an uncategorized changes entry, except if it contains "status", + # "changes", "post-release housekeeping" or "follow-up". + # + # Examples: + # [U:major] Better interactive conflict resolution for tree conflicts + # ra_serf: Adjustments for serf versions with HTTP/2 support [U:minor] + # [U] Fix 'svn diff URL@REV WC' wrongly looks up URL@HEAD (issue #4597) + # Fix bug with canonicalizing Window-specific drive-relative URL [] + # New svn_ra_list() API function [D:api] + # [D:bindings] JavaHL: Allow access to constructors of a couple JavaHL classes + + branch = secure_repos + '/' + args.branch + previous = secure_repos + '/' + args.previous + include_unlabeled = args.include_unlabeled + + mergeinfo = subprocess.check_output(['svn', 'mergeinfo', '--show-revs', + 'eligible', '--log', branch, previous]).splitlines() + + separator_pattern = re.compile('^-{72}$') + revline_pattern = re.compile('^r(\d+) \| [^\|]+ \| [^\|]+ \| \d+ lines?$') + changes_prefix_pattern = re.compile('^\[(U|D)?:?([^\]]+)?\](.+)$') + changes_suffix_pattern = re.compile('^(.+)\[(U|D)?:?([^\]]+)?\]$') + + changes_dict = dict() # audience -> (section -> (change -> set(revision))) + revision = -1 + got_firstline = False + unlabeled_summary = None + changes_ignore = False + audience = None + section = None + message = None + + for line in mergeinfo: + if separator_pattern.match(line): + # New revision section. Reset variables. + # If there's an unlabeled summary from a previous section, and + # include_unlabeled is True, put it into uncategorized_changes. + if include_unlabeled and unlabeled_summary and not changes_ignore: + add_to_changes_dict(changes_dict, None, None, + unlabeled_summary, revision) + revision = -1 + got_firstline = False + unlabeled_summary = None + changes_ignore = False + audience = None + section = None + message = None + continue + + revmatch = revline_pattern.match(line) + if revmatch and (revision == -1): + # A revision line: get the revision number + revision = int(revmatch.group(1)) + logging.debug('Changelog processing revision r%d' % revision) + continue + + if line.strip() == '': + # Skip empty / whitespace lines + continue + + if not got_firstline: + got_firstline = True + if (not re.search('status|changes|post-release housekeeping|follow-up|^\*', + line, re.IGNORECASE) + and not changes_prefix_pattern.match(line) + and not changes_suffix_pattern.match(line)): + unlabeled_summary = line + + if re.search('\[(c:)?(skip|ignore)\]', line, re.IGNORECASE): + changes_ignore = True + + prefix_match = changes_prefix_pattern.match(line) + if prefix_match: + audience = prefix_match.group(1) + section = prefix_match.group(2) + message = prefix_match.group(3) + add_to_changes_dict(changes_dict, audience, section, message, revision) + + suffix_match = changes_suffix_pattern.match(line) + if suffix_match: + message = suffix_match.group(1) + audience = suffix_match.group(2) + section = suffix_match.group(3) + add_to_changes_dict(changes_dict, audience, section, message, revision) + + # Output the sorted changelog entries + # 1) Uncategorized changes + print_section(changes_dict, None, None, None) + print + # 2) User-visible changes + print(' User-visible changes:') + print_section(changes_dict, 'U', None, None) + print_section(changes_dict, 'U', 'general', 'General') + print_section(changes_dict, 'U', 'major', 'Major new features') + print_section(changes_dict, 'U', 'minor', 'Minor new features and improvements') + print_section(changes_dict, 'U', 'client', 'Client-side bugfixes', mandatory=True) + print_section(changes_dict, 'U', 'server', 'Server-side bugfixes', mandatory=True) + print_section(changes_dict, 'U', 'clientserver', 'Client-side and server-side bugfixes') + print_section(changes_dict, 'U', 'other', 'Other tool improvements and bugfixes') + print_section(changes_dict, 'U', 'bindings', 'Bindings bugfixes', mandatory=True) + print + # 3) Developer-visible changes + print(' Developer-visible changes:') + print_section(changes_dict, 'D', None, None) + print_section(changes_dict, 'D', 'general', 'General', mandatory=True) + print_section(changes_dict, 'D', 'api', 'API changes', mandatory=True) + print_section(changes_dict, 'D', 'bindings', 'Bindings') + #---------------------------------------------------------------------- # Main entry point for argument parsing and handling @@ -1338,6 +1505,29 @@ def main(): separate subcommand.''') subparser.set_defaults(func=cleanup) + # write-changelog + subparser = subparsers.add_parser('write-changelog', + help='''Output to stdout changelog entries parsed from + commit messages, optionally labeled with a category + like [U:client], [D:api], [U], ...''') + subparser.set_defaults(func=write_changelog) + subparser.add_argument('branch', + help='''The branch (or tag or trunk), relative to + ^/subversion/, of which to generate the + changelog, when compared to "previous".''') + subparser.add_argument('previous', + help='''The "previous" branch or tag, relative to + ^/subversion/, to compare "branch" against.''') + subparser.add_argument('--include-unlabeled-summaries', + dest='include_unlabeled', + action='store_true', default=False, + help='''Include summary lines that do not have a changes + label, unless an explicit [c:skip] or [c:ignore] + is part of the commit message (except if the + summary line contains 'STATUS', 'CHANGES', + 'Post-release housekeeping', 'Follow-up' or starts + with '*').''') + # Parse the arguments args = parser.parse_args() Modified: subversion/branches/swig-py3/win-tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/win-tests.py?rev=1819203&r1=1819202&r2=1819203&view=diff ============================================================================== --- subversion/branches/swig-py3/win-tests.py (original) +++ subversion/branches/swig-py3/win-tests.py Sun Dec 24 05:23:08 2017 @@ -192,6 +192,7 @@ memcached_dir = None skip_c_tests = None dump_load_cross_check = None fsfs_compression = None +fsfs_dir_deltification = None for opt, val in opts: if opt in ('-h', '--help'): @@ -288,6 +289,8 @@ for opt, val in opts: run_memcached = 1 elif opt == '--fsfs-compression': fsfs_compression = val + elif opt == '--fsfs-dir-deltification': + fsfs_dir_deltification = val # Calculate the source and test directory names abs_srcdir = os.path.abspath("") @@ -1114,6 +1117,7 @@ if not test_javahl and not test_swig: opts.skip_c_tests = skip_c_tests opts.dump_load_cross_check = dump_load_cross_check opts.fsfs_compression = fsfs_compression + opts.fsfs_dir_deltification = fsfs_dir_deltification th = run_tests.TestHarness(abs_srcdir, abs_builddir, log_file, fail_log_file, opts) old_cwd = os.getcwd()
