Okay. I tweaked the log message and fixed some spelling.
========================================================================
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/util.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)
@@ -414,8 +414,165 @@
}
-#define EDITOR_EOF_PREFIX "--This line, and those below, will be ignored--"
+#define EDITOR_EOF_PREFIX "--This line, and those below, " \
+ "are the list of files to commit--" \
+ APR_EOL_STR \
+ "--and will not be included in the log message--"
+/* 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 *committed_list,
+ apr_pool_t *pool)
+{
+ char *end_str, *prev_str = NULL;
+
+ /* Find the generated message. */
+ end_str = committed_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 committed 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 +626,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 +687,20 @@
/* Strip the prefix from the buffer. */
if (message)
+ {
+ svn_error_t *list_err;
+ char *committed_list = apr_pstrdup (pool, msg2);
+ apr_hash_t *seen = apr_hash_make(pool);
+
+ list_err = process_comitted_list (seen, committed_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
Received on Fri May 9 20:01:30 2003