You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Mark Grosberg <ma...@nolab.conman.org> on 2003/05/09 08:31:03 UTC

[PATCH] Issue #1295 (take 4)

Here it is. Sander: Does this make you feel better?

========================================================================

Fix for issue #1295.

* subversion/libsvn_client/commit_util.c
  (svn_client__condense_commit_items): Skip targets that have the
  new SVN_CLIENT_COMMIT_ITEM_UNMARKED flag set.
  (svn_client__sort_commit_item_urls): Always sort unmarked items
  at the end of the list. This way, they are easy to remove.
* subversion/clients/cmdline.c
  (get_item_path): [New] Factored out log path name generator.
  (flag_unmarked): [New] Set the SVN_CLIENT_COMMIT_ITEM_UNMARKED flag
  (log_msg_fatal_error): [New] Helper error factory function.
  for paths not found in the specified hash.
  (process_comitted_list): Parse the edited message to see what file
  names remain and add them to a hash.
  (svn_cl__get_log_message): Mark the entries in the comitted items
  list that should not be comitted.
* subversion/include/svn_client.h
  Add new flag: SVN_CLIENT_COMMIT_ITEM_UNMARKED
* subversion/include/svn_error_codes.h
  Add new client error: SVN_ERR_CLIENT_NO_WORK
  Add new command line error: SVN_ERR_CL_NO_LOG_MESSAGE_FILE_LIST

-------------------------------------------------------------------------

Index: include/svn_error_codes.h
===================================================================
--- include/svn_error_codes.h	(revision 5857)
+++ include/svn_error_codes.h	(working copy)
@@ -688,6 +688,11 @@
               SVN_ERR_CLIENT_CATEGORY_START + 8,
               "Revision range is not allowed")

+  SVN_ERRDEF (SVN_ERR_CLIENT_NO_WORK,
+              SVN_ERR_CLIENT_CATEGORY_START + 9,
+              "No work to do")
+
+
   /* misc errors */

   SVN_ERRDEF (SVN_ERR_BASE,
@@ -800,6 +805,10 @@
               SVN_ERR_CL_CATEGORY_START + 8,
               "Something is wrong with the log message's contents.")

+  SVN_ERRDEF (SVN_ERR_CL_NO_LOG_MESSAGE_FILE_LIST,
+              SVN_ERR_CL_CATEGORY_START + 9,
+              "No generated file list found")
+
 SVN_ERROR_END


Index: include/svn_client.h
===================================================================
--- include/svn_client.h	(revision 5857)
+++ include/svn_client.h	(working copy)
@@ -292,6 +292,7 @@
 #define SVN_CLIENT_COMMIT_ITEM_TEXT_MODS   0x04
 #define SVN_CLIENT_COMMIT_ITEM_PROP_MODS   0x08
 #define SVN_CLIENT_COMMIT_ITEM_IS_COPY     0x10
+#define SVN_CLIENT_COMMIT_ITEM_UNMARKED    0x20
 /** @} */

 /** The commit candidate structure. */
Index: libsvn_client/commit_util.c
===================================================================
--- libsvn_client/commit_util.c	(revision 5857)
+++ libsvn_client/commit_util.c	(working copy)
@@ -730,7 +730,13 @@
     = *((const svn_client_commit_item_t * const *) a);
   const svn_client_commit_item_t *item2
     = *((const svn_client_commit_item_t * const *) b);
-  return svn_path_compare_paths (item1->url, item2->url);
+
+  int cmp = ((item1->state_flags & SVN_CLIENT_COMMIT_ITEM_UNMARKED)
+             - (item2->state_flags & SVN_CLIENT_COMMIT_ITEM_UNMARKED));
+  if (cmp == 0)
+    cmp = svn_path_compare_paths (item1->url, item2->url);
+
+  return cmp;
 }


@@ -751,6 +757,20 @@
   qsort (ci->elts, ci->nelts,
          ci->elt_size, svn_client__sort_commit_item_urls);

+  /* Delete unrequested items. */
+  for (i = ci->nelts; i > 0; i--)
+    {
+       item = (((svn_client_commit_item_t **) ci->elts)[i - 1]);
+       if (!(item->state_flags & SVN_CLIENT_COMMIT_ITEM_UNMARKED))
+         break;
+    }
+
+  ci->nelts = i;
+  if (ci->nelts == 0)
+    return svn_error_create (SVN_ERR_CLIENT_NO_WORK, NULL,
+                             "No entires submitted for commit.");
+
+
   /* Loop through the URLs, finding the longest usable ancestor common
      to all of them, and making sure there are no duplicate URLs.  */
   for (i = 0; i < ci->nelts; i++)
Index: clients/cmdline/util.c
===================================================================
--- clients/cmdline/util.c	(revision 5857)
+++ clients/cmdline/util.c	(working copy)
@@ -416,6 +416,160 @@

 #define EDITOR_EOF_PREFIX  "--This line, and those below, will be ignored--"

+/* Get the full path string for the specificed item. */
+static const char *
+get_item_path (svn_client_commit_item_t *item,
+               struct log_msg_baton *lmb,
+               apr_pool_t *pool)
+{
+  const char *item_path = item->path;
+
+  if (! item_path)
+    item_path = item->url;
+  else if (! *item_path)
+    item_path = ".";
+
+  if (item_path && lmb->base_dir)
+    item_path = svn_path_is_child (lmb->base_dir, item_path, pool);
+
+  /* If still no path, then just use current directory. */
+  if (! item_path)
+    item_path = ".";
+
+  return item_path;
+}
+
+/* Helper function to create fatal parse error messages. */
+static svn_error_t *
+log_msg_fatal_error (void)
+{
+  return svn_error_create (SVN_ERR_CL_BAD_LOG_MESSAGE, NULL,
+                           "Aborting commit -- invalid log");
+}
+
+/* Parse the edited comitted message and store the named paths
+   in the hash. Failures of SVN_ERR_CL_NO_LOG_MESSAGE_FILE_LIST are
+   not fatal but cause all files to be comitted. */
+static svn_error_t *
+process_comitted_list (apr_hash_t *seen,
+                       char *commited_list,
+                       apr_pool_t *pool)
+{
+  char *end_str, *prev_str = NULL;
+
+  /* Find the generated message. */
+  end_str = commited_list;
+  while (end_str != NULL)
+    {
+      end_str = strstr (end_str, EDITOR_EOF_PREFIX);
+      if (end_str == NULL)
+        break;
+
+      end_str  = end_str + (sizeof(EDITOR_EOF_PREFIX) - 1);
+      prev_str = end_str;
+    }
+
+  if (prev_str == NULL)
+    return svn_error_create (SVN_ERR_CL_NO_LOG_MESSAGE_FILE_LIST, NULL,
+                             "Selective commit aborted; comitting all files.");
+
+  while (*prev_str != '\0')
+    {
+      if (!apr_isspace (*prev_str))
+        break;
+      prev_str++;
+    }
+
+  /* Now, parse each line and make sure that the commited item is named. */
+  for (;;)
+    {
+      char *end_of_path;
+
+      /* Skip leading whitespace. */
+      for (;;)
+        {
+          if (*prev_str == '\0')
+            return SVN_NO_ERROR;
+
+          if (!apr_isspace (*prev_str))
+            break;
+          prev_str++;
+        }
+      if (*prev_str == '\0')
+        break;
+
+      /* The next byte had better be one of the text mod's below. */
+      switch (*prev_str++)
+        {
+        case '_':
+        case 'R':
+        case 'A':
+        case 'D':
+        case 'M': break;
+        default:  return log_msg_fatal_error ();
+        }
+
+      /* The next byte had better be one of the prop mod's below. */
+      switch (*prev_str++)
+        {
+        case ' ':
+        case 'M': break;
+        default:  return log_msg_fatal_error ();
+        }
+
+      /* Skip more whitespace. */
+      for (;;)
+        {
+          if (*prev_str == '\0')
+            return log_msg_fatal_error ();
+          if (!apr_isspace(*prev_str))
+            break;
+          prev_str++;
+        }
+
+      /* Chop up the path. */
+      for (end_of_path = prev_str; *end_of_path != '\0'; end_of_path++)
+        {
+          if (*end_of_path == '\n')
+            break;
+        }
+      if (*end_of_path == '\0')
+        return log_msg_fatal_error ();
+
+      /* Truncate the string. The path is now in prev_str. */
+      *end_of_path++ = '\0';
+
+      /* Note the existence. */
+      apr_hash_set(seen, prev_str, APR_HASH_KEY_STRING, "");
+
+      /* Advance the pointer. */
+      prev_str = end_of_path;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Find the paths that are marked in the seen hash and set their
+   unmarked flags. */
+static void
+flag_unmarked (struct log_msg_baton *lmb,
+               apr_array_header_t *commit_items,
+               apr_hash_t *seen,
+               apr_pool_t *pool)
+{
+  int i;
+
+  for (i = 0; i < commit_items->nelts; i++)
+    {
+      svn_client_commit_item_t *item
+        = ((svn_client_commit_item_t **) commit_items->elts)[i];
+      const char *path = get_item_path (item, lmb, pool);
+
+      if (! apr_hash_get (seen, path, APR_HASH_KEY_STRING))
+        item->state_flags |= SVN_CLIENT_COMMIT_ITEM_UNMARKED;
+    }
+}
+
 /* This function is of type svn_client_get_commit_log_t. */
 svn_error_t *
 svn_cl__get_log_message (const char **log_msg,
@@ -469,21 +623,9 @@
         {
           svn_client_commit_item_t *item
             = ((svn_client_commit_item_t **) commit_items->elts)[i];
-          const char *path = item->path;
+          const char *path = get_item_path (item, lmb, pool);
           char text_mod = '_', prop_mod = ' ';

-          if (! path)
-            path = item->url;
-          else if (! *path)
-            path = ".";
-
-          if (path && lmb->base_dir)
-            path = svn_path_is_child (lmb->base_dir, path, pool);
-
-          /* If still no path, then just use current directory. */
-          if (! path)
-            path = ".";
-
           if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
               && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
             text_mod = 'R';
@@ -542,8 +684,20 @@

       /* Strip the prefix from the buffer. */
       if (message)
+      {
+        svn_error_t *list_err;
+        char *commited_list = apr_pstrdup (pool, msg2);
+        apr_hash_t *seen = apr_hash_make(pool);
+
+        list_err = process_comitted_list (seen, commited_list, pool);
+        if (list_err == SVN_NO_ERROR)
+          flag_unmarked (lmb, commit_items, seen, pool);
+        else if (list_err->apr_err != SVN_ERR_CL_NO_LOG_MESSAGE_FILE_LIST)
+          return (list_err);
+
         truncate_buffer_at_prefix (&message->len, message->data,
                                    EDITOR_EOF_PREFIX);
+      }

       if (message)
         {


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org