[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] svnlook --revprop patch, take two

From: Oliver Klozoff <stevieoh_at_fastmail.fm>
Date: 2004-12-14 03:55:01 CET

This patch adds --revprop support to svnlook propget and svnlook proplist.
It also adds more basic regression tests for other svnlook subcommands.

--- log-message-worthy content follows ---

* subversion/svnlook/main.c
     (subcommand_plist, subcommand_pget):
         Changed to pass NULL for the path argument to do_plist/do_pget
         when --revprop is specified.

     (do_plist, do_pget):
         When the 'path' argument is NULL, switch from svn_fs_node_proplist/
         svn_fs_node_prop to svn_fs_revision_proplist/svn_fs_revision_prop.

* subversion/tests/clients/cmdline/svnlook_tests.py
     Added the following tests:
         test_propget_revprop (tests svnlook propget --revprop)
         test_propget_revprop_missing (tests svnlook --revprop
              for a revision property that doesn't exist)
         test_proplist_revprop (tests svnlook proplist --revprop)
         test_uuid (tests svnlook uuid)
         test_logmsg (tests svnlook log)
         test_author (tests svnlook author)

* subversion/tests/clients/cmdline/svntest/main.py
     Created function 'run_command_stdin'. Just like 'run_command',
     except it allows the caller to specify data to be piped into
     the command's stdin (needed by 'test_uuid').

Index: subversion/svnlook/main.c
===================================================================
--- subversion/svnlook/main.c (revision 12233)
+++ subversion/svnlook/main.c (working copy)
@@ -72,7 +72,8 @@
   {
     svnlook__version = SVN_OPT_FIRST_LONGOPT_ID,
     svnlook__show_ids,
- svnlook__no_diff_deleted
+ svnlook__no_diff_deleted,
+ svnlook__revprop_opt
   };
 
 /*
@@ -107,6 +108,9 @@
     {"no-diff-deleted", svnlook__no_diff_deleted, 0,
      N_("do not print differences for deleted files")},
 
+ {"revprop", svnlook__revprop_opt, 0,
+ N_("operate on a revision property (use with -r)")},
+
     {0, 0, 0, 0}
   };
 
@@ -170,15 +174,17 @@
      {'r', 't'} },
 
     {"propget", subcommand_pget, {"pget", "pg"},
- N_("usage: svnlook propget REPOS_PATH PROPNAME PATH_IN_REPOS\n\n"
- "Print the raw value of a property on a path in the repository.\n"),
- {'r', 't'} },
+ N_("usage: svnlook propget REPOS_PATH PROPNAME [PATH_IN_REPOS]\n\n"
+ "Print the raw value of a property on a path in the repository.\n"
+ "With --revprop, prints the raw value of a revision property.\n"),
+ {'r', 't', svnlook__revprop_opt} },
 
     {"proplist", subcommand_plist, {"plist", "pl"},
- N_("usage: svnlook proplist REPOS_PATH PATH_IN_REPOS\n\n"
- "List the properties of a path in the repository.\n"
+ N_("usage: svnlook proplist REPOS_PATH [PATH_IN_REPOS]\n\n"
+ "List the properties of a path in the repository, or\n"
+ "with the --revprop option, revision properties.\n"
         "With -v, show the property values too.\n"),
- {'r', 't', 'v'} },
+ {'r', 't', 'v', svnlook__revprop_opt} },
 
     {"tree", subcommand_tree, {0},
      N_("usage: svnlook tree REPOS_PATH [PATH_IN_REPOS]\n\n"
@@ -213,6 +219,7 @@
   svn_boolean_t help; /* --help */
   svn_boolean_t no_diff_deleted; /* --no-diff-deleted */
   svn_boolean_t verbose; /* --verbose */
+ svn_boolean_t revprop; /* --revprop */
 };
 
 
@@ -1429,13 +1436,25 @@
   apr_size_t len;
   
   SVN_ERR (get_root (&root, c, pool));
- SVN_ERR (verify_path (&kind, root, path, pool));
- SVN_ERR (svn_fs_node_prop (&prop, root, path, propname, pool));
+ if (path != NULL)
+ {
+ SVN_ERR (verify_path (&kind, root, path, pool));
+ SVN_ERR (svn_fs_node_prop (&prop, root, path, propname, pool));
+ }
+ else
+ SVN_ERR (svn_fs_revision_prop (&prop, c->fs, c->rev_id, propname, pool));
 
   if (prop == NULL)
- return svn_error_createf
- (SVN_ERR_PROPERTY_NOT_FOUND, NULL,
- _("Property '%s' not found on path '%s'"), propname, path);
+ {
+ if (path == NULL)
+ return svn_error_createf
+ (SVN_ERR_PROPERTY_NOT_FOUND, NULL,
+ _("Property '%s' not found on revision %d"), propname, c->rev_id);
+ else
+ return svn_error_createf
+ (SVN_ERR_PROPERTY_NOT_FOUND, NULL,
+ _("Property '%s' not found on path '%s'"), propname, path);
+ }
 
   /* Else. */
 
@@ -1468,10 +1487,15 @@
   apr_hash_index_t *hi;
   svn_node_kind_t kind;
 
+ SVN_ERR (svn_stream_for_stdout (&stdout_stream, pool));
   SVN_ERR (get_root (&root, c, pool));
- SVN_ERR (verify_path (&kind, root, path, pool));
- SVN_ERR (svn_fs_node_proplist (&props, root, path, pool));
- SVN_ERR (svn_stream_for_stdout (&stdout_stream, pool));
+ if (path != NULL)
+ {
+ SVN_ERR (verify_path (&kind, root, path, pool));
+ SVN_ERR (svn_fs_node_proplist (&props, root, path, pool));
+ }
+ else
+ SVN_ERR (svn_fs_revision_proplist (&props, c->fs, c->rev_id, pool));
 
   for (hi = apr_hash_first (pool, props); hi; hi = apr_hash_next (hi))
     {
@@ -1724,7 +1748,7 @@
         (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
          _("Missing propname and repository path arguments"));
     }
- else if (opt_state->arg2 == NULL)
+ else if (!opt_state->revprop && opt_state->arg2 == NULL)
     {
       return svn_error_createf
         (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
@@ -1732,7 +1756,7 @@
     }
 
   SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
- SVN_ERR (do_pget (c, opt_state->arg1, opt_state->arg2, pool));
+ SVN_ERR (do_pget (c, opt_state->arg1, opt_state->revprop ? NULL : opt_state->arg2, pool));
   return SVN_NO_ERROR;
 }
 
@@ -1742,14 +1766,23 @@
 {
   struct svnlook_opt_state *opt_state = baton;
   svnlook_ctxt_t *c;
+
+ /* some might argue that we should error here if --revprop is specified
+ * with no explicit revision, instead of implicitly behaving as -r HEAD.
+ *
+ * Those people might be right, but I'll leave that change to them,
+ * primarily because I don't fully understand how error handling works
+ * in this code.
+ */
 
- if (opt_state->arg1 == NULL)
+ if (!opt_state->revprop && opt_state->arg1 == NULL)
     return svn_error_createf
       (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
        _("Missing repository path argument"));
 
   SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
- SVN_ERR (do_plist (c, opt_state->arg1, opt_state->verbose, pool));
+ SVN_ERR (do_plist (c, opt_state->revprop ? NULL : opt_state->arg1,
+ opt_state->verbose, pool));
   return SVN_NO_ERROR;
 }
 
@@ -1896,6 +1929,10 @@
         case '?':
           opt_state.help = TRUE;
           break;
+
+ case svnlook__revprop_opt:
+ opt_state.revprop = TRUE;
+ break;
 
         case svnlook__version:
           opt_state.version = TRUE;
Index: subversion/tests/clients/cmdline/svnlook_tests.py
===================================================================
--- subversion/tests/clients/cmdline/svnlook_tests.py (revision 12287)
+++ subversion/tests/clients/cmdline/svnlook_tests.py (working copy)
@@ -38,9 +38,199 @@
 # Therefore, we can simply parse transaction headers.
 #
 ######################################################################
+
+# Convenient functions to make writing more tests easier
+
+# get the value of 'propname' for the given repository
+# on revision HEAD
+
+def svnlook_propget_revprop(rep_dir, propname):
+ output, errput = svntest.main.run_svnlook("propget", "--revprop", rep_dir, propname)
+
+ if not(output) or errput:
+ raise svntest.Failure
+
+ return output[0]
+
+
 # Tests
 
+def test_author(sbox):
+ "test 'svnlook author'"
 
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ repo_dir = sbox.repo_dir
+
+ # code stolen from test_youngest() below
+ mu_path = os.path.join(wc_dir, 'A', 'mu')
+ rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
+ svntest.main.file_append (mu_path, 'appended mu text')
+ svntest.main.file_append (rho_path, 'new appended text for rho')
+
+ logmsg = "Frobozz Magic Log Message Company"
+ author = 'lorddimwitflathead'
+
+ # commit with a silly (and uncommon) log message and author
+ svntest.main.run_svn(None, 'ci', '-m', logmsg, '--username', author, wc_dir)
+
+ output, errput = svntest.main.run_svnlook("author", repo_dir)
+
+ if not(output) or errput:
+ raise svntest.Failure
+
+ output[0] = output[0].rstrip("\n")
+
+ if output[0] != author:
+ print "Expected: '", author, "', got '", output[0], "'"
+ raise svntest.main.SVNUnmatchedError
+
+
+def test_logmsg(sbox):
+ "test 'svnlook log'"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ repo_dir = sbox.repo_dir
+
+ # code stolen from test_youngest() below
+ mu_path = os.path.join(wc_dir, 'A', 'mu')
+ rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
+ svntest.main.file_append (mu_path, 'appended mu text')
+ svntest.main.file_append (rho_path, 'new appended text for rho')
+
+ logmsg = "Frobozz Magic Log Message Company"
+ author = 'lorddimwitflathead'
+
+ # commit with a silly (and uncommon) log message and author
+ svntest.main.run_svn(None, 'ci', '-m', logmsg, '--username', author, wc_dir)
+
+ output, errput = svntest.main.run_svnlook("log", repo_dir)
+
+ if not(output) or errput:
+ raise svntest.Failure
+
+ output[0] = output[0].rstrip("\n")
+
+ if output[0] != logmsg:
+ print "Expected: '", logmsg, "', got '", output[0], "'"
+ raise svntest.main.SVNUnmatchedError
+
+
+def test_uuid(sbox):
+ "test 'svnlook uuid'"
+
+ sbox.build()
+ repo_dir = sbox.repo_dir
+
+ uuid = "01234567-89ab-cdef-89ab-cdef01234567"
+
+ # give the rep a new UUID
+ svntest.main.run_command_stdin(svntest.main.svnadmin_binary, None, 0,
+ ["SVN-fs-dump-format-version: 2\n",
+ "\n",
+ "UUID: ", uuid, "\n",
+ ],
+ 'load', '--force-uuid', repo_dir)
+
+ # now read the UUID
+ output, errput = svntest.main.run_svnlook('uuid', repo_dir)
+
+ if not(output) or output[0].strip() != uuid:
+ raise svntest.main.SVNUnmatchedError
+
+
+def test_proplist_revprop(sbox):
+ "test 'svnlook proplist --revprop'"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ repo_dir = sbox.repo_dir
+
+ # code stolen from test_youngest() below
+ mu_path = os.path.join(wc_dir, 'A', 'mu')
+ rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
+ svntest.main.file_append (mu_path, 'appended mu text')
+ svntest.main.file_append (rho_path, 'new appended text for rho')
+
+ logmsg = 'foo bar'
+ author = 'bazquux'
+
+ # commit with a silly (and uncommon) log message and author
+ svntest.main.run_svn(None, 'ci', '-m', logmsg, '--username', author, wc_dir)
+
+ # now here's where we actually do our work.
+ # test both svn:log and svn:author here -- the more, the merrier!
+
+ output, errput = svntest.main.run_svnlook("proplist", "--revprop", repo_dir)
+
+ # clean output
+ output = [prop.strip() for prop in output]
+
+ expected = [ 'svn:author', 'svn:log', 'svn:date' ]
+
+ expected.sort()
+ output.sort()
+
+ if not(output) or output != expected:
+ print "Expected: ", expected
+ print "Got: ", output
+ raise svntest.main.SVNUnmatchedError
+
+
+def test_propget_revprop(sbox):
+ "'svnlook propget' on existing revprops"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ repo_dir = sbox.repo_dir
+
+ # code stolen from test_youngest() below
+ mu_path = os.path.join(wc_dir, 'A', 'mu')
+ rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
+ svntest.main.file_append (mu_path, 'appended mu text')
+ svntest.main.file_append (rho_path, 'new appended text for rho')
+
+ logmsg = 'foo bar'
+ author = 'bazquux'
+
+ # commit with a silly (and uncommon) log message and author
+ svntest.main.run_svn(None, 'ci', '-m', logmsg, '--username', author, wc_dir)
+
+ # now here's where we actually do our work.
+ # test both svn:log and svn:author here -- the more, the merrier!
+
+ propval = svnlook_propget_revprop(repo_dir, "svn:log")
+
+ if propval != logmsg:
+ print "Mismatch: Expected '", logmsg, "', got '", propval, "'"
+ raise svntest.main.SVNUnmatchedError
+
+ propval = svnlook_propget_revprop(repo_dir, "svn:author")
+
+ if propval != author:
+ print "Mismatch: Expected '", author, "', got '", propval, "'"
+ raise svntest.main.SVNUnmatchedError
+
+
+def test_propget_revprop_missing(sbox):
+ "'svnlook propget' on nonexistent revprops"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ repo_dir = sbox.repo_dir
+
+ # don't even need to make any changes here -- sbox.build() already gave us a test commit
+
+ output, errput = svntest.main.run_svnlook("propget", "--revprop", repo_dir, "foo:bar-baz-quux")
+
+ rm = re.compile("Property.*not found")
+ for line in errput:
+ match = rm.search(line)
+ if match:
+ return
+ raise svntest.main.SVNUnmatchedError
+
 #----------------------------------------------------------------------
 
 def test_youngest(sbox):
@@ -185,6 +375,12 @@
               test_youngest,
               delete_file_in_moved_dir,
               test_print_property_diffs,
+ test_propget_revprop,
+ test_propget_revprop_missing,
+ test_proplist_revprop,
+ test_uuid,
+ test_logmsg,
+ test_author,
              ]
 
 if __name__ == '__main__':
Index: subversion/tests/clients/cmdline/svntest/main.py
===================================================================
--- subversion/tests/clients/cmdline/svntest/main.py (revision 12287)
+++ subversion/tests/clients/cmdline/svntest/main.py (working copy)
@@ -1,4 +1,3 @@
-
 #!/usr/bin/env python
 #
 # main.py: a shared, automated test suite for Subversion
@@ -199,6 +198,16 @@
   """Run COMMAND with VARARGS; return stdout, stderr as lists of lines.
   If ERROR_EXPECTED is None, any stderr also will be printed."""
 
+ return run_command_stdin(command, error_expected, binary_mode,
+ None, *varargs)
+
+# Run any binary, supplying input text, logging the command line
+def run_command_stdin(command, error_expected, binary_mode=0,
+ stdin_lines = None, *varargs):
+ """Run COMMAND with VARARGS; input stdin_lines (a list of lines) to
+ program via stdin, return stdout, stderr as lists of lines.
+ If ERROR_EXPECTED is None, any stderr also will be printed."""
+
   args = ''
   for arg in varargs: # build the command string
     args = args + ' "' + str(arg) + '"'
@@ -215,11 +224,15 @@
   start = time.time()
   infile, outfile, errfile = os.popen3(command + args, mode)
 
+ if stdin_lines:
+ map(infile.write, stdin_lines)
+
+ infile.close()
+
   stdout_lines = outfile.readlines()
   stderr_lines = errfile.readlines()
 
   outfile.close()
- infile.close()
   errfile.close()
 
   if verbose_mode:

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Tue Dec 14 03:56:39 2004

This is an archived mail posted to the Subversion Dev mailing list.