Index: subversion/include/svn_subst.h
===================================================================
--- subversion/include/svn_subst.h (revision 31461)
+++ subversion/include/svn_subst.h (working copy)
@@ -115,18 +115,33 @@
* Set @a *kw to a new keywords hash filled with the appropriate contents
* given a @a keywords_string (the contents of the svn:keywords
* property for the file in question), the revision @a rev, the @a url,
- * the @a date the file was committed on, and the @a author of the last
- * commit. Any of these can be @c NULL to indicate that the information is
- * not present, or @c 0 for @a date.
+ * the url of the root of the @a repos, the @a date the file was committed
+ * on, and the @a author of the last commit. Any of these can be @c NULL
+ * to indicate that the information is not present, or @c 0 for @a date.
*
* Hash keys are of type const char *.
* Hash values are of type svn_string_t *.
*
* All memory is allocated out of @a pool.
*
- * @since New in 1.3.
+ * @since New in 1.6
*/
svn_error_t *
+svn_subst_build_keywords3(apr_hash_t **kw,
+ const char *keywords_string,
+ const char *rev,
+ const char *url,
+ const char *repos,
+ apr_time_t date,
+ const char *author,
+ apr_pool_t *pool);
+
+/** Similar to svn_subst_build_keywords3() except that it does not
+ * supply the repository location.
+ *
+ * @deprecated Provided for backward compatibility with the 1.3 API.
+ */
+svn_error_t *
svn_subst_build_keywords2(apr_hash_t **kw,
const char *keywords_string,
const char *rev,
Index: subversion/libsvn_wc/merge.c
===================================================================
--- subversion/libsvn_wc/merge.c (revision 31461)
+++ subversion/libsvn_wc/merge.c (working copy)
@@ -386,7 +386,7 @@
target_marker,
right_marker,
"=======", /* seperator */
- FALSE, /* display original */
+ TRUE, /* display original */
FALSE, /* resolve conflicts */
pool));
SVN_ERR(svn_stream_close(ostream));
Index: subversion/libsvn_wc/translate.c
===================================================================
--- subversion/libsvn_wc/translate.c (revision 31461)
+++ subversion/libsvn_wc/translate.c (working copy)
@@ -266,11 +266,12 @@
SVN_ERR(svn_wc__entry_versioned(&entry, path, adm_access, FALSE, pool));
- SVN_ERR(svn_subst_build_keywords2(keywords,
+ SVN_ERR(svn_subst_build_keywords3(keywords,
list,
apr_psprintf(pool, "%ld",
entry->cmt_rev),
entry->url,
+ entry->repos,
entry->cmt_date,
entry->cmt_author,
pool));
Index: subversion/libsvn_subr/subst.c
===================================================================
--- subversion/libsvn_subr/subst.c (revision 31461)
+++ subversion/libsvn_subr/subst.c (working copy)
@@ -180,8 +180,11 @@
* %b basename of the URL of this file
* %d short format of date of this revision
* %D long format of date of this revision
+ * %P path relative to root of repos
* %r number of this revision
+ * %R root url of repository
* %u URL of this file
+ * %_ a space
* %% a literal %
*
* All memory is allocated out of @a pool.
@@ -190,12 +193,14 @@
keyword_printf(const char *fmt,
const char *rev,
const char *url,
+ const char *repos,
apr_time_t date,
const char *author,
apr_pool_t *pool)
{
svn_stringbuf_t *value = svn_stringbuf_ncreate("", 0, pool);
const char *cur;
+ const char *relative;
int n;
for (;;)
@@ -249,6 +254,23 @@
svn_stringbuf_appendcstr(value,
svn_time_to_human_cstring(date, pool));
break;
+ case 'P': /* relative path of this file */
+ relative = url;
+ if (relative && repos)
+ {
+ int len = strlen(repos);
+
+ if (strncmp(repos, relative, len) == 0
+ && relative[len] == '/')
+ relative += len + 1;
+ }
+ if (relative)
+ svn_stringbuf_appendcstr(value, relative);
+ break;
+ case 'R': /* root of repos */
+ if (repos)
+ svn_stringbuf_appendcstr(value, repos);
+ break;
case 'r': /* number of this revision */
if (rev)
svn_stringbuf_appendcstr(value, rev);
@@ -257,6 +279,9 @@
if (url)
svn_stringbuf_appendcstr(value, url);
break;
+ case '_': /* '%_' => a space */
+ svn_stringbuf_appendbytes(value, " ", 1);
+ break;
case '%': /* '%%' => a literal % */
svn_stringbuf_appendbytes(value, cur, 1);
break;
@@ -346,8 +371,8 @@
apr_hash_t *kwhash;
const svn_string_t *val;
- SVN_ERR(svn_subst_build_keywords2(&kwhash, keywords_val, rev,
- url, date, author, pool));
+ SVN_ERR(svn_subst_build_keywords3(&kwhash, keywords_val, rev,
+ url, "", date, author, pool));
/* The behaviour of pre-1.3 svn_subst_build_keywords, which we are
* replicating here, is to write to a slot in the svn_subst_keywords_t
@@ -386,6 +411,21 @@
const char *author,
apr_pool_t *pool)
{
+ SVN_ERR(svn_subst_build_keywords3(kw, keywords_val, rev,
+ url, "", date, author, pool));
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_subst_build_keywords3(apr_hash_t **kw,
+ const char *keywords_val,
+ const char *rev,
+ const char *url,
+ const char *repos,
+ apr_time_t date,
+ const char *author,
+ apr_pool_t *pool)
+{
apr_array_header_t *keyword_tokens;
int i;
*kw = apr_hash_make(pool);
@@ -396,14 +436,32 @@
for (i = 0; i < keyword_tokens->nelts; ++i)
{
const char *keyword = APR_ARRAY_IDX(keyword_tokens, i, const char *);
+ apr_array_header_t *keyword_tokens2;
+ keyword_tokens2 = svn_cstring_split(keyword, "=", TRUE /* chop */, pool);
+ if (keyword_tokens2->nelts == 2)
+ {
+ svn_string_t *custom_val;
+ const char *custom_expand;
+
+ keyword = APR_ARRAY_IDX(keyword_tokens2, 0, const char*);
+ custom_expand = APR_ARRAY_IDX(keyword_tokens2, 1, const char*);
+ if (! strcmp(custom_expand, "%H"))
+ custom_expand = "%P %r %d %a";
+ else if (! strcmp(custom_expand, "%I"))
+ custom_expand = "%b %r %d %a";
+ custom_val = keyword_printf(custom_expand, rev, url, repos, date, author, pool);
+ apr_hash_set(*kw, keyword, APR_HASH_KEY_STRING, custom_val);
+ return SVN_NO_ERROR;
+ }
+
if ((! strcmp(keyword, SVN_KEYWORD_REVISION_LONG))
|| (! strcmp(keyword, SVN_KEYWORD_REVISION_MEDIUM))
|| (! svn_cstring_casecmp(keyword, SVN_KEYWORD_REVISION_SHORT)))
{
svn_string_t *revision_val;
- revision_val = keyword_printf("%r", rev, url, date, author, pool);
+ revision_val = keyword_printf("%r", rev, url, repos, date, author, pool);
apr_hash_set(*kw, SVN_KEYWORD_REVISION_LONG,
APR_HASH_KEY_STRING, revision_val);
apr_hash_set(*kw, SVN_KEYWORD_REVISION_MEDIUM,
@@ -416,7 +474,7 @@
{
svn_string_t *date_val;
- date_val = keyword_printf("%D", rev, url, date, author, pool);
+ date_val = keyword_printf("%D", rev, url, repos, date, author, pool);
apr_hash_set(*kw, SVN_KEYWORD_DATE_LONG,
APR_HASH_KEY_STRING, date_val);
apr_hash_set(*kw, SVN_KEYWORD_DATE_SHORT,
@@ -427,7 +485,7 @@
{
svn_string_t *author_val;
- author_val = keyword_printf("%a", rev, url, date, author, pool);
+ author_val = keyword_printf("%a", rev, url, repos, date, author, pool);
apr_hash_set(*kw, SVN_KEYWORD_AUTHOR_LONG,
APR_HASH_KEY_STRING, author_val);
apr_hash_set(*kw, SVN_KEYWORD_AUTHOR_SHORT,
@@ -438,7 +496,7 @@
{
svn_string_t *url_val;
- url_val = keyword_printf("%u", rev, url, date, author, pool);
+ url_val = keyword_printf("%u", rev, url, repos, date, author, pool);
apr_hash_set(*kw, SVN_KEYWORD_URL_LONG,
APR_HASH_KEY_STRING, url_val);
apr_hash_set(*kw, SVN_KEYWORD_URL_SHORT,
@@ -448,7 +506,7 @@
{
svn_string_t *id_val;
- id_val = keyword_printf("%b %r %d %a", rev, url, date, author,
+ id_val = keyword_printf("%b %r %d %a", rev, url, repos, date, author,
pool);
apr_hash_set(*kw, SVN_KEYWORD_ID,
APR_HASH_KEY_STRING, id_val);
Index: subversion/libsvn_client/export.c
===================================================================
--- subversion/libsvn_client/export.c (revision 31461)
+++ subversion/libsvn_client/export.c (working copy)
@@ -188,10 +188,10 @@
author = entry->cmt_author;
}
- SVN_ERR(svn_subst_build_keywords2
+ SVN_ERR(svn_subst_build_keywords3
(&kw, keywords->data,
apr_psprintf(pool, fmt, entry->cmt_rev),
- entry->url, tm, author, pool));
+ entry->url, entry->repos, tm, author, pool));
}
SVN_ERR(svn_subst_copy_and_translate3(base, to, eol, FALSE,
@@ -474,6 +474,7 @@
/* Any keyword vals to be substituted */
const char *revision;
const char *url;
+ const char *repos;
const char *author;
apr_time_t date;
@@ -590,6 +591,7 @@
fb->edit_baton = eb;
fb->path = full_path;
fb->url = full_url;
+ fb->repos = eb->root_url;
fb->pool = pool;
*baton = fb;
@@ -743,8 +745,8 @@
eb->native_eol));
if (fb->keywords_val)
- SVN_ERR(svn_subst_build_keywords2(&final_kw, fb->keywords_val->data,
- fb->revision, fb->url, fb->date,
+ SVN_ERR(svn_subst_build_keywords3(&final_kw, fb->keywords_val->data,
+ fb->revision, fb->url, fb->repos, fb->date,
fb->author, pool));
SVN_ERR(svn_subst_copy_and_translate3
Index: subversion/libsvn_client/cat.c
===================================================================
--- subversion/libsvn_client/cat.c (revision 31461)
+++ subversion/libsvn_client/cat.c (working copy)
@@ -131,10 +131,10 @@
author = entry->cmt_author;
}
- SVN_ERR(svn_subst_build_keywords2
+ SVN_ERR(svn_subst_build_keywords3
(&kw, keywords->data,
apr_psprintf(pool, fmt, entry->cmt_rev),
- entry->url, tm, author, pool));
+ entry->url, entry->repos, tm, author, pool));
}
SVN_ERR(svn_io_file_open(&input_file, base,
@@ -167,6 +167,7 @@
svn_string_t *keywords;
apr_hash_t *props;
const char *url;
+ const char *repos_root_url;
svn_stream_t *output = out;
if (! svn_path_is_url(path_or_url)
@@ -198,6 +199,8 @@
&url, path_or_url, NULL,
peg_revision,
revision, ctx, pool));
+ /* Find the repos root URL */
+ SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, pool));
/* Make sure the object isn't a directory. */
SVN_ERR(svn_ra_check_path(ra_session, "", rev, &url_kind, pool));
@@ -242,10 +245,11 @@
if (cmt_date)
SVN_ERR(svn_time_from_cstring(&when, cmt_date->data, pool));
- SVN_ERR(svn_subst_build_keywords2
+ SVN_ERR(svn_subst_build_keywords3
(&kw, keywords->data,
cmt_rev->data,
url,
+ repos_root_url,
when,
cmt_author ? cmt_author->data : NULL,
pool));
Index: subversion/libsvn_client/commit.c
===================================================================
--- subversion/libsvn_client/commit.c (revision 31461)
+++ subversion/libsvn_client/commit.c (working copy)
@@ -118,9 +118,9 @@
}
if (keywords_val)
- SVN_ERR(svn_subst_build_keywords2(&keywords, keywords_val->data,
+ SVN_ERR(svn_subst_build_keywords3(&keywords, keywords_val->data,
APR_STRINGIFY(SVN_INVALID_REVNUM),
- "", 0, "", pool));
+ "", "", 0, "", pool));
else
keywords = NULL;
Index: subversion/svn/util.c
===================================================================
--- subversion/svn/util.c (revision 31461)
+++ subversion/svn/util.c (working copy)
@@ -631,6 +631,67 @@
}
+/*
+ * Since we're adding freebsd-specific tokens to the log message,
+ * clean out any leftovers to avoid accidently sending them to other
+ * projects that won't be expecting them.
+ */
+
+#define NPREFIX 7
+char *prefixes[NPREFIX] = {
+ "PR:",
+ "Submitted by:",
+ "Reviewed by:",
+ "Approved by:",
+ "Obtained from:",
+ "MFC after:",
+ "Security:",
+};
+
+void
+cleanmsg(apr_size_t *l, char *s)
+{
+ int i;
+ char *pos;
+ char *kw;
+ char *p;
+ int empty;
+
+ for (i = 0; i < NPREFIX; i++) {
+ pos = s;
+ while ((kw = strstr(pos, prefixes[i])) != NULL) {
+ /* Check to see if keyword is at start of line (or buffer) */
+ if (!(kw == s || kw[-1] == '\r' || kw[-1] == '\n')) {
+ pos = s + 1;
+ continue;
+ }
+ p = kw + strlen(prefixes[i]);
+ empty = 1;
+ while (1) {
+ if (*p == ' ' || *p == '\t') {
+ p++;
+ continue;
+ }
+ if (*p == '\0' || *p == '\r' || *p == '\n')
+ break;
+ empty = 0;
+ break;
+ }
+ if (empty && (*p == '\r' || *p == '\n')) {
+ memmove(kw, p + 1, strlen(p + 1) + 1);
+ if (l)
+ *l -= (p + 1 - kw);
+ } else if (empty) {
+ *kw = '\0';
+ if (l)
+ *l -= (p - kw);
+ } else {
+ pos = p;
+ }
+ }
+ }
+}
+
#define EDITOR_EOF_PREFIX _("--This line, and those below, will be ignored--")
svn_error_t *
@@ -646,8 +707,26 @@
/* Set default message. */
default_msg = svn_stringbuf_create(APR_EOL_STR, pool);
+ svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "PR:\t\t" APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "Submitted by:\t" APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "Reviewed by:\t" APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "Approved by:\t" APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "Obtained from:\t" APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "MFC after:\t" APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "Security:\t" APR_EOL_STR);
svn_stringbuf_appendcstr(default_msg, EDITOR_EOF_PREFIX);
- svn_stringbuf_appendcstr(default_msg, APR_EOL_STR APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "> Description of fields to fill in above: 78 columns --|" APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "> PR: If a GNATS PR is affected by the change." APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "> Submitted by: If someone else sent in the change." APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "> Reviewed by: If someone else reviewed your modification." APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "> Approved by: If you needed approval for this commit." APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "> Obtained from: If the change is from a third party." APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "> MFC after: N [day[s]|week[s]|month[s]]. Request a reminder email." APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "> Security: Vulnerability reference (one per line) or description." APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, "> Empty fields above will be automatically removed." APR_EOL_STR);
+ svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
*tmp_file = NULL;
if (lmb->message)
@@ -663,6 +742,7 @@
/* Trim incoming messages the EOF marker text and the junk that
follows it. */
truncate_buffer_at_prefix(NULL, (char*)*log_msg, EDITOR_EOF_PREFIX);
+ cleanmsg(NULL, (char*)*log_msg);
return SVN_NO_ERROR;
}
@@ -783,6 +863,13 @@
if (message)
truncate_buffer_at_prefix(&message->len, message->data,
EDITOR_EOF_PREFIX);
+ /*
+ * Since we're adding freebsd-specific tokens to the log message,
+ * clean out any leftovers to avoid accidently sending them to other
+ * projects that won't be expecting them.
+ */
+ if (message)
+ cleanmsg(&message->len, message->data);
if (message)
{