You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ar...@apache.org on 2011/08/16 11:38:43 UTC

svn commit: r1158171 [10/10] - in /subversion/branches/svn-bisect: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ notes/ subversion/bindings/ctypes-python/csvn/ subversion/bindings/ctypes-python/test/ subversion/bindings/javahl/nativ...

Modified: subversion/branches/svn-bisect/subversion/tests/libsvn_diff/parse-diff-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/tests/libsvn_diff/parse-diff-test.c?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/tests/libsvn_diff/parse-diff-test.c (original)
+++ subversion/branches/svn-bisect/subversion/tests/libsvn_diff/parse-diff-test.c Tue Aug 16 09:38:37 2011
@@ -247,28 +247,28 @@ static const char *bad_git_diff_header =
   "new file mode 100644"                                                NL;
 
 
-/* Create a PATCH_FILE with name FNAME containing the contents of DIFF. */
+/* Create a PATCH_FILE containing the contents of DIFF. */
 static svn_error_t *
-create_patch_file(svn_patch_file_t **patch_file, const char *fname,
+create_patch_file(svn_patch_file_t **patch_file,
                   const char *diff, apr_pool_t *pool)
 {
+  apr_size_t bytes;
   apr_size_t len;
-  apr_status_t status;
+  const char *path;
   apr_file_t *apr_file;
 
   /* Create a patch file. */
-  status = apr_file_open(&apr_file, fname,
-                        (APR_READ | APR_WRITE | APR_CREATE | APR_TRUNCATE |
-                         APR_DELONCLOSE), APR_OS_DEFAULT, pool);
-  if (status != APR_SUCCESS)
-    return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "Cannot open '%s'",
-                             fname);
-  len = strlen(diff);
-  status = apr_file_write_full(apr_file, diff, len, &len);
-  if (status || len != strlen(diff))
+  SVN_ERR(svn_io_open_unique_file3(&apr_file, &path, NULL,
+                                   svn_io_file_del_on_pool_cleanup,
+                                   pool, pool));
+
+  bytes = strlen(diff);
+  SVN_ERR(svn_io_file_write_full(apr_file, diff, bytes, &len, pool));
+  if (len != bytes)
     return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
-                             "Cannot write to '%s'", fname);
-  SVN_ERR(svn_diff_open_patch_file(patch_file, fname, pool));
+                             "Cannot write to '%s'", path);
+  SVN_ERR(svn_io_file_close(apr_file, pool));
+  SVN_ERR(svn_diff_open_patch_file(patch_file, path, pool));
 
   return SVN_NO_ERROR;
 }
