On Sat, Feb 09, 2013 at 07:12:38AM -0800, Alfred Perlstein wrote: > [[ Adding us...@subversion.apache.org ]] > > He folks. I am in no way a Subversion expert, however per request > I've taken the FreeBSD patch for adding custom keyword expansion and > forward ported it to what is soon to be Subversion 1.8. > > I am wondering if anyone can help me test this or give me some > things to try to ensure that it works properly. > > -Alfred
Hi Alfred, Patches should go to dev@, not users@. I've changed the Cc to the right list in this reply. I'll try to review this during the coming week. Thanks! > On 2/1/13 7:40 AM, Alfred Perlstein wrote: > >[[ bringing in Lev Serebryakov, FreeBSD port maintainer for Subversion ]] > > > >Hello Lev, > > > >Stefan of the Subversion project asked me about bringing in our > >keywords patch for subversion 1.8. > > > >I've taken a bit of time and gotten the patch to apply to > >subversion trunk (untested). > > > >Can you have a look and let us know what we need to do with > >regards to testing or anything else? > > > > > >Stefan, any suggestions on going forward? > > > >-Alfred > > > >On 2/1/13 8:34 AM, Stefan Sperling wrote: > >>On Fri, Feb 01, 2013 at 08:01:02AM -0500, Alfred Perlstein wrote: > >>>[[ reply private ]] > >>> > >>>First of all, thank you very much for taking the time to explain this. > >>> > >>>I've forwarded your response to a few people who are more > >>>knowledgeable about Subversion in our community (John Baldwin / > >>>Peter Wemm) to hopefully get back us on the issue of mergeinfo and > >>>reintegrate. > >>Thanks! > >> > >>>Regarding the patch: > >>>http://subversion.tigris.org/issues/show_bug.cgi?id=890 > >>>I just read this. What can I do to help on this issue? > >>See the mailing list thread linked from > >>http://subversion.tigris.org/issues/show_bug.cgi?id=890#desc40 > >>That's the last time the patch got reviewed. It needs to be updated > >>to Subversion's trunk (to-be-1.8) before it can be committed. > >> > > > > Index: subversion/include/private/svn_subst_private.h > =================================================================== > --- subversion/include/private/svn_subst_private.h (revision 0) > +++ subversion/include/private/svn_subst_private.h (working copy) > @@ -0,0 +1,68 @@ > +/** > + * @copyright > + * ==================================================================== > + * Licensed to the Apache Software Foundation (ASF) under one > + * or more contributor license agreements. See the NOTICE file > + * distributed with this work for additional information > + * regarding copyright ownership. The ASF licenses this file > + * to you under the Apache License, Version 2.0 (the > + * "License"); you may not use this file except in compliance > + * with the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, > + * software distributed under the License is distributed on an > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > + * KIND, either express or implied. See the License for the > + * specific language governing permissions and limitations > + * under the License. > + * ==================================================================== > + * @endcopyright > + * > + * @file svn_subst_private.h > + * @brief Non-public subst utility functions. > + */ > + > + > +#ifndef SVN_SUBST_PRIVATE_H > +#define SVN_SUBST_PRIVATE_H > + > +#include "svn_subst.h" /* for svn_boolean_t, svn_error_t */ > + > +#ifdef __cplusplus > +extern "C" { > +#endif /* __cplusplus */ > + > +/** > + * 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 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 <tt>const char *</tt>. > + * Hash values are of type <tt>svn_string_t *</tt>. > + * > + * All memory is allocated out of @a pool. > + * > + * @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); > + > + > + > +#ifdef __cplusplus > +} > +#endif /* __cplusplus */ > + > +#endif /* SVN_SUBST_PRIVATE_H */ > Index: subversion/libsvn_client/cat.c > =================================================================== > --- subversion/libsvn_client/cat.c (revision 1441445) > +++ subversion/libsvn_client/cat.c (working copy) > @@ -40,6 +40,7 @@ > > #include "svn_private_config.h" > #include "private/svn_wc_private.h" > +#include "private/svn_subst_private.h" > > > /*** Code. ***/ > @@ -124,12 +125,15 @@ > const char *author; > const char *url; > apr_time_t tm; > + const char *repos; > > SVN_ERR(svn_wc__node_get_changed_info(&changed_rev, &tm, &author, > wc_ctx, > local_abspath, scratch_pool, > scratch_pool)); > SVN_ERR(svn_wc__node_get_url(&url, wc_ctx, local_abspath, scratch_pool, > scratch_pool)); > + SVN_ERR(svn_wc__node_get_repos_info(&repos, NULL, wc_ctx, > local_abspath, > + scratch_pool, scratch_pool)); > > if (local_mod) > { > @@ -152,8 +156,8 @@ > rev_str = apr_psprintf(scratch_pool, "%ld", changed_rev); > } > > - SVN_ERR(svn_subst_build_keywords2(&kw, keywords->data, rev_str, url, > tm, > - author, scratch_pool)); > + SVN_ERR(svn_subst_build_keywords3(&kw, keywords->data, rev_str, url, > + repos, tm, author, scratch_pool)); > } > > /* Wrap the output stream if translation is needed. */ > @@ -181,6 +185,7 @@ > svn_string_t *eol_style; > svn_string_t *keywords; > apr_hash_t *props; > + const char *repos_root_url; > svn_stream_t *output = out; > svn_error_t *err; > > @@ -225,6 +230,9 @@ > peg_revision, > revision, ctx, pool)); > > + /* Find the repos root URL */ > + SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, pool)); > + > /* Grab some properties we need to know in order to figure out if anything > special needs to be done with this file. */ > err = svn_ra_get_file(ra_session, "", loc->rev, NULL, NULL, &props, pool); > @@ -275,10 +283,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, > loc->url, > + repos_root_url, > when, > cmt_author ? cmt_author->data : NULL, > pool)); > Index: subversion/libsvn_client/commit.c > =================================================================== > --- subversion/libsvn_client/commit.c (revision 1441445) > +++ subversion/libsvn_client/commit.c (working copy) > @@ -44,6 +44,7 @@ > #include "client.h" > #include "private/svn_wc_private.h" > #include "private/svn_ra_private.h" > +#include "private/svn_subst_private.h" > > #include "svn_private_config.h" > > Index: subversion/libsvn_client/export.c > =================================================================== > --- subversion/libsvn_client/export.c (revision 1441445) > +++ subversion/libsvn_client/export.c (working copy) > @@ -45,6 +45,7 @@ > #include "private/svn_subr_private.h" > #include "private/svn_delta_private.h" > #include "private/svn_wc_private.h" > +#include "private/svn_subst_private.h" > > #ifndef ENABLE_EV2_IMPL > #define ENABLE_EV2_IMPL 0 > @@ -377,6 +378,7 @@ > { > svn_revnum_t changed_rev = status->changed_rev; > const char *suffix; > + const char *repos; > const char *url = svn_path_url_add_component2(status->repos_root_url, > status->repos_relpath, > scratch_pool); > @@ -395,10 +397,13 @@ > suffix = ""; > } > > - SVN_ERR(svn_subst_build_keywords2 > + SVN_ERR(svn_wc__node_get_repos_info(&repos, NULL, wc_ctx, > + eib->origin_abspath /* XXX: ?? from_abspath */, > + scratch_pool, scratch_pool)); > + SVN_ERR(svn_subst_build_keywords3 > (&kw, keywords->data, > apr_psprintf(scratch_pool, "%ld%s", changed_rev, suffix), > - url, tm, author, scratch_pool)); > + url, repos, tm, author, scratch_pool)); > } > > /* For atomicity, we translate to a tmp file and then rename the tmp file > @@ -544,6 +549,7 @@ > /* Any keyword vals to be substituted */ > const char *revision; > const char *url; > + const char *repos; > const char *author; > apr_time_t date; > > @@ -665,6 +671,7 @@ > fb->edit_baton = eb; > fb->path = full_path; > fb->url = full_url; > + fb->repos = eb->root_url; > fb->pool = pool; > > *baton = fb; > @@ -830,8 +837,8 @@ > } > > 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_translate4(fb->tmppath, fb->path, > Index: subversion/libsvn_client/import.c > =================================================================== > --- subversion/libsvn_client/import.c (revision 1441445) > +++ subversion/libsvn_client/import.c (working copy) > @@ -49,6 +49,7 @@ > #include "private/svn_subr_private.h" > #include "private/svn_ra_private.h" > #include "private/svn_magic.h" > +#include "private/svn_subst_private.h" > > #include "svn_private_config.h" > > @@ -133,9 +134,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/libsvn_subr/subst.c > =================================================================== > --- subversion/libsvn_subr/subst.c (revision 1441445) > +++ subversion/libsvn_subr/subst.c (working copy) > @@ -49,6 +49,7 @@ > #include "svn_private_config.h" > > #include "private/svn_string_private.h" > +#include "private/svn_subst_private.h" > > /** > * The textual elements of a detranslated special file. One of these > @@ -135,8 +136,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. > @@ -145,12 +149,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; > size_t n; > > for (;;) > @@ -203,6 +209,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); > @@ -211,6 +234,9 @@ > if (url) > svn_stringbuf_appendcstr(value, url); > break; > + case '_': /* '%_' => a space */ > + svn_stringbuf_appendbytes(value, " ", 1); > + break; > case '%': /* '%%' => a literal % */ > svn_stringbuf_appendbyte(value, *cur); > break; > @@ -246,8 +272,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 > @@ -286,6 +312,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); > @@ -296,14 +337,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, > @@ -316,7 +375,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, > @@ -327,7 +386,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, > @@ -338,7 +397,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, > @@ -348,7 +407,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); > @@ -357,7 +416,7 @@ > { > svn_string_t *header_val; > > - header_val = keyword_printf("%u %r %d %a", rev, url, date, author, > + header_val = keyword_printf("%u %r %d %a", rev, url, repos, date, > author, > pool); > apr_hash_set(*kw, SVN_KEYWORD_HEADER, > APR_HASH_KEY_STRING, header_val); > Index: subversion/libsvn_wc/translate.c > =================================================================== > --- subversion/libsvn_wc/translate.c (revision 1441445) > +++ subversion/libsvn_wc/translate.c (working copy) > @@ -46,6 +46,7 @@ > > #include "svn_private_config.h" > #include "private/svn_wc_private.h" > +#include "private/svn_subst_private.h" > > > > @@ -313,10 +314,10 @@ > apr_time_t changed_date; > const char *changed_author; > const char *url; > + const char *repos_root_url; > > if (! for_normalization) > { > - const char *repos_root_url; > const char *repos_relpath; > > SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, &repos_relpath, > @@ -341,13 +342,23 @@ > changed_rev = SVN_INVALID_REVNUM; > changed_date = 0; > changed_author = ""; > + > + SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, NULL, > + &repos_root_url, NULL, NULL, > + NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, NULL, NULL, NULL, > + NULL, NULL, NULL, NULL, > + db, local_abspath, > + scratch_pool, scratch_pool)); > } > > - SVN_ERR(svn_subst_build_keywords2(keywords, > + SVN_ERR(svn_subst_build_keywords3(keywords, > keyword_list, > apr_psprintf(scratch_pool, "%ld", > changed_rev), > url, > + repos_root_url, > changed_date, > changed_author, > result_pool));