Hi folks, over a year ago, I submitted a patch to make the svn_auth_get_platform_specific_client_providers perl bindings work, to allow git-svn to work with gnome_keyring. Since then, I've been working on some further improvements, which I've attached as patches.
For consistency, I've also fixed the svn_auth_get_platform_specific_client_providers bindings for python and ruby, even though I don't really require them. The more fun change is the addition of a new binding that allows you to set a gnome_keyring prompt function: Using this, git-svn can ask for a keyring unlock password if the keyring is not locked yet (fixing a long-standing annoyance where I previously had to open some GUI-thingy to unlock the keyring before using git-svn). Again, I've spent some time figuring out the python and ruby bindings as well, and made this work there too. All changes have been tested using two example scripts (needed changes included in the patches) for python and ruby and using git-svn for perl (for lack of any example scripts). The ruby example script is new, since there was no example that accessed a remote url yet. I also fixed the python example I used, since it didn't work on trunk. I've included testcases for perl and python, but my lacking Ruby skills didn't manage to produce testcases for Ruby (there's not much to test, anyway...) Patches are against svn trunk (r1227522), but also apply with just a single trivial conflict to 1.6.17. Let me know if there's any further improvments required. Gr. Matthijs
[[[ Fix the get-location-segments.py example When trying to run the example, it throws: TypeError: Unexpected NULL parent pool on proxy object Somehow, the "_parent_pool" property wasn't initialized on the context. Not sure how this works, but creating a context using client.svn_client_create_context() instead of client.ctx_t() (which subversion/bindings/swig/python/tests/pool.py also does) fixes this error and makes the example work again. * tools/examples/get-location-segments.py Use client.svn_client_create_context instead of client.ctx_t. Patch by: Matthijs Kooijman <matth...@stdin.nl> ]]] Index: subversion-trunk/tools/examples/get-location-segments.py =================================================================== --- subversion-trunk.orig/tools/examples/get-location-segments.py 2012-01-05 14:29:12.146977757 +0100 +++ subversion-trunk/tools/examples/get-location-segments.py 2012-01-05 14:31:20.179645368 +0100 @@ -124,7 +124,7 @@ sys.exit(1) core.svn_config_ensure(None) - ctx = client.ctx_t() + ctx = client.svn_client_create_context() providers = [ client.get_simple_provider(), core.svn_auth_get_ssl_server_trust_file_provider(),
[[[ Fix the python bindings for svn_auth_get_platform_specific_client_providers. The bindings were present, but due to a missing argout typemap for apr_array_header_t **providers, they threw a not implemented error. This was fixed for perl in r1035745, but was still broken for python and ruby. [in subversion/bindings/swig] * include/svn_containers.swg Add an argout typemap for apr_array_header_t **providers, using the new svn_swig_py_pointerlist_to_list. * python/libsvn_swig_py/swigutil_py.c Generalize convert_rangelist and svn_swig_py_ranglist_to_list to work with any apr_array containing pointers and rename them to convert_pointerlist and svn_swig_py_pointerlist_to_list respectively. * python/libsvn_swig_py/swigutil_py.h Rename svn_swig_py_ranglist_to_list to svn_swig_py_pointerlist_to_list. * python/test/client.py (test_platform_providers): Add testcase. [in /tools/examples] * get-location-segments.py Let this example use svn_auth_get_platform_specific_client_providers. Patch by: Matthijs Kooijman <matth...@stdin.nl> ]]] Index: subversion-trunk/subversion/bindings/swig/include/svn_containers.swg =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/include/svn_containers.swg 2012-01-05 17:49:08.650432037 +0100 +++ subversion-trunk/subversion/bindings/swig/include/svn_containers.swg 2012-01-05 19:07:46.277024680 +0100 @@ -825,8 +825,8 @@ #ifdef SWIGPYTHON %typemap(argout) apr_array_header_t **RANGELIST { %append_output - (svn_swig_py_rangelist_to_list(*$1, $descriptor(svn_merge_range_t *), - _global_py_pool)); + (svn_swig_py_pointerlist_to_list(*$1, $descriptor(svn_merge_range_t *), + _global_py_pool)); if (PyErr_Occurred()) { SWIG_fail; } @@ -873,3 +873,14 @@ $descriptor(svn_auth_provider_object_t *))); } #endif + +#ifdef SWIGPYTHON +%typemap(argout) apr_array_header_t **providers { + %append_output + (svn_swig_py_pointerlist_to_list(*$1, $descriptor(svn_auth_provider_object_t *), + _global_py_pool)); + if (PyErr_Occurred()) { + SWIG_fail; + } +} +#endif Index: subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c 2012-01-05 17:49:08.602431774 +0100 +++ subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c 2012-01-05 19:06:45.060676127 +0100 @@ -650,7 +650,7 @@ return convert_hash(hash, convert_string, NULL, NULL); } -static PyObject *convert_rangelist(void *value, void *ctx, PyObject *py_pool) +static PyObject *convert_pointerlist(void *value, void *ctx, PyObject *py_pool) { int i; PyObject *list; @@ -659,8 +659,8 @@ list = PyList_New(0); for (i = 0; i < array->nelts; i++) { - svn_merge_range_t *range = APR_ARRAY_IDX(array, i, svn_merge_range_t *); - if (PyList_Append(list, convert_to_swigtype(range, ctx, py_pool)) == -1) + void *obj = APR_ARRAY_IDX(array, i, void *); + if (PyList_Append(list, convert_to_swigtype(obj, ctx, py_pool)) == -1) goto error; } return list; @@ -669,18 +669,18 @@ return NULL; } -PyObject *svn_swig_py_rangelist_to_list(apr_array_header_t *rangelist, - swig_type_info *type, - PyObject *py_pool) +PyObject *svn_swig_py_pointerlist_to_list(apr_array_header_t *list, + swig_type_info *type, + PyObject *py_pool) { - return convert_rangelist(rangelist, type, py_pool); + return convert_pointerlist(list, type, py_pool); } PyObject *svn_swig_py_mergeinfo_to_dict(apr_hash_t *hash, swig_type_info *type, PyObject *py_pool) { - return convert_hash(hash, convert_rangelist, type, py_pool); + return convert_hash(hash, convert_pointerlist, type, py_pool); } static PyObject *convert_mergeinfo_hash(void *value, void *ctx, Index: subversion-trunk/tools/examples/get-location-segments.py =================================================================== --- subversion-trunk.orig/tools/examples/get-location-segments.py 2012-01-05 19:06:40.024647447 +0100 +++ subversion-trunk/tools/examples/get-location-segments.py 2012-01-05 19:06:45.064676149 +0100 @@ -125,7 +125,13 @@ core.svn_config_ensure(None) ctx = client.svn_client_create_context() - providers = [ + + # Make sure that these are at the start of the list, so passwords from + # gnome-keyring / kwallet are checked before asking for new passwords. + # Note that we don't pass our config here, since we can't seem to access + # ctx.config.config (ctx.config is opaque). + providers = core.svn_auth_get_platform_specific_client_providers(None, None) + providers.extend([ client.get_simple_provider(), core.svn_auth_get_ssl_server_trust_file_provider(), core.svn_auth_get_simple_prompt_provider(prompt_func_simple_prompt, 2), @@ -134,7 +140,8 @@ client.get_ssl_server_trust_file_provider(), client.get_ssl_client_cert_file_provider(), client.get_ssl_client_cert_pw_file_provider(), - ] + ]) + ctx.auth_baton = core.svn_auth_open(providers) ctx.config = core.svn_config_get_config(None) Index: subversion-trunk/subversion/bindings/swig/python/tests/client.py =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/python/tests/client.py 2012-01-05 17:49:08.634431949 +0100 +++ subversion-trunk/subversion/bindings/swig/python/tests/client.py 2012-01-05 19:06:45.064676149 +0100 @@ -374,6 +374,11 @@ self.assertEqual(readme_text, 'This is a test.\n') + def test_platform_providers(self): + providers = core.svn_auth_get_platform_specific_client_providers(None, None) + # Not much more we can test in this minimal environment. + self.assert_(isinstance(providers, list)) + def suite(): return unittest.defaultTestLoader.loadTestsFromTestCase( SubversionClientTestCase) Index: subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h 2012-01-05 17:49:08.770432697 +0100 +++ subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h 2012-01-05 19:06:45.064676149 +0100 @@ -135,9 +135,9 @@ /* helper function to convert an apr_array_header_t* (of svn_merge_range_t *) to a Python list */ SVN_SWIG_SWIGUTIL_EXPORT -PyObject *svn_swig_py_rangelist_to_list(apr_array_header_t *rangelist, - swig_type_info *type, - PyObject *py_pool); +PyObject *svn_swig_py_pointerlist_to_list(apr_array_header_t *list, + swig_type_info *type, + PyObject *py_pool); /* helper function to convert an apr_hash_t* (const char *->array of svn_merge_range_t *) to a Python dict */
[[[ Fix the ruby bindings for svn_auth_get_platform_specific_client_providers. The bindings were present, but due to a missing argout typemap for apr_array_header_t **providers, they threw a not implemented error. This was fixed for perl in r1035745 and for python in the previous commit, but was still broken for ruby. [in subversion/bindings/swig] * include/svn_containers.swg Add an argout typemap for apr_array_header_t **providers, using the new svn_swig_rb_apr_array_to_array_auth_provider_object. * ruby/libsvn_swig_ruby/swigutil_rb.c, ruby/libsvn_swig_ruby/swigutil_rb.h (svn_swig_rb_apr_array_to_array_auth_provider_object): Add function. * ruby/svn/core.rb (add_platform_specific_client_providers, add_providers): Add functions. [in tools/examples] * info.rb Add a new example that shows how to do remote access instead of working on an existing working copy (like the existing examples do). This example also shows how to call svn_auth_get_platform_specific_client_providers. Patch by: Matthijs Kooijman <matth...@stdin.nl> ]]] Index: subversion-trunk/subversion/bindings/swig/include/svn_containers.swg =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/include/svn_containers.swg 2012-01-05 19:55:40.544949667 +0100 +++ subversion-trunk/subversion/bindings/swig/include/svn_containers.swg 2012-01-05 19:55:40.568949797 +0100 @@ -884,3 +884,9 @@ } } #endif + +#ifdef SWIGRUBY +%typemap(argout) apr_array_header_t **providers { + %append_output(svn_swig_rb_apr_array_to_array_auth_provider_object(*$1)); +} +#endif Index: subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c 2012-01-05 19:14:17.787265008 +0100 +++ subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c 2012-01-05 20:10:54.641914327 +0100 @@ -1313,6 +1313,9 @@ DEFINE_APR_ARRAY_TO_ARRAY(VALUE, svn_swig_rb_apr_array_to_array_merge_range, c2r_merge_range_dup, EMPTY_CPP_ARGUMENT, svn_merge_range_t *, NULL) +DEFINE_APR_ARRAY_TO_ARRAY(VALUE, svn_swig_rb_apr_array_to_array_auth_provider_object, + c2r_swig_type, EMPTY_CPP_ARGUMENT, + svn_auth_provider_object_t *, "svn_auth_provider_object_t*") static VALUE c2r_merge_range_array(void *value, void *ctx) Index: subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h 2012-01-05 19:14:17.771264917 +0100 +++ subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h 2012-01-05 20:10:54.625914222 +0100 @@ -154,6 +154,8 @@ VALUE svn_swig_rb_apr_array_to_array_external_item2(const apr_array_header_t *ary); SVN_RB_SWIG_SWIGUTIL_EXPORT VALUE svn_swig_rb_apr_array_to_array_merge_range(const apr_array_header_t *ary); +SVN_RB_SWIG_SWIGUTIL_EXPORT +VALUE svn_swig_rb_apr_array_to_array_auth_provider_object(const apr_array_header_t *ary); SVN_RB_SWIG_SWIGUTIL_EXPORT VALUE svn_swig_rb_prop_apr_array_to_hash_prop(const apr_array_header_t *ary); Index: subversion-trunk/tools/examples/info.rb =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ subversion-trunk/tools/examples/info.rb 2012-01-05 20:38:00.378378028 +0100 @@ -0,0 +1,54 @@ +# Example based on a blogpost by Mark Deepwell +# http://www.markdeepwell.com/2010/06/ruby-subversion-bindings/ + +require "svn/core" +require "svn/client" +require "svn/wc" +require "svn/repos" + +# Prompt function mimicking svn's own prompt +simple_prompt = Proc.new do + |result, realm, username, default, may_save, pool| + + puts "Authentication realm: #{realm}" + if username != nil + result.username = username + else + print "Username: " + result.username = STDIN.gets.strip + end + print "Password for '#{result.username}': " + result.password = STDIN.gets.strip +end + + +if ARGV.length != 1 + puts "Usage: info.rb URL[@REV]" +else + ctx = Svn::Client::Context.new() + ctx.add_platform_specific_client_providers + ctx.add_simple_provider + ctx.add_simple_prompt_provider(2, simple_prompt) + ctx.add_username_provider + ctx.add_ssl_server_trust_file_provider + ctx.add_ssl_client_cert_file_provider + ctx.add_ssl_client_cert_pw_file_provider + + repos_uri, revision = ARGV[0].split("@", 2) + if revision + revision = Integer(revision) + end + + begin + ctx.info(repos_uri, revision) do |path, info| + puts("Url: #{info.url}") + puts("Last changed rev: #{info.last_changed_rev}") + puts("Last changed author: #{info.last_changed_author}") + puts("Last changed date: #{info.last_changed_date}") + puts("Kind: #{info.kind}") + end + rescue Svn::Error => e + # catch a generic svn error + raise "Failed to retrieve SVN info at revision " + revision.to_s + end +end Index: subversion-trunk/subversion/bindings/swig/ruby/svn/core.rb =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/ruby/svn/core.rb 2012-01-05 19:14:17.755264824 +0100 +++ subversion-trunk/subversion/bindings/swig/ruby/svn/core.rb 2012-01-05 19:55:40.572949818 +0100 @@ -279,6 +279,10 @@ add_prompt_provider("ssl_client_cert_pw", args, prompt, klass) end + def add_platform_specific_client_providers(config=nil) + add_providers(Core.auth_get_platform_specific_client_providers(config)) + end + private def add_prompt_provider(name, args, prompt, credential_class) real_prompt = Proc.new do |*prompt_args| @@ -294,6 +298,10 @@ end def add_provider(provider) + add_providers([provider]) + end + + def add_providers(new_providers) if auth_baton providers = auth_baton.providers parameters = auth_baton.parameters @@ -301,7 +309,7 @@ providers = [] parameters = {} end - self.auth_baton = AuthBaton.new(providers + [provider], parameters) + self.auth_baton = AuthBaton.new(providers + new_providers, parameters) end end
[[[ Allow setting the SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC authentication parameter from the perl, python and ruby bindings. This parameter cannot be set using the regular svn_auth_set_parameter function, since the function from perl/python/ruby space must be wrapped in a C function to allow it to be called. For this reason, a new function, svn_auth_set_gnome_keyring_unlock_prompt_func, is introduced (in the bindings only). [in subversion/bindings/swig] * core.i (svn_auth_set_gnome_keyring_unlock_prompt_func): Add function and setup corresponding authprompt_callback_typemap. * perl/libsvn_swig_perl/swigutil_pl.c, perl/libsvn_swig_perl/swigutil_pl.h (svn_swig_pl_thunk_gnome_keyring_unlock_prompt): Add function (called by authprompt_callback_typemap) * python/libsvn_swig_py/swigutil_py.c python/libsvn_swig_py/swigutil_py.h (svn_swig_py_auth_gnome_keyring_unlock_prompt_func): Add function (called by authprompt_callback_typemap) * ruby/libsvn_swig_ruby/swigutil_rb.c, ruby/libsvn_swig_ruby/swigutil_rb.h (svn_swig_rb_auth_gnome_keyring_unlock_prompt_func): Add function (called by authprompt_callback_typemap) * perl/native/t/3client.t, python/tests/client.py Add test for svn_auth_set_gnome_keyring_unlock_prompt_func. [in tools/examples] * get-location-segments.py, info.rb Use the new svn_auth_set_gnome_keyring_unlock_prompt_func function. Patch by: Matthijs Kooijman <matth...@stdin.nl> ]]] Index: subversion-trunk/subversion/bindings/swig/core.i =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/core.i 2012-01-05 20:10:54.701914646 +0100 +++ subversion-trunk/subversion/bindings/swig/core.i 2012-01-05 20:38:07.594414588 +0100 @@ -699,6 +699,34 @@ %authprompt_callback_typemap(ssl_client_cert) %authprompt_callback_typemap(ssl_client_cert_pw) +%{ +#ifdef SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC +/* Helper function to set the gnome-keyring unlock prompt function. This + * C function accepts an auth baton, a function and a prompt baton, but + * the below callback_typemap uses both the function and the prompt + * baton, so the resulting binding has just two arguments: The auth + * baton and the prompt function. + * The prompt function should again have two arguments: The keyring name + * (string) and a pool (except for the ruby version, which doesn't have + * the pool argument). It should return the entered password (string). + * This binding generated for this function generates a reference to the + * prompt function that was passed into this. The caller should store + * that reference somewhere, to prevent the function from being garbage + * collected... + */ +static void svn_auth_set_gnome_keyring_unlock_prompt_func(svn_auth_baton_t *ab, + svn_auth_gnome_keyring_unlock_prompt_func_t prompt_func, + void *prompt_baton) { + svn_auth_set_parameter(ab, SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC, + prompt_func); + svn_auth_set_parameter(ab, SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_BATON, + prompt_baton); +} +#endif +%} + +%authprompt_callback_typemap(gnome_keyring_unlock) + /* ----------------------------------------------------------------------- * For all the various functions that set a callback baton create a reference * for the baton (which in this case is an SV pointing to the callback) @@ -764,6 +792,12 @@ %include svn_pools_h.swg %include svn_version_h.swg +/* This is the function defined above */ +void svn_auth_set_gnome_keyring_unlock_prompt_func(svn_auth_baton_t *ab, + svn_auth_gnome_keyring_unlock_prompt_func_t prompt_func, + void *prompt_baton); + + /* The constant SVN_PROP_REVISION_ALL_PROPS is a C fragment, not a single data value, so the SWIG parser will raise a 305 warning if we don't suppress it. */ Index: subversion-trunk/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c 2012-01-05 20:10:54.593914029 +0100 +++ subversion-trunk/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c 2012-01-05 20:38:07.594414588 +0100 @@ -984,6 +984,34 @@ return SVN_NO_ERROR; } +svn_error_t *svn_swig_pl_thunk_gnome_keyring_unlock_prompt(char **keyring_password, + const char *keyring_name, + void *baton, + apr_pool_t *pool) +{ + SV *result; + STRLEN len; + /* The baton is the actual prompt function passed from perl, so we + * call that one and process the result. */ + svn_swig_pl_callback_thunk(CALL_SV, + baton, &result, + "sS", keyring_name, + pool, POOLINFO); + if (!SvOK(result) || result == &PL_sv_undef) { + *keyring_password = NULL; + } + else if (SvPOK(result)) { + *keyring_password = apr_pstrdup(pool, SvPV(result, len)); + } + else { + SvREFCNT_dec(result); + croak("not a string"); + } + + SvREFCNT_dec(result); + return SVN_NO_ERROR; +} + svn_error_t *svn_swig_pl_thunk_simple_prompt(svn_auth_cred_simple_t **cred, void *baton, const char *realm, Index: subversion-trunk/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.h =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.h 2012-01-05 20:10:54.609914166 +0100 +++ subversion-trunk/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.h 2012-01-05 20:38:07.598414690 +0100 @@ -144,6 +144,11 @@ SV *perl_callbacks, apr_pool_t *pool); +/* thunked gnome_keyring_unlock_prompt callback function */ +svn_error_t *svn_swig_pl_thunk_gnome_keyring_unlock_prompt(char **keyring_password, + const char *keyring_name, + void *baton, + apr_pool_t *pool); /* thunked simple_prompt callback function */ svn_error_t *svn_swig_pl_thunk_simple_prompt(svn_auth_cred_simple_t **cred, void *baton, Index: subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c 2012-01-05 20:10:54.653914386 +0100 +++ subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c 2012-01-05 20:38:07.598414690 +0100 @@ -2792,6 +2792,41 @@ } svn_error_t * +svn_swig_py_auth_gnome_keyring_unlock_prompt_func(char **keyring_passwd, + const char *keyring_name, + void *baton, + apr_pool_t *pool) +{ + /* The baton is the actual prompt function passed from python */ + PyObject *function = baton; + PyObject *result; + svn_error_t *err = SVN_NO_ERROR; + *keyring_passwd = NULL; + + if ((function == NULL) || (function == Py_None)) + return SVN_NO_ERROR; + + svn_swig_py_acquire_py_lock(); + + if ((result = PyObject_CallFunction(function, + (char *)"sO&", + keyring_name, + make_ob_pool, pool)) == NULL) + { + err = callback_exception_error(); + } + else + { + *keyring_passwd = make_string_from_ob(result, pool); + Py_DECREF(result); + } + + svn_swig_py_release_py_lock(); + return err; +} + + +svn_error_t * svn_swig_py_auth_simple_prompt_func(svn_auth_cred_simple_t **cred, void *baton, const char *realm, Index: subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h 2012-01-05 20:10:54.669914473 +0100 +++ subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h 2012-01-05 20:38:07.598414690 +0100 @@ -423,6 +423,13 @@ /* auth provider callbacks */ SVN_SWIG_SWIGUTIL_EXPORT +svn_error_t * svn_swig_py_auth_gnome_keyring_unlock_prompt_func( + char **keyring_passwd, + const char *keyring_name, + void *baton, + apr_pool_t *pool); + +SVN_SWIG_SWIGUTIL_EXPORT svn_error_t *svn_swig_py_auth_simple_prompt_func( svn_auth_cred_simple_t **cred, void *baton, Index: subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c 2012-01-05 20:10:54.641914327 +0100 +++ subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c 2012-01-05 20:38:07.602414751 +0100 @@ -2963,6 +2963,41 @@ } svn_error_t * +svn_swig_rb_auth_gnome_keyring_unlock_prompt_func(char **keyring_passwd, + const char *keyring_name, + void *baton, + apr_pool_t *pool) +{ + svn_error_t *err = SVN_NO_ERROR; + VALUE proc, rb_pool; + *keyring_passwd = NULL; + + svn_swig_rb_from_baton((VALUE)baton, &proc, &rb_pool); + + if (!NIL_P(proc)) { + char error_message[] = + "svn_auth_gnome_keyring_unlock_prompt_func_t should" + "return a string, not '%s'."; + + callback_baton_t cbb; + VALUE result; + + cbb.receiver = proc; + cbb.message = id_call; + cbb.args = rb_ary_new3(1, c2r_string2(keyring_name)); + result = invoke_callback_handle_error((VALUE)(&cbb), rb_pool, &err); + + if (!NIL_P(result)) { + if (!RTEST(rb_obj_is_kind_of(result, rb_cString))) + rb_raise(rb_eTypeError, error_message, r2c_inspect(result)); + *keyring_passwd = (char *)r2c_string(result, NULL, pool); + } + } + + return err; +} + +svn_error_t * svn_swig_rb_auth_username_prompt_func(svn_auth_cred_username_t **cred, void *baton, const char *realm, Index: subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h 2012-01-05 20:10:54.625914222 +0100 +++ subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h 2012-01-05 20:38:07.602414751 +0100 @@ -380,6 +380,13 @@ /* auth provider callbacks */ SVN_RB_SWIG_SWIGUTIL_EXPORT +svn_error_t * svn_swig_rb_auth_gnome_keyring_unlock_prompt_func( + char **keyring_passwd, + const char *keyring_name, + void *baton, + apr_pool_t *pool); + +SVN_RB_SWIG_SWIGUTIL_EXPORT svn_error_t *svn_swig_rb_auth_simple_prompt_func( svn_auth_cred_simple_t **cred, void *baton, Index: subversion-trunk/subversion/bindings/swig/perl/native/t/3client.t =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/perl/native/t/3client.t 2012-01-05 20:10:54.581914016 +0100 +++ subversion-trunk/subversion/bindings/swig/perl/native/t/3client.t 2012-01-05 20:38:07.602414751 +0100 @@ -20,7 +20,7 @@ # # -use Test::More tests => 119; +use Test::More tests => 120; use strict; # shut up about variables that are only used once. @@ -477,6 +477,23 @@ } ok($ok, 'svn_auth_get_platform_specific_client_providers returns _p_svn_auth_provider_object_t\'s'); +# Test setting gnome_keyring prompt function. This just sets the proper +# attributes in the auth baton and checks the return value (which should +# be a reference to the passed function reference). This does not +# actually try the prompt, since that would require setting up a +# gnome-keyring-daemon... +sub gnome_keyring_unlock_prompt { + my $keyring_name = shift; + my $pool = shift; + + 'test'; +} + +my $callback = \&gnome_keyring_unlock_prompt; +my $result = SVN::Core::auth_set_gnome_keyring_unlock_prompt_func( + $ctx->auth(), $callback); +is(${$result}, $callback, 'auth_set_gnome_keyring_unlock_prompt_func result equals paramter'); + END { diag('cleanup'); rmtree($testpath); Index: subversion-trunk/subversion/bindings/swig/python/tests/client.py =================================================================== --- subversion-trunk.orig/subversion/bindings/swig/python/tests/client.py 2012-01-05 20:10:54.685914561 +0100 +++ subversion-trunk/subversion/bindings/swig/python/tests/client.py 2012-01-05 20:38:07.602414751 +0100 @@ -379,6 +379,17 @@ # Not much more we can test in this minimal environment. self.assert_(isinstance(providers, list)) + def testGnomeKeyring(self): + # This tests setting the gnome-keyring unlock prompt function as an + # auth baton parameter. It doesn't actually call gnome-keyring + # stuff, since that would require having a gnome-keyring running. We + # just test if this doesn't error out, there's not even a return + # value to test. + def prompt_func(realm_string, pool): + return "Foo" + + core.svn_auth_set_gnome_keyring_unlock_prompt_func(self.client_ctx.auth_baton, prompt_func) + def suite(): return unittest.defaultTestLoader.loadTestsFromTestCase( SubversionClientTestCase) Index: subversion-trunk/tools/examples/get-location-segments.py =================================================================== --- subversion-trunk.orig/tools/examples/get-location-segments.py 2012-01-05 20:10:54.713914714 +0100 +++ subversion-trunk/tools/examples/get-location-segments.py 2012-01-05 20:38:07.602414751 +0100 @@ -105,6 +105,9 @@ simple_cred.may_save = False return simple_cred +def prompt_func_gnome_keyring_prompt(keyring, pool): + return getpass.getpass(prompt="Password for '%s' GNOME keyring: " % keyring) + def main(): try: url, peg_revision, start_revision, end_revision = parse_args(sys.argv[1:]) @@ -145,6 +148,9 @@ ctx.auth_baton = core.svn_auth_open(providers) ctx.config = core.svn_config_get_config(None) + if hasattr(core, 'svn_auth_set_gnome_keyring_unlock_prompt_func'): + core.svn_auth_set_gnome_keyring_unlock_prompt_func(ctx.auth_baton, prompt_func_gnome_keyring_prompt) + ra_callbacks = ra.callbacks_t() ra_callbacks.auth_baton = ctx.auth_baton ra_session = ra.open(url, ra_callbacks, None, ctx.config) Index: subversion-trunk/tools/examples/info.rb =================================================================== --- subversion-trunk.orig/tools/examples/info.rb 2012-01-05 20:38:00.378378028 +0100 +++ subversion-trunk/tools/examples/info.rb 2012-01-05 20:46:50.477075228 +0100 @@ -1,7 +1,9 @@ +#!/usr/bin/ruby # Example based on a blogpost by Mark Deepwell # http://www.markdeepwell.com/2010/06/ruby-subversion-bindings/ require "svn/core" +require "svn/ext/core" require "svn/client" require "svn/wc" require "svn/repos" @@ -21,6 +23,12 @@ result.password = STDIN.gets.strip end +gnome_keyring_prompt = Proc.new do + |keyring_name| + + print "Password for '#{keyring_name}' GNOME keyring: " + STDIN.gets.strip +end if ARGV.length != 1 puts "Usage: info.rb URL[@REV]" @@ -34,6 +42,12 @@ ctx.add_ssl_client_cert_file_provider ctx.add_ssl_client_cert_pw_file_provider + # Allow asking for the gnome keyring password, in case the keyring is + # locked. + if Svn::Ext::Core.respond_to?(:svn_auth_set_gnome_keyring_unlock_prompt_func) + Svn::Ext::Core::svn_auth_set_gnome_keyring_unlock_prompt_func(ctx.auth_baton, gnome_keyring_prompt) + end + repos_uri, revision = ARGV[0].split("@", 2) if revision revision = Integer(revision)
signature.asc
Description: Digital signature