You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2012/12/21 11:58:42 UTC
svn commit: r1424862 [3/3] - in /subversion/branches/tweak-build-take-two:
./ build/ subversion/include/ subversion/libsvn_client/
subversion/libsvn_ra/ subversion/libsvn_repos/ subversion/libsvn_subr/
subversion/libsvn_wc/ subversion/mod_authz_svn/ su...
Modified: subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tests.py?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tests.py Fri Dec 21 10:58:41 2012
@@ -7812,8 +7812,8 @@ def merge_to_sparse_directories(sbox):
# Merge r4:9 into the immediates WC.
# The root of the immediates WC should get inheritable r4:9 as should
# the one file present 'mu'. The three directory children present, 'B',
- # 'C', and 'D' are checked out at depth empty; the two of these affected
- # by the merge, 'B' and 'D', get non-inheritable mergeinfo for r4:9.
+ # 'C', and 'D' are checked out at depth empty; the one of these affected
+ # by the merge, 'D', gets non-inheritable mergeinfo for r4:9.
# The root and 'D' do should also get the changes
# that affect them directly (the prop adds from r8 and r9).
expected_output = wc.State(immediates_dir, {
@@ -7823,14 +7823,14 @@ def merge_to_sparse_directories(sbox):
})
expected_mergeinfo_output = wc.State(immediates_dir, {
'' : Item(status=' U'),
- 'B' : Item(status=' U'),
'D' : Item(status=' U'),
})
expected_elision_output = wc.State(immediates_dir, {
+ 'D' : Item(status=' U'),
})
expected_status = wc.State(immediates_dir, {
'' : Item(status=' M', wc_rev=9),
- 'B' : Item(status=' M', wc_rev=9),
+ 'B' : Item(status=' ', wc_rev=9),
'mu' : Item(status='M ', wc_rev=9),
'C' : Item(status=' ', wc_rev=9),
'D' : Item(status=' M', wc_rev=9),
@@ -7838,15 +7838,12 @@ def merge_to_sparse_directories(sbox):
expected_disk = wc.State('', {
'' : Item(props={SVN_PROP_MERGEINFO : '/A:5-9',
"prop:name" : "propval"}),
- 'B' : Item(props={SVN_PROP_MERGEINFO : '/A/B:5-9*'}),
+ 'B' : Item(),
'mu' : Item("New content"),
'C' : Item(),
- 'D' : Item(props={SVN_PROP_MERGEINFO : '/A/D:5-9*',
- "prop:name" : "propval"}),
+ 'D' : Item(props={"prop:name" : "propval"}),
})
expected_skip = svntest.wc.State(immediates_dir, {
- 'D/H' : Item(),
- 'B/E' : Item(),
})
svntest.actions.run_and_verify_merge(immediates_dir, '4', '9',
sbox.repo_url + '/A', None,
@@ -7900,7 +7897,6 @@ def merge_to_sparse_directories(sbox):
})
expected_skip = svntest.wc.State(files_dir, {
'D' : Item(),
- 'B' : Item(),
})
svntest.actions.run_and_verify_merge(files_dir, '4', '9',
sbox.repo_url + '/A', None,
@@ -7944,7 +7940,6 @@ def merge_to_sparse_directories(sbox):
expected_skip = svntest.wc.State(empty_dir, {
'mu' : Item(),
'D' : Item(),
- 'B' : Item(),
})
svntest.actions.run_and_verify_merge(empty_dir, '4', '9',
sbox.repo_url + '/A', None,
Modified: subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tree_conflict_tests.py (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tree_conflict_tests.py Fri Dec 21 10:58:41 2012
@@ -1332,12 +1332,8 @@ def tree_conflicts_merge_edit_onto_missi
expected_skip = svntest.wc.State('', {
'F/alpha' : Item(),
# BH: After fixing several issues in the obstruction handling
- # I get the following Skip notifications. Please review!
+ # I get the following Skip notification. Please review!
'D/D1' : Item(),
- 'DD/D1' : Item(),
- 'DF/D1' : Item(),
- 'DDD/D1' : Item(),
- 'DDF/D1' : Item(),
})
@@ -1414,13 +1410,6 @@ def tree_conflicts_merge_del_onto_missin
expected_skip = svntest.wc.State('', {
'F/alpha' : Item(),
'D/D1' : Item(),
- # BH: After fixing several issues in the obstruction handling
- # I get the following Skip notifications. Please review!
- 'D/D1' : Item(),
- 'DD/D1' : Item(),
- 'DF/D1' : Item(),
- 'DDD/D1' : Item(),
- 'DDF/D1' : Item(),
})
svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox,
Modified: subversion/branches/tweak-build-take-two/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/libsvn_repos/repos-test.c?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/libsvn_repos/repos-test.c Fri Dec 21 10:58:41 2012
@@ -1147,6 +1147,60 @@ authz_get_handle(svn_authz_t **authz_p,
return SVN_NO_ERROR;
}
+struct check_access_tests {
+ const char *path;
+ const char *repo_name;
+ const char *user;
+ const svn_repos_authz_access_t required;
+ const svn_boolean_t expected;
+};
+
+/* Helper for the authz test. Runs a set of tests against AUTHZ_CFG
+ * as defined in TESTS. */
+static svn_error_t *
+authz_check_access(svn_authz_t *authz_cfg,
+ const struct check_access_tests *tests,
+ apr_pool_t *pool)
+{
+ int i;
+ svn_boolean_t access_granted;
+
+ /* Loop over the test array and test each case. */
+ for (i = 0; !(tests[i].path == NULL
+ && tests[i].required == svn_authz_none); i++)
+ {
+ SVN_ERR(svn_repos_authz_check_access(authz_cfg,
+ tests[i].repo_name,
+ tests[i].path,
+ tests[i].user,
+ tests[i].required,
+ &access_granted, pool));
+
+ if (access_granted != tests[i].expected)
+ {
+ return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "Authz incorrectly %s %s%s access "
+ "to %s%s%s for user %s",
+ access_granted ?
+ "grants" : "denies",
+ tests[i].required
+ & svn_authz_recursive ?
+ "recursive " : "",
+ tests[i].required
+ & svn_authz_read ?
+ "read" : "write",
+ tests[i].repo_name ?
+ tests[i].repo_name : "",
+ tests[i].repo_name ?
+ ":" : "",
+ tests[i].path,
+ tests[i].user ?
+ tests[i].user : "-");
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
/* Test that authz is giving out the right authorizations. */
@@ -1160,34 +1214,28 @@ authz(apr_pool_t *pool)
apr_pool_t *subpool = svn_pool_create(pool);
int i;
/* Definition of the paths to test and expected replies for each. */
- struct
- {
- const char *path;
- const char *user;
- const svn_repos_authz_access_t required;
- const svn_boolean_t expected;
- } test_set[] = {
+ struct check_access_tests test_set[] = {
/* Test that read rules are correctly used. */
- { "/A", NULL, svn_authz_read, TRUE },
- { "/iota", NULL, svn_authz_read, FALSE },
+ { "/A", "greek", NULL, svn_authz_read, TRUE },
+ { "/iota", "greek", NULL, svn_authz_read, FALSE },
/* Test that write rules are correctly used. */
- { "/A", "plato", svn_authz_write, TRUE },
- { "/A", NULL, svn_authz_write, FALSE },
+ { "/A", "greek", "plato", svn_authz_write, TRUE },
+ { "/A", "greek", NULL, svn_authz_write, FALSE },
/* Test that pan-repository rules are found and used. */
- { "/A/B/lambda", "plato", svn_authz_read, TRUE },
- { "/A/B/lambda", NULL, svn_authz_read, FALSE },
+ { "/A/B/lambda", "greek", "plato", svn_authz_read, TRUE },
+ { "/A/B/lambda", "greek", NULL, svn_authz_read, FALSE },
/* Test that authz uses parent path ACLs if no rule for the path
exists. */
- { "/A/C", NULL, svn_authz_read, TRUE },
+ { "/A/C", "greek", NULL, svn_authz_read, TRUE },
/* Test that recursive access requests take into account the rules
of subpaths. */
- { "/A/D", "plato", svn_authz_read | svn_authz_recursive, TRUE },
- { "/A/D", NULL, svn_authz_read | svn_authz_recursive, FALSE },
+ { "/A/D", "greek", "plato", svn_authz_read | svn_authz_recursive, TRUE },
+ { "/A/D", "greek", NULL, svn_authz_read | svn_authz_recursive, FALSE },
/* Test global write access lookups. */
- { NULL, "plato", svn_authz_read, TRUE },
- { NULL, NULL, svn_authz_write, FALSE },
+ { NULL, "greek", "plato", svn_authz_read, TRUE },
+ { NULL, "greek", NULL, svn_authz_write, FALSE },
/* Sentinel */
- { NULL, NULL, svn_authz_none, FALSE }
+ { NULL, NULL, NULL, svn_authz_none, FALSE }
};
/* The test logic:
@@ -1242,34 +1290,7 @@ authz(apr_pool_t *pool)
SVN_ERR(authz_get_handle(&authz_cfg, contents, subpool));
/* Loop over the test array and test each case. */
- for (i = 0; !(test_set[i].path == NULL
- && test_set[i].required == svn_authz_none); i++)
- {
- SVN_ERR(svn_repos_authz_check_access(authz_cfg, "greek",
- test_set[i].path,
- test_set[i].user,
- test_set[i].required,
- &access_granted, subpool));
-
- if (access_granted != test_set[i].expected)
- {
- return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
- "Authz incorrectly %s %s%s access "
- "to greek:%s for user %s",
- access_granted ?
- "grants" : "denies",
- test_set[i].required
- & svn_authz_recursive ?
- "recursive " : "",
- test_set[i].required
- & svn_authz_read ?
- "read" : "write",
- test_set[i].path,
- test_set[i].user ?
- test_set[i].user : "-");
- }
- }
-
+ SVN_ERR(authz_check_access(authz_cfg, test_set, subpool));
/* The authz rules for the phase 2 tests, first case (cyclic
dependency). */
@@ -1341,6 +1362,119 @@ authz(apr_pool_t *pool)
return SVN_NO_ERROR;
}
+
+/* Test in-repo authz paths */
+static svn_error_t *
+in_repo_authz(const svn_test_opts_t *opts,
+ apr_pool_t *pool)
+{
+ svn_repos_t *repos;
+ svn_fs_t *fs;
+ svn_fs_txn_t *txn;
+ svn_fs_root_t *txn_root;
+ svn_revnum_t youngest_rev;
+ svn_authz_t *authz_cfg;
+ const char *authz_contents;
+ const char *repos_root;
+ const char *repos_url;
+ const char *authz_url;
+ svn_error_t *err;
+ struct check_access_tests test_set[] = {
+ /* reads */
+ { "/A", NULL, NULL, svn_authz_read, FALSE },
+ { "/A", NULL, "plato", svn_authz_read, TRUE },
+ { "/A", NULL, "socrates", svn_authz_read, TRUE },
+ /* writes */
+ { "/A", NULL, NULL, svn_authz_write, FALSE },
+ { "/A", NULL, "socrates", svn_authz_write, FALSE },
+ { "/A", NULL, "plato", svn_authz_write, TRUE },
+ /* Sentinel */
+ { NULL, NULL, NULL, svn_authz_none, FALSE }
+ };
+
+ /* Test plan:
+ * Create an authz file and put it in the repository.
+ * Verify it can be read with an relative URL.
+ * Verify it can be read with an absolute URL.
+ * Verify non-existant path does not error out when must_exist is FALSE.
+ * Verify non-existant path does error out when must_exist is TRUE.
+ * Verify that an http:// URL produces an error.
+ * Verify that an svn:// URL produces an error.
+ */
+
+ /* What we'll put in the authz file, it's simple since we're not testing
+ * the parsing, just that we got what we expected. */
+ authz_contents =
+ "" NL
+ "" NL
+ "[/]" NL
+ "plato = rw" NL
+ "socrates = r";
+
+ /* Create a filesystem and repository. */
+ SVN_ERR(svn_test__create_repos(&repos, "test-repo-in-repo-authz",
+ opts, pool));
+ fs = svn_repos_fs(repos);
+
+ /* Commit the authz file to the repo. */
+ SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
+ SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+ SVN_ERR(svn_fs_make_file(txn_root, "authz", pool));
+ SVN_ERR(svn_test__set_file_contents(txn_root, "authz", authz_contents,
+ pool));
+ SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
+ SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
+
+ /* repos relative URL */
+ repos_root = svn_repos_path(repos, pool);
+ SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/authz", TRUE, repos_root,
+ pool));
+ SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+ /* absolute file URL, repos_root is NULL to validate the contract that it
+ * is not needed except when a repos relative URL is passed. */
+ SVN_ERR(svn_uri_get_file_url_from_dirent(&repos_url, repos_root, pool));
+ authz_url = apr_pstrcat(pool, repos_url, "/authz", (char *)NULL);
+ SVN_ERR(svn_repos_authz_read2(&authz_cfg, authz_url, TRUE, NULL, pool));
+ SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+ /* Non-existant path in the repo with must_exist set to FALSE */
+ SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/A/authz", FALSE, repos_root,
+ pool));
+
+ /* Non-existant path in the repo with must_exist set to TRUE */
+ err = svn_repos_authz_read2(&authz_cfg, "^/A/authz", TRUE, repos_root,
+ pool);
+ if (!err || err->apr_err != SVN_ERR_AUTHZ_INVALID_CONFIG)
+ return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+ "Got %s error instead of expected "
+ "SVN_ERR_AUTHZ_INVALID_CONFIG",
+ err ? "unexpected" : "no");
+ svn_error_clear(err);
+
+ /* http:// URL which is unsupported */
+ err = svn_repos_authz_read2(&authz_cfg, "http://example.com/repo/authz",
+ TRUE, repos_root, pool);
+ if (!err || err->apr_err != SVN_ERR_RA_ILLEGAL_URL)
+ return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+ "Got %s error instead of expected "
+ "SVN_ERR_RA_ILLEGAL_URL",
+ err ? "unexpected" : "no");
+ svn_error_clear(err);
+
+ /* svn:// URL which is unsupported */
+ err = svn_repos_authz_read2(&authz_cfg, "svn://example.com/repo/authz",
+ TRUE, repos_root, pool);
+ if (!err || err->apr_err != SVN_ERR_RA_ILLEGAL_URL)
+ return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+ "Got %s error instead of expected "
+ "SVN_ERR_RA_ILLEGAL_URL",
+ err ? "unexpected" : "no");
+ svn_error_clear(err);
+
+
+ return SVN_NO_ERROR;
+}
/* Callback for the commit editor tests that relays requests to
@@ -2585,6 +2719,8 @@ struct svn_test_descriptor_t test_funcs[
"test removal of defunct locks"),
SVN_TEST_PASS2(authz,
"test authz access control"),
+ SVN_TEST_OPTS_PASS(in_repo_authz,
+ "test authz stored in the repo"),
SVN_TEST_OPTS_PASS(commit_editor_authz,
"test authz in the commit editor"),
SVN_TEST_OPTS_PASS(commit_continue_txn,
Modified: subversion/branches/tweak-build-take-two/subversion/tests/libsvn_subr/config-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/libsvn_subr/config-test.c?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/libsvn_subr/config-test.c (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/libsvn_subr/config-test.c Fri Dec 21 10:58:41 2012
@@ -269,6 +269,31 @@ test_has_section_case_sensitive(apr_pool
return SVN_NO_ERROR;
}
+
+static svn_error_t *
+test_stream_interface(apr_pool_t *pool)
+{
+ svn_config_t *cfg;
+ const char *cfg_file;
+ svn_stream_t *stream;
+
+ if (!srcdir)
+ SVN_ERR(init_params(pool));
+
+ cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL);
+ SVN_ERR(svn_stream_open_readonly(&stream, cfg_file, pool, pool));
+
+ SVN_ERR(svn_config_parse(&cfg, stream, TRUE, pool));
+
+ /* nominal test to make sure cfg is populated with something since
+ * svn_config_parse will happily return an empty cfg if the stream is
+ * empty. */
+ if (! svn_config_has_section(cfg, "section1"))
+ return fail(pool, "Failed to find section1");
+
+ return SVN_NO_ERROR;
+}
+
/*
====================================================================
If you add a new test to this file, update this array.
@@ -288,5 +313,7 @@ struct svn_test_descriptor_t test_funcs[
"test svn_config_has_section (case insensitive)"),
SVN_TEST_PASS2(test_has_section_case_sensitive,
"test svn_config_has_section (case sensitive)"),
+ SVN_TEST_PASS2(test_stream_interface,
+ "test svn_config_parse"),
SVN_TEST_NULL
};
Modified: subversion/branches/tweak-build-take-two/subversion/tests/libsvn_subr/path-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/libsvn_subr/path-test.c?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/libsvn_subr/path-test.c (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/libsvn_subr/path-test.c Fri Dec 21 10:58:41 2012
@@ -1624,6 +1624,71 @@ test_path_condense_targets(apr_pool_t *p
return SVN_NO_ERROR;
}
+static svn_error_t *
+test_path_is_repos_relative_url(apr_pool_t *pool)
+{
+ int i;
+ struct {
+ const char* path;
+ svn_boolean_t result;
+ } tests[] = {
+ { "^/A", TRUE },
+ { "http://host/A", FALSE },
+ { "/A/B", FALSE },
+ };
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
+ {
+ svn_boolean_t result = svn_path_is_repos_relative_url(tests[i].path);
+
+ if (tests[i].result != result)
+ return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "svn_path_is_repos_relative_url(\"%s\")"
+ " returned \"%s\" expected \"%s\"",
+ tests[i].path,
+ result ? "TRUE" : "FALSE",
+ tests[i].result ? "TRUE" : "FALSE");
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_path_resolve_repos_relative_url(apr_pool_t *pool)
+{
+ int i;
+ struct {
+ const char *relative_url;
+ const char *repos_root_url;
+ const char *absolute_url;
+ } tests[] = {
+ { "^/A", "file:///Z/X", "file:///Z/X/A" },
+ { "^/A", "file:///Z/X/", "file:///Z/X//A" }, /* doesn't canonicalize */
+ { "^/A@2", "file:///Z/X", "file:///Z/X/A@2" }, /* peg rev */
+ { "^/A", "/Z/X", "/Z/X/A" }, /* doesn't verify repos_root is URL */
+ };
+
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
+ {
+ const char *result;
+
+ SVN_ERR(svn_path_resolve_repos_relative_url(&result,
+ tests[i].relative_url,
+ tests[i].repos_root_url,
+ pool));
+
+ if (strcmp(tests[i].absolute_url,result))
+ return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "svn_path_resolve_repos_relative_url(\"%s\","
+ "\"%s\") returned \"%s\" expected \"%s\"",
+ tests[i].relative_url,
+ tests[i].repos_root_url,
+ result, tests[i].absolute_url);
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* local define to support XFail-ing tests on Windows/Cygwin only */
#ifdef SVN_USE_DOS_PATHS
@@ -1688,5 +1753,9 @@ struct svn_test_descriptor_t test_funcs[
"test svn_path_internal_style"),
SVN_TEST_PASS2(test_path_condense_targets,
"test svn_path_condense_targets"),
+ SVN_TEST_PASS2(test_path_is_repos_relative_url,
+ "test svn_path_is_repos_relative_url"),
+ SVN_TEST_PASS2(test_path_resolve_repos_relative_url,
+ "test svn_path_resolve_repos_relative_url"),
SVN_TEST_NULL
};
Modified: subversion/branches/tweak-build-take-two/subversion/tests/libsvn_wc/conflict-data-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/libsvn_wc/conflict-data-test.c?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/libsvn_wc/conflict-data-test.c (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/libsvn_wc/conflict-data-test.c Fri Dec 21 10:58:41 2012
@@ -202,8 +202,8 @@ test_read_write_tree_conflicts(const svn
SVN_ERR(svn_test__sandbox_create(&sbox, "read_write_tree_conflicts", opts, pool));
parent_abspath = svn_dirent_join(sbox.wc_abspath, "A", pool);
- SVN_ERR(svn_wc__db_op_add_directory(sbox.wc_ctx->db, parent_abspath, NULL,
- pool));
+ SVN_ERR(svn_wc__db_op_add_directory(sbox.wc_ctx->db, parent_abspath,
+ NULL /*props*/, NULL, pool));
child1_abspath = svn_dirent_join(parent_abspath, "foo", pool);
child2_abspath = svn_dirent_join(parent_abspath, "bar", pool);
Modified: subversion/branches/tweak-build-take-two/subversion/tests/libsvn_wc/utils.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/libsvn_wc/utils.c?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/libsvn_wc/utils.c (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/libsvn_wc/utils.c Fri Dec 21 10:58:41 2012
@@ -174,7 +174,8 @@ sbox_wc_add(svn_test__sandbox_t *b, cons
parent_abspath = svn_dirent_dirname(path, b->pool);
SVN_ERR(svn_wc__acquire_write_lock(NULL, b->wc_ctx, parent_abspath, FALSE,
b->pool, b->pool));
- SVN_ERR(svn_wc_add_from_disk(b->wc_ctx, path, NULL, NULL, b->pool));
+ SVN_ERR(svn_wc_add_from_disk2(b->wc_ctx, path, NULL /*props*/,
+ NULL, NULL, b->pool));
SVN_ERR(svn_wc__release_write_lock(b->wc_ctx, parent_abspath, b->pool));
return SVN_NO_ERROR;
}
@@ -294,8 +295,12 @@ sbox_wc_commit(svn_test__sandbox_t *b, c
APR_ARRAY_PUSH(targets, const char *) = sbox_wc_path(b, path);
SVN_ERR(svn_client_create_context2(&ctx, NULL, b->pool));
- return svn_client_commit5(targets, svn_depth_infinity,
- FALSE, FALSE, TRUE, /* keep locks/cl's/use_ops*/
+ return svn_client_commit6(targets, svn_depth_infinity,
+ FALSE /* keep_locks */,
+ FALSE /* keep_changelist */,
+ TRUE /* commit_as_operations */,
+ TRUE /* include_file_externals */,
+ FALSE /* include_dir_externals */,
NULL, NULL, NULL, NULL, ctx, b->pool);
}
Modified: subversion/branches/tweak-build-take-two/tools/dist/release.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/tools/dist/release.py?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/tools/dist/release.py (original)
+++ subversion/branches/tweak-build-take-two/tools/dist/release.py Fri Dec 21 10:58:41 2012
@@ -381,7 +381,7 @@ def compare_changes(repos, branch, revis
# Treat this as a warning since we are now putting entries for future
# minor releases in CHANGES on trunk.
logging.warning('CHANGES has unmerged revisions: %s' %
- stdout.replace("\n", " "))
+ stdout.replace("\n", " "))
def roll_tarballs(args):
'Create the release artifacts.'
@@ -627,7 +627,13 @@ def write_news(args):
def get_sha1info(args, replace=False):
'Return a list of sha1 info for the release'
- sha1s = glob.glob(os.path.join(get_deploydir(args.base_dir), '*.sha1'))
+
+ if args.target:
+ target = args.target
+ else:
+ target = get_deploydir(args.base_dir)
+
+ sha1s = glob.glob(os.path.join(target, '*.sha1'))
class info(object):
pass
@@ -651,10 +657,11 @@ def get_sha1info(args, replace=False):
def write_announcement(args):
'Write the release announcement.'
sha1info = get_sha1info(args)
+ siginfo = "\n".join(get_siginfo(args, True)) + "\n"
data = { 'version' : str(args.version),
'sha1info' : sha1info,
- 'siginfo' : open('getsigs-output', 'r').read(),
+ 'siginfo' : siginfo,
'major-minor' : '%d.%d' % (args.version.major,
args.version.minor),
'major-minor-patch' : args.version.base,
@@ -689,8 +696,8 @@ def write_downloads(args):
key_start = '-----BEGIN PGP SIGNATURE-----'
fp_pattern = re.compile(r'^pub\s+(\w+\/\w+)[^\n]*\n\s+Key\sfingerprint\s=((\s+[0-9A-F]{4}){10})\nuid\s+([^<\(]+)\s')
-def check_sigs(args):
- 'Check the signatures for the release.'
+def get_siginfo(args, quiet=False):
+ 'Returns a list of signatures for the release.'
try:
import gnupg
@@ -704,13 +711,16 @@ def check_sigs(args):
target = get_deploydir(args.base_dir)
good_sigs = {}
+ fingerprints = {}
+ output = []
glob_pattern = os.path.join(target, 'subversion*-%s*.asc' % args.version)
for filename in glob.glob(glob_pattern):
text = open(filename).read()
keys = text.split(key_start)
- logging.info("Checking %d sig(s) in %s" % (len(keys[1:]), filename))
+ if not quiet:
+ logging.info("Checking %d sig(s) in %s" % (len(keys[1:]), filename))
for key in keys[1:]:
fd, fn = tempfile.mkstemp()
os.write(fd, key_start + key)
@@ -740,18 +750,30 @@ def check_sigs(args):
if l[0:7] != 'Warning' ])
fp = fp_pattern.match(gpg_output).groups()
- print(" %s [%s] with fingerprint:" % (fp[3], fp[0]))
- print(" %s" % fp[1])
+ fingerprints["%s [%s] %s" % (fp[3], fp[0], fp[1])] = fp
+ for entry in sorted(fingerprints.keys()):
+ fp = fingerprints[entry]
+ output.append(" %s [%s] with fingerprint:" % (fp[3], fp[0]))
+ output.append(" %s" % fp[1])
+
+ return output
+
+def check_sigs(args):
+ 'Check the signatures for the release.'
+
+ output = get_siginfo(args)
+ for line in output:
+ print(line)
def get_keys(args):
'Import the LDAP-based KEYS file to gpg'
# We use a tempfile because urlopen() objects don't have a .fileno()
with tempfile.SpooledTemporaryFile() as fd:
- fd.write(urllib2.urlopen(KEYS).read())
- fd.flush()
+ fd.write(urllib2.urlopen(KEYS).read())
+ fd.flush()
fd.seek(0)
- subprocess.check_call(['gpg', '--import'], stdin=fd)
+ subprocess.check_call(['gpg', '--import'], stdin=fd)
#----------------------------------------------------------------------
# Main entry point for argument parsing and handling
@@ -865,6 +887,9 @@ def main():
help='''Output to stdout template text for the emailed
release announcement.''')
subparser.set_defaults(func=write_announcement)
+ subparser.add_argument('--target',
+ help='''The full path to the directory containing
+ release artifacts.''')
subparser.add_argument('version', type=Version,
help='''The release label, such as '1.7.0-alpha1'.''')
Modified: subversion/branches/tweak-build-take-two/tools/server-side/fsfs-reorg.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/tools/server-side/fsfs-reorg.c?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/tools/server-side/fsfs-reorg.c (original)
+++ subversion/branches/tweak-build-take-two/tools/server-side/fsfs-reorg.c Fri Dec 21 10:58:41 2012
@@ -1,4 +1,5 @@
-/* diff.c -- test driver for text diffs
+/* fsfs-reorg.c -- prototypic tool to reorganize packed FSFS repositories
+ * to reduce seeks
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -45,7 +46,7 @@
#define _(x) x
#endif
-#define ERROR_TAG "diff: "
+#define ERROR_TAG "fsfs-reporg: "
/* forward declarations */
typedef struct noderev_t noderev_t;
Modified: subversion/branches/tweak-build-take-two/tools/server-side/fsfs-stats.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/tools/server-side/fsfs-stats.c?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/tools/server-side/fsfs-stats.c (original)
+++ subversion/branches/tweak-build-take-two/tools/server-side/fsfs-stats.c Fri Dec 21 10:58:41 2012
@@ -1,4 +1,4 @@
-/* diff.c -- test driver for text diffs
+/* fsfs-stats.c -- gather size statistics on FSFS repositories
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -22,7 +22,6 @@
#include <assert.h>
-#include <sys/stat.h>
#include <apr.h>
#include <apr_general.h>
@@ -46,20 +45,29 @@
#define _(x) x
#endif
-#define ERROR_TAG "diff: "
+#define ERROR_TAG "fsfs-stats: "
+/* We group representations into 2x2 different kinds plus one default:
+ * [dir / file] x [text / prop]. The assignment is done by the first node
+ * that references the respective representation.
+ */
typedef enum rep_kind_t
{
+ /* The representation is _directly_ unused, i.e. not referenced by any
+ * noderev. However, some other representation may use it as delta base.
+ * null value. Should not occur in real-word repositories. */
unused_rep,
+ /* a properties on directory rep */
dir_property_rep,
+ /* a properties on file rep */
file_property_rep,
- /* a directory rep (including PLAIN / DELTA header) */
+ /* a directory rep */
dir_rep,
- /* a file rep (including PLAIN / DELTA header) */
+ /* a file rep */
file_rep
} rep_kind_t;
@@ -73,6 +81,7 @@ typedef struct representation_t
/* item length in bytes */
apr_size_t size;
+ /* item length after de-deltification */
apr_size_t expanded_size;
/* deltification base, or NULL if there is none */
@@ -80,13 +89,15 @@ typedef struct representation_t
/* revision that contains this representation
* (may be referenced by other revisions, though) */
-
svn_revnum_t revision;
+
+ /* number of nodes that reference this representation */
apr_uint32_t ref_count;
/* length of the PLAIN / DELTA line in the source file in bytes */
apr_uint16_t header_size;
+ /* classification of the representation. values of rep_kind_t */
char kind;
/* the source content has a PLAIN header, so we may simply copy the
@@ -118,9 +129,16 @@ typedef struct revision_info_t
* for non-packed revs) */
apr_size_t end;
+ /* number of directory noderevs in this revision */
apr_size_t dir_noderev_count;
+
+ /* number of file noderevs in this revision */
apr_size_t file_noderev_count;
+
+ /* total size of directory noderevs (i.e. the structs - not the rep) */
apr_size_t dir_noderev_size;
+
+ /* total size of file noderevs (i.e. the structs - not the rep) */
apr_size_t file_noderev_size;
/* all representation_t of this revision (in no particular order),
@@ -315,7 +333,7 @@ get_window_cache_index(fs_fs_t *fs,
return (revision + offset * 0xd1f3da69) % fs->window_cache->entry_count;
}
-/* Return the cached txdelta window stored in REPRESENTAION within FS.
+/* Return the cached txdelta window stored in REPRESENTATION within FS.
* If that has not been found in cache, return NULL.
*/
static svn_stringbuf_t *
@@ -334,7 +352,7 @@ get_cached_window(fs_fs_t *fs,
: NULL;
}
-/* Cache the undeltified txdelta WINDOW for REPRESENTAION within FS.
+/* Cache the undeltified txdelta WINDOW for REPRESENTATION within FS.
*/
static void
set_cached_window(fs_fs_t *fs,
@@ -365,8 +383,9 @@ set_cached_window(fs_fs_t *fs,
entry->revision = revision;
}
-/* Given REV in FS, set *REV_OFFSET to REV's offset in the packed file.
- Use POOL for temporary allocations. */
+/* Given rev pack PATH in FS, read the manifest file and return the offsets
+ * in *MANIFEST. Use POOL for allocations.
+ */
static svn_error_t *
read_manifest(apr_array_header_t **manifest,
fs_fs_t *fs,
@@ -409,6 +428,10 @@ read_manifest(apr_array_header_t **manif
return svn_stream_close(manifest_stream);
}
+/* Read header information for the revision stored in FILE_CONTENT (one
+ * whole revision). Return the offsets within FILE_CONTENT for the
+ * *ROOT_NODEREV, the list of *CHANGES and its len in *CHANGES_LEN.
+ * Use POOL for temporary allocations. */
static svn_error_t *
read_revision_header(apr_size_t *changes,
apr_size_t *changes_len,
@@ -447,8 +470,10 @@ read_revision_header(apr_size_t *changes
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
_("Final line in revision file missing space"));
+ /* terminate the header line */
*space = 0;
-
+
+ /* extract information */
SVN_ERR(svn_cstring_strtoui64(&val, line+1, 0, APR_SIZE_MAX, 10));
*root_noderev = (apr_size_t)val;
SVN_ERR(svn_cstring_strtoui64(&val, space+1, 0, APR_SIZE_MAX, 10));
@@ -458,6 +483,10 @@ read_revision_header(apr_size_t *changes
return SVN_NO_ERROR;
}
+/* Read the FSFS format number and sharding size from the format file at
+ * PATH and return it in *PFORMAT and *MAX_FILES_PER_DIR respectively.
+ * Use POOL for temporary allocations.
+ */
static svn_error_t *
read_format(int *pformat, int *max_files_per_dir,
const char *path, apr_pool_t *pool)
@@ -467,6 +496,7 @@ read_format(int *pformat, int *max_files
char buf[80];
apr_size_t len;
+ /* open format file and read the first line */
err = svn_io_file_open(&file, path, APR_READ | APR_BUFFERED,
APR_OS_DEFAULT, pool);
if (err && APR_STATUS_IS_ENOENT(err->apr_err))
@@ -541,21 +571,27 @@ read_format(int *pformat, int *max_files
return svn_io_file_close(file, pool);
}
+/* Read the content of the file at PATH and return it in *RESULT.
+ * Use POOL for temporary allocations.
+ */
static svn_error_t *
read_number(svn_revnum_t *result, const char *path, apr_pool_t *pool)
{
svn_stringbuf_t *content;
- apr_int64_t number;
+ apr_uint64_t number;
SVN_ERR(svn_stringbuf_from_file2(&content, path, pool));
content->data[content->len-1] = 0;
- SVN_ERR(svn_cstring_atoi64(&number, content->data));
+ SVN_ERR(svn_cstring_strtoui64(&number, content->data, 0, LONG_MAX, 10));
*result = (svn_revnum_t)number;
return SVN_NO_ERROR;
}
+/* Create *FS for the repository at PATH and read the format and size info.
+ * Use POOL for temporary allocations.
+ */
static svn_error_t *
fs_open(fs_fs_t **fs, const char *path, apr_pool_t *pool)
{
@@ -570,7 +606,8 @@ fs_open(fs_fs_t **fs, const char *path,
pool));
if (((*fs)->format != 4) && ((*fs)->format != 6))
return svn_error_create(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL, NULL);
-
+
+ /* read size (HEAD) info */
SVN_ERR(read_number(&(*fs)->min_unpacked_rev,
svn_dirent_join(path, "db/min-unpacked-rev", pool),
pool));
@@ -579,12 +616,18 @@ fs_open(fs_fs_t **fs, const char *path,
pool);
}
+/* Utility function that returns true if STRING->DATA matches KEY.
+ */
static svn_boolean_t
key_matches(svn_string_t *string, const char *key)
{
return strcmp(string->data, key) == 0;
}
+/* Comparator used for binary search comparing the absolute file offset
+ * of a representation to some other offset. DATA is a *representation_t,
+ * KEY is a pointer to an apr_size_t.
+ */
static int
compare_representation_offsets(const void *data, const void *key)
{
@@ -597,6 +640,15 @@ compare_representation_offsets(const voi
return diff > 0 ? 1 : 0;
}
+/* Find the revision_info_t object to the given REVISION in FS and return
+ * it in *REVISION_INFO. For performance reasons, we skip the lookup if
+ * the info is already provided.
+ *
+ * In that revision, look for the representation_t object for offset OFFSET.
+ * If it already exists, set *IDX to its index in *REVISION_INFO's
+ * representations list and return the representation object. Otherwise,
+ * set the index to where it must be inserted and return NULL.
+ */
static representation_t *
find_representation(int *idx,
fs_fs_t *fs,
@@ -606,7 +658,8 @@ find_representation(int *idx,
{
revision_info_t *info;
*idx = -1;
-
+
+ /* first let's find the revision */
info = revision_info ? *revision_info : NULL;
if (info == NULL || info->revision != revision)
{
@@ -617,23 +670,36 @@ find_representation(int *idx,
*revision_info = info;
}
+ /* not found -> no result */
if (info == NULL)
return NULL;
+
+ assert(revision == info->revision);
+ /* look for the representation */
*idx = svn_sort__bsearch_lower_bound(&offset,
info->representations,
compare_representation_offsets);
if (*idx < info->representations->nelts)
{
+ /* return the representation, if this is the one we were looking for */
representation_t *result
= APR_ARRAY_IDX(info->representations, *idx, representation_t *);
if (result->offset == offset)
return result;
}
+ /* not parsed, yet */
return NULL;
}
+/* Read the representation header in FILE_CONTENT at OFFSET. Return its
+ * size in *HEADER_SIZE, set *IS_PLAIN if no deltification was used and
+ * return the deltification base representation in *REPRESENTATION. If
+ * there is none, set it to NULL. Use FS to it look up.
+ *
+ * Use POOL for allocations and SCRATCH_POOL for temporaries.
+ */
static svn_error_t *
read_rep_base(representation_t **representation,
apr_size_t *header_size,
@@ -649,10 +715,12 @@ read_rep_base(representation_t **represe
svn_revnum_t revision;
apr_uint64_t temp;
+ /* identify representation header (1 line) */
const char *buffer = file_content->data + offset;
const char *line_end = strchr(buffer, '\n');
*header_size = line_end - buffer + 1;
+ /* check for PLAIN rep */
if (strncmp(buffer, "PLAIN\n", *header_size) == 0)
{
*is_plain = TRUE;
@@ -660,6 +728,7 @@ read_rep_base(representation_t **represe
return SVN_NO_ERROR;
}
+ /* check for DELTA against empty rep */
*is_plain = FALSE;
if (strncmp(buffer, "DELTA\n", *header_size) == 0)
{
@@ -671,7 +740,7 @@ read_rep_base(representation_t **represe
str = apr_pstrndup(scratch_pool, buffer, line_end - buffer);
last_str = str;
- /* We hopefully have a DELTA vs. a non-empty base revision. */
+ /* parse it. */
str = svn_cstring_tokenize(" ", &last_str);
str = svn_cstring_tokenize(" ", &last_str);
SVN_ERR(svn_revnum_parse(&revision, str, NULL));
@@ -679,10 +748,18 @@ read_rep_base(representation_t **represe
str = svn_cstring_tokenize(" ", &last_str);
SVN_ERR(svn_cstring_strtoui64(&temp, str, 0, APR_SIZE_MAX, 10));
+ /* it should refer to a rep in an earlier revision. Look it up */
*representation = find_representation(&idx, fs, NULL, revision, (apr_size_t)temp);
return SVN_NO_ERROR;
}
+/* Parse the representation reference (text: or props:) in VALUE, look
+ * it up in FS and return it in *REPRESENTATION. To be able to parse the
+ * base rep, we pass the FILE_CONTENT as well.
+ *
+ * If necessary, allocate the result in POOL; use SCRATCH_POOL for temp.
+ * allocations.
+ */
static svn_error_t *
parse_representation(representation_t **representation,
fs_fs_t *fs,
@@ -700,15 +777,20 @@ parse_representation(representation_t **
apr_uint64_t expanded_size;
int idx;
+ /* read location (revision, offset) and size */
char *c = (char *)value->data;
SVN_ERR(svn_revnum_parse(&revision, svn_cstring_tokenize(" ", &c), NULL));
SVN_ERR(svn_cstring_strtoui64(&offset, svn_cstring_tokenize(" ", &c), 0, APR_SIZE_MAX, 10));
SVN_ERR(svn_cstring_strtoui64(&size, svn_cstring_tokenize(" ", &c), 0, APR_SIZE_MAX, 10));
SVN_ERR(svn_cstring_strtoui64(&expanded_size, svn_cstring_tokenize(" ", &c), 0, APR_SIZE_MAX, 10));
+ /* look it up */
result = find_representation(&idx, fs, &revision_info, revision, (apr_size_t)offset);
if (!result)
{
+ /* not parsed, yet (probably a rep in the same revision).
+ * Create a new rep object and determine its base rep as well.
+ */
apr_size_t header_size;
svn_boolean_t is_plain;
@@ -732,8 +814,10 @@ parse_representation(representation_t **
return SVN_NO_ERROR;
}
-/* Get the file content of revision REVISION in FS and return it in *DATA.
- * Use SCRATCH_POOL for temporary allocations.
+/* Get the unprocessed (i.e. still deltified) content of REPRESENTATION in
+ * FS and return it in *CONTENT. If no NULL, FILE_CONTENT must contain
+ * the contents of the revision that also contains the representation.
+ * Use POOL for allocations.
*/
static svn_error_t *
get_rep_content(svn_stringbuf_t **content,
@@ -773,8 +857,12 @@ get_rep_content(svn_stringbuf_t **conten
}
-/* Skip forwards to THIS_CHUNK in REP_STATE and then read the next delta
- window into *NWIN. */
+/* Read the delta window contents of all windows in REPRESENTATION in FS.
+ * If no NULL, FILE_CONTENT must contain the contents of the revision that
+ * also contains the representation.
+ * Return the data as svn_txdelta_window_t* instances in *WINDOWS.
+ * Use POOL for allocations.
+ */
static svn_error_t *
read_windows(apr_array_header_t **windows,
fs_fs_t *fs,
@@ -789,13 +877,16 @@ read_windows(apr_array_header_t **window
*windows = apr_array_make(pool, 0, sizeof(svn_txdelta_window_t *));
+ /* get the whole revision content */
SVN_ERR(get_rep_content(&content, fs, representation, file_content, pool));
+ /* create a read stream and position it directly after the rep header */
content->data += 3;
content->len -= 3;
stream = svn_stream_from_stringbuf(content, pool);
SVN_ERR(svn_stream_read(stream, &version, &len));
+ /* read the windows from that stream */
while (TRUE)
{
svn_txdelta_window_t *window;
@@ -816,9 +907,12 @@ read_windows(apr_array_header_t **window
return SVN_NO_ERROR;
}
-/* Get the undeltified window that is a result of combining all deltas
- from the current desired representation identified in *RB with its
- base representation. Store the window in *RESULT. */
+/* Get the undeltified representation that is a result of combining all
+ * deltas from the current desired REPRESENTATION in FS with its base
+ * representation. If no NULL, FILE_CONTENT must contain the contents of
+ * the revision that also contains the representation. Store the result
+ * in *CONTENT. Use POOL for allocations.
+ */
static svn_error_t *
get_combined_window(svn_stringbuf_t **content,
fs_fs_t *fs,
@@ -833,20 +927,28 @@ get_combined_window(svn_stringbuf_t **co
apr_pool_t *sub_pool = svn_pool_create(pool);
apr_pool_t *iter_pool = svn_pool_create(pool);
+ /* special case: no un-deltification necessary */
if (representation->is_plain)
return get_rep_content(content, fs, representation, file_content, pool);
+ /* special case: data already in cache */
*content = get_cached_window(fs, representation, pool);
if (*content)
return SVN_NO_ERROR;
+ /* read the delta windows for this representation */
+ sub_pool = svn_pool_create(pool);
+ iter_pool = svn_pool_create(pool);
SVN_ERR(read_windows(&windows, fs, representation, file_content, sub_pool));
+
+ /* fetch the / create a base content */
if (representation->delta_base && representation->delta_base->revision)
SVN_ERR(get_combined_window(&base_content, fs,
representation->delta_base, NULL, sub_pool));
else
base_content = svn_stringbuf_create_empty(sub_pool);
+ /* apply deltas */
result = svn_stringbuf_create_empty(pool);
source = base_content->data;
@@ -869,12 +971,15 @@ get_combined_window(svn_stringbuf_t **co
svn_pool_destroy(iter_pool);
svn_pool_destroy(sub_pool);
-
+
+ /* cache result and return it */
set_cached_window(fs, representation, result);
*content = result;
+
return SVN_NO_ERROR;
}
+/* forward declaration */
static svn_error_t *
read_noderev(fs_fs_t *fs,
svn_stringbuf_t *file_content,
@@ -883,6 +988,12 @@ read_noderev(fs_fs_t *fs,
apr_pool_t *pool,
apr_pool_t *scratch_pool);
+/* Starting at the directory in REPRESENTATION in FILE_CONTENT, read all
+ * DAG nodes, directories and representations linked in that tree structure.
+ * Store them in FS and REVISION_INFO. Also, read them only once.
+ *
+ * Use POOL for persistent allocations and SCRATCH_POOL for temporaries.
+ */
static svn_error_t *
parse_dir(fs_fs_t *fs,
svn_stringbuf_t *file_content,
@@ -898,9 +1009,11 @@ parse_dir(fs_fs_t *fs,
const char *revision_key;
apr_size_t key_len;
+ /* special case: empty dir rep */
if (representation == NULL)
return SVN_NO_ERROR;
+ /* get the directory as unparsed string */
iter_pool = svn_pool_create(scratch_pool);
text_pool = svn_pool_create(scratch_pool);
@@ -908,14 +1021,16 @@ parse_dir(fs_fs_t *fs,
text_pool));
current = text->data;
+ /* calculate some invariants */
revision_key = apr_psprintf(text_pool, "r%ld/", representation->revision);
key_len = strlen(revision_key);
- /* Translate the string dir entries into real entries. */
+ /* Parse and process all directory entries. */
while (*current != 'E')
{
char *next;
+ /* skip "K ???\n<name>\nV ???\n" lines*/
current = strchr(current, '\n');
if (current)
current = strchr(current+1, '\n');
@@ -927,11 +1042,14 @@ parse_dir(fs_fs_t *fs,
_("Corrupt directory representation in rev %ld at offset %ld"),
representation->revision,
(long)representation->offset);
-
+
+ /* iff this entry refers to a node in the same revision as this dir,
+ * recurse into that node */
*next = 0;
current = strstr(current, revision_key);
if (current)
{
+ /* recurse */
apr_uint64_t offset;
SVN_ERR(svn_cstring_strtoui64(&offset, current + key_len, 0,
@@ -949,6 +1067,13 @@ parse_dir(fs_fs_t *fs,
return SVN_NO_ERROR;
}
+/* Starting at the noderev at OFFSET in FILE_CONTENT, read all DAG nodes,
+ * directories and representations linked in that tree structure. Store
+ * them in FS and REVISION_INFO. Also, read them only once. Return the
+ * result in *NODEREV.
+ *
+ * Use POOL for persistent allocations and SCRATCH_POOL for temporaries.
+ */
static svn_error_t *
read_noderev(fs_fs_t *fs,
svn_stringbuf_t *file_content,
@@ -964,9 +1089,11 @@ read_noderev(fs_fs_t *fs,
svn_boolean_t is_dir = FALSE;
scratch_pool = svn_pool_create(scratch_pool);
-
+
+ /* parse the noderev line-by-line until we find an empty line */
while (1)
{
+ /* for this line, extract key and value. Ignore invalid values */
svn_string_t key;
svn_string_t value;
char *sep;
@@ -975,6 +1102,8 @@ read_noderev(fs_fs_t *fs,
line = svn_string_ncreate(start, end - start, scratch_pool);
offset += end - start + 1;
+
+ /* empty line -> end of noderev data */
if (line->len == 0)
break;
@@ -992,6 +1121,7 @@ read_noderev(fs_fs_t *fs,
value.data = sep + 2;
value.len = line->len - (key.len + 2);
+ /* translate (key, value) into noderev elements */
if (key_matches(&key, "type"))
is_dir = strcmp(value.data, "dir") == 0;
else if (key_matches(&key, "text"))
@@ -999,6 +1129,8 @@ read_noderev(fs_fs_t *fs,
SVN_ERR(parse_representation(&text, fs, file_content,
&value, revision_info,
pool, scratch_pool));
+
+ /* if we are the first to use this rep, mark it as "text rep" */
if (++text->ref_count == 1)
text->kind = is_dir ? dir_rep : file_rep;
}
@@ -1007,15 +1139,20 @@ read_noderev(fs_fs_t *fs,
SVN_ERR(parse_representation(&props, fs, file_content,
&value, revision_info,
pool, scratch_pool));
+
+ /* if we are the first to use this rep, mark it as "prop rep" */
if (++props->ref_count == 1)
props->kind = is_dir ? dir_property_rep : file_property_rep;
}
}
+ /* if this is a directory and has not been processed, yet, read and
+ * process it recursively */
if (is_dir && text && text->ref_count == 1)
SVN_ERR(parse_dir(fs, file_content, text, revision_info,
pool, scratch_pool));
+ /* update stats */
if (is_dir)
{
revision_info->dir_noderev_size += offset - start_offset;
@@ -1031,6 +1168,9 @@ read_noderev(fs_fs_t *fs,
return SVN_NO_ERROR;
}
+/* Given the unparsed changes list in CHANGES with LEN chars, return the
+ * number of changed paths encoded in it.
+ */
static apr_size_t
get_change_count(const char *changes,
apr_size_t len)
@@ -1038,19 +1178,27 @@ get_change_count(const char *changes,
apr_size_t lines = 0;
const char *end = changes + len;
+ /* line count */
for (; changes < end; ++changes)
if (*changes == '\n')
++lines;
+ /* two lines per change */
return lines / 2;
}
-static void print_progress(svn_revnum_t revision)
+/* Simple utility to print a REVISION number and make it appear immediately.
+ */
+static void
+print_progress(svn_revnum_t revision)
{
printf("%8ld", revision);
fflush(stdout);
}
+/* Read the content of the pack file staring at revision BASE and store it
+ * in FS. Use POOL for allocations.
+ */
static svn_error_t *
read_pack_file(fs_fs_t *fs,
svn_revnum_t base,
@@ -1063,17 +1211,20 @@ read_pack_file(fs_fs_t *fs,
apr_off_t file_size = 0;
const char *pack_folder = get_pack_folder(fs, base, local_pool);
+ /* parse the manifest file */
SVN_ERR(read_manifest(&manifest, fs, pack_folder, local_pool));
if (manifest->nelts != fs->max_files_per_dir)
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, NULL);
SVN_ERR(rev_or_pack_file_size(&file_size, fs, base, pool));
+ /* process each revision in the pack file */
for (i = 0; i < manifest->nelts; ++i)
{
apr_size_t root_node_offset;
svn_stringbuf_t *rev_content;
+ /* create the revision info for the current rev */
revision_info_t *info = apr_pcalloc(pool, sizeof(*info));
info->representations = apr_array_make(iter_pool, 4, sizeof(representation_t*));
@@ -1103,15 +1254,20 @@ read_pack_file(fs_fs_t *fs,
info->representations = apr_array_copy(pool, info->representations);
APR_ARRAY_PUSH(fs->revisions, revision_info_t*) = info;
+ /* destroy temps */
svn_pool_clear(iter_pool);
}
+ /* one more pack file processed */
print_progress(base);
apr_pool_destroy(local_pool);
return SVN_NO_ERROR;
}
+/* Read the content of the file for REVSION and store its contents in FS.
+ * Use POOL for allocations.
+ */
static svn_error_t *
read_revision_file(fs_fs_t *fs,
svn_revnum_t revision,
@@ -1123,8 +1279,10 @@ read_revision_file(fs_fs_t *fs,
revision_info_t *info = apr_pcalloc(pool, sizeof(*info));
apr_off_t file_size = 0;
+ /* read the whole pack file into memory */
SVN_ERR(rev_or_pack_file_size(&file_size, fs, revision, pool));
+ /* create the revision info for the current rev */
info->representations = apr_array_make(pool, 4, sizeof(representation_t*));
info->revision = revision;
@@ -1139,16 +1297,19 @@ read_revision_file(fs_fs_t *fs,
rev_content,
local_pool));
+ /* put it into our containers */
APR_ARRAY_PUSH(fs->revisions, revision_info_t*) = info;
info->change_count
= get_change_count(rev_content->data + info->changes,
info->changes_len);
+ /* parse the revision content recursively. */
SVN_ERR(read_noderev(fs, rev_content,
root_node_offset, info,
pool, local_pool));
+ /* show progress every 1000 revs or so */
if (revision % fs->max_files_per_dir == 0)
print_progress(revision);
@@ -1157,6 +1318,10 @@ read_revision_file(fs_fs_t *fs,
return SVN_NO_ERROR;
}
+/* Read the repository at PATH beginning with revision START_REVISION and
+ * return the result in *FS. Allocate caches with MEMSIZE bytes total
+ * capacity. Use POOL for non-cache allocations.
+ */
static svn_error_t *
read_revisions(fs_fs_t **fs,
const char *path,
@@ -1176,6 +1341,7 @@ read_revisions(fs_fs_t **fs,
SVN_ERR(fs_open(fs, path, pool));
+ /* create data containers and caches */
(*fs)->start_revision = start_revision
- (start_revision % (*fs)->max_files_per_dir);
(*fs)->revisions = apr_array_make(pool,
@@ -1187,41 +1353,71 @@ read_revisions(fs_fs_t **fs,
(svn_pool_create_allocator(FALSE)),
10000, window_cache_size);
+ /* read all packed revs */
for ( revision = start_revision
; revision < (*fs)->min_unpacked_rev
; revision += (*fs)->max_files_per_dir)
SVN_ERR(read_pack_file(*fs, revision, pool));
-
+
+ /* read non-packed revs */
for ( ; revision <= (*fs)->max_revision; ++revision)
SVN_ERR(read_revision_file(*fs, revision, pool));
return SVN_NO_ERROR;
}
+/* Compression statistics we collect over a given set of representations.
+ */
typedef struct rep_pack_stats_t
{
+ /* number of representations */
apr_int64_t count;
+
+ /* total size after deltification (i.e. on disk size) */
apr_int64_t packed_size;
+
+ /* total size after de-deltification (i.e. plain text size) */
apr_int64_t expanded_size;
+
+ /* total on-disk header size */
apr_int64_t overhead_size;
} rep_pack_stats_t;
+/* Statistics we collect over a given set of representations.
+ * We group them into shared and non-shared ("unique") reps.
+ */
typedef struct representation_stats_t
{
+ /* stats over all representations */
rep_pack_stats_t total;
+
+ /* stats over those representations with ref_count == 1 */
rep_pack_stats_t uniques;
+
+ /* stats over those representations with ref_count > 1 */
rep_pack_stats_t shared;
+ /* sum of all ref_counts */
apr_int64_t references;
+
+ /* sum of ref_count * expanded_size,
+ * i.e. total plaintext content if there was no rep sharing */
apr_int64_t expanded_size;
} representation_stats_t;
+/* Basic statistics we collect over a given set of noderevs.
+ */
typedef struct node_stats_t
{
+ /* number of noderev structs */
apr_int64_t count;
+
+ /* their total size on disk (structs only) */
apr_int64_t size;
} node_stats_t;
+/* Accumulate stats of REP in STATS.
+ */
static void
add_rep_pack_stats(rep_pack_stats_t *stats,
representation_t *rep)
@@ -1230,9 +1426,11 @@ add_rep_pack_stats(rep_pack_stats_t *sta
stats->packed_size += rep->size;
stats->expanded_size += rep->expanded_size;
- stats->overhead_size += rep->header_size + 7;
+ stats->overhead_size += rep->header_size + 7 /* ENDREP\n */;
}
+/* Accumulate stats of REP in STATS.
+ */
static void
add_rep_stats(representation_stats_t *stats,
representation_t *rep)
@@ -1247,6 +1445,9 @@ add_rep_stats(representation_stats_t *st
stats->expanded_size += rep->ref_count * rep->expanded_size;
}
+/* Print statistics for the given group of representations to console.
+ * Use POOL for allocations.
+ */
static void
print_rep_stats(representation_stats_t *stats,
apr_pool_t *pool)
@@ -1267,12 +1468,16 @@ print_rep_stats(representation_stats_t *
svn__i64toa_sep(stats->references - stats->total.count, ',', pool));
}
+/* Post-process stats for FS and print them to the console.
+ * Use POOL for allocations.
+ */
static void
print_stats(fs_fs_t *fs,
apr_pool_t *pool)
{
int i, k;
-
+
+ /* initialize stats to collect */
representation_stats_t file_rep_stats = { { 0 } };
representation_stats_t dir_rep_stats = { { 0 } };
representation_stats_t file_prop_rep_stats = { { 0 } };
@@ -1286,11 +1491,14 @@ print_stats(fs_fs_t *fs,
apr_int64_t total_size = 0;
apr_int64_t change_count = 0;
apr_int64_t change_len = 0;
-
+
+ /* aggregate info from all revisions */
for (i = 0; i < fs->revisions->nelts; ++i)
{
revision_info_t *revision = APR_ARRAY_IDX(fs->revisions, i,
revision_info_t *);
+
+ /* data gathered on a revision level */
change_count += revision->change_count;
change_len += revision->changes_len;
total_size += revision->end - revision->offset;
@@ -1303,11 +1511,14 @@ print_stats(fs_fs_t *fs,
+ revision->file_noderev_count;
total_node_stats.size += revision->dir_noderev_size
+ revision->file_noderev_size;
-
+
+ /* process representations */
for (k = 0; k < revision->representations->nelts; ++k)
{
representation_t *rep = APR_ARRAY_IDX(revision->representations,
k, representation_t *);
+
+ /* accumulate in the right bucket */
switch(rep->kind)
{
case file_rep:
@@ -1330,6 +1541,7 @@ print_stats(fs_fs_t *fs,
}
}
+ /* print results */
printf("\nGlobal statistics:\n");
printf(_("%20s bytes in %12s revisions\n"
"%20s bytes in %12s changes\n"
@@ -1388,6 +1600,9 @@ print_stats(fs_fs_t *fs,
print_rep_stats(&file_prop_rep_stats, pool);
}
+/* Write tool usage info text to OSTREAM using PROGNAME as a prefix and
+ * POOL for allocations.
+ */
static void
print_usage(svn_stream_t *ostream, const char *progname,
apr_pool_t *pool)
@@ -1404,6 +1619,7 @@ print_usage(svn_stream_t *ostream, const
progname));
}
+/* linear control flow */
int main(int argc, const char *argv[])
{
apr_pool_t *pool;
Modified: subversion/branches/tweak-build-take-two/tools/server-side/svnauthz-validate.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/tools/server-side/svnauthz-validate.c?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/tools/server-side/svnauthz-validate.c (original)
+++ subversion/branches/tweak-build-take-two/tools/server-side/svnauthz-validate.c Fri Dec 21 10:58:41 2012
@@ -34,6 +34,7 @@
#include "svn_pools.h"
#include "svn_repos.h"
#include "svn_utf.h"
+#include "svn_path.h"
enum {
OPT_USERNAME = SVN_OPT_FIRST_LONGOPT_ID,
@@ -49,6 +50,8 @@ usage(const char *argv0)
"Optionally prints the access available to USER for FSPATH in\n"
"repository with authz name REPOS_NAME. If FSPATH is omitted, reports\n"
"whether USER has any access at all.\n"
+ "FILE can also be an absolute file:// URL to a authz file in a\n"
+ "repository, but cannot be a repository relative URL (^/).\n"
"Returns:\n"
" 0 when syntax is OK.\n"
" 1 when syntax is invalid.\n"
@@ -141,10 +144,15 @@ main(int argc, const char **argv)
return 2;
}
- opts.authz_file = svn_dirent_internal_style(opts.authz_file, pool);
+ /* Can't accept repos relative urls since we don't have the path to the
+ * repository and URLs don't need to be converted to internal style. */
+ if (svn_path_is_repos_relative_url(opts.authz_file))
+ return usage(argv[0]);
+ else if (!svn_path_is_url(opts.authz_file))
+ opts.authz_file = svn_dirent_internal_style(opts.authz_file, pool);
/* Read the access file and validate it. */
- err = svn_repos_authz_read(&authz, opts.authz_file, TRUE, pool);
+ err = svn_repos_authz_read2(&authz, opts.authz_file, TRUE, NULL, pool);
/* Optionally, print the access a USER has to a given PATH in REPOS.
PATH and REPOS may be NULL. */
Modified: subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/commit-hook.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/commit-hook.py?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/commit-hook.py (original)
+++ subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/commit-hook.py Fri Dec 21 10:58:41 2012
@@ -42,11 +42,11 @@ def svncmd_uuid(repo):
def svncmd_info(repo, revision):
cmd = "%s info -r %s %s" % (SVNLOOK, revision, repo)
p = svncmd(cmd)
- data = p.stdout.read().strip().split("\n")
+ data = p.stdout.read().split("\n")
#print data
- return {'author': data[0],
- 'date': data[1],
- 'log': "\n".join(data[3:])}
+ return {'author': data[0].strip(),
+ 'date': data[1].strip(),
+ 'log': "\n".join(data[3:]).strip()}
def svncmd_dirs(repo, revision):
cmd = "%s dirs-changed -r %s %s" % (SVNLOOK, revision, repo)
@@ -59,6 +59,19 @@ def svncmd_dirs(repo, revision):
dirs.append(line.strip())
return dirs
+def svncmd_changed(repo, revision):
+ cmd = "%s changed -r %s %s" % (SVNLOOK, revision, repo)
+ p = svncmd(cmd)
+ changed = {}
+ while True:
+ line = p.stdout.readline()
+ if not line:
+ break
+ line = line.strip()
+ (flags, filename) = (line[0:3], line[4:])
+ changed[filename] = {'flags': flags}
+ return changed
+
def do_put(body):
opener = urllib2.build_opener(urllib2.HTTPHandler)
request = urllib2.Request("http://%s:%d/dirs-changed" %(HOST, PORT), data=body)
@@ -72,12 +85,14 @@ def main(repo, revision):
i = svncmd_info(repo, revision)
data = {'revision': int(revision),
'dirs_changed': [],
+ 'changed': {},
'repos': svncmd_uuid(repo),
'author': i['author'],
'log': i['log'],
'date': i['date'],
}
data['dirs_changed'].extend(svncmd_dirs(repo, revision))
+ data['changed'].update(svncmd_changed(repo, revision))
body = json.dumps(data)
#print body
do_put(body)
Modified: subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/irkerbridge.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/irkerbridge.py?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/irkerbridge.py (original)
+++ subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/irkerbridge.py Fri Dec 21 10:58:41 2012
@@ -145,6 +145,12 @@ class BigDoEverythingClass(object):
return result
def fill_in_extra_args(self, rev):
+ # Set any empty members to the string "<null>"
+ v = vars(rev)
+ for k in v.keys():
+ if not v[k]:
+ v[k] = '<null>'
+
# Add entries to the rev object that are useful for
# formatting.
rev.log_firstline = rev.log.split("\n",1)[0]
Modified: subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/rc.d/svnpubsub.freebsd
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/rc.d/svnpubsub.freebsd?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/rc.d/svnpubsub.freebsd (original)
+++ subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/rc.d/svnpubsub.freebsd Fri Dec 21 10:58:41 2012
@@ -20,11 +20,13 @@ svnpubsub_user=${svnpubsub_user-"svn"}
svnpubsub_group=${svnpubsub_group-"svn"}
svnpubsub_reactor=${svnpubsub_reactor-"poll"}
svnpubsub_pidfile=${svnpubsub_pidfile-"/var/run/svnpubsub/svnpubsub.pid"}
+svnpubsub_cmd_int=${svnpubsub_cmd_int-"python"}
pidfile="${svnpubsub_pidfile}"
export PYTHON_EGG_CACHE="/home/svn/.python-eggs"
command="/usr/local/bin/twistd"
+command_interpreter="/usr/local/bin/${svnwcsub_cmd_int}"
command_args="-y /usr/local/svnpubsub/svnpubsub.tac \
--logfile=/var/log/vc/svnpubsub.log \
--pidfile=${pidfile} \
Modified: subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/svnpubsub/client.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/svnpubsub/client.py?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/svnpubsub/client.py (original)
+++ subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/svnpubsub/client.py Fri Dec 21 10:58:41 2012
@@ -119,10 +119,15 @@ class XMLStreamHandler(xml.sax.handler.C
self.rev = None
self.chars = ''
+ self.parent = None
+ self.attrs = [ ]
def startElement(self, name, attrs):
+ self.attrs = attrs
if name == 'commit':
self.rev = Revision(attrs['repository'], int(attrs['revision']))
+ elif name == "dirs_changed" or name == "changed":
+ self.parent = name
# No other elements to worry about.
def characters(self, data):
@@ -134,10 +139,15 @@ class XMLStreamHandler(xml.sax.handler.C
self.rev = None
elif name == 'stillalive':
self.event_callback('ping')
+ elif name == self.parent:
+ self.parent = None
elif self.chars and self.rev:
value = self.chars.strip()
- if name == 'path':
+ if self.parent == 'dirs_changed' and name == 'path':
self.rev.dirs_changed.append(value.decode('unicode_escape'))
+ elif self.parent == 'changed' and name == 'path':
+ path = value.decode('unicode_escape')
+ self.rev.changed[path] = dict(p for p in self.attrs.items())
elif name == 'author':
self.rev.author = value.decode('unicode_escape')
elif name == 'date':
@@ -147,6 +157,8 @@ class XMLStreamHandler(xml.sax.handler.C
# Toss out any accumulated characters for this element.
self.chars = ''
+ # Toss out the saved attributes for this element.
+ self.attrs = [ ]
class Revision(object):
@@ -154,6 +166,7 @@ class Revision(object):
self.uuid = uuid
self.rev = rev
self.dirs_changed = [ ]
+ self.changed = { }
self.author = None
self.date = None
self.log = None
Modified: subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/svnpubsub/server.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/svnpubsub/server.py?rev=1424862&r1=1424861&r2=1424862&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/svnpubsub/server.py (original)
+++ subversion/branches/tweak-build-take-two/tools/server-side/svnpubsub/svnpubsub/server.py Fri Dec 21 10:58:41 2012
@@ -78,7 +78,8 @@ class Revision:
# thus creating invalid XML, so the XML code paths do escaping.
self.rev = r.get('revision')
self.repos = r.get('repos')
- self.dirs_changed = [x for x in r.get('dirs_changed')]
+ self.dirs_changed = r.get('dirs_changed')
+ self.changed = r.get('changed')
self.author = r.get('author')
self.log = r.get('log')
self.date = r.get('date')
@@ -88,6 +89,7 @@ class Revision:
return json.dumps({'commit': {'repository': self.repos,
'revision': self.rev,
'dirs_changed': self.dirs_changed,
+ 'changed': self.changed,
'author': self.author,
'log': self.log,
'date': self.date}}) +","
@@ -100,6 +102,11 @@ class Revision:
for p in self.dirs_changed:
x = ET.SubElement(d, 'path')
x.text = p.encode('unicode_escape')
+ ch = ET.SubElement(c, 'changed')
+ for chp in self.changed.keys():
+ x = ET.SubElement(ch, 'path', self.changed[chp])
+ x.text = chp.encode('unicode_escape')
+
str = ET.tostring(c, 'UTF-8') + "\n"
return str[39:]
else: