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

Re: [PATCH] Issue #692: Handle "svn log" with empty repos

From: Michael W Thelen <thelenm_at_cs.utah.edu>
Date: 2004-07-04 02:51:47 CEST

* Michael W Thelen <thelenm@cs.utah.edu> [2004-07-03 15:25]:
> Anyway, this discussion is a bit separate from the actual patch. In a
> little while I'll send a new patch containing what you suggested: only
> the (b) special case handling, with the other changes removed.

Okay, here's a new patch. It only contains the changes necessary to fix
the problem of running 'svn log' on a working copy at BASE revision 0.
This time I also delved into the wondrous world of Python and added a
test case. I'm hoping that it actually does what I think it does, and
tests this change. Happily, the test fails on /trunk but passes after
applying this patch. :-) Just a warning that you may want to inspect
the Python code particularly closely.

I think I'll also produce a patch for the changes I was proposing
before, just so you have the clearest possible idea (i.e. source code)
of what I'm suggesting.

Log:
Fix and document the special case when the user runs "svn log" with no
arguments in a working copy at BASE revision 0. This case is handled as if
the user requested -rBASE:1. But if the repository is not empty, we don't
want to print the log message for r1, since the working copy is at r0.
Also add a test case.

* subversion/include/svn_client.h
  (svn_client_log): Add documentation for this special case.

* subversion/libsvn_client/log.c
  (svn_client_log): Detect the special case condition and if it occurs, invoke
    the log message receiver manually with a message for revision 0.

* subversion/tests/clients/cmdline/log_tests.py
  (log_with_wc_at_revision_zero): New test case for the above functionality.
  (parse_log_output): Add support for recognizing a revision 0 log message,
    since it is radically different from normal log messages.
  (check_log_chain): Only test log message text for revisions greater than 0.
    Also, fail if there are extra log messages in the list after checking all
    expected messages.

Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h (revision 10131)
+++ subversion/include/svn_client.h (working copy)
@@ -753,6 +753,19 @@
  * revision 1. That works fine, except when there are no commits in
  * the repository, hence this special case.
  *
+ * Special case for working copies at revision 0:
+ *
+ * If @a start->kind is @c svn_opt_revision_base, and @a end->kind is
+ * @c svn_opt_revision_number && @a end->number is @c 1, then handle an
+ * a working copy at revision 0 specially: instead of invoking @a receiver
+ * on revisions 0 through 1, only invoke @a receiver on revision 0, passing
+ * @c NULL for changed paths and empty strings for the author and date. This
+ * is because that particular combination of @a start and @a end usually
+ * indicates the common case of log invocation from the working copy -- the
+ * user wants to see all log messages from the BASE revision back through
+ * revision 1. That works fine, except when the BASE revision is 0, hence
+ * this special case.
+ *
  * If @a ctx->notify_func is non-null, then call @a ctx->notify_func/baton
  * with a 'skip' signal on any unversioned targets.
  *
Index: subversion/libsvn_client/log.c
===================================================================
--- subversion/libsvn_client/log.c (revision 10131)
+++ subversion/libsvn_client/log.c (working copy)
@@ -113,7 +113,7 @@
       apr_array_header_t *target_urls;
       apr_array_header_t *real_targets;
       int i;
-
+
       /* Get URLs for each target */
       target_urls = apr_array_make (pool, 1, sizeof (const char *));
       real_targets = apr_array_make (pool, 1, sizeof (const char *));
@@ -135,7 +135,6 @@
                                      svn_wc_notify_state_unknown,
                                      SVN_INVALID_REVNUM);
 
-
               continue;
             }
           if (! entry->url)
@@ -243,20 +242,46 @@
             if (start_is_local)
               SVN_ERR (svn_client__get_revision_number
                        (&start_revnum, ra_lib, session, start, target, pool));
-
+
             if (end_is_local)
               SVN_ERR (svn_client__get_revision_number
                        (&end_revnum, ra_lib, session, end, target, pool));
 
- err = ra_lib->get_log (session,
- condensed_targets,
- start_revnum,
- end_revnum,
- discover_changed_paths,
- strict_node_history,
- receiver,
- receiver_baton,
- pool);
+ /* Special case: If the BASE revision is 0 but the HEAD revision
+ * of the repository is > 0, then we'll get the log message for
+ * revision 1 when running "svn log" with no arguments in the
+ * working copy. That's because the default behavior of "svn log"
+ * in a working copy is to give revisions BASE through 1, on the
+ * assumption that BASE >= 1. So if we see a start revision of
+ * BASE and an end revision of 1, then we just invoke the receiver
+ * manually on a hand-constructed log message for revision 0. */
+ if ((start->kind == svn_opt_revision_base)
+ && (start_revnum == 0)
+ && (end->kind == svn_opt_revision_number)
+ && (end->value.number == 1))
+ {
+ err = SVN_NO_ERROR;
+
+ /* Log receivers are free to handle revision 0 specially... But
+ just in case some don't, we make up a message here. */
+ SVN_ERR (receiver (receiver_baton,
+ NULL, 0, "", "",
+ _("No commits in BASE revision"),
+ pool));
+ }
+ else
+ {
+ err = ra_lib->get_log (session,
+ condensed_targets,
+ start_revnum,
+ end_revnum,
+ discover_changed_paths,
+ strict_node_history,
+ receiver,
+ receiver_baton,
+ pool);
+ }
+
             if (err)
               break;
           }
@@ -273,7 +298,7 @@
                                receiver_baton,
                                pool);
       }
-
+
     /* Special case: If there have been no commits, we'll get an error
      * for requesting log of a revision higher than 0. But the
      * default behavior of "svn log" is to give revisions HEAD through
@@ -293,12 +318,12 @@
             && (end->value.number == 1)))
       {
         svn_revnum_t youngest_rev;
-
+
         SVN_ERR (ra_lib->get_latest_revnum (session, &youngest_rev, pool));
         if (youngest_rev == 0)
           {
             err = SVN_NO_ERROR;
-
+
             /* Log receivers are free to handle revision 0 specially... But
                just in case some don't, we make up a message here. */
             SVN_ERR (receiver (receiver_baton,
@@ -307,6 +332,6 @@
           }
       }
   }
-
+
   return err;
 }
Index: subversion/tests/clients/cmdline/log_tests.py
===================================================================
--- subversion/tests/clients/cmdline/log_tests.py (revision 10131)
+++ subversion/tests/clients/cmdline/log_tests.py (working copy)
@@ -255,6 +255,22 @@
       if this_item:
         this_item['msg'] = msg
         chain.append (this_item)
+ this_item = None
+ elif this_line == "No commit for revision 0.\n":
+ # Add previous log message
+ if this_item:
+ this_item['msg'] = msg
+ chain.append (this_item)
+ this_item = {}
+ this_item['revision'] = '0'
+ this_item['author'] = '(no author)'
+ this_item['date'] = '1970-01-01 00:00:00 -0000 (Thu, 01 Jan 1970)'
+ this_item['msg'] = this_line
+ chain.append (this_item)
+ this_item = None
+ # Remove the message separator line - it comes after the r0 log message,
+ # not before it.
+ log_lines.pop (0)
     else: # if didn't see separator now, then something's wrong
       raise SVNLogParseError, "trailing garbage after log message"
 
@@ -297,14 +313,17 @@
              or author == '(no author)')): raise svntest.Failure
     # Check that the log message looks right:
     msg_re = re.compile ('Log message for revision ' + `saw_rev`)
- if (not msg_re.search (msg)): raise svntest.Failure
+ if (saw_rev > 0 and not msg_re.search (msg)): raise svntest.Failure
 
   ### todo: need some multi-line log messages mixed in with the
   ### one-liners. Easy enough, just make the prime revisions use REV
   ### lines, and the rest use 1 line, or something, so it's
   ### predictable based on REV.
 
+ # If any log messages are still on the chain, that's a failure
+ if chain: raise svntest.Failure
 
+
 ######################################################################
 # Tests
 #
@@ -515,7 +534,21 @@
                                       'log', '-r', '2', mu2_path)
   svntest.actions.run_and_verify_svn (None, [], SVNAnyOutput,
                                       'log', '-r', '2', mu2_URL)
-
+
+#----------------------------------------------------------------------
+def log_with_wc_at_revision_zero(sbox):
+ "'svn log', no args, top of wc at BASE revision 0"
+
+ guarantee_repos_and_wc(sbox)
+
+ svntest.main.run_svn (None, 'up', '-r', '0', sbox.wc_dir)
+ output, err = svntest.actions.run_and_verify_svn(
+ None, None, [], 'log', sbox.wc_dir)
+
+ log_chain = parse_log_output (output)
+ if check_log_chain (log_chain, [0]):
+ raise svntest.Failure
+
 ########################################################################
 # Run the tests
 
@@ -530,6 +563,7 @@
               log_with_path_args,
               url_missing_in_head,
               log_through_copyfrom_history,
+ log_with_wc_at_revision_zero,
              ]
 
 if __name__ == '__main__':

-- Mike

-- 
Michael W. Thelen
Never express yourself more clearly than you are able to think.
                -- Niels Bohr

Received on Sun Jul 4 02:52:59 2004

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