1 //
2 // ====================================================================
3 // Copyright (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_cmd_prop.cpp
12 //
13 #if defined( _MSC_VER )
14 // disable warning C4786: symbol greater than 255 character,
15 // nessesary to ignore as <map> causes lots of warning
16 #pragma warning(disable: 4786)
17 #endif
18 
19 #include "pysvn.hpp"
20 #include "pysvn_svnenv.hpp"
21 #include "pysvn_static_strings.hpp"
22 
cmd_add(const Py::Tuple & a_args,const Py::Dict & a_kws)23 Py::Object pysvn_client::cmd_add( const Py::Tuple &a_args, const Py::Dict &a_kws )
24 {
25     static argument_description args_desc[] =
26     {
27     { true,  name_path },
28     { false, name_recurse },
29 #if defined( PYSVN_HAS_CLIENT_ADD2 )
30     { false, name_force },
31 #endif
32 #if defined( PYSVN_HAS_CLIENT_ADD3 )
33     { false, name_ignore },
34 #endif
35 #if defined( PYSVN_HAS_CLIENT_ADD4 )
36     { false, name_depth },
37     { false, name_add_parents },
38 #endif
39 #if defined( PYSVN_HAS_CLIENT_ADD5 )
40     { false, name_autoprops },
41 #endif
42 
43     { false, NULL }
44     };
45     FunctionArguments args( "add", args_desc, a_args, a_kws );
46     args.check();
47 
48     Py::List path_list( toListOfStrings( args.getArg( name_path ) ) );
49 
50 #if defined( PYSVN_HAS_CLIENT_ADD2 )
51     bool force = args.getBoolean( name_force, false );
52 #endif
53 #if defined( PYSVN_HAS_CLIENT_ADD3 )
54     bool ignore = args.getBoolean( name_ignore, true );
55 #endif
56 #if defined( PYSVN_HAS_CLIENT_ADD4 )
57     svn_depth_t depth = args.getDepth( name_depth, name_recurse, svn_depth_infinity, svn_depth_infinity, svn_depth_empty );
58     bool add_parents = args.getBoolean( name_add_parents, false );
59 #else
60     bool recurse = args.getBoolean( name_recurse, true );
61 #endif
62 #if defined( PYSVN_HAS_CLIENT_ADD5 )
63     bool autoprops = args.getBoolean( name_autoprops, true );
64 #endif
65 
66     SvnPool pool( m_context );
67     try
68     {
69         for( Py::List::size_type i=0; i<path_list.length(); i++ )
70         {
71             Py::Bytes path_str( asUtf8Bytes( path_list[i] ) );
72             std::string norm_path( svnNormalisedIfPath( path_str.as_std_string(), pool ) );
73 
74             checkThreadPermission();
75 
76             PythonAllowThreads permission( m_context );
77 
78             SvnPool pool( m_context );
79 
80 #if defined( PYSVN_HAS_CLIENT_ADD5 )
81             svn_error_t * error = svn_client_add5
82                 (
83                 norm_path.c_str(),
84                 depth,
85                 force,
86                 !ignore,
87                 !autoprops,
88                 add_parents,
89                 m_context,
90                 pool
91                 );
92 #elif defined( PYSVN_HAS_CLIENT_ADD4 )
93             svn_error_t * error = svn_client_add4
94                 (
95                 norm_path.c_str(),
96                 depth,
97                 force,
98                 !ignore,
99                 add_parents,
100                 m_context,
101                 pool
102                 );
103 #elif defined( PYSVN_HAS_CLIENT_ADD3 )
104             svn_error_t * error = svn_client_add3
105                 (
106                 norm_path.c_str(),
107                 recurse,
108                 force,
109                 !ignore,
110                 m_context,
111                 pool
112                 );
113 #elif defined( PYSVN_HAS_CLIENT_ADD2 )
114             svn_error_t * error = svn_client_add2
115                 (
116                 norm_path.c_str(),
117                 recurse,
118                 force,
119                 m_context,
120                 pool
121                 );
122 #else
123             svn_error_t * error = svn_client_add
124                 (
125                 norm_path.c_str(),
126                 recurse,
127                 m_context,
128                 pool
129                 );
130 #endif
131             permission.allowThisThread();
132             if( error != NULL )
133                 throw SvnException( error );
134         }
135     }
136     catch( SvnException &e )
137     {
138         // use callback error over ClientException
139         m_context.checkForError( m_module.client_error );
140 
141         throw_client_error( e );
142     }
143 
144     return Py::None();
145 }
146 
cmd_cat(const Py::Tuple & a_args,const Py::Dict & a_kws)147 Py::Object pysvn_client::cmd_cat( const Py::Tuple &a_args, const Py::Dict &a_kws )
148 {
149     static argument_description args_desc[] =
150     {
151     { true,  name_url_or_path },
152     { false, name_revision },
153 #if defined( PYSVN_HAS_CLIENT_CAT2 )
154     { false, name_peg_revision },
155 #endif
156 #if defined( PYSVN_HAS_CLIENT_CAT3 )
157     { false, name_expand_keywords },
158     { false, name_get_props },
159 #endif
160     { false, NULL }
161     };
162     FunctionArguments args( "cat", args_desc, a_args, a_kws );
163     args.check();
164 
165     std::string path( args.getUtf8String( name_url_or_path ) );
166     svn_opt_revision_t revision = args.getRevision( name_revision, svn_opt_revision_head );
167 #if defined( PYSVN_HAS_CLIENT_CAT2 )
168     svn_opt_revision_t peg_revision = args.getRevision( name_peg_revision, revision );
169 
170 #endif
171     bool is_url = is_svn_url( path );
172 #if defined( PYSVN_HAS_CLIENT_CAT2 )
173     revisionKindCompatibleCheck( is_url, peg_revision, name_peg_revision, name_url_or_path );
174 #endif
175     revisionKindCompatibleCheck( is_url, revision, name_revision, name_url_or_path );
176 
177     SvnPool pool( m_context );
178 
179     svn_stringbuf_t * stringbuf = svn_stringbuf_create( empty_string, pool );
180     svn_stream_t * stream = svn_stream_from_stringbuf( stringbuf, pool );
181 
182 #if defined( PYSVN_HAS_CLIENT_CAT3 )
183     bool get_props = args.getBoolean( name_get_props, false );
184     bool expand_keywords = args.getBoolean( name_expand_keywords, false );
185 
186     apr_hash_t *props = NULL;
187     apr_hash_t **props_ptr;
188     if( get_props )
189     {
190         props_ptr = &props;
191     }
192     else
193     {
194         props_ptr = NULL;
195     }
196 #endif
197 
198     try
199     {
200         std::string norm_path( svnNormalisedIfPath( path, pool ) );
201 
202         checkThreadPermission();
203 
204         PythonAllowThreads permission( m_context );
205 #if defined( PYSVN_HAS_CLIENT_CAT3 )
206         svn_error_t *error = svn_client_cat3
207             (
208             props_ptr,
209             stream,
210             norm_path.c_str(),
211             &peg_revision,
212             &revision,
213             expand_keywords,
214             m_context,
215             pool,
216             pool
217             );
218 #elif defined( PYSVN_HAS_CLIENT_CAT2 )
219         svn_error_t *error = svn_client_cat2
220             (
221             stream,
222             norm_path.c_str(),
223             &peg_revision,
224             &revision,
225             m_context,
226             pool
227             );
228 #else
229         svn_error_t *error = svn_client_cat
230             (
231             stream,
232             norm_path.c_str(),
233             &revision,
234             m_context,
235             pool
236             );
237 #endif
238 
239         permission.allowThisThread();
240         if (error != 0)
241             throw SvnException (error);
242     }
243     catch( SvnException &e )
244     {
245         // use callback error over ClientException
246         m_context.checkForError( m_module.client_error );
247 
248         throw_client_error( e );
249     }
250 
251     // return the bytes as is to the application
252     // we can assume nothing about them
253     Py::Bytes contents( stringbuf->data, (int)stringbuf->len );
254 #if defined( PYSVN_HAS_CLIENT_CAT3 )
255     if( get_props )
256     {
257         Py::Tuple result( 2 );
258 
259         result[0] = contents;
260         result[1] = propsToObject( props, pool );
261 
262         return result;
263     }
264     else
265 #endif
266     {
267         return contents;
268     }
269 }
270 
cmd_mkdir(const Py::Tuple & a_args,const Py::Dict & a_kws)271 Py::Object pysvn_client::cmd_mkdir( const Py::Tuple &a_args, const Py::Dict &a_kws )
272 {
273     static argument_description args_desc[] =
274     {
275     { true,  name_url_or_path },
276     { false, name_log_message },
277 #if defined( PYSVN_HAS_CLIENT_MKDIR3 )
278     { false, name_make_parents },
279     { false, name_revprops },
280 #endif
281     { false, NULL }
282     };
283     FunctionArguments args( "mkdir", args_desc, a_args, a_kws );
284     args.check();
285 
286     // message that explains to the user the type error that may be thrown next
287     std::string type_error_message;
288 
289     // args to the mkdir call
290     std::string message;
291     bool have_message = false;
292 
293     SvnPool pool( m_context );
294 
295     apr_array_header_t *targets = targetsFromStringOrList( args.getArg( name_url_or_path ), pool );
296 
297 #if defined( PYSVN_HAS_CLIENT_MKDIR3 )
298     bool make_parents = args.getBoolean( name_make_parents, false );
299 
300     apr_hash_t *revprops = NULL;
301     if( args.hasArg( name_revprops ) )
302     {
303         Py::Object py_revprop = args.getArg( name_revprops );
304         if( !py_revprop.isNone() )
305         {
306             revprops = hashOfStringsFromDictOfStrings( py_revprop, pool );
307         }
308     }
309 #endif
310 
311     try
312     {
313         type_error_message = "expecting string message (arg 2)";
314         if( args.hasArg( name_log_message ) )
315         {
316             message = args.getUtf8String( name_log_message );
317             have_message = true;
318         }
319     }
320     catch( Py::TypeError & )
321     {
322         throw Py::TypeError( type_error_message );
323     }
324 
325 
326 #if defined( PYSVN_HAS_CLIENT_MKDIR4 )
327     CommitInfoResult commit_info( pool );
328 #else
329     pysvn_commit_info_t *commit_info = NULL;
330 #endif
331 
332     try
333     {
334         checkThreadPermission();
335 
336         PythonAllowThreads permission( m_context );
337 
338         if( have_message )
339         {
340             m_context.setLogMessage( message.c_str() );
341         }
342 
343 #if defined( PYSVN_HAS_CLIENT_MKDIR4 )
344         svn_error_t *error = svn_client_mkdir4
345             (
346             targets,
347             make_parents,
348             revprops,
349             commit_info.callback(),
350             commit_info.baton(),
351             m_context,
352             pool
353             );
354 #elif defined( PYSVN_HAS_CLIENT_MKDIR3 )
355         svn_error_t *error = svn_client_mkdir3
356             (
357             &commit_info,       // changed type
358             targets,
359             make_parents,
360             revprops,
361             m_context,
362             pool
363             );
364 #elif defined( PYSVN_HAS_CLIENT_MKDIR2 )
365         svn_error_t *error = svn_client_mkdir2
366             (
367             &commit_info,       // changed type
368             targets,
369             m_context,
370             pool
371             );
372 #else
373         svn_error_t *error = svn_client_mkdir
374             (
375             &commit_info,
376             targets,
377             m_context,
378             pool
379             );
380 #endif
381         permission.allowThisThread();
382         if( error != 0 )
383             throw SvnException( error );
384     }
385     catch( SvnException &e )
386     {
387         // use callback error over ClientException
388         m_context.checkForError( m_module.client_error );
389 
390         throw_client_error( e );
391     }
392 
393 #if defined( PYSVN_HAS_CLIENT_MKDIR4 )
394     return toObject( commit_info, m_wrapper_commit_info, m_commit_info_style );
395 #else
396     return toObject( commit_info, m_commit_info_style );
397 #endif
398 }
399 
cmd_remove(const Py::Tuple & a_args,const Py::Dict & a_kws)400 Py::Object pysvn_client::cmd_remove( const Py::Tuple &a_args, const Py::Dict &a_kws )
401 {
402     static argument_description args_desc[] =
403     {
404     { true,  name_url_or_path },
405     { false, name_force },
406 #if defined( PYSVN_HAS_CLIENT_DELETE3 )
407     { false, name_keep_local },
408     { false, name_revprops },
409 #endif
410     { false, NULL }
411     };
412     FunctionArguments args( "remove", args_desc, a_args, a_kws );
413     args.check();
414 
415     SvnPool pool( m_context );
416 
417     bool force = args.getBoolean( name_force, false );
418 #if defined( PYSVN_HAS_CLIENT_DELETE3 )
419 
420     bool keep_local = args.getBoolean( name_keep_local, false );
421 
422     apr_hash_t *revprops = NULL;
423     if( args.hasArg( name_revprops ) )
424     {
425         Py::Object py_revprop = args.getArg( name_revprops );
426         if( !py_revprop.isNone() )
427         {
428             revprops = hashOfStringsFromDictOfStrings( py_revprop, pool );
429         }
430     }
431 #endif
432 
433     apr_array_header_t *targets = targetsFromStringOrList( args.getArg( name_url_or_path ), pool );
434 
435 #if defined( PYSVN_HAS_CLIENT_MKDIR4 )
436     CommitInfoResult commit_info( pool );
437 #else
438     pysvn_commit_info_t *commit_info = NULL;
439 #endif
440 
441     try
442     {
443         checkThreadPermission();
444 
445         PythonAllowThreads permission( m_context );
446 
447 #if defined( PYSVN_HAS_CLIENT_DELETE4 )
448         svn_error_t *error = svn_client_delete4
449             (
450             targets,
451             force,
452             keep_local,
453             revprops,
454             commit_info.callback(),
455             commit_info.baton(),
456             m_context,
457             pool
458             );
459 #elif defined( PYSVN_HAS_CLIENT_DELETE3 )
460         svn_error_t *error = svn_client_delete3
461             (
462             &commit_info,
463             targets,
464             force,
465             keep_local,
466             revprops,
467             m_context,
468             pool
469             );
470 #elif defined( PYSVN_HAS_CLIENT_DELETE2 )
471         svn_error_t *error = svn_client_delete2
472             (
473             &commit_info,       // commit_info changed
474             targets,
475             force,
476             m_context,
477             pool
478             );
479 #else
480         svn_error_t *error = svn_client_delete
481             (
482             &commit_info,
483             targets,
484             force,
485             m_context,
486             pool
487             );
488 #endif
489         permission.allowThisThread();
490         if( error != NULL )
491             throw SvnException( error );
492     }
493     catch( SvnException &e )
494     {
495         // use callback error over ClientException
496         m_context.checkForError( m_module.client_error );
497 
498         throw_client_error( e );
499     }
500 
501 #if defined( PYSVN_HAS_CLIENT_MKDIR4 )
502     return toObject( commit_info, m_wrapper_commit_info, m_commit_info_style );
503 #else
504     return toObject( commit_info, m_commit_info_style );
505 #endif
506 }
507 
cmd_revert(const Py::Tuple & a_args,const Py::Dict & a_kws)508 Py::Object pysvn_client::cmd_revert( const Py::Tuple &a_args, const Py::Dict &a_kws )
509 {
510     static argument_description args_desc[] =
511     {
512     { true,  name_path },
513     { false, name_recurse },
514 #if defined( PYSVN_HAS_CLIENT_REVERT2 )
515     { false, name_depth },
516     { false, name_changelists },
517 #endif
518 #if defined( PYSVN_HAS_CLIENT_REVERT3 )
519     { false, name_clear_changelists },
520     { false, name_metadata_only },
521 #endif
522     { false, NULL }
523     };
524     FunctionArguments args( "revert", args_desc, a_args, a_kws );
525     args.check();
526 
527     std::string type_error_message;
528 
529     SvnPool pool( m_context );
530     apr_array_header_t *targets = targetsFromStringOrList( args.getArg( name_path ), pool );
531 
532     try
533     {
534 #if defined( PYSVN_HAS_CLIENT_REVERT2 )
535         apr_array_header_t *changelists = NULL;
536 
537         if( args.hasArg( name_changelists ) )
538         {
539             changelists = arrayOfStringsFromListOfStrings( args.getArg( name_changelists ), pool );
540         }
541         svn_depth_t depth = args.getDepth( name_depth, name_recurse, svn_depth_empty, svn_depth_infinity, svn_depth_empty );
542 #else
543         bool recurse = args.getBoolean( name_recurse, false );
544 #endif
545 
546 #if defined( PYSVN_HAS_CLIENT_REVERT3 )
547     bool clear_changelists = args.getBoolean( name_clear_changelists, false );
548     bool metadata_only = args.getBoolean( name_metadata_only, false );
549 #endif
550         try
551         {
552             checkThreadPermission();
553 
554             PythonAllowThreads permission( m_context );
555 
556 #if defined( PYSVN_HAS_CLIENT_REVERT3 )
557             svn_error_t *error = svn_client_revert3
558                 (
559                 targets,
560                 depth,
561                 changelists,
562                 clear_changelists,
563                 metadata_only,
564                 m_context,
565                 pool
566                 );
567 #elif defined( PYSVN_HAS_CLIENT_REVERT2 )
568             svn_error_t *error = svn_client_revert2
569                 (
570                 targets,
571                 depth,
572                 changelists,
573                 m_context,
574                 pool
575                 );
576 #else
577             svn_error_t *error = svn_client_revert
578                 (
579                 targets,
580                 recurse,
581                 m_context,
582                 pool
583                 );
584 #endif
585             permission.allowThisThread();
586             if( error != NULL )
587                 throw SvnException( error );
588         }
589         catch( SvnException &e )
590         {
591             // use callback error over ClientException
592             m_context.checkForError( m_module.client_error );
593 
594             throw_client_error( e );
595         }
596     }
597     catch( Py::TypeError & )
598     {
599         throw Py::TypeError( type_error_message );
600     }
601 
602     return Py::None();
603 }
604 
605