1 //
2 // ====================================================================
3 // (c) 2003-2009 Barry A Scott.  All rights reserved.
4 //
5 // This software is licensed as described in the file LICENSE.txt,
6 // which you should have received as part of this distribution.
7 //
8 // ====================================================================
9 //
10 //
11 //  pysvn_client.cpp
12 //
13 
14 #if defined( _MSC_VER )
15 // disable warning C4786: symbol greater than 255 character,
16 // nessesary to ignore as <map> causes lots of warning
17 #pragma warning(disable: 4786)
18 #endif
19 
20 #include "pysvn.hpp"
21 #include "pysvn_docs.hpp"
22 #include "pysvn_svnenv.hpp"
23 #include "svn_path.h"
24 #include "svn_config.h"
25 #include "svn_sorts.h"
26 #include "pysvn_static_strings.hpp"
27 
28 static const char *g_utf_8 = "utf-8";
29 
init_py_names()30 static void init_py_names()
31 {
32     static bool init_done = false;
33     if( init_done )
34     {
35         return;
36     }
37 
38     py_name_callback_cancel = new Py::String( name_callback_cancel );
39     py_name_callback_conflict_resolver = new Py::String( name_callback_conflict_resolver );
40     py_name_callback_get_log_message = new Py::String( name_callback_get_log_message );
41     py_name_callback_get_login = new Py::String( name_callback_get_login );
42     py_name_callback_notify = new Py::String( name_callback_notify );
43     py_name_callback_ssl_client_cert_password_prompt = new Py::String( name_callback_ssl_client_cert_password_prompt );
44     py_name_callback_ssl_client_cert_prompt = new Py::String( name_callback_ssl_client_cert_prompt );
45     py_name_callback_ssl_server_prompt = new Py::String( name_callback_ssl_server_prompt );
46     py_name_callback_ssl_server_trust_prompt = new Py::String( name_callback_ssl_server_trust_prompt );
47     py_name_commit_info_style = new Py::String( name_commit_info_style );
48     py_name_created_rev = new Py::String( name_created_rev );
49     py_name_exception_style = new Py::String( name_exception_style );
50     py_name_has_props = new Py::String( name_has_props );
51     py_name_kind = new Py::String( name_kind );
52     py_name_last_author = new Py::String( name_last_author );
53     py_name_lock = new Py::String( name_lock );
54     py_name_name = new Py::String( name_name );
55     py_name_node_kind = new Py::String( name_node_kind );
56     py_name_path = new Py::String( name_path );
57     py_name_prop_changed = new Py::String( name_prop_changed );
58     py_name_repos_path = new Py::String( name_repos_path );
59     py_name_size = new Py::String( name_size );
60     py_name_summarize_kind = new Py::String( name_summarize_kind );
61     py_name_time = new Py::String( name_time );
62 
63     init_done = true;
64 }
65 
66 //--------------------------------------------------------------------------------
67 #if defined( PYSVN_HAS_CLIENT_STATUS_T )
68 std::string name_wrapper_status2("PysvnStatus2");
69 #endif
70 std::string name_wrapper_status("PysvnStatus");
71 std::string name_wrapper_entry("PysvnEntry");
72 std::string name_wrapper_info("PysvnInfo");
73 std::string name_wrapper_lock("PysvnLock");
74 std::string name_wrapper_list("PysvnList");
75 std::string name_wrapper_log("PysvnLog");
76 std::string name_wrapper_log_changed_path("PysvnLogChangedPath");
77 std::string name_wrapper_dirent("PysvnDirent");
78 std::string name_wrapper_wc_info("PysvnWcInfo");
79 std::string name_wrapper_diff_summary("PysvnDiffSummary");
80 std::string name_wrapper_commit_info("PysvnCommitInfo");
81 
pysvn_client(pysvn_module & _module,const std::string & config_dir,Py::Dict result_wrappers)82 pysvn_client::pysvn_client
83     (
84     pysvn_module &_module,
85     const std::string &config_dir,
86     Py::Dict result_wrappers
87     )
88 : m_module( _module )
89 , m_result_wrappers( result_wrappers )
90 , m_context( config_dir )
91 , m_exception_style( 0 )
92 , m_commit_info_style( 0 )
93 #if defined( PYSVN_HAS_CLIENT_STATUS_T )
94 , m_wrapper_status2( result_wrappers, name_wrapper_status2 )
95 #endif
96 , m_wrapper_status( result_wrappers, name_wrapper_status )
97 , m_wrapper_entry( result_wrappers, name_wrapper_entry )
98 , m_wrapper_info( result_wrappers, name_wrapper_info )
99 , m_wrapper_lock( result_wrappers, name_wrapper_lock )
100 , m_wrapper_list( result_wrappers, name_wrapper_list )
101 , m_wrapper_log( result_wrappers, name_wrapper_log )
102 , m_wrapper_log_changed_path( result_wrappers, name_wrapper_log_changed_path )
103 , m_wrapper_dirent( result_wrappers, name_wrapper_dirent )
104 , m_wrapper_wc_info( result_wrappers, name_wrapper_wc_info )
105 , m_wrapper_diff_summary( result_wrappers, name_wrapper_diff_summary )
106 , m_wrapper_commit_info( result_wrappers, name_wrapper_commit_info )
107 {
108     init_py_names();
109 }
110 
~pysvn_client()111 pysvn_client::~pysvn_client()
112 {
113 }
114 
getattr(const char * _name)115 Py::Object pysvn_client::getattr( const char *_name )
116 {
117     std::string name( _name );
118 
119     // std::cout << "getattr( " << name << " )" << std::endl << std::flush;
120 
121     if( name == name___members__ )
122     {
123         Py::List members;
124 
125         members.append( *py_name_callback_get_login );
126         members.append( *py_name_callback_notify );
127         members.append( *py_name_callback_cancel );
128         members.append( *py_name_callback_conflict_resolver );
129         members.append( *py_name_callback_get_log_message );
130         members.append( *py_name_callback_ssl_server_prompt );
131         members.append( *py_name_callback_ssl_server_trust_prompt );
132         members.append( *py_name_callback_ssl_client_cert_prompt );
133         members.append( *py_name_callback_ssl_client_cert_password_prompt );
134 
135         members.append( *py_name_exception_style );
136         members.append( *py_name_commit_info_style );
137 
138         return members;
139     }
140 
141     if( name == name_callback_get_login )
142         return m_context.m_pyfn_GetLogin;
143 
144     if( name == name_callback_notify )
145         return m_context.m_pyfn_Notify;
146 
147 #if defined( PYSVN_HAS_CONTEXT_PROGRESS )
148     if( name == name_callback_progress )
149         return m_context.m_pyfn_Progress;
150 #endif
151 
152 #if defined( PYSVN_HAS_SVN_CLIENT_CTX_T__CONFLICT_FUNC )
153     if( name == name_callback_conflict_resolver )
154         return m_context.m_pyfn_ConflictResolver;
155 #endif
156 
157     if( name == name_callback_cancel )
158         return m_context.m_pyfn_Cancel;
159 
160     if( name == name_callback_get_log_message )
161         return m_context.m_pyfn_GetLogMessage;
162 
163     if( name == name_callback_ssl_server_prompt )
164         return m_context.m_pyfn_SslServerPrompt;
165 
166     if( name == name_callback_ssl_server_trust_prompt )
167         return m_context.m_pyfn_SslServerTrustPrompt;
168 
169     if( name == name_callback_ssl_client_cert_prompt )
170         return m_context.m_pyfn_SslClientCertPrompt;
171 
172     if( name == name_callback_ssl_client_cert_password_prompt )
173         return m_context.m_pyfn_SslClientCertPwPrompt;
174 
175     if( name == name_callback_ssl_client_cert_password_prompt )
176         return m_context.m_pyfn_SslClientCertPwPrompt;
177 
178     if( name == name_exception_style )
179         return Py::Int( m_exception_style );
180 
181     if( name == name_commit_info_style )
182         return Py::Int( m_commit_info_style );
183 
184     return getattr_default( _name );
185 }
186 
set_callable(Py::Object & callback,const Py::Object & value)187 static bool set_callable( Py::Object &callback, const Py::Object &value )
188 {
189     if( value.isCallable() )
190     {
191         callback = value;
192         return true;
193     }
194 
195     else
196     if( value.is( Py::None() ) )
197     {
198         callback = value;
199         return false;
200     }
201 
202     else
203     {
204         throw Py::AttributeError( "expecting None or a callable object" );
205     }
206 }
207 
setattr(const char * _name,const Py::Object & value)208 int pysvn_client::setattr( const char *_name, const Py::Object &value )
209 {
210     std::string name( _name );
211     if( name == name_callback_get_login )
212         set_callable( m_context.m_pyfn_GetLogin, value );
213 
214     else if( name == name_callback_notify )
215         m_context.installNotify( set_callable( m_context.m_pyfn_Notify, value ) );
216 
217 #if defined( PYSVN_HAS_CONTEXT_PROGRESS )
218     else if( name == name_callback_progress )
219         m_context.installProgress( set_callable( m_context.m_pyfn_Progress, value ) );
220 #endif
221 
222 #if defined( PYSVN_HAS_SVN_CLIENT_CTX_T__CONFLICT_FUNC )
223     else if( name == name_callback_conflict_resolver )
224         m_context.installConflictResolver( set_callable( m_context.m_pyfn_ConflictResolver, value ) );
225 #endif
226 
227     else if( name == name_callback_cancel )
228         m_context.installCancel( set_callable( m_context.m_pyfn_Cancel, value ) );
229 
230     else if( name == name_callback_get_log_message )
231         set_callable( m_context.m_pyfn_GetLogMessage, value );
232 
233     else if( name == name_callback_ssl_server_prompt )
234         set_callable( m_context.m_pyfn_SslServerPrompt, value );
235 
236     else if( name == name_callback_ssl_server_trust_prompt )
237         set_callable( m_context.m_pyfn_SslServerTrustPrompt, value );
238 
239     else if( name == name_callback_ssl_client_cert_prompt )
240         set_callable( m_context.m_pyfn_SslClientCertPrompt, value );
241 
242     else if( name == name_callback_ssl_client_cert_password_prompt )
243         set_callable( m_context.m_pyfn_SslClientCertPwPrompt, value );
244 
245     else if( name == name_exception_style )
246     {
247         Py::Int style( value );
248         if( style == 0l || style == 1l )
249         {
250             m_exception_style = style;
251         }
252             else
253         {
254             throw Py::AttributeError( "exception_style value must be 0 or 1" );
255         }
256     }
257 
258     else if( name == name_commit_info_style )
259     {
260         Py::Int style( value );
261         if( style == 0l || style == 1l || style == 2l )
262         {
263             m_commit_info_style = style;
264         }
265             else
266         {
267             throw Py::AttributeError( "commit_info_style value must be 0, 1 or 2" );
268         }
269     }
270 
271     else
272     {
273         std::string msg( "Unknown attribute: " );
274         msg += name;
275         throw Py::AttributeError( msg );
276     }
277 
278     return 0;
279 }
280 
281 
helper_boolean_auth_set(FunctionArguments & a_args,const char * a_arg_name,const char * a_param_name)282 Py::Object pysvn_client::helper_boolean_auth_set( FunctionArguments &a_args, const char *a_arg_name, const char *a_param_name )
283 {
284     a_args.check();
285 
286     bool enable( a_args.getBoolean( a_arg_name ) );
287     try
288     {
289         void *param = 0;
290         if( !enable )
291             param = (void *)"1";
292 
293         svn_auth_set_parameter
294             (
295             m_context.ctx()->auth_baton,
296             a_param_name,
297             param
298             );
299     }
300     catch( SvnException &e )
301     {
302         // use callback error over ClientException
303         m_context.checkForError( m_module.client_error );
304 
305         throw_client_error( e );
306     }
307 
308     return Py::None();
309 }
310 
helper_boolean_auth_get(FunctionArguments & a_args,const char * a_param_name)311 Py::Object pysvn_client::helper_boolean_auth_get( FunctionArguments &a_args, const char *a_param_name )
312 {
313     a_args.check();
314 
315     char *param = NULL;
316     try
317     {
318         param = (char *)svn_auth_get_parameter
319             (
320             m_context.ctx()->auth_baton,
321             a_param_name
322             );
323     }
324     catch( SvnException &e )
325     {
326         // use callback error over ClientException
327         m_context.checkForError( m_module.client_error );
328 
329         throw_client_error( e );
330     }
331 
332     bool not_set = param != NULL && param[0] == '1';
333     if( not_set )
334         return Py::Int( 0 );
335     return Py::Int( 1 );
336 }
337 
helper_string_auth_set(FunctionArguments & a_args,const char * a_arg_name,const char * a_param_name,std::string & ctx_str)338 Py::Object pysvn_client::helper_string_auth_set
339     (
340     FunctionArguments &a_args,
341     const char *a_arg_name,
342     const char *a_param_name,
343     std::string &ctx_str
344     )
345 {
346     a_args.check();
347 
348     const char *param = NULL;
349     Py::Object param_obj( a_args.getArg( a_arg_name ) );
350     if( !param_obj.is( Py::None() ) )
351     {
352         Py::String param_str( param_obj );
353         ctx_str = param_str.as_std_string( g_utf_8 );
354         param = ctx_str.c_str();
355     }
356 
357     try
358     {
359         svn_auth_set_parameter
360             (
361             m_context.ctx()->auth_baton,
362             a_param_name,
363             param
364             );
365     }
366     catch( SvnException &e )
367     {
368         // use callback error over ClientException
369         m_context.checkForError( m_module.client_error );
370 
371         throw_client_error( e );
372     }
373 
374     return Py::None();
375 }
376 
helper_string_auth_get(FunctionArguments & a_args,const char * a_param_name)377 Py::Object pysvn_client::helper_string_auth_get( FunctionArguments &a_args, const char *a_param_name )
378 {
379     a_args.check();
380 
381     char *param = NULL;
382     try
383     {
384         param = (char *)svn_auth_get_parameter
385             (
386             m_context.ctx()->auth_baton,
387             a_param_name
388             );
389     }
390     catch( SvnException &e )
391     {
392         // use callback error over ClientException
393         m_context.checkForError( m_module.client_error );
394 
395         throw_client_error( e );
396     }
397 
398     if( param != NULL )
399         return Py::String( param );
400 
401     return Py::None();
402 }
403 
404 #if defined( PYSVN_HAS_WC_ADM_DIR )
get_adm_dir(const Py::Tuple & a_args,const Py::Dict & a_kws)405 Py::Object pysvn_client::get_adm_dir( const Py::Tuple &a_args, const Py::Dict &a_kws )
406 {
407     static argument_description args_desc[] =
408     {
409     { false, NULL }
410     };
411     FunctionArguments args( "get_adm_dir", args_desc, a_args, a_kws );
412     args.check();
413 
414     const char *name = NULL;
415 
416     try
417     {
418         name = svn_wc_get_adm_dir
419             (
420             m_context.getContextPool()
421             );
422     }
423     catch( SvnException &e )
424     {
425         // use callback error over ClientException
426         m_context.checkForError( m_module.client_error );
427 
428         throw_client_error( e );
429     }
430 
431     return Py::String( name );
432 }
433 #endif
434 
get_auth_cache(const Py::Tuple & a_args,const Py::Dict & a_kws)435 Py::Object pysvn_client::get_auth_cache( const Py::Tuple &a_args, const Py::Dict &a_kws )
436 {
437     static argument_description args_desc[] =
438     {
439     { false, NULL }
440     };
441     FunctionArguments args( "get_auth_cache", args_desc, a_args, a_kws );
442 
443     return helper_boolean_auth_get( args, SVN_AUTH_PARAM_NO_AUTH_CACHE );
444 }
445 
get_interactive(const Py::Tuple & a_args,const Py::Dict & a_kws)446 Py::Object pysvn_client::get_interactive( const Py::Tuple &a_args, const Py::Dict &a_kws )
447 {
448     static argument_description args_desc[] =
449     {
450     { false, NULL }
451     };
452     FunctionArguments args( "get_interactive", args_desc, a_args, a_kws );
453 
454     return helper_boolean_auth_get( args, SVN_AUTH_PARAM_NON_INTERACTIVE );
455 }
456 
get_store_passwords(const Py::Tuple & a_args,const Py::Dict & a_kws)457 Py::Object pysvn_client::get_store_passwords( const Py::Tuple &a_args, const Py::Dict &a_kws )
458 {
459     static argument_description args_desc[] =
460     {
461     { false, NULL }
462     };
463     FunctionArguments args( "get_store_passwords", args_desc, a_args, a_kws );
464 
465     return helper_boolean_auth_get( args, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS );
466 }
467 
get_default_username(const Py::Tuple & a_args,const Py::Dict & a_kws)468 Py::Object pysvn_client::get_default_username( const Py::Tuple &a_args, const Py::Dict &a_kws )
469 {
470     static argument_description args_desc[] =
471     {
472     { false, NULL }
473     };
474     FunctionArguments args( "get_default_username", args_desc, a_args, a_kws );
475 
476     return helper_string_auth_get( args, SVN_AUTH_PARAM_DEFAULT_USERNAME );
477 }
478 
get_default_password(const Py::Tuple & a_args,const Py::Dict & a_kws)479 Py::Object pysvn_client::get_default_password( const Py::Tuple &a_args, const Py::Dict &a_kws )
480 {
481     static argument_description args_desc[] =
482     {
483     { false, NULL }
484     };
485     FunctionArguments args( "get_default_password", args_desc, a_args, a_kws );
486 
487     return helper_string_auth_get( args, SVN_AUTH_PARAM_DEFAULT_PASSWORD );
488 }
489 
490 #if defined( PYSVN_HAS_WC_ADM_DIR )
set_adm_dir(const Py::Tuple & a_args,const Py::Dict & a_kws)491 Py::Object pysvn_client::set_adm_dir( const Py::Tuple &a_args, const Py::Dict &a_kws )
492 {
493     static argument_description args_desc[] =
494     {
495     { true,  name_name },
496     { false, NULL }
497     };
498     FunctionArguments args( "set_adm_dir", args_desc, a_args, a_kws );
499 
500     args.check();
501 
502     std::string name( args.getBytes( name_name ) );
503 
504     try
505     {
506         svn_wc_set_adm_dir
507             (
508             name.c_str(),
509             m_context.getContextPool()
510             );
511     }
512     catch( SvnException &e )
513     {
514         // use callback error over ClientException
515         m_context.checkForError( m_module.client_error );
516 
517         throw_client_error( e );
518     }
519 
520     return Py::None();
521 }
522 #endif
523 
set_auth_cache(const Py::Tuple & a_args,const Py::Dict & a_kws)524 Py::Object pysvn_client::set_auth_cache( const Py::Tuple &a_args, const Py::Dict &a_kws )
525 {
526     static argument_description args_desc[] =
527     {
528     { true,  name_enable },
529     { false, NULL }
530     };
531     FunctionArguments args( "set_auth_cache", args_desc, a_args, a_kws );
532 
533     return helper_boolean_auth_set( args, name_enable, SVN_AUTH_PARAM_NO_AUTH_CACHE );
534 }
535 
set_interactive(const Py::Tuple & a_args,const Py::Dict & a_kws)536 Py::Object pysvn_client::set_interactive( const Py::Tuple &a_args, const Py::Dict &a_kws )
537 {
538     static argument_description args_desc[] =
539     {
540     { true,  name_enable },
541     { false, NULL }
542     };
543     FunctionArguments args( "set_interactive", args_desc, a_args, a_kws );
544 
545     return helper_boolean_auth_set( args, name_enable, SVN_AUTH_PARAM_NON_INTERACTIVE );
546 }
547 
set_store_passwords(const Py::Tuple & a_args,const Py::Dict & a_kws)548 Py::Object pysvn_client::set_store_passwords( const Py::Tuple &a_args, const Py::Dict &a_kws )
549 {
550     static argument_description args_desc[] =
551     {
552     { true,  name_enable },
553     { false, NULL }
554     };
555     FunctionArguments args( "set_store_passwords", args_desc, a_args, a_kws );
556 
557     return helper_boolean_auth_set( args, name_enable, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS );
558 }
559 
set_default_username(const Py::Tuple & a_args,const Py::Dict & a_kws)560 Py::Object pysvn_client::set_default_username( const Py::Tuple &a_args, const Py::Dict &a_kws )
561 {
562     static argument_description args_desc[] =
563     {
564     { true,  name_username },
565     { false, NULL }
566     };
567     FunctionArguments args( "set_default_username", args_desc, a_args, a_kws );
568 
569     return helper_string_auth_set( args, name_username, SVN_AUTH_PARAM_DEFAULT_USERNAME, m_context.m_default_username );
570 }
571 
set_default_password(const Py::Tuple & a_args,const Py::Dict & a_kws)572 Py::Object pysvn_client::set_default_password( const Py::Tuple &a_args, const Py::Dict &a_kws )
573 {
574     static argument_description args_desc[] =
575     {
576     { true,  name_password },
577     { false, NULL }
578     };
579     FunctionArguments args( "set_default_password", args_desc, a_args, a_kws );
580 
581     return helper_string_auth_set( args, name_password, SVN_AUTH_PARAM_DEFAULT_PASSWORD, m_context.m_default_password );
582 }
583 
get_auto_props(const Py::Tuple & a_args,const Py::Dict & a_kws)584 Py::Object pysvn_client::get_auto_props( const Py::Tuple &a_args, const Py::Dict &a_kws )
585 {
586     static argument_description args_desc[] =
587     {
588     { false, NULL }
589     };
590     FunctionArguments args( "get_auto_props", args_desc, a_args, a_kws );
591     args.check();
592 
593     svn_boolean_t enable = false;
594     try
595     {
596         svn_config_t *cfg = (svn_config_t *)apr_hash_get
597             (
598             m_context.ctx()->config,
599             SVN_CONFIG_CATEGORY_CONFIG,
600             APR_HASH_KEY_STRING
601             );
602         svn_error_t *error = svn_config_get_bool
603             (
604             cfg,
605             &enable,
606             SVN_CONFIG_SECTION_MISCELLANY,
607             SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS,
608             enable
609             );
610         if( error != NULL )
611             throw SvnException( error );
612     }
613     catch( SvnException &e )
614     {
615         // use callback error over ClientException
616         m_context.checkForError( m_module.client_error );
617 
618         throw_client_error( e );
619     }
620 
621     return Py::Int( enable );
622 }
623 
set_auto_props(const Py::Tuple & a_args,const Py::Dict & a_kws)624 Py::Object pysvn_client::set_auto_props( const Py::Tuple &a_args, const Py::Dict &a_kws )
625 {
626     static argument_description args_desc[] =
627     {
628     { true,  name_enable },
629     { false, NULL }
630     };
631     FunctionArguments args( "set_auto_props", args_desc, a_args, a_kws );
632     args.check();
633 
634     bool enable( args.getBoolean( name_enable ) );
635     try
636     {
637         svn_config_t *cfg = (svn_config_t *)apr_hash_get
638             (
639             m_context.ctx()->config,
640             SVN_CONFIG_CATEGORY_CONFIG,
641             APR_HASH_KEY_STRING
642             );
643         svn_config_set_bool
644             (
645             cfg,
646             SVN_CONFIG_SECTION_MISCELLANY,
647             SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS,
648             enable
649             );
650     }
651     catch( SvnException &e )
652     {
653         // use callback error over ClientException
654         m_context.checkForError( m_module.client_error );
655 
656         throw_client_error( e );
657     }
658 
659     return Py::None();
660 }
661 
662 #if defined( PYSVN_HAS_WC_ADM_DIR )
is_adm_dir(const Py::Tuple & a_args,const Py::Dict & a_kws)663 Py::Object pysvn_client::is_adm_dir( const Py::Tuple &a_args, const Py::Dict &a_kws )
664 {
665     static argument_description args_desc[] =
666     {
667     { true,  name_name },
668     { false, NULL }
669     };
670     FunctionArguments args( "is_adm_dir", args_desc, a_args, a_kws );
671 
672     args.check();
673 
674     std::string name( args.getBytes( name_name ) );
675 
676     svn_boolean_t name_is_adm_dir = 0;
677     try
678     {
679         name_is_adm_dir = svn_wc_is_adm_dir
680             (
681             name.c_str(),
682             m_context.getContextPool()
683             );
684     }
685     catch( SvnException &e )
686     {
687         // use callback error over ClientException
688         m_context.checkForError( m_module.client_error );
689 
690         throw_client_error( e );
691     }
692 
693     return Py::Int( name_is_adm_dir );
694 }
695 #endif
696 
is_url(const Py::Tuple & a_args,const Py::Dict & a_kws)697 Py::Object pysvn_client::is_url( const Py::Tuple &a_args, const Py::Dict &a_kws )
698 {
699     static argument_description args_desc[] =
700     {
701     { true,  name_url },
702     { false, NULL }
703     };
704     FunctionArguments args( "is_url", args_desc, a_args, a_kws );
705     args.check();
706 
707     Py::String path( args.getUtf8String( name_url ) );
708 
709     Py::Int result( is_svn_url( path ) );
710     return result;
711 }
712 
713 #if defined( PYSVN_HAS_CLIENT_ROOT_URL_FROM_PATH )
cmd_root_url_from_path(const Py::Tuple & a_args,const Py::Dict & a_kws)714 Py::Object pysvn_client::cmd_root_url_from_path( const Py::Tuple& a_args, const Py::Dict &a_kws )
715 {
716     static argument_description args_desc[] =
717     {
718     { true,  name_url_or_path },
719     { false, NULL }
720     };
721     FunctionArguments args( "root_url_from_path", args_desc, a_args, a_kws );
722 
723     args.check();
724 
725     std::string path( args.getUtf8String( name_url_or_path ) );
726 
727     SvnPool pool( m_context );
728     const char *root_url = NULL;
729     try
730     {
731         std::string norm_path( svnNormalisedIfPath( path, pool ) );
732 
733         checkThreadPermission();
734 
735         PythonAllowThreads permission( m_context );
736 
737         // known to call back into pysvn
738 #if defined( PYSVN_HAS_CLIENT_GET_REPOS_ROOT )
739         const char *repos_uuid = NULL;
740         svn_error_t *error = svn_client_get_repos_root
741             (
742             &root_url,
743             &repos_uuid,
744             norm_path.c_str(),
745             m_context,
746             pool,
747             pool
748             );
749 #else
750         svn_error_t *error = svn_client_root_url_from_path
751             (
752             &root_url,
753             norm_path.c_str(),
754             m_context,
755             pool
756             );
757 #endif
758         if( error != NULL )
759             throw SvnException( error );
760     }
761     catch( SvnException &e )
762     {
763         // use callback error over ClientException
764         m_context.checkForError( m_module.client_error );
765 
766         throw_client_error( e );
767     }
768 
769     return Py::String( root_url );
770 }
771 #endif
772 
773 // check that we are not in use on another thread
checkThreadPermission()774 void pysvn_client::checkThreadPermission()
775 {
776     if( m_context.hasPermission() )
777     {
778         throw Py::BaseException( m_module.client_error,
779             "client in use on another thread" );
780     }
781 }
782 
throw_client_error(SvnException & e)783 void pysvn_client::throw_client_error( SvnException &e )
784 {
785     throw Py::BaseException(
786         m_module.client_error,
787         e.pythonExceptionArg( m_exception_style ) );
788 }
789 
revisionKindCompatibleCheck(bool is_url,const svn_opt_revision_t & revision,const char * revision_name,const char * url_or_path_name)790 void revisionKindCompatibleCheck
791     (
792     bool is_url,
793     const svn_opt_revision_t &revision,
794     const char *revision_name,
795     const char *url_or_path_name
796     )
797 {
798     std::string message;
799     if( is_url )
800     {
801         // URL compatibility
802         switch( revision.kind )
803         {
804         case svn_opt_revision_number:
805         case svn_opt_revision_date:
806         case svn_opt_revision_committed:
807         case svn_opt_revision_previous:
808         case svn_opt_revision_head:
809         case svn_opt_revision_unspecified:
810             break;
811 
812         case svn_opt_revision_working:
813         case svn_opt_revision_base:
814         default:
815             message += revision_name;
816             message += " is not compatible with URL ";
817             message += url_or_path_name;
818             throw Py::AttributeError( message );
819         }
820     }
821 #if defined( there_are_any_checks_for_path )
822     else
823     {
824         // PATH compatibility
825         switch( revision.kind )
826         {
827         case svn_opt_revision_working:
828         case svn_opt_revision_base:
829         case svn_opt_revision_unspecified:
830             break;
831 
832         case svn_opt_revision_number:
833         case svn_opt_revision_date:
834         case svn_opt_revision_committed:
835         case svn_opt_revision_previous:
836         case svn_opt_revision_head:
837         default:
838             message += revision_name;
839             message += " is not compatible with path ";
840             message += url_or_path_name;
841             throw Py::AttributeError( message );
842         }
843     }
844 #endif
845 }
846 
init_type()847 void pysvn_client::init_type()
848 {
849     behaviors().name("Client");
850     behaviors().doc( pysvn_client_doc );
851     behaviors().supportGetattr();
852     behaviors().supportSetattr();
853 
854     add_keyword_method("add", &pysvn_client::cmd_add, pysvn_client_add_doc );
855 #if defined( PYSVN_HAS_CLIENT_ADD_TO_CHANGELIST )
856     add_keyword_method("add_to_changelist", &pysvn_client::cmd_add_to_changelist, pysvn_client_add_to_changelist_doc );
857 #endif
858     add_keyword_method("annotate", &pysvn_client::cmd_annotate, pysvn_client_annotate_doc );
859 #if defined( PYSVN_HAS_CLIENT_ANNOTATE5 )
860     add_keyword_method("annotate2", &pysvn_client::cmd_annotate2, pysvn_client_annotate2_doc );
861 #endif
862     add_keyword_method("cat", &pysvn_client::cmd_cat, pysvn_client_cat_doc );
863     add_keyword_method("checkin", &pysvn_client::cmd_checkin, pysvn_client_checkin_doc );
864     add_keyword_method("checkout", &pysvn_client::cmd_checkout, pysvn_client_checkout_doc );
865     add_keyword_method("cleanup", &pysvn_client::cmd_cleanup, pysvn_client_cleanup_doc );
866     add_keyword_method("copy", &pysvn_client::cmd_copy, pysvn_client_copy_doc );
867 #if defined( PYSVN_HAS_CLIENT_COPY4 )
868     add_keyword_method("copy2", &pysvn_client::cmd_copy2, pysvn_client_copy2_doc );
869 #endif
870     add_keyword_method("diff", &pysvn_client::cmd_diff, pysvn_client_diff_doc );
871 #if defined( PYSVN_HAS_CLIENT_DIFF_PEG )
872     add_keyword_method("diff_peg", &pysvn_client::cmd_diff_peg, pysvn_client_diff_peg_doc );
873 #endif
874 #if defined( PYSVN_HAS_CLIENT_DIFF_SUMMARIZE )
875     add_keyword_method("diff_summarize", &pysvn_client::cmd_diff_summarize, pysvn_client_diff_summarize_doc );
876     add_keyword_method("diff_summarize_peg", &pysvn_client::cmd_diff_summarize_peg, pysvn_client_diff_summarize_peg_doc );
877 #endif
878     add_keyword_method("export", &pysvn_client::cmd_export, pysvn_client_export_doc );
879 #if defined( PYSVN_HAS_CLIENT_GET_CHANGELIST )
880     add_keyword_method("get_changelist", &pysvn_client::cmd_get_changelist, pysvn_client_get_changelist_doc );
881 #endif
882 #if defined( PYSVN_HAS_WC_ADM_DIR )
883     add_keyword_method("get_adm_dir", &pysvn_client::get_adm_dir, pysvn_client_get_adm_dir_doc );
884 #endif
885     add_keyword_method("get_auth_cache", &pysvn_client::get_auth_cache, pysvn_client_get_auth_cache_doc );
886     add_keyword_method("get_auto_props", &pysvn_client::get_auto_props, pysvn_client_get_auto_props_doc );
887     add_keyword_method("get_default_password", &pysvn_client::get_default_password, pysvn_client_get_default_password_doc );
888     add_keyword_method("get_default_username", &pysvn_client::get_default_username, pysvn_client_get_default_username_doc );
889     add_keyword_method("get_interactive", &pysvn_client::get_interactive, pysvn_client_get_interactive_doc );
890     add_keyword_method("get_store_passwords", &pysvn_client::get_store_passwords, pysvn_client_get_store_passwords_doc );
891     add_keyword_method("import_", &pysvn_client::cmd_import, pysvn_client_import__doc );
892     add_keyword_method("info", &pysvn_client::cmd_info, pysvn_client_info_doc );
893 #if defined( PYSVN_HAS_CLIENT_INFO )
894     add_keyword_method("info2", &pysvn_client::cmd_info2, pysvn_client_info2_doc );
895 #endif
896 #if defined( PYSVN_HAS_WC_ADM_DIR )
897     add_keyword_method("is_adm_dir", &pysvn_client::is_adm_dir, pysvn_client_is_adm_dir_doc );
898 #endif
899     add_keyword_method("is_url", &pysvn_client::is_url, pysvn_client_is_url_doc );
900 #if defined( PYSVN_HAS_CLIENT_LOCK )
901     add_keyword_method("lock", &pysvn_client::cmd_lock, pysvn_client_lock_doc );
902 #endif
903     add_keyword_method("log", &pysvn_client::cmd_log, pysvn_client_log_doc );
904 #if defined( PYSVN_HAS_CLIENT_LIST )
905     add_keyword_method("list", &pysvn_client::cmd_list, pysvn_client_list_doc );
906 #endif
907     add_keyword_method("ls", &pysvn_client::cmd_ls, pysvn_client_ls_doc );
908     add_keyword_method("merge", &pysvn_client::cmd_merge, pysvn_client_merge_doc );
909 #if defined( PYSVN_HAS_CLIENT_MERGE_PEG )
910     add_keyword_method("merge_peg", &pysvn_client::cmd_merge_peg, pysvn_client_merge_peg_doc );
911 #endif
912 #if defined( PYSVN_HAS_CLIENT_MERGE_PEG3 )
913     add_keyword_method("merge_peg2", &pysvn_client::cmd_merge_peg2, pysvn_client_merge_peg2_doc );
914 #endif
915 #if defined( PYSVN_HAS_CLIENT_MERGE_REINTEGRATE )
916     add_keyword_method("merge_reintegrate", &pysvn_client::cmd_merge_reintegrate, pysvn_client_merge_reintegrate_doc );
917 #endif
918     add_keyword_method("mkdir", &pysvn_client::cmd_mkdir, pysvn_client_mkdir_doc );
919 #if defined( PYSVN_HAS_CLIENT_MOVE5 )
920     add_keyword_method("move2", &pysvn_client::cmd_move2, pysvn_client_move2_doc );
921 #endif
922     add_keyword_method("move", &pysvn_client::cmd_move, pysvn_client_move_doc );
923 #if defined( PYSVN_HAS_CLIENT_PATCH )
924     add_keyword_method("patch", &pysvn_client::cmd_patch, pysvn_client_patch_doc );
925 #endif
926     add_keyword_method("propdel", &pysvn_client::cmd_propdel, pysvn_client_propdel_doc );
927     add_keyword_method("propget", &pysvn_client::cmd_propget, pysvn_client_propget_doc );
928     add_keyword_method("proplist", &pysvn_client::cmd_proplist, pysvn_client_proplist_doc );
929     add_keyword_method("propset", &pysvn_client::cmd_propset, pysvn_client_propset_doc );
930 #if defined( PYSVN_HAS_CLIENT_PROPSET_LOCAL )
931     add_keyword_method("propdel_local", &pysvn_client::cmd_propdel_local, pysvn_client_propdel_local_doc );
932     add_keyword_method("propset_local", &pysvn_client::cmd_propset_local, pysvn_client_propset_local_doc );
933 #endif
934 #if defined( PYSVN_HAS_CLIENT_PROPSET_REMOTE )
935     add_keyword_method("propdel_remote", &pysvn_client::cmd_propdel_remote, pysvn_client_propdel_remote_doc );
936     add_keyword_method("propset_remote", &pysvn_client::cmd_propset_remote, pysvn_client_propset_remote_doc );
937 #endif
938     add_keyword_method("relocate", &pysvn_client::cmd_relocate, pysvn_client_relocate_doc );
939     add_keyword_method("remove", &pysvn_client::cmd_remove, pysvn_client_remove_doc );
940 #if defined( PYSVN_HAS_CLIENT_REMOVE_FROM_CHANGELISTS )
941     add_keyword_method("remove_from_changelists", &pysvn_client::cmd_remove_from_changelists, pysvn_client_remove_from_changelists_doc );
942 #endif
943     add_keyword_method("resolved", &pysvn_client::cmd_resolved, pysvn_client_resolved_doc );
944     add_keyword_method("revert", &pysvn_client::cmd_revert, pysvn_client_revert_doc );
945     add_keyword_method("revpropdel", &pysvn_client::cmd_revpropdel, pysvn_client_revpropdel_doc );
946     add_keyword_method("revpropget", &pysvn_client::cmd_revpropget, pysvn_client_revpropget_doc );
947     add_keyword_method("revproplist", &pysvn_client::cmd_revproplist, pysvn_client_revproplist_doc );
948     add_keyword_method("revpropset", &pysvn_client::cmd_revpropset, pysvn_client_revpropset_doc );
949 #if defined( PYSVN_HAS_CLIENT_ROOT_URL_FROM_PATH )
950     add_keyword_method("root_url_from_path", &pysvn_client::cmd_root_url_from_path, pysvn_client_root_url_from_path_doc );
951 #endif
952 #if defined( PYSVN_HAS_WC_ADM_DIR )
953     add_keyword_method("set_adm_dir", &pysvn_client::set_adm_dir, pysvn_client_set_adm_dir_doc );
954 #endif
955     add_keyword_method("set_auth_cache", &pysvn_client::set_auth_cache, pysvn_client_set_auth_cache_doc );
956     add_keyword_method("set_auto_props", &pysvn_client::set_auto_props, pysvn_client_set_auto_props_doc );
957     add_keyword_method("set_default_password", &pysvn_client::set_default_password, pysvn_client_set_default_password_doc );
958     add_keyword_method("set_default_username", &pysvn_client::set_default_username, pysvn_client_set_default_username_doc );
959     add_keyword_method("set_interactive", &pysvn_client::set_interactive, pysvn_client_set_interactive_doc );
960     add_keyword_method("set_store_passwords", &pysvn_client::set_store_passwords, pysvn_client_set_store_passwords_doc );
961 #if defined( PYSVN_HAS_CLIENT_STATUS5 )
962     add_keyword_method("status2", &pysvn_client::cmd_status2, pysvn_client_status2_doc );
963 #endif
964     add_keyword_method("status", &pysvn_client::cmd_status, pysvn_client_status_doc );
965     add_keyword_method("switch", &pysvn_client::cmd_switch, pysvn_client_switch_doc );
966 #if defined( PYSVN_HAS_CLIENT_LOCK )
967     add_keyword_method("unlock", &pysvn_client::cmd_unlock, pysvn_client_unlock_doc );
968 #endif
969 #if defined( PYSVN_HAS_CLIENT_UPGRADE )
970     add_keyword_method("upgrade", &pysvn_client::cmd_upgrade, pysvn_client_upgrade_doc );
971 #endif
972     add_keyword_method("update", &pysvn_client::cmd_update, pysvn_client_update_doc );
973 #if defined( PYSVN_HAS_CLIENT_VACUUM )
974     add_keyword_method("vacuum", &pysvn_client::cmd_vacuum, pysvn_client_vacuum_doc );
975 #endif
976 }
977