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

Re: [PATCH] pre-update and pre-getfile hook

From: Srinivasa Kanduru <skanduru_at_siliconrock.com>
Date: 2006-02-07 09:53:07 CET

Hi Mathias,

Thanks a lot. This will be really useful. One more issue I was
thinking was to have a customized log message easily parseable
in the pre-commit hook to check for certain mandatory things to put
restrictions in there before commits like

ISSUE:
DESCRIPTION:
Bug-ID:
 etc

Changing the EDITOR_EOF_PREFIX doesn't seem to be an elegant way
as it needs a recompile everytime.

One hack I could think of is to use SNV_EDITOR as follows:

SVN_EDITOR="rm svn-commit.tmp && cp $REPOS/hooks/log.tmpl svn-commit.tmp && vi svn-commit.tmp"

This will work, but is a crude way of solving the problem.

It would be nice if it is possible to load the log template instead of
printing EDITOR_EOF_PREFIX in the preferred editor.

There might be a simple way for this already which I am missing. I appreciate if anyone can let me know.

Thanks,
Srini.

On Mon, Feb 06, 2006 at 02:11:39PM +0100, Mathias Weinert wrote:
> Hi there,
>
> I once wrote a pre-update hook and a pre-getfile hook. They only
> work for ra_svn and ra_local until now (at least they work in my
> environment). The pre-update hook is used for 'svn update' and
> 'svn checkout' whereas the pre-getfile hook is used for things
> like 'svn cat'.
>
> I mentioned this on this list some months ago but no one seemed
> to be interested. But as I received a request for it these days
> I decided not only to send it to Srini who asked me for it but
> to the dev list, too.
>
> As already said these two hooks work for me and may not work in
> other environments. Please regard this just as an example or a
> point to start from but not as a complete solution. But may be
> there is someone out there who wants to improve this and add it
> to Subversion at the end.
>
> The provided patches are built against Subversion 1.3.0.
>
> Both hooks get the same five parameters:
> REPOS: local path to repository
> REVNUM: revision number requested
> TARGET: target path within repository
> IP_ADDR: ip address of calling client (if available)
> USER: user
>
> I haven't included an example hook script yet. So you have to
> write your own one, probably starting with something like
> #!/bin/bash
> REPOS="$1"
> REVNUM="$2"
> TARGET="$3"
> IP_ADDR="$4"
> USER="$5"
>
> Regards
>
> Mathias
>
> --- subversion/include/svn_ra_svn.h.orig 2005-09-23 12:28:00.000000000 +0200
> +++ subversion/include/svn_ra_svn.h 2005-09-23 14:22:37.224279000 +0200
> @@ -304,6 +304,10 @@
> svn_error_t *svn_ra_svn_write_cmd_failure(svn_ra_svn_conn_t *conn,
> apr_pool_t *pool, svn_error_t *err);
>
> +/** Get remote IP address from connection. */
> +svn_error_t *svn_ra_svn_get_ip(svn_ra_svn_conn_t *conn, char **ip_addr,
> + apr_pool_t *pool);
> +
> /** Set @a *editor and @a *edit_baton to an editor which will pass editing
> * operations over the network, using @a conn and @a pool.
> *
> --- subversion/include/svn_repos.h.orig 2005-09-23 12:28:02.000000000 +0200
> +++ subversion/include/svn_repos.h 2005-09-23 14:22:37.318029000 +0200
> @@ -332,6 +332,11 @@
> const char *svn_repos_post_revprop_change_hook (svn_repos_t *repos,
> apr_pool_t *pool);
>
> +/** Return the path to @a repos's pre-update hook, allocated in @a pool. */
> +const char *svn_repos_pre_update_hook (svn_repos_t *repos, apr_pool_t *pool);
> +
> +/** Return the path to @a repos's pre-getfile hook, allocated in @a pool. */
> +const char *svn_repos_pre_getfile_hook (svn_repos_t *repos, apr_pool_t *pool);
>
> /** @defgroup svn_repos_lock_hooks paths to lock hooks
> * @{
> @@ -405,6 +410,7 @@
> svn_error_t *
> svn_repos_begin_report (void **report_baton,
> svn_revnum_t revnum,
> + const char *ip_addr,
> const char *username,
> svn_repos_t *repos,
> const char *fs_base,
> --- subversion/libsvn_ra_local/ra_plugin.c.orig 2005-10-20 10:36:18.000000000 +0200
> +++ subversion/libsvn_ra_local/ra_plugin.c 2005-10-20 11:11:57.158266800 +0200
> @@ -588,6 +588,7 @@
> /* Build a reporter baton. */
> SVN_ERR (svn_repos_begin_report (&rbaton,
> revision,
> + "localhost",
> sbaton->username,
> sbaton->repos,
> sbaton->fs_path,
> @@ -906,6 +907,18 @@
> else
> SVN_ERR (svn_fs_revision_root (&root, sbaton->fs, revision, pool));
>
> + svn_error_t *err = svn_repos__hooks_pre_getfile (sbaton->repos, revision,
> + abs_path, "localhost",
> + get_username (session, pool),
> + pool);
> + if (err!=SVN_NO_ERROR)
> + {
> + return svn_error_createf(SVN_ERR_REPOS_DISABLED_FEATURE, NULL, "%s\n%s",
> + "Operation has been cancelled by server;\n"
> + "perhaps you do not have sufficiant rights\n"
> + "Details:", err->message);
> + }
> +
> if (stream)
> {
> /* Get a stream representing the file's contents. */
> --- subversion/libsvn_ra_svn/marshal.c.orig 2005-09-23 12:30:10.000000000 +0200
> +++ subversion/libsvn_ra_svn/marshal.c 2005-09-23 14:22:37.521154000 +0200
> @@ -908,3 +908,21 @@
> SVN_ERR(svn_ra_svn_end_list(conn, pool));
> return SVN_NO_ERROR;
> }
> +
> +svn_error_t *svn_ra_svn_get_ip(svn_ra_svn_conn_t *conn, char **ip_addr,
> + apr_pool_t *pool)
> +{
> + if (conn && conn->sock)
> + {
> + apr_status_t status;
> + apr_sockaddr_t *sa;
> + status = apr_socket_addr_get (&sa, APR_REMOTE, conn->sock);
> + if (status==APR_SUCCESS)
> + status = apr_sockaddr_ip_get (ip_addr, sa);
> + if (status==APR_SUCCESS)
> + return SVN_NO_ERROR;
> + }
> + // don't generate an error, just save message in ip_addr
> + *ip_addr = apr_psprintf (pool, "<unknown>" );
> + return SVN_NO_ERROR;
> +}
> --- subversion/libsvn_repos/hooks.c.orig 2005-08-18 09:50:38.000000000 +0200
> +++ subversion/libsvn_repos/hooks.c 2005-08-18 10:25:17.875239600 +0200
> @@ -416,6 +416,75 @@
> }
>
>
> +svn_error_t *
> +svn_repos__hooks_pre_update (svn_repos_t *repos,
> + svn_revnum_t revnum,
> + const char *target,
> + const char *ip_addr,
> + const char *user,
> + apr_pool_t *pool)
> +{
> + const char *hook = svn_repos_pre_update_hook (repos, pool);
> + svn_boolean_t broken_link;
> +
> + if ((hook = check_hook_cmd (hook, &broken_link, pool)) && broken_link)
> + {
> + return hook_symlink_error (hook);
> + }
> + else if (hook)
> + {
> + const char *args[6];
> +
> + args[0] = hook;
> + args[1] = svn_repos_path (repos, pool);
> + args[2] = apr_psprintf (pool, "%ld", revnum);
> + args[3] = target;
> + args[4] = ip_addr;
> + args[5] = user ? user : "<anonymous>";
> + args[6] = NULL;
> +
> + SVN_ERR (run_hook_cmd (SVN_REPOS__HOOK_PRE_UPDATE,
> + hook, args, TRUE, NULL, pool));
> + }
> +
> + return SVN_NO_ERROR;
> +}
> +
> +
> +svn_error_t *
> +svn_repos__hooks_pre_getfile (svn_repos_t *repos,
> + svn_revnum_t revnum,
> + const char *target,
> + const char *ip_addr,
> + const char *user,
> + apr_pool_t *pool)
> +{
> + const char *hook = svn_repos_pre_getfile_hook (repos, pool);
> + svn_boolean_t broken_link;
> +
> + if ((hook = check_hook_cmd (hook, &broken_link, pool)) && broken_link)
> + {
> + return hook_symlink_error (hook);
> + }
> + else if (hook)
> + {
> + const char *args[6];
> +
> + args[0] = hook;
> + args[1] = svn_repos_path (repos, pool);
> + args[2] = apr_psprintf (pool, "%ld", revnum);
> + args[3] = target;
> + args[4] = ip_addr;
> + args[5] = user ? user : "<anonymous>";
> + args[6] = NULL;
> +
> + SVN_ERR (run_hook_cmd (SVN_REPOS__HOOK_PRE_GETFILE,
> + hook, args, TRUE, NULL, pool));
> + }
> +
> + return SVN_NO_ERROR;
> +}
> +
>
> svn_error_t *
> svn_repos__hooks_pre_lock (svn_repos_t *repos,
> --- subversion/libsvn_repos/reporter.c.orig 2005-08-18 09:50:44.000000000 +0200
> +++ subversion/libsvn_repos/reporter.c 2005-08-18 10:25:17.984613900 +0200
> @@ -1006,6 +1006,7 @@
> svn_error_t *
> svn_repos_begin_report (void **report_baton,
> svn_revnum_t revnum,
> + const char *ip_addr,
> const char *username,
> svn_repos_t *repos,
> const char *fs_base,
> @@ -1023,6 +1024,17 @@
> report_baton_t *b;
> const char *tempdir, *dummy;
>
> + /* Run the pre-update hook via direct call (not wrapped) */
> + const char *fs_target = switch_path ? switch_path
> + : svn_path_join (fs_base, s_operand, pool);
> + svn_error_t *err = svn_repos__hooks_pre_update (repos, revnum, fs_target,
> + ip_addr, username, pool);
> + if (err!=SVN_NO_ERROR)
> + return svn_error_createf(SVN_ERR_REPOS_DISABLED_FEATURE, NULL, "%s\n%s",
> + "Operation has been cancelled by server;\n"
> + "perhaps you do not have sufficiant rights\n"
> + "Details:", err->message);
> +
> /* Build a reporter baton. Copy strings in case the caller doesn't
> keep track of them. */
> b = apr_palloc (pool, sizeof (*b));
> --- subversion/libsvn_repos/repos.c.orig 2005-04-26 08:36:19.000000000 +0200
> +++ subversion/libsvn_repos/repos.c 2005-05-09 08:43:20.873677000 +0200
> @@ -155,6 +155,20 @@
> }
>
>
> +const char *
> +svn_repos_pre_update_hook (svn_repos_t *repos, apr_pool_t *pool)
> +{
> + return svn_path_join (repos->hook_path, SVN_REPOS__HOOK_PRE_UPDATE, pool);
> +}
> +
> +
> +const char *
> +svn_repos_pre_getfile_hook (svn_repos_t *repos, apr_pool_t *pool)
> +{
> + return svn_path_join (repos->hook_path, SVN_REPOS__HOOK_PRE_GETFILE, pool);
> +}
> +
> +
> static svn_error_t *
> create_repos_dir (const char *path, apr_pool_t *pool)
> {
> --- subversion/libsvn_repos/repos.h.orig 2005-09-30 11:19:12.000000000 +0200
> +++ subversion/libsvn_repos/repos.h 2005-09-30 12:19:28.837117900 +0200
> @@ -57,6 +57,8 @@
> #define SVN_REPOS__HOOK_WRITE_SENTINEL "write-sentinels"
> #define SVN_REPOS__HOOK_PRE_REVPROP_CHANGE "pre-revprop-change"
> #define SVN_REPOS__HOOK_POST_REVPROP_CHANGE "post-revprop-change"
> +#define SVN_REPOS__HOOK_PRE_UPDATE "pre-update"
> +#define SVN_REPOS__HOOK_PRE_GETFILE "pre-getfile"
> #define SVN_REPOS__HOOK_PRE_LOCK "pre-lock"
> #define SVN_REPOS__HOOK_POST_LOCK "post-lock"
> #define SVN_REPOS__HOOK_PRE_UNLOCK "pre-unlock"
> @@ -183,6 +185,26 @@
> char action,
> apr_pool_t *pool);
>
> +/* Run the pre-update hook for REPOS. Use POOL for any temporary
> + allocations. If the hook fails, return SVN_ERR_REPOS_HOOK_FAILURE.*/
> +svn_error_t *
> +svn_repos__hooks_pre_update (svn_repos_t *repos,
> + svn_revnum_t revnum,
> + const char *target,
> + const char *ip_addr,
> + const char *user,
> + apr_pool_t *pool);
> +
> +/* Run the pre-getfile hook for REPOS. Use POOL for any temporary
> + allocations. If the hook fails, return SVN_ERR_REPOS_HOOK_FAILURE.*/
> +svn_error_t *
> +svn_repos__hooks_pre_getfile (svn_repos_t *repos,
> + svn_revnum_t revnum,
> + const char *target,
> + const char *ip_addr,
> + const char *user,
> + apr_pool_t *pool);
> +
> /* Run the pre-lock hook for REPOS. Use POOL for any temporary
> allocations. If the hook fails, return SVN_ERR_REPOS_HOOK_FAILURE.
>
> --- subversion/mod_dav_svn/update.c.orig 2005-09-27 20:51:42.000000000 +0200
> +++ subversion/mod_dav_svn/update.c 2006-01-17 10:22:26.745612700 +0100
> @@ -1257,7 +1257,7 @@
> editor->close_file = upd_close_file;
> editor->absent_file = upd_absent_file;
> editor->close_edit = upd_close_edit;
> - if ((serr = svn_repos_begin_report(&rbaton, revnum, repos->username,
> + if ((serr = svn_repos_begin_report(&rbaton, revnum, "", repos->username,
> repos->repos,
> src_path, target,
> dst_path,
> --- subversion/svnserve/serve.c.orig 2005-11-02 23:47:08.000000000 +0100
> +++ subversion/svnserve/serve.c 2005-11-22 10:34:04.375364000 +0100
> @@ -547,10 +547,13 @@
> /* Make an svn_repos report baton. Tell it to drive the network editor
> * when the report is complete. */
> svn_ra_svn_get_editor(&editor, &edit_baton, conn, pool, NULL, NULL);
> - SVN_CMD_ERR(svn_repos_begin_report(&report_baton, rev, b->user, b->repos,
> - b->fs_path, target, tgt_path, text_deltas,
> - recurse, ignore_ancestry, editor,
> - edit_baton, authz_check_access_cb, b, pool));
> + char *ip_addr;
> + err = svn_ra_svn_get_ip (conn, &ip_addr, pool);
> + SVN_CMD_ERR(svn_repos_begin_report(&report_baton, rev, ip_addr, b->user,
> + b->repos, b->fs_path, target, tgt_path,
> + text_deltas, recurse, ignore_ancestry,
> + editor, edit_baton,
> + authz_check_access_cb, b, pool));
>
> rb.sb = b;
> rb.repos_url = svn_path_uri_decode(b->repos_url, pool);
> @@ -977,6 +980,23 @@
> if (!SVN_IS_VALID_REVNUM(rev))
> SVN_CMD_ERR(svn_fs_youngest_rev(&rev, b->fs, pool));
>
> + char *ip_addr;
> + err = svn_ra_svn_get_ip (conn, &ip_addr, pool);
> + err = svn_repos__hooks_pre_getfile (b->repos, rev, full_path,
> + ip_addr, b->user, pool);
> + if (err!=SVN_NO_ERROR)
> + {
> + err = svn_error_createf(SVN_ERR_REPOS_DISABLED_FEATURE, NULL, "%s\n%s",
> + "Operation has been cancelled by server;\n"
> + "perhaps you do not have sufficiant rights\n"
> + "Details:", err->message);
> + svn_error_t *write_err = svn_ra_svn_write_cmd_failure(conn, pool, err);
> + svn_error_clear(err);
> + if (write_err)
> + return write_err;
> + return SVN_NO_ERROR;
> + }
> +
> /* Fetch the properties and a stream for the contents. */
> SVN_CMD_ERR(svn_fs_revision_root(&root, b->fs, rev, pool));
> SVN_CMD_ERR(svn_fs_file_md5_checksum(digest, root, full_path, pool));
> --- subversion/tests/libsvn_repos/repos-test.c.orig 2005-09-23 12:37:30.000000000 +0200
> +++ subversion/tests/libsvn_repos/repos-test.c 2005-09-23 14:22:38.193029000 +0200
> @@ -1011,9 +1011,9 @@
> SVN_ERR (create_rmlocks_editor (&editor, &edit_baton, &removed, subpool));
>
> /* Report what we have. */
> - SVN_ERR (svn_repos_begin_report (&report_baton, 1, "user1", repos, "/", "",
> - NULL, FALSE, TRUE, FALSE, editor,
> - edit_baton, NULL, NULL, subpool));
> + SVN_ERR (svn_repos_begin_report (&report_baton, 1, "127.0.0.1", "user1",
> + repos, "/", "", NULL, FALSE, TRUE, FALSE,
> + editor, edit_baton, NULL, NULL, subpool));
> SVN_ERR (svn_repos_set_path2 (report_baton, "", 1, FALSE, NULL,
> subpool));
> SVN_ERR (svn_repos_set_path2 (report_baton, "iota", 1, FALSE, l1->token,

-- 
======================= CAUTION - Disclaimer =========================
This e-mail contains PRIVILEGED AND CONFIDENTIAL INFORMATION intended
solely for the use of the addressee(s). If you are not the intended
recipient, please notify the sender by e-mail and delete the original
message. Further, you are not to copy, disclose, or distribute this
e-mail or its contents to any other person and any such actions are
unlawful. This e-mail may contain viruses. Siliconrock has taken every
reasonable precaution to minimize this risk, but is not liable for any
damage you may sustain as a result of any virus in this e-mail. You
should carry out your own virus checks before opening the e-mail or
attachment. Siliconrock reserves the right to monitor and review the
content of all messages sent to or from this e-mail address. Messages
sent to or from this e-mail address may be stored on the Siliconrock
e-mail system.
====Siliconrock========== End of Disclaimer ==========Siliconrock====
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Wed Feb 8 16:50:18 2006

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

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.