@@ -314,7 +314,6 @@ static svn_error_t *
 test_parse_unidiff(apr_pool_t *pool)
 {
   svn_patch_file_t *patch_file;
-  const char *fname = "test_parse_unidiff.patch";
   svn_boolean_t reverse;
   svn_boolean_t ignore_whitespace;
   int i;
@@ -330,7 +329,7 @@ test_parse_unidiff(apr_pool_t *pool)
 
       svn_pool_clear(iterpool);
 
-      SVN_ERR(create_patch_file(&patch_file, fname, unidiff, pool));
+      SVN_ERR(create_patch_file(&patch_file, unidiff, pool));
 
       /* We have two patches with one hunk each.
        * Parse the first patch. */
@@ -393,9 +392,8 @@ test_parse_git_diff(apr_pool_t *pool)
   svn_patch_file_t *patch_file;
   svn_patch_t *patch;
   svn_diff_hunk_t *hunk;
-  const char *fname = "test_parse_git_diff.patch";
 
-  SVN_ERR(create_patch_file(&patch_file, fname, git_unidiff, pool));
+  SVN_ERR(create_patch_file(&patch_file, git_unidiff, pool));
 
   /* Parse a deleted empty file */
   SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
@@ -467,10 +465,8 @@ test_parse_git_tree_and_text_diff(apr_po
   svn_patch_file_t *patch_file;
   svn_patch_t *patch;
   svn_diff_hunk_t *hunk;
-  const char *fname = "test_parse_git_tree_and_text_diff.patch";
 
-  SVN_ERR(create_patch_file(&patch_file, fname, git_tree_and_text_unidiff,
-                            pool));
+  SVN_ERR(create_patch_file(&patch_file, git_tree_and_text_unidiff, pool));
 
   /* Parse a copied file with text modifications. */
   SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
@@ -567,10 +563,8 @@ test_bad_git_diff_headers(apr_pool_t *po
   svn_patch_file_t *patch_file;
   svn_patch_t *patch;
   svn_diff_hunk_t *hunk;
-  const char *fname = "test_bad_git_diff_header.patch";
 
-  SVN_ERR(create_patch_file(&patch_file, fname, bad_git_diff_header,
-                            pool));
+  SVN_ERR(create_patch_file(&patch_file, bad_git_diff_header, pool));
 
   SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                     FALSE, /* reverse */
@@ -607,9 +601,8 @@ test_parse_property_diff(apr_pool_t *poo
   svn_prop_patch_t *prop_patch;
   svn_diff_hunk_t *hunk;
   apr_array_header_t *hunks;
-  const char *fname = "test_parse_property_diff.patch";
 
-  SVN_ERR(create_patch_file(&patch_file, fname, property_unidiff, pool));
+  SVN_ERR(create_patch_file(&patch_file, property_unidiff, pool));
 
   SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                     FALSE, /* reverse */
@@ -710,10 +703,8 @@ test_parse_property_and_text_diff(apr_po
   svn_prop_patch_t *prop_patch;
   svn_diff_hunk_t *hunk;
   apr_array_header_t *hunks;
-  const char *fname = "test_parse_property_and_text_diff.patch";
 
-  SVN_ERR(create_patch_file(&patch_file, fname, property_and_text_unidiff,
-                            pool));
+  SVN_ERR(create_patch_file(&patch_file, property_and_text_unidiff, pool));
 
   SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                     FALSE, /* reverse */
@@ -766,10 +757,8 @@ test_parse_diff_symbols_in_prop_unidiff(
   svn_prop_patch_t *prop_patch;
   svn_diff_hunk_t *hunk;
   apr_array_header_t *hunks;
-  const char *fname = "test_parse_diff_symbols_in_prop_unidiff.patch";
 
-  SVN_ERR(create_patch_file(&patch_file, fname, diff_symbols_in_prop_unidiff,
-                            pool));
+  SVN_ERR(create_patch_file(&patch_file, diff_symbols_in_prop_unidiff, pool));
 
   SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                     FALSE, /* reverse */
@@ -865,10 +854,8 @@ test_git_diffs_with_spaces_diff(apr_pool
 {
   svn_patch_file_t *patch_file;
   svn_patch_t *patch;
-  const char *fname = "test_git_diffs_with_spaces_diff.patch";
 
-  SVN_ERR(create_patch_file(&patch_file, fname, path_with_spaces_unidiff,
-                            pool));
+  SVN_ERR(create_patch_file(&patch_file, path_with_spaces_unidiff, pool));
 
   SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                     FALSE, /* reverse */

Modified: subversion/branches/svn-bisect/subversion/tests/libsvn_subr/auth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/tests/libsvn_subr/auth-test.c?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/tests/libsvn_subr/auth-test.c (original)
+++ subversion/branches/svn-bisect/subversion/tests/libsvn_subr/auth-test.c Tue Aug 16 09:38:37 2011
@@ -54,6 +54,9 @@ test_platform_specific_auth_providers(ap
 #ifdef SVN_HAVE_KWALLET
   number_of_providers += 2;
 #endif
+#ifdef SVN_HAVE_GPG_AGENT
+  number_of_providers += 1;
+#endif
 #ifdef SVN_HAVE_KEYCHAIN_SERVICES
   number_of_providers += 2;
 #endif

Modified: subversion/branches/svn-bisect/subversion/tests/libsvn_wc/create_wc_for_upgrade.sh
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/tests/libsvn_wc/create_wc_for_upgrade.sh?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/tests/libsvn_wc/create_wc_for_upgrade.sh (original)
+++ subversion/branches/svn-bisect/subversion/tests/libsvn_wc/create_wc_for_upgrade.sh Tue Aug 16 09:38:37 2011
@@ -83,10 +83,10 @@ echo epsilon > epsilon
 ### row is created).
 
 # a file with just .working
-### what comes after epsilon??
-echo lambda > lambda
-"${SVN}" add lambda
-"${SVN}" propset l-prop l-value lambda
+# zeta = epsilon+1
+echo zeta > zeta
+"${SVN}" add zeta
+"${SVN}" propset z-prop z-value zeta
 
 # a file with .base and .working
 "${SVN}" propset b-more b-value2 beta

Modified: subversion/branches/svn-bisect/subversion/tests/libsvn_wc/db-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/tests/libsvn_wc/db-test.c?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/tests/libsvn_wc/db-test.c (original)
+++ subversion/branches/svn-bisect/subversion/tests/libsvn_wc/db-test.c Tue Aug 16 09:38:37 2011
@@ -140,7 +140,7 @@ static const char * const TESTING_DATA =
   "  null, null, null, null);"
   "insert into nodes values ("
   "  1, 'J/J-e', 0, 'J', 1, 'J/J-e', 1, 'normal',"
-  "  null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "',"
+  "  null, 'other/place', 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "',"
   "  null, null, null, null);"
   "insert into nodes values ("
   "  1, 'J/J-e/J-e-a', 0, 'J/J-e', 1, 'J/J-e/J-e-a', 1, 'normal',"
@@ -172,7 +172,7 @@ static const char * const TESTING_DATA =
   "  15, null, null, null);"
   "insert into nodes values ("
   "  1, 'K/K-b', 0, 'K', 1, 'K/K-b', 1, 'normal',"
-  "  null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "',"
+  "  null, 'moved/away', 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "',"
   "  15, null, null, null);"
   ""
    /* Load data into NODES table;
@@ -228,8 +228,12 @@ static const char * const TESTING_DATA =
   "  1, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 2, " TIME_2s ", '" AUTHOR_2 "',"
   "  10, null, null, null);"
   "insert into nodes values ("
+  "  1, 'moved/file', 0, 'moved', 2, 'moved/file', 2, 'base-deleted',"
+  "  0, 'J/J-d', 'file', '()', null, '$sha1$" SHA1_1 "', null, 2, " TIME_2s ", '" AUTHOR_2 "',"
+  "  10, null, null, null);"
+  "insert into nodes values ("
   "  1, 'J/J-e', 1, 'J', null, null, null, 'normal',"
-  "  0, 'other/place', 'dir', '()', null, null, null, null, null, null,"
+  "  0, null, 'dir', '()', null, null, null, null, null, null,"
   "  null, null, null, null);"
   "insert into nodes values ("
   "  1, 'J/J-e/J-e-a', 1, 'J/J-e', null, null, null, 'normal',"
@@ -241,7 +245,7 @@ static const char * const TESTING_DATA =
   "  null, null, null, null);"
   "insert into nodes values ("
   "  1, 'J/J-e', 2, 'J', null, null, null, 'base-deleted',"
-  "  0, 'other/place', 'dir', '()', null, null, null, null, null, null,"
+  "  0, null, 'dir', '()', null, null, null, null, null, null,"
   "  null, null, null, null);"
   "insert into nodes values ("
   "  1, 'J/J-e/J-e-a', 2, 'J/J-e', null, null, null, 'base-deleted',"
@@ -273,7 +277,7 @@ static const char * const TESTING_DATA =
   "  null, null, null, null);"
   "insert into nodes values ("
   "  1, 'K/K-b', 1, 'K', null, null, null, 'base-deleted',"
-  "  0, 'moved/away', 'file', '()', null, null, null, null, null, null,"
+  "  0, null, 'file', '()', null, null, null, null, null, null,"
   "  null, null, null, null);"
   "insert into nodes values ("
   "  1, 'L', 1, '', null, null, null, 'normal',"
@@ -295,6 +299,22 @@ static const char * const TESTING_DATA =
   "  1, 'L/L-a/L-a-a', 2, 'L/L-a', null, null, null, 'base-deleted',"
   "  0, null, 'dir', '()', 'immediates', null, null, null, null, null,"
   "  null, null, null, null);"
+  "insert into nodes values ("
+  "  1, 'other/place', 2, 'other', null, null, null, 'normal',"
+  "  1, null, 'dir', '()', 'immediates', null, null, null, null, null,"
+  "  null, null, null, null);"
+  "insert into nodes values ("
+  "  1, 'other/place/J-e-a', 2, 'other/place', null, null, null, 'normal',"
+  "  0, null, 'dir', '()', 'immediates', null, null, null, null, null,"
+  "  null, null, null, null);"
+  "insert into nodes values ("
+  "  1, 'other/place/J-e-b', 2, 'other/place', null, null, null, 'normal',"
+  "  null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "',"
+  "  null, null, null, null);"
+  "insert into nodes values ("
+  "  1, 'other/place/J-e-b/Jeba', 0, 'other/place/J-e-b', null, null, null, 'normal',"
+  "  null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "',"
+  "  15, null, null, null);"
    "insert into actual_node values ("
    "  1, 'I', '', null, null, null, null, null, 'changelist', null, "
    "  null, null, null, null, null);"
@@ -888,6 +908,8 @@ test_scan_addition(apr_pool_t *pool)
   const char *original_root_url;
   const char *original_uuid;
   svn_revnum_t original_revision;
+  const char *moved_from_abspath;
+  const char *delete_op_root_abspath;
 
   SVN_ERR(create_open(&db, &local_abspath, "test_scan_addition", pool));
 
@@ -896,7 +918,7 @@ test_scan_addition(apr_pool_t *pool)
             &status, &op_root_abspath,
             &repos_relpath, &repos_root_url, &repos_uuid,
             &original_repos_relpath, &original_root_url, &original_uuid,
-            &original_revision,
+            &original_revision, NULL, NULL,
             db, svn_dirent_join(local_abspath, "J", pool),
             pool, pool));
   SVN_TEST_ASSERT(status == svn_wc__db_status_added);
@@ -914,7 +936,7 @@ test_scan_addition(apr_pool_t *pool)
             &status, &op_root_abspath,
             &repos_relpath, &repos_root_url, &repos_uuid,
             &original_repos_relpath, &original_root_url, &original_uuid,
-            &original_revision,
+            &original_revision, NULL, NULL,
             db, svn_dirent_join(local_abspath, "J/J-a", pool),
             pool, pool));
   SVN_TEST_ASSERT(status == svn_wc__db_status_added);
@@ -932,12 +954,16 @@ test_scan_addition(apr_pool_t *pool)
             &status, &op_root_abspath,
             &repos_relpath, &repos_root_url, &repos_uuid,
             &original_repos_relpath, &original_root_url, &original_uuid,
-            &original_revision,
+            &original_revision, &moved_from_abspath, &delete_op_root_abspath,
             db, svn_dirent_join(local_abspath, "J/J-d", pool),
             pool, pool));
   SVN_TEST_ASSERT(status == svn_wc__db_status_moved_here);
   SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-d",
                                    op_root_abspath, pool));
+  SVN_TEST_ASSERT(validate_abspath(local_abspath, "moved/file",
+                                   moved_from_abspath, pool));
+  SVN_TEST_ASSERT(validate_abspath(local_abspath, "moved/file",
+                                   delete_op_root_abspath, pool));
   SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-d");
   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
@@ -951,7 +977,7 @@ test_scan_addition(apr_pool_t *pool)
             &status, &op_root_abspath,
             &repos_relpath, &repos_root_url, &repos_uuid,
             &original_repos_relpath, &original_root_url, &original_uuid,
-            &original_revision,
+            &original_revision, NULL, NULL,
             db, svn_dirent_join(local_abspath, "J/J-b", pool),
             pool, pool));
   SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
@@ -970,7 +996,7 @@ test_scan_addition(apr_pool_t *pool)
             &status, &op_root_abspath,
             &repos_relpath, &repos_root_url, &repos_uuid,
             &original_repos_relpath, &original_root_url, &original_uuid,
-            &original_revision,
+            &original_revision, NULL, NULL,
             db, svn_dirent_join(local_abspath, "J/J-b/J-b-a", pool),
             pool, pool));
   SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
@@ -989,7 +1015,7 @@ test_scan_addition(apr_pool_t *pool)
             &status, &op_root_abspath,
             &repos_relpath, &repos_root_url, &repos_uuid,
             &original_repos_relpath, &original_root_url, &original_uuid,
-            &original_revision,
+            &original_revision, NULL, NULL,
             db, svn_dirent_join(local_abspath, "J/J-b/J-b-b", pool),
             pool, pool));
   SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
@@ -1015,6 +1041,7 @@ test_scan_deletion(apr_pool_t *pool)
   const char *base_del_abspath;
   const char *work_del_abspath;
   const char *moved_to_abspath;
+  const char *copy_op_root_abspath;
 
   SVN_ERR(create_open(&db, &local_abspath, "test_scan_deletion", pool));
 
@@ -1023,6 +1050,7 @@ test_scan_deletion(apr_pool_t *pool)
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            &copy_op_root_abspath,
             db, svn_dirent_join(local_abspath, "J/J-e", pool),
             pool, pool));
   SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-e",
@@ -1031,26 +1059,32 @@ test_scan_deletion(apr_pool_t *pool)
                                    moved_to_abspath, pool));
   SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-e",
                                    work_del_abspath, pool));
+  SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place",
+                                   copy_op_root_abspath, pool));
 
   /* Node was moved elsewhere (child of operation root). */
   SVN_ERR(svn_wc__db_scan_deletion(
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            &copy_op_root_abspath,
             db, svn_dirent_join(local_abspath, "J/J-e/J-e-a", pool),
             pool, pool));
   SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-e",
                                    base_del_abspath, pool));
-  SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place",
+  SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place/J-e-a",
                                    moved_to_abspath, pool));
   SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-e",
                                    work_del_abspath, pool));
+  SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place",
+                                   copy_op_root_abspath, pool));
 
   /* Root of delete. Parent is a WORKING node. */
   SVN_ERR(svn_wc__db_scan_deletion(
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            NULL,
             db, svn_dirent_join(local_abspath, "J/J-c", pool),
             pool, pool));
   /* Implicit delete of "J" (via replacement).  */
@@ -1065,6 +1099,7 @@ test_scan_deletion(apr_pool_t *pool)
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            NULL,
             db, svn_dirent_join(local_abspath, "J/J-c/J-c-a", pool),
             pool, pool));
   /* Implicit delete of "J" (via replacement).  */
@@ -1079,6 +1114,7 @@ test_scan_deletion(apr_pool_t *pool)
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            NULL,
             db, svn_dirent_join(local_abspath, "J/J-e/J-e-b/Jeba", pool),
             pool, pool));
   /* ### I don't understand this.  "J/J-e/J-e-b/Jeba" is a deleted
@@ -1086,7 +1122,7 @@ test_scan_deletion(apr_pool_t *pool)
      Why does base_del_abspath refer to "J-e"?  */
   SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-e",
                                    base_del_abspath, pool));
-  SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place",
+  SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place/J-e-b/Jeba",
                                    moved_to_abspath, pool));
   SVN_TEST_ASSERT(work_del_abspath == NULL);
 
@@ -1095,6 +1131,7 @@ test_scan_deletion(apr_pool_t *pool)
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            NULL,
             db, svn_dirent_join(local_abspath, "J/J-f/J-f-a", pool),
             pool, pool));
   /* Implicit delete of "J" (via replacement).  */
@@ -1108,6 +1145,7 @@ test_scan_deletion(apr_pool_t *pool)
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            NULL,
             db, svn_dirent_join(local_abspath, "K", pool),
             pool, pool));
   SVN_TEST_ASSERT(validate_abspath(local_abspath, "K",
@@ -1120,6 +1158,7 @@ test_scan_deletion(apr_pool_t *pool)
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            NULL,
             db, svn_dirent_join(local_abspath, "K/K-a", pool),
             pool, pool));
   SVN_TEST_ASSERT(validate_abspath(local_abspath, "K",
@@ -1132,12 +1171,15 @@ test_scan_deletion(apr_pool_t *pool)
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            &copy_op_root_abspath,
             db, svn_dirent_join(local_abspath, "K/K-b", pool),
             pool, pool));
   SVN_TEST_ASSERT(validate_abspath(local_abspath, "K/K-b",
                                    base_del_abspath, pool));
   SVN_TEST_ASSERT(validate_abspath(local_abspath, "moved/away",
                                    moved_to_abspath, pool));
+  SVN_TEST_ASSERT(validate_abspath(local_abspath, "moved/away",
+                                   copy_op_root_abspath, pool));
   SVN_TEST_ASSERT(work_del_abspath == NULL);
 
   /* Subtree deletion of added tree. Start at child.  */
@@ -1145,6 +1187,7 @@ test_scan_deletion(apr_pool_t *pool)
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            NULL,
             db, svn_dirent_join(local_abspath, "L/L-a/L-a-a", pool),
             pool, pool));
   SVN_TEST_ASSERT(base_del_abspath == NULL);
@@ -1157,6 +1200,7 @@ test_scan_deletion(apr_pool_t *pool)
             &base_del_abspath,
             &moved_to_abspath,
             &work_del_abspath,
+            NULL,
             db, svn_dirent_join(local_abspath, "L/L-a", pool),
             pool, pool));
   SVN_TEST_ASSERT(base_del_abspath == NULL);

Modified: subversion/branches/svn-bisect/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/tests/libsvn_wc/op-depth-test.c?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/branches/svn-bisect/subversion/tests/libsvn_wc/op-depth-test.c Tue Aug 16 09:38:37 2011
@@ -40,6 +40,7 @@
 
 #include "private/svn_wc_private.h"
 #include "private/svn_sqlite.h"
+#include "private/svn_dep_compat.h"
 #include "../../libsvn_wc/wc.h"
 #include "../../libsvn_wc/wc_db.h"
 #define SVN_WC__I_AM_WC_DB
@@ -267,41 +268,19 @@ wc_move(svn_test__sandbox_t *b, const ch
 static svn_error_t *
 add_and_commit_greek_tree(svn_test__sandbox_t *b)
 {
-  const char *greek_tree_dirs[8] =
-  {
-    "A",
-    "A/B",
-    "A/B/E",
-    "A/B/F",
-    "A/C",
-    "A/D",
-    "A/D/G",
-    "A/D/H"
-  };
-  const char *greek_tree_files[12][2] =
-  {
-    { "iota",         "This is the file 'iota'.\n" },
-    { "A/mu",         "This is the file 'mu'.\n" },
-    { "A/B/lambda",   "This is the file 'lambda'.\n" },
-    { "A/B/E/alpha",  "This is the file 'alpha'.\n" },
-    { "A/B/E/beta",   "This is the file 'beta'.\n" },
-    { "A/D/gamma",    "This is the file 'gamma'.\n" },
-    { "A/D/G/pi",     "This is the file 'pi'.\n" },
-    { "A/D/G/rho",    "This is the file 'rho'.\n" },
-    { "A/D/G/tau",    "This is the file 'tau'.\n" },
-    { "A/D/H/chi",    "This is the file 'chi'.\n" },
-    { "A/D/H/psi",    "This is the file 'psi'.\n" },
-    { "A/D/H/omega",  "This is the file 'omega'.\n" }
-  };
-  int i;
-
-  for (i = 0; i < 8; i++)
-    SVN_ERR(wc_mkdir(b, greek_tree_dirs[i]));
+  const struct svn_test__tree_entry_t *node;
 
-  for (i = 0; i < 12; i++)
+  for (node = svn_test__greek_tree_nodes; node->path; node++)
     {
-      file_write(b, greek_tree_files[i][0], greek_tree_files[i][1]);
-      SVN_ERR(wc_add(b, greek_tree_files[i][0]));
+      if (node->contents)
+        {
+          file_write(b, node->path, node->contents);
+          SVN_ERR(wc_add(b, node->path));
+        }
+      else
+        {
+          SVN_ERR(wc_mkdir(b, node->path));
+        }
     }
 
   SVN_ERR(wc_commit(b, ""));
@@ -2784,7 +2763,7 @@ do_delete(svn_test__sandbox_t *b,
   SVN_ERR(insert_actual(b, actual_before));
   SVN_ERR(check_db_rows(b, "", before));
   SVN_ERR(check_db_actual(b, actual_before));
-  SVN_ERR(svn_wc__db_op_delete(b->wc_ctx->db, local_abspath,
+  SVN_ERR(svn_wc__db_op_delete(b->wc_ctx->db, local_abspath, NULL,
                                NULL, NULL /* notification */,
                                NULL, NULL /* cancellation */,
                                b->pool));

Modified: subversion/branches/svn-bisect/subversion/tests/svn_test.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/tests/svn_test.h?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/tests/svn_test.h (original)
+++ subversion/branches/svn-bisect/subversion/tests/svn_test.h Tue Aug 16 09:38:37 2011
@@ -177,6 +177,27 @@ apr_uint32_t svn_test_rand(apr_uint32_t 
 void svn_test_add_dir_cleanup(const char *path);
 
 
+/* A simple representation for a tree node. */
+typedef struct svn_test__tree_entry_t
+{
+  const char *path;     /* relpath of this node */
+  const char *contents; /* text contents, or NULL for a directory */
+}
+svn_test__tree_entry_t;
+
+/* Wrapper for an array of svn_test__tree_entry_t's. */
+typedef struct svn_test__tree_t
+{
+  svn_test__tree_entry_t *entries;
+  int num_entries;
+}
+svn_test__tree_t;
+
+
+/* The standard Greek tree, terminated by a node with path=NULL. */
+extern const svn_test__tree_entry_t svn_test__greek_tree_nodes[21];
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/svn-bisect/subversion/tests/svn_test_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/tests/svn_test_fs.c?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/tests/svn_test_fs.c (original)
+++ subversion/branches/svn-bisect/subversion/tests/svn_test_fs.c Tue Aug 16 09:38:37 2011
@@ -135,6 +135,9 @@ create_fs(svn_fs_t **fs_p,
   return SVN_NO_ERROR;
 }
 
+/* If OPTS specifies a filesystem type of 'fsfs' and provides a config file,
+ * copy that file into the filesystem FS and set *MUST_REOPEN to TRUE, else
+ * set *MUST_REOPEN to FALSE. */
 static svn_error_t *
 maybe_install_fsfs_conf(svn_fs_t *fs,
                         const svn_test_opts_t *opts,
@@ -149,7 +152,7 @@ maybe_install_fsfs_conf(svn_fs_t *fs,
   return svn_io_copy_file(opts->config_file,
                           svn_path_join(svn_fs_path(fs, pool),
                                         "fsfs.conf", pool),
-                          FALSE,
+                          FALSE /* copy_perms */,
                           pool);
 }
 
@@ -569,6 +572,30 @@ svn_test__txn_script_exec(svn_fs_root_t 
 }
 
 
+const struct svn_test__tree_entry_t svn_test__greek_tree_nodes[21] = {
+  { "iota",         "This is the file 'iota'.\n" },
+  { "A",            NULL },
+  { "A/mu",         "This is the file 'mu'.\n" },
+  { "A/B",          NULL },
+  { "A/B/lambda",   "This is the file 'lambda'.\n" },
+  { "A/B/E",        NULL },
+  { "A/B/E/alpha",  "This is the file 'alpha'.\n" },
+  { "A/B/E/beta",   "This is the file 'beta'.\n" },
+  { "A/B/F",        NULL },
+  { "A/C",          NULL },
+  { "A/D",          NULL },
+  { "A/D/gamma",    "This is the file 'gamma'.\n" },
+  { "A/D/G",        NULL },
+  { "A/D/G/pi",     "This is the file 'pi'.\n" },
+  { "A/D/G/rho",    "This is the file 'rho'.\n" },
+  { "A/D/G/tau",    "This is the file 'tau'.\n" },
+  { "A/D/H",        NULL },
+  { "A/D/H/chi",    "This is the file 'chi'.\n" },
+  { "A/D/H/psi",    "This is the file 'psi'.\n" },
+  { "A/D/H/omega",  "This is the file 'omega'.\n" },
+  { NULL,           NULL },
+};
+
 svn_error_t *
 svn_test__check_greek_tree(svn_fs_root_t *root,
                            apr_pool_t *pool)
@@ -576,115 +603,47 @@ svn_test__check_greek_tree(svn_fs_root_t
   svn_stream_t *rstream;
   svn_stringbuf_t *rstring;
   svn_stringbuf_t *content;
-  int i;
-
-  const char *file_contents[12][2] =
-  {
-    { "iota", "This is the file 'iota'.\n" },
-    { "A/mu", "This is the file 'mu'.\n" },
-    { "A/B/lambda", "This is the file 'lambda'.\n" },
-    { "A/B/E/alpha", "This is the file 'alpha'.\n" },
-    { "A/B/E/beta", "This is the file 'beta'.\n" },
-    { "A/D/gamma", "This is the file 'gamma'.\n" },
-    { "A/D/G/pi", "This is the file 'pi'.\n" },
-    { "A/D/G/rho", "This is the file 'rho'.\n" },
-    { "A/D/G/tau", "This is the file 'tau'.\n" },
-    { "A/D/H/chi", "This is the file 'chi'.\n" },
-    { "A/D/H/psi", "This is the file 'psi'.\n" },
-    { "A/D/H/omega", "This is the file 'omega'.\n" }
-  };
+  const struct svn_test__tree_entry_t *node;
 
   /* Loop through the list of files, checking for matching content. */
-  for (i = 0; i < 12; i++)
+  for (node = svn_test__greek_tree_nodes; node->path; node++)
     {
-      SVN_ERR(svn_fs_file_contents(&rstream, root,
-                                   file_contents[i][0], pool));
-      SVN_ERR(svn_test__stream_to_string(&rstring, rstream, pool));
-      content = svn_stringbuf_create(file_contents[i][1], pool);
-      if (! svn_stringbuf_compare(rstring, content))
-        return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
-                                 "data read != data written in file '%s'.",
-                                 file_contents[i][0]);
+      if (node->contents)
+        {
+          SVN_ERR(svn_fs_file_contents(&rstream, root, node->path, pool));
+          SVN_ERR(svn_test__stream_to_string(&rstring, rstream, pool));
+          content = svn_stringbuf_create(node->contents, pool);
+          if (! svn_stringbuf_compare(rstring, content))
+            return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
+                                     "data read != data written in file '%s'.",
+                                     node->path);
+        }
     }
   return SVN_NO_ERROR;
 }
 
-/**
- * Loads the greek tree in a directory at ROOT_DIR under transaction TXN_ROOT.
- * ROOT_DIR should be created by the caller.
- *
- * Note: this function will not commit the transaction.
- */
 svn_error_t *
 svn_test__create_greek_tree_at(svn_fs_root_t *txn_root,
                                const char *root_dir,
                                apr_pool_t *pool)
 {
-  char *iota =     svn_relpath_join(root_dir, "iota", pool);
-  char *A =        svn_relpath_join(root_dir, "A", pool);
-  char *Amu =      svn_relpath_join(root_dir, "A/mu", pool);
-  char *AB =       svn_relpath_join(root_dir, "A/B", pool);
-  char *ABlambda = svn_relpath_join(root_dir, "A/B/lambda", pool);
-  char *ABE =      svn_relpath_join(root_dir, "A/B/E", pool);
-  char *ABEalpha = svn_relpath_join(root_dir, "A/B/E/alpha", pool);
-  char *ABEbeta =  svn_relpath_join(root_dir, "A/B/E/beta", pool);
-  char *ABF =      svn_relpath_join(root_dir, "A/B/F", pool);
-  char *AC =       svn_relpath_join(root_dir, "A/C", pool);
-  char *AD =       svn_relpath_join(root_dir, "A/D", pool);
-  char *ADgamma =  svn_relpath_join(root_dir, "A/D/gamma", pool);
-  char *ADG =      svn_relpath_join(root_dir, "A/D/G", pool);
-  char *ADGpi =    svn_relpath_join(root_dir, "A/D/G/pi", pool);
-  char *ADGrho =   svn_relpath_join(root_dir, "A/D/G/rho", pool);
-  char *ADGtau =   svn_relpath_join(root_dir, "A/D/G/tau", pool);
-  char *ADH =      svn_relpath_join(root_dir, "A/D/H", pool);
-  char *ADHchi =   svn_relpath_join(root_dir, "A/D/H/chi", pool);
-  char *ADHpsi =   svn_relpath_join(root_dir, "A/D/H/psi", pool);
-  char *ADHomega = svn_relpath_join(root_dir, "A/D/H/omega", pool);
-
-  SVN_ERR(svn_fs_make_file(txn_root, iota, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, iota, "This is the file 'iota'.\n", pool));
-  SVN_ERR(svn_fs_make_dir  (txn_root, A, pool));
-  SVN_ERR(svn_fs_make_file(txn_root, Amu, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, Amu, "This is the file 'mu'.\n", pool));
-  SVN_ERR(svn_fs_make_dir  (txn_root, AB, pool));
-  SVN_ERR(svn_fs_make_file(txn_root, ABlambda, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, ABlambda, "This is the file 'lambda'.\n", pool));
-  SVN_ERR(svn_fs_make_dir  (txn_root, ABE, pool));
-  SVN_ERR(svn_fs_make_file(txn_root, ABEalpha, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, ABEalpha, "This is the file 'alpha'.\n", pool));
-  SVN_ERR(svn_fs_make_file(txn_root, ABEbeta, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, ABEbeta, "This is the file 'beta'.\n", pool));
-  SVN_ERR(svn_fs_make_dir  (txn_root, ABF, pool));
-  SVN_ERR(svn_fs_make_dir  (txn_root, AC, pool));
-  SVN_ERR(svn_fs_make_dir  (txn_root, AD, pool));
-  SVN_ERR(svn_fs_make_file(txn_root, ADgamma, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, ADgamma, "This is the file 'gamma'.\n", pool));
-  SVN_ERR(svn_fs_make_dir  (txn_root, ADG, pool));
-  SVN_ERR(svn_fs_make_file(txn_root, ADGpi, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, ADGpi, "This is the file 'pi'.\n", pool));
-  SVN_ERR(svn_fs_make_file(txn_root, ADGrho, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, ADGrho, "This is the file 'rho'.\n", pool));
-  SVN_ERR(svn_fs_make_file(txn_root, ADGtau, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, ADGtau, "This is the file 'tau'.\n", pool));
-  SVN_ERR(svn_fs_make_dir  (txn_root, ADH, pool));
-  SVN_ERR(svn_fs_make_file(txn_root, ADHchi, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, ADHchi, "This is the file 'chi'.\n", pool));
-  SVN_ERR(svn_fs_make_file(txn_root, ADHpsi, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, ADHpsi, "This is the file 'psi'.\n", pool));
-  SVN_ERR(svn_fs_make_file(txn_root, ADHomega, pool));
-  SVN_ERR(svn_test__set_file_contents
-          (txn_root, ADHomega, "This is the file 'omega'.\n", pool));
+  const struct svn_test__tree_entry_t *node;
+
+  for (node = svn_test__greek_tree_nodes; node->path; node++)
+    {
+      const char *path = svn_relpath_join(root_dir, node->path, pool);
+
+      if (node->contents)
+        {
+          SVN_ERR(svn_fs_make_file(txn_root, path, pool));
+          SVN_ERR(svn_test__set_file_contents(txn_root, path, node->contents,
+                                              pool));
+        }
+      else
+        {
+          SVN_ERR(svn_fs_make_dir(txn_root, path, pool));
+        }
+    }
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/svn-bisect/subversion/tests/svn_test_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/tests/svn_test_fs.h?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/tests/svn_test_fs.h (original)
+++ subversion/branches/svn-bisect/subversion/tests/svn_test_fs.h Tue Aug 16 09:38:37 2011
@@ -102,25 +102,6 @@ svn_test__get_file_contents(svn_fs_root_
 
 /* The Helper Functions to End All Helper Functions */
 
-/* Structure used for testing integrity of the filesystem's revision
-   using validate_tree(). */
-typedef struct svn_test__tree_entry_t
-{
-  const char *path;     /* full path of this node */
-  const char *contents; /* text contents (NULL for directories) */
-}
-svn_test__tree_entry_t;
-
-
-/* Wrapper for an array of the above svn_test__tree_entry_t's.  */
-typedef struct svn_test__tree_t
-{
-  svn_test__tree_entry_t *entries;
-  int num_entries;
-}
-svn_test__tree_t;
-
-
 /* Given a transaction or revision root (ROOT), check to see if the
    tree that grows from that root has all the path entries, and only
    those entries, passed in the array ENTRIES (which is an array of
@@ -168,7 +149,10 @@ svn_error_t *
 svn_test__create_greek_tree(svn_fs_root_t *txn_root,
                             apr_pool_t *pool);
 
-/* Create the Greek Tree under TXN_ROOT at dir ROOT_DIR.  */
+/* Create the Greek Tree under TXN_ROOT at dir ROOT_DIR.
+ * ROOT_DIR should be created by the caller.
+ *
+ * Note: this function will not commit the transaction.  */
 svn_error_t *
 svn_test__create_greek_tree_at(svn_fs_root_t *txn_root,
                                const char *root_dir,

Modified: subversion/branches/svn-bisect/tools/dev/benchmarks/suite1/benchmark.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/tools/dev/benchmarks/suite1/benchmark.py?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/tools/dev/benchmarks/suite1/benchmark.py (original)
+++ subversion/branches/svn-bisect/tools/dev/benchmarks/suite1/benchmark.py Tue Aug 16 09:38:37 2011
@@ -164,10 +164,10 @@ class Timings:
     s = ['COMPARE %s to %s' % (othername, selfname)]
 
     if TOTAL_RUN in self.timings and TOTAL_RUN in other.timings:
-      s.append('  %s times: %5.1f seconds avg for %s' % (TOTAL_RUN,
-                                                         othertotal, othername))
-      s.append('  %s        %5.1f seconds avg for %s' % (' ' * len(TOTAL_RUN),
-                                                         selftotal, selfname))
+      s.append('  %s timings: %5.1f seconds avg for %s'
+               % (TOTAL_RUN, othertotal, othername))
+      s.append('  %s          %5.1f seconds avg for %s'
+               % (' ' * len(TOTAL_RUN), selftotal, selfname))
 
 
     s.append('      min              max              avg         operation')
@@ -201,9 +201,9 @@ class Timings:
                  name))
 
     s.extend([
-         '("1.23|+0.45"  means factor=1.23, difference in seconds = 0.45',
-         'factor < 1 or difference < 0 means \'%s\' is faster than \'%s\')'
-           % (self.name, othername)])
+      '(legend: "1.23|+0.45" means: slower by factor 1.23 and by 0.45 seconds;',
+      ' factor < 1 and difference < 0 means \'%s\' is faster than \'%s\')'
+      % (self.name, othername)])
 
     return '\n'.join(s)
 
@@ -418,7 +418,8 @@ def run(levels, spread, N):
 
       so, se = svn('--version')
       if not so:
-        print "Can't find svn."
+        ### options comes from the global namespace; it should be passed
+        print "Can't find svn at", options.svn
         exit(1)
       version = ', '.join([s.strip() for s in so.split('\n')[:2]])
 
@@ -565,6 +566,9 @@ def cmd_run(timings_path, levels, spread
   print '\n\nHi, going to run a Subversion benchmark series of %d runs...' % N
 
   ### UGH! should pass to run()
+  ### neels: Today I contemplated doing that, but at the end of the day
+  ###        it merely blows up the code without much benefit. If this
+  ###        ever becomes part of an imported python package, call again.
   global timings
 
   if os.path.isfile(timings_path):

Modified: subversion/branches/svn-bisect/tools/dev/benchmarks/suite1/run
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/tools/dev/benchmarks/suite1/run?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/tools/dev/benchmarks/suite1/run (original)
+++ subversion/branches/svn-bisect/tools/dev/benchmarks/suite1/run Tue Aug 16 09:38:37 2011
@@ -19,11 +19,15 @@
 
 # Where are the svn binaries you want to benchmark?
 if [ "$USER" = "neels" ]; then
-  SVN_1_6="$HOME/pat/stable/prefix/bin/svn"
-  SVN_trunk="$HOME/pat/trunk/prefix/bin/svn"
+  SVN_A_NAME="1.7.x"
+  SVN_A="$HOME/pat/bench/prefix/bin/svn"
+  SVN_B_NAME="trunk"
+  SVN_B="$HOME/pat/trunk/prefix/bin/svn"
 else
-  SVN_1_6="$HOME/src/svn-1.6.x/subversion/svn/svn"
-  SVN_trunk="$HOME/src/svn/subversion/svn/svn"
+  SVN_A_NAME="1.6"
+  SVN_A="$HOME/src/svn-1.6.x/subversion/svn/svn"
+  SVN_B_NAME="trunk"
+  SVN_B="$HOME/src/svn/subversion/svn/svn"
 fi
 
 benchmark="$PWD/benchmark.py"
@@ -44,9 +48,9 @@ batch(){
   echo "---------------------------------------------------------------------"
   echo
   echo "Results for dir levels: $levels  spread: $spread"
-  "$benchmark" "--svn=${SVN_1_6}" run ${pre}1.6 $levels $spread $N >/dev/null
-  "$benchmark" "--svn=${SVN_trunk}" run ${pre}trunk $levels $spread $N > /dev/null
-  "$benchmark" compare ${pre}1.6 ${pre}trunk
+  "$benchmark" "--svn=$SVN_A" run "${pre}$SVN_A_NAME" $levels $spread $N >/dev/null
+  "$benchmark" "--svn=$SVN_B" run "${pre}$SVN_B_NAME" $levels $spread $N >/dev/null
+  "$benchmark" compare "${pre}$SVN_A_NAME" "${pre}$SVN_B_NAME"
 }
 
 N=6
@@ -80,11 +84,11 @@ batch $cl $cs $N
 echo ""
 echo =========================================================================
 echo ""
-"$benchmark" combine total_1.6 *x*_1.6 >/dev/null
-"$benchmark" combine total_trunk *x*_trunk >/dev/null
+"$benchmark" combine "total_$SVN_A_NAME" *x*"_$SVN_A_NAME" >/dev/null
+"$benchmark" combine "total_$SVN_B_NAME" *x*"_$SVN_B_NAME" >/dev/null
 
 echo "comparing averaged totals..."
-"$benchmark" compare total_1.6 total_trunk
+"$benchmark" compare "total_$SVN_A_NAME" "total_$SVN_B_NAME"
 
 echo ""
 echo "Had started at $started,"

Modified: subversion/branches/svn-bisect/tools/dev/unix-build/Makefile.svn
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/tools/dev/unix-build/Makefile.svn?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/tools/dev/unix-build/Makefile.svn (original)
+++ subversion/branches/svn-bisect/tools/dev/unix-build/Makefile.svn Tue Aug 16 09:38:37 2011
@@ -1448,12 +1448,11 @@ svn-check-swig-py:
 # We add the svn prefix to PATH here because the ruby tests
 # attempt to start an svnserve binary found in PATH.
 svn-check-swig-rb:
-	(cd $(svn_builddir)/subversion/bindings/swig/ruby/test && \
+	(cd $(svn_builddir) && \
 		env RUBYLIB=$(RUBYLIB) \
 		LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) \
 		PATH=$(SVN_PREFIX)/bin:$$PATH \
-		$(PREFIX)/ruby/bin/ruby run-test.rb \
-			--verbose=verbose 2>&1) | \
+			make check-swig-rb 2>&1) | \
 			tee $(svn_builddir)/tests.log.bindings.rb
 
 svn-check-javahl:

Modified: subversion/branches/svn-bisect/tools/dist/backport.pl
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/tools/dist/backport.pl?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/tools/dist/backport.pl (original)
+++ subversion/branches/svn-bisect/tools/dist/backport.pl Tue Aug 16 09:38:37 2011
@@ -28,6 +28,7 @@ my $SVN = $ENV{SVN} || 'svn'; # passed u
 my $VIM = 'vim';
 my $STATUS = './STATUS';
 my $BRANCHES = '^/subversion/branches';
+my $WET_RUN = qw[false true][1]; # don't commit
 
 sub usage {
   my $basename = $0;
@@ -61,27 +62,33 @@ sub merge {
   my %entry = @_;
 
   my ($logmsg_fh, $logmsg_filename) = tempfile();
-  my $mergeargs;
+  my ($mergeargs, $pattern);
 
   my $backupfile = "backport_pl.$$.tmp";
 
   if ($entry{branch}) {
+    # NOTE: This doesn't escape the branch into the pattern.
+    $pattern = printf '^ [*] %s branch\|Branch:\n *%s', $entry{branch}, $entry{branch};
     $mergeargs = "--reintegrate $BRANCHES/$entry{branch}";
-    print $logmsg_fh "Reintergrate the $BRANCHES/$entry{branch} branch:";
+    print $logmsg_fh "Reintergrate the $entry{header}:";
     print $logmsg_fh "";
-  } else {
+  } elsif (@{$entry{revisions}}) {
+    $pattern = 'r' . $entry{revisions}->[0];
     $mergeargs = join " ", (map { "-c$_" } @{$entry{revisions}}), '^/subversion/trunk';
     if (@{$entry{revisions}} > 1) {
-      print $logmsg_fh "Merge the r$entry{revisions}->[0] group from trunk:";
+      print $logmsg_fh "Merge the $entry{header} from trunk:";
       print $logmsg_fh "";
     } else {
       print $logmsg_fh "Merge r$entry{revisions}->[0] from trunk:";
       print $logmsg_fh "";
     }
+  } else {
+    die "Don't know how to call $entry{header}";
   }
   print $logmsg_fh $_ for @{$entry{entry}};
   close $logmsg_fh or die "Can't close $logmsg_filename: $!";
 
+  $pattern = '\V'.$pattern;
   my $script = <<"EOF";
 #!/bin/sh
 set -e
@@ -89,14 +96,24 @@ $SVN diff > $backupfile
 $SVN revert -R .
 $SVN up
 $SVN merge $mergeargs
-$VIM -e -s -n -N -i NONE -u NONE -c '/^ [*] r$entry{revisions}->[0]/normal! dap' -c wq $STATUS
-$SVN commit -F $logmsg_filename
+$VIM -e -s -n -N -i NONE -u NONE -c '/^ [*] $pattern/normal! dap' -c wq $STATUS
+if $WET_RUN; then
+  $SVN commit -F $logmsg_filename
+else
+  echo "Committing:"
+  $SVN status -q
+  cat $logmsg_filename
+fi
 EOF
 
   $script .= <<"EOF" if $entry{branch};
 reinteg_rev=\`$SVN info $STATUS | sed -ne 's/Last Changed Rev: //p'\`
-$SVN rm $BRANCHES/$entry{branch}\
-        -m "Remove the '$entry{branch}' branch, reintegrated in r\$reinteg_rev."
+if $WET_RUN; then
+  $SVN rm $BRANCHES/$entry{branch}\
+          -m "Remove the '$entry{branch}' branch, reintegrated in r\$reinteg_rev."
+else
+  echo "Removing reintegrated '$entry{branch}' branch"
+fi
 EOF
 
   open SHELL, '|-', qw#/bin/sh -x# or die $!;
@@ -107,6 +124,14 @@ EOF
   unlink $logmsg_filename unless $? or $!;
 }
 
+sub sanitize_branch {
+  local $_ = shift;
+  s#.*/##;
+  s/^\s*//;
+  s/\s*$//;
+  return $_;
+}
+
 # TODO: may need to parse other headers too?
 sub parse_entry {
   my @lines = @_;
@@ -118,6 +143,7 @@ sub parse_entry {
   s/^   // for @_;
 
   # revisions
+  $branch = sanitize_branch $1 if $_[0] =~ /^(\S*) branch$/;
   while ($_[0] =~ /^r/) {
     while ($_[0] =~ s/^r(\d+)(?:,\s*)?//) {
       push @revisions, $1;
@@ -126,25 +152,29 @@ sub parse_entry {
   }
 
   # summary
-  push @logsummary, shift until $_[0] =~ /^\w+:/;
+  push @logsummary, shift until $_[0] =~ /^\s*\w+:/ or not defined $_[0];
 
   # votes
-  unshift @votes, pop until $_[-1] =~ /^Votes:/;
+  unshift @votes, pop until $_[-1] =~ /^\s*Votes:/ or not defined $_[-1];
   pop;
 
   # branch
   while (@_) {
-    shift and next unless $_[0] =~ s/^Branch:\s*//;
-    $branch = (shift || shift || die "Branch header found without value");
-    $branch =~ s#.*/##;
-    $branch =~ s/^\s*//;
-    $branch =~ s/\s*$//;
+    shift and next unless $_[0] =~ s/^\s*Branch:\s*//;
+    $branch = sanitize_branch (shift || shift || die "Branch header found without value");
   }
 
+  # Compute a header.
+  my $header;
+  $header = "r$revisions[0] group" if @revisions;
+  $header = "$branch branch" if $branch;
+  warn "No header for [@lines]" unless $header;
+
   return (
     revisions => [@revisions],
     logsummary => [@logsummary],
     branch => $branch,
+    header => $header,
     votes => [@votes],
     entry => [@lines],
   );
@@ -154,7 +184,7 @@ sub handle_entry {
   my %entry = parse_entry @_;
 
   print "";
-  print "\n>>> The r$entry{revisions}->[0] group:";
+  print "\n>>> The $entry{header}:";
   print join ", ", map { "r$_" } @{$entry{revisions}};
   print "$BRANCHES/$entry{branch}" if $entry{branch};
   print "";

Modified: subversion/branches/svn-bisect/tools/dist/collect_sigs.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/tools/dist/collect_sigs.py?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/tools/dist/collect_sigs.py (original)
+++ subversion/branches/svn-bisect/tools/dist/collect_sigs.py Tue Aug 16 09:38:37 2011
@@ -199,24 +199,6 @@ def save_valid_sig(db, filename, keyid, 
 
   generate_asc_files(config.sigdir)
 
-  # Attempt to copy the results to a remote location
-  try:
-    import paramiko
-
-    client = paramiko.SSHClient()
-    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
-    client.connect(config.ssh['host'], username = config.ssh['user'],
-                   key_filename = config.ssh['key'])
-    sftp = client.open_sftp()
-
-    sftp.put(os.path.join(config.sigdir, filename + '.asc'),
-             os.path.join(config.ssh['dir'], config.version, 'deploy',
-                          filename + '.asc'))
-    client.close()
-  except:
-    # Ignore any errors
-    pass
-
 def verify_sig_for_file(signature, filename):
   args = ['gpg', '--logger-fd', '1', '--no-tty',
           '--status-fd', '2', '--verify', '-',

Modified: subversion/branches/svn-bisect/tools/dist/release.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/tools/dist/release.py?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/tools/dist/release.py (original)
+++ subversion/branches/svn-bisect/tools/dist/release.py Tue Aug 16 09:38:37 2011
@@ -45,6 +45,7 @@ import hashlib
 import tarfile
 import logging
 import datetime
+import tempfile
 import operator
 import itertools
 import subprocess
@@ -341,6 +342,38 @@ def build_env(args):
 #----------------------------------------------------------------------
 # Create release artifacts
 
+def fetch_changes(repos, branch, revision):
+    changes_peg_url = '%s/%s/CHANGES@%d' % (repos, branch, revision)
+    proc = subprocess.Popen(['svn', 'cat', changes_peg_url],
+                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    (stdout, stderr) = proc.communicate()
+    proc.wait()
+    return stdout.split('\n')
+
+
+def compare_changes(repos, branch, revision):
+    # Compare trunk's version of CHANGES with that of the branch,
+    # ignoring any lines in trunk's version precede what *should*
+    # match the contents of the branch's version.  (This allows us to
+    # continue adding new stuff at the top of trunk's CHANGES that
+    # might relate to the *next* major release line.)
+    branch_CHANGES = fetch_changes(repos, branch, revision)
+    trunk_CHANGES = fetch_changes(repos, 'trunk', revision)
+    try:
+        first_matching_line = trunk_CHANGES.index(branch_CHANGES[0])
+    except ValueError:
+        raise RuntimeError('CHANGES not synced between trunk and branch')
+
+    trunk_CHANGES = trunk_CHANGES[first_matching_line:]
+    saw_diff = False
+    import difflib
+    for diff_line in difflib.unified_diff(trunk_CHANGES, branch_CHANGES):
+        saw_diff = True
+        logging.debug('%s', diff_line)
+    if saw_diff:
+        raise RuntimeError('CHANGES not synced between trunk and branch')
+
+
 def roll_tarballs(args):
     'Create the release artifacts.'
     extns = ['zip', 'tar.gz', 'tar.bz2']
@@ -362,21 +395,10 @@ def roll_tarballs(args):
         if not dep.have_usable():
            raise RuntimeError('Cannot find usable %s' % dep.label)
 
-    # Make sure CHANGES is sync'd
     if branch != 'trunk':
-        trunk_CHANGES = '%s/trunk/CHANGES@%d' % (repos, args.revnum)
-        branch_CHANGES = '%s/%s/CHANGES@%d' % (repos, branch,
-                                                        args.revnum)
-        proc = subprocess.Popen(['svn', 'diff', '--summarize', branch_CHANGES,
-                                   trunk_CHANGES],
-                                  stdout=subprocess.PIPE,
-                                  stderr=subprocess.STDOUT)
-        (stdout, stderr) = proc.communicate()
-        proc.wait()
-
-        if stdout:
-            raise RuntimeError('CHANGES not synced between trunk and branch')
-
+        # Make sure CHANGES is sync'd.    
+        compare_changes(repos, branch, args.revnum)
+    
     # Create the output directory
     if not os.path.exists(get_deploydir(args.base_dir)):
         os.mkdir(get_deploydir(args.base_dir))
@@ -491,12 +513,42 @@ def clean_dist(args):
 
 
 #----------------------------------------------------------------------
+# Move to dist
+
+def move_to_dist(args):
+    'Move candidate artifacts to the distribution directory.'
+
+    if not args.dist_dir:
+        assert_people()
+        args.dist_dir = people_dist_dir
+
+    if args.target:
+        target = args.target
+    else:
+        target = os.path.join(os.getenv('HOME'), 'public_html', 'svn',
+                              str(args.version), 'deploy')
+
+    if args.code_name:
+        dirname = args.code_name
+    else:
+        dirname = 'deploy'
+
+    logging.info('Moving %s to dist dir \'%s\'' % (str(args.version),
+                                                   args.dist_dir) )
+    filenames = glob.glob(os.path.join(target,
+                                       'subversion-%s.*' % str(args.version)))
+    for filename in filenames:
+        shutil.copy(filename, args.dist_dir)
+
+
+#----------------------------------------------------------------------
 # Write announcements
 
 def write_news(args):
     'Write text for the Subversion website.'
     data = { 'date' : datetime.date.today().strftime('%Y%m%d'),
              'date_pres' : datetime.date.today().strftime('%Y-%m-%d'),
+             'major-minor' : args.version.base[:3],
              'version' : str(args.version),
              'version_base' : args.version.base,
            }
@@ -550,6 +602,61 @@ def write_announcement(args):
 
 
 #----------------------------------------------------------------------
+# Validate the signatures for a release
+
+key_start = '-----BEGIN PGP SIGNATURE-----\n'
+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.'
+
+    import gnupg
+    gpg = gnupg.GPG()
+
+    if args.target:
+        target = args.target
+    else:
+        target = os.path.join(os.getenv('HOME'), 'public_html', 'svn',
+                              str(args.version), 'deploy')
+
+    good_sigs = {}
+
+    for filename in glob.glob(os.path.join(target, 'subversion-*.asc')):
+        text = open(filename).read()
+        keys = text.split(key_start)
+
+        for key in keys[1:]:
+            fd, fn = tempfile.mkstemp()
+            os.write(fd, key_start + key)
+            os.close(fd)
+            verified = gpg.verify_file(open(fn, 'rb'), filename[:-4])
+            os.unlink(fn)
+
+            if verified.valid:
+                good_sigs[verified.key_id[-8:]] = True
+            else:
+                sys.stderr.write("BAD SIGNATURE for %s\n" % filename)
+                sys.exit(1)
+
+    for id in good_sigs.keys():
+        gpg = subprocess.Popen(['gpg', '--fingerprint', id],
+                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        rc = gpg.wait()
+        gpg_output = gpg.stdout.read()
+        if rc:
+            print(gpg_output)
+            sys.stderr.write("UNABLE TO GET FINGERPRINT FOR %s" % id)
+            sys.exit(1)
+
+        gpg_output = "\n".join([ l for l in gpg_output.splitlines()
+                                                     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])
+
+
+#----------------------------------------------------------------------
 # Main entry point for argument parsing and handling
 
 def main():
@@ -618,6 +725,24 @@ def main():
     subparser.add_argument('--dist-dir',
                     help='''The directory to clean.''')
 
+    # The move-to-dist subcommand
+    subparser = subparsers.add_parser('move-to-dist',
+                    help='''Move candiates and signatures from the temporary
+                            post location to the permanent distribution
+                            directory.  If no dist-dir is given, this command
+                            will assume it is running on people.apache.org.''')
+    subparser.set_defaults(func=move_to_dist)
+    subparser.add_argument('version', type=Version,
+                    help='''The release label, such as '1.7.0-alpha1'.''')
+    subparser.add_argument('--dist-dir',
+                    help='''The directory to clean.''')
+    subparser.add_argument('--code-name',
+                    help='''A whimsical name for the release, used only for
+                            naming the download directory.''')
+    subparser.add_argument('--target',
+                    help='''The full path to the destination used in
+                            'post-candiates'..''')
+
     # The write-news subcommand
     subparser = subparsers.add_parser('write-news',
                     help='''Output to stdout template text for use in the news
@@ -633,6 +758,17 @@ def main():
     subparser.add_argument('version', type=Version,
                     help='''The release label, such as '1.7.0-alpha1'.''')
 
+    # The check sigs subcommand
+    subparser = subparsers.add_parser('check-sigs',
+                    help='''Output to stdout the signatures collected for this
+                            release''')
+    subparser.set_defaults(func=check_sigs)
+    subparser.add_argument('version', type=Version,
+                    help='''The release label, such as '1.7.0-alpha1'.''')
+    subparser.add_argument('--target',
+                    help='''The full path to the destination used in
+                            'post-candiates'..''')
+
     # A meta-target
     subparser = subparsers.add_parser('clean',
                     help='''The same as the '--clean' switch, but as a

Modified: subversion/branches/svn-bisect/tools/dist/templates/rc-news.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/tools/dist/templates/rc-news.ezt?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/tools/dist/templates/rc-news.ezt (original)
+++ subversion/branches/svn-bisect/tools/dist/templates/rc-news.ezt Tue Aug 16 09:38:37 2011
@@ -4,16 +4,16 @@
     title="Link to this section">&para;</a> 
 </h3> 
  
-<p>We are please to announce to release of Apache Subversion [version].  This
+<p>We are pleased to announce to release of Apache Subversion [version].  This
    release is not intended for production use, but is provided as a milestone
    to encourage wider testing and feedback from intrepid users and maintainers.
    Please see the
    <a href="">release
    announcement</a> for more information about this release, and the
-   <a href="/docs/release-notes/[version_base].html">release notes</a> and 
+   <a href="/docs/release-notes/[major-minor].html">release notes</a> and 
    <a href="http://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES"> 
    change log</a> for information about what will eventually be
-   in the [version_base].0 release.</p> 
+   in the [version_base] release.</p> 
  
 <p>To get this release from the nearest mirror, please visit our
    <a href="/download/#pre-releases">download page</a>.</p> 

Modified: subversion/branches/svn-bisect/tools/server-side/svnpredumpfilter.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/tools/server-side/svnpredumpfilter.py?rev=1158171&r1=1158170&r2=1158171&view=diff
==============================================================================
--- subversion/branches/svn-bisect/tools/server-side/svnpredumpfilter.py (original)
+++ subversion/branches/svn-bisect/tools/server-side/svnpredumpfilter.py Tue Aug 16 09:38:37 2011
@@ -34,10 +34,16 @@ will be filtered by a user with universa
 repository's data.  Do not use the --use-merge-history (-g) or
 --stop-on-copy when generating this revision log stream.
 
+Return errorcode 0 if there are no additional dependencies found, 1 if
+there were; any other errorcode indicates a fatal error.
+
 Options:
 
    --help (-h)           Show this usage message and exit.
-   
+
+   --targets FILE        Read INCLUDE-PATHs and EXCLUDE-PATHs from FILE,
+                         one path per line.
+
    --verbose (-v)        Provide more information.  May be used multiple
                          times for additional levels of information (-vv).
 """
@@ -50,7 +56,11 @@ verbosity = 0
 
 class LogStreamError(Exception): pass
 class EOFError(Exception): pass
-  
+
+EXIT_SUCCESS = 0
+EXIT_MOREDEPS = 1
+EXIT_FAILURE = 2
+
 def sanitize_path(path):
   return '/'.join(filter(None, path.split('/')))
 
@@ -139,15 +149,21 @@ def svn_log_stream_get_dependencies(stre
   copy_action_re = re.compile(r'^   [AR] /(.*) \(from /(.*):[0-9]+\)$')
   line_buf = None
   last_revision = 0
+  eof = False
+  path_copies = {}
+  found_changed_path = False
   
-  while 1:
+  while not eof:
     try:
       line = line_buf is not None and line_buf or readline(stream)
     except EOFError:
       break
+
+    # We should be sitting at a log divider line.
     if line != '-' * 72:
       raise LogStreamError("Expected log divider line; not found.")
 
+    # Next up is a log header line.
     try:
       line = readline(stream)
     except EOFError:
@@ -155,7 +171,6 @@ def svn_log_stream_get_dependencies(stre
     match = header_re.search(line)
     if not match:
       raise LogStreamError("Expected log header line; not found.")
-
     pieces = map(string.strip, line.split('|'))
     revision = int(pieces[0][1:])
     if last_revision and revision >= last_revision:
@@ -170,51 +185,59 @@ def svn_log_stream_get_dependencies(stre
     else:
       log_lines = 0
 
+    # Now see if there are any changed paths.  If so, parse and process them.
     line = readline(stream)
-    if line != 'Changed paths:':
-      raise LogStreamError("Expected 'Changed paths:' line; not found.  Make "
-                           "sure log stream is from 'svn log' with the "
-                           "--verbose (-v) option.")
-
-    path_copies = {}
-    while 1:
-      try:
-        line = readline(stream)
-      except EOFError:
-        break
-      match = action_re.search(line)
-      if match:
-        match = copy_action_re.search(line)
+    if line == 'Changed paths:':
+      while 1:
+        try:
+          line = readline(stream)
+        except EOFError:
+          eof = True
+          break
+        match = action_re.search(line)
         if match:
-          path_copies[sanitize_path(match.group(1))] = sanitize_path(match.group(2))
-      else:
-        dt.handle_changes(path_copies)
-        if log_lines:
-          for i in range(log_lines):
-            readline(stream)
-          line_buf = None
+          found_changed_path = True
+          match = copy_action_re.search(line)
+          if match:
+            path_copies[sanitize_path(match.group(1))] = \
+              sanitize_path(match.group(2))
         else:
-          line_buf = line
-        break
+          break
+      dt.handle_changes(path_copies)
 
+    # Finally, skip any log message lines.  (If there are none,
+    # remember the last line we read, because it probably has
+    # something important in it.)
+    if log_lines:
+      for i in range(log_lines):
+        readline(stream)
+      line_buf = None
+    else:
+      line_buf = line
+
+  if not found_changed_path:
+    raise LogStreamError("No changed paths found; did you remember to run "
+                         "'svn log' with the --verbose (-v) option when "
+                         "generating the input to this script?")
+    
   return dt
 
 def analyze_logs(included_paths):
   print "Initial include paths:"
   for path in included_paths:
-    print "   /%s" % (path)
+    print " + /%s" % (path)
 
   dt = svn_log_stream_get_dependencies(sys.stdin, included_paths)
 
   if dt.dependent_paths:
+    found_new_deps = True
     print "Dependent include paths found:"
     for path in dt.dependent_paths:
-      print "   /%s" % (path)
+      print " + /%s" % (path)
     print "You need to also include them (or one of their parents)."
   else:
-    print "No new dependencies found!  You might still need " \
-          "to manually create parent directories for the " \
-          "included paths before loading a filtered dump:"
+    found_new_deps = False
+    print "No new dependencies found!"
     parents = {}
     for path in dt.include_paths:
       while 1:
@@ -224,9 +247,14 @@ def analyze_logs(included_paths):
         parents[parent] = 1
         path = parent
     parents = parents.keys()
-    parents.sort(compare_paths)
-    for parent in parents:
-      print "   /%s" % (parent)
+    if parents:
+      print "You might still need to manually create parent directories " \
+            "for the included paths before loading a filtered dump:"
+      parents.sort(compare_paths)
+      for parent in parents:
+        print "   /%s" % (parent)
+
+  return found_new_deps and EXIT_MOREDEPS or EXIT_SUCCESS
 
 def usage_and_exit(errmsg=None):
   program = os.path.basename(sys.argv[0])
@@ -234,14 +262,15 @@ def usage_and_exit(errmsg=None):
   stream.write(__doc__.replace("{PROGRAM}", program))
   if errmsg:
     stream.write("\nERROR: %s\n" % (errmsg))
-  sys.exit(errmsg and 1 or 0)
+  sys.exit(errmsg and EXIT_FAILURE or EXIT_SUCCESS)
 
 def main():
   config_dir = None
+  targets_file = None
   
   try:
     opts, args = getopt.getopt(sys.argv[1:], "hv",
-                               ["help", "verbose"])
+                               ["help", "verbose", "targets="])
   except getopt.GetoptError, e:
     usage_and_exit(str(e))
     
@@ -251,20 +280,39 @@ def main():
     elif option in ['-v', '--verbose']:
       global verbosity
       verbosity = verbosity + 1
+    elif option in ['--targets']:
+      targets_file = value
 
-  if len(args) < 2:
+  if len(args) == 0:
     usage_and_exit("Not enough arguments")
 
+  if targets_file is None:
+    targets = args[1:]
+  else:
+    targets = map(lambda x: x.rstrip('\n\r'),
+                  open(targets_file, 'r').readlines())
+  if not targets:
+    usage_and_exit("No target paths specified")
+
   try:
     if args[0] == 'include':
-      analyze_logs(map(sanitize_path, args[1:]))
+      sys.exit(analyze_logs(map(sanitize_path, targets)))
     elif args[0] == 'exclude':
       usage_and_exit("Feature not implemented")
     else:
       usage_and_exit("Valid subcommands are 'include' and 'exclude'")
+  except SystemExit:
+    raise
   except (LogStreamError, EOFError), e:
     log("ERROR: " + str(e), 0)
-    sys.exit(1)
+    sys.exit(EXIT_FAILURE)
+  except:
+    import traceback
+    exc_type, exc, exc_tb = sys.exc_info()
+    tb = traceback.format_exception(exc_type, exc, exc_tb)
+    sys.stderr.write(''.join(tb))
+    sys.exit(EXIT_FAILURE)
+
 
 if __name__ == "__main__":
     main()