1 //
2 // ====================================================================
3 // (c) 2003-2019 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 #ifndef __PYSVN_SVNENV__
11 #define __PYSVN_SVNENV__
12 
13 #include "CXX/Objects.hxx"
14 
15 #if !defined( PYCXX_MAKEVERSION ) || PYCXX_VERSION < PYCXX_MAKEVERSION( 6, 2, 4 )
16 #error PyCXX version 6.2.4 or later required
17 #endif
18 
19 #include <svn_version.h>
20 #include <svn_client.h>
21 #include <svn_dirent_uri.h>
22 #include <svn_path.h>
23 #include <svn_props.h>
24 #include <svn_fs.h>
25 #include <svn_repos.h>
26 #include <apr_xlate.h>
27 
28 #include <string>
29 
30 #if !defined( SVN_VER_MAJOR )
31 #error "SVN_VER_MAJOR not defined"
32 #endif
33 
34 #if !defined( SVN_VER_MINOR )
35 #error "SVN_VER_MINOR not defined"
36 #endif
37 
38 // SVN 1.1 or later
39 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 1) || SVN_VER_MAJOR > 1
40 #define PYSVN_HAS_CLIENT_ADD2
41 #define PYSVN_HAS_CLIENT_DIFF_PEG
42 #define PYSVN_HAS_CLIENT_EXPORT2
43 #define PYSVN_HAS_CLIENT_MERGE_PEG
44 #define PYSVN_HAS_CLIENT_VERSION
45 #endif
46 
47 // SVN 1.2 or later
48 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 2) || SVN_VER_MAJOR > 1
49 #define PYSVN_HAS_CLIENT_ANNOTATE2
50 #define PYSVN_HAS_CLIENT_CAT2
51 #define PYSVN_HAS_CLIENT_CHECKOUT2
52 #define PYSVN_HAS_CLIENT_COMMIT2
53 #define PYSVN_HAS_CLIENT_DIFF_PEG2
54 #define PYSVN_HAS_CLIENT_DIFF2
55 #define PYSVN_HAS_CLIENT_EXPORT3
56 #define PYSVN_HAS_CLIENT_INFO
57 #define PYSVN_HAS_CLIENT_LOCK
58 #define PYSVN_HAS_CLIENT_LOG2
59 #define PYSVN_HAS_CLIENT_LS2
60 #define PYSVN_HAS_CLIENT_MOVE2
61 #define PYSVN_HAS_CLIENT_PROPGET2
62 #define PYSVN_HAS_CLIENT_PROPLIST2
63 #define PYSVN_HAS_CLIENT_PROPSET2
64 #define PYSVN_HAS_CLIENT_STATUS2
65 #define PYSVN_HAS_CLIENT_UPDATE2
66 #define PYSVN_HAS_CONTEXT_NOTIFY2
67 #define PYSVN_HAS_WC_ADM_PROBE_OPEN3
68 #endif
69 
70 // SVN 1.3 or later
71 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 3) || SVN_VER_MAJOR > 1
72 #define PYSVN_HAS_SVN_CLIENT_COMMIT_ITEM2_T
73 #define PYSVN_HAS_SVN_COMMIT_INFO_T
74 #define PYSVN_HAS_CONTEXT_LOG_MSG2
75 #define PYSVN_HAS_CONTEXT_PROGRESS
76 
77 #define PYSVN_HAS_WC_ADM_DIR
78 
79 #define PYSVN_HAS_CLIENT_ADD3
80 #define PYSVN_HAS_CLIENT_COMMIT3
81 #define PYSVN_HAS_CLIENT_COPY2
82 #define PYSVN_HAS_CLIENT_DELETE2
83 #define PYSVN_HAS_CLIENT_DIFF_PEG3
84 #define PYSVN_HAS_CLIENT_DIFF3
85 #define PYSVN_HAS_CLIENT_IMPORT2
86 #define PYSVN_HAS_CLIENT_LS3
87 #define PYSVN_HAS_CLIENT_MKDIR2
88 #define PYSVN_HAS_CLIENT_MOVE3
89 #endif
90 
91 // SVN 1.4 or later
92 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 4) || SVN_VER_MAJOR > 1
93 #define PYSVN_HAS_CLIENT_ANNOTATE3
94 #define PYSVN_HAS_CLIENT_COPY3
95 #define PYSVN_HAS_CLIENT_DIFF_SUMMARIZE
96 #define PYSVN_HAS_CLIENT_LIST
97 #define PYSVN_HAS_CLIENT_LOG3
98 #define PYSVN_HAS_CLIENT_MERGE2
99 #define PYSVN_HAS_CLIENT_MERGE_PEG2
100 #define PYSVN_HAS_CLIENT_MOVE4
101 #define PYSVN_HAS_DIFF_FILE_IGNORE_SPACE
102 #define PYSVN_HAS_SVN_AUTH_PROVIDERS
103 #define PYSVN_HAS_IO_OPEN_UNIQUE_FILE2
104 #endif
105 
106 // SVN 1.5 or later
107 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 5) || SVN_VER_MAJOR > 1
108 #define PYSVN_HAS_SVN__DEPTH_PARAMETER
109 #define PYSVN_HAS_CLIENT_ADD4
110 #define PYSVN_HAS_CLIENT_ADD_TO_CHANGELIST
111 #define PYSVN_HAS_SVN_CLIENT_BLAME_RECEIVER2_T QQQ
112 #define PYSVN_HAS_CLIENT_ANNOTATE4
113 #define PYSVN_HAS_CLIENT_CHECKOUT3
114 #define PYSVN_HAS_CLIENT_COMMIT4
115 #define PYSVN_HAS_CLIENT_COPY4
116 #define PYSVN_HAS_SVN_CLIENT_CTX_T__CONFLICT_FUNC
117 #define PYSVN_HAS_SVN_CLIENT_CTX_T__LOG_MSG_FUNC3 QQQ
118 #define PYSVN_HAS_SVN_CLIENT_CTX_T__MIMETYPES_MAP QQQ
119 #define PYSVN_HAS_CLIENT_DELETE3
120 #define PYSVN_HAS_CLIENT_DIFF4
121 #define PYSVN_HAS_CLIENT_DIFF_PEG4
122 #define PYSVN_HAS_CLIENT_DIFF_SUMMARIZE2
123 #define PYSVN_HAS_CLIENT_DIFF_SUMMARIZE_PEG2
124 #define PYSVN_HAS_CLIENT_EXPORT4
125 #define PYSVN_HAS_CLIENT_GET_CHANGELIST
126 #define PYSVN_HAS_CLIENT_GET_CHANGELIST_STREAMY QQQ
127 #define PYSVN_HAS_SVN_CLIENT_GET_COMMIT_LOG3_T QQQ
128 #define PYSVN_HAS_CLIENT_IMPORT3
129 #define PYSVN_HAS_CLIENT_INFO2
130 #define PYSVN_HAS_CLIENT_LIST2
131 #define PYSVN_HAS_CLIENT_LOG4
132 #define PYSVN_HAS_CLIENT_MERGE3
133 #define PYSVN_HAS_CLIENT_MERGE_REINTEGRATE
134 #define PYSVN_HAS_CLIENT_MERGEINFO_GET_AVAILABLE QQQ
135 #define PYSVN_HAS_CLIENT_MERGEINFO_GET_MERGED QQQ
136 #define PYSVN_HAS_CLIENT_MERGE_PEG3 QQQ
137 #define PYSVN_HAS_CLIENT_MKDIR3
138 #define PYSVN_HAS_CLIENT_MOVE5
139 #define PYSVN_HAS_CLIENT_PROPGET3
140 #define PYSVN_HAS_CLIENT_PROPLIST3
141 #define PYSVN_HAS_CLIENT_PROPSET3
142 #define PYSVN_HAS_CLIENT_REMOVE_FROM_CHANGELISTS
143 #define PYSVN_HAS_CLIENT_RESOLVE
144 #define PYSVN_HAS_CLIENT_REVERT2
145 #define PYSVN_HAS_CLIENT_ROOT_URL_FROM_PATH
146 #define PYSVN_HAS_CLIENT_STATUS3
147 #define PYSVN_HAS_CLIENT_SUGGEST_MERGE_SOURCES QQQ
148 #define PYSVN_HAS_CLIENT_SWITCH2
149 #define PYSVN_HAS_CLIENT_UPDATE3
150 #define PYSVN_HAS_SVN_INFO_T__CHANGELIST
151 #define PYSVN_HAS_SVN_INFO_T__SIZES
152 #define PYSVN_HAS_SVN_WC_NOTIFY_ACTION_T__1_5 QQQ
153 #define PYSVN_HAS_SVN_WC_CONFLICT_CHOICE_T
154 #endif
155 
156 // SVn 1.6 or later
157 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 6) || SVN_VER_MAJOR > 1
158 #define PYSVN_HAS_SVN_1_6
159 #define PYSVN_HAS_CLIENT_COPY5
160 #define PYSVN_HAS_IO_OPEN_UNIQUE_FILE3
161 #define PYSVN_HAS_CLIENT_LOG5
162 #define PYSVN_HAS_CLIENT_REVPROP_SET2 1
163 #define PYSVN_HAS_CLIENT_STATUS4
164 #define PYSVN_HAS_AUTH_GET_SIMPLE_PROVIDER2
165 #define PYSVN_HAS_AUTH_GET_SSL_CLIENT_CERT_PW_FILE_PROVIDER2
166 #define PYSVN_HAS_SVN_CLIENT_CTX_T__CONFLICT_FUNC_1_6
167 #define PYSVN_HAS_SVN_WC_OPERATION_T
168 #define PYSVN_HAS_SVN_WC_CONFLICT_RESULT_T__SAVE_MERGED
169 #define PYSVN_HAS_SVN_AUTH_GET_PLATFORM_SPECIFIC_CLIENT_PROVIDERS
170 #endif
171 
172 // SVN 1.7 or later
173 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 7) || SVN_VER_MAJOR > 1
174 #define PYSVN_HAS_SVN_1_7
175 #define PYSVN_HAS_COMMIT_CALLBACK2_T qqq
176 #define PYSNV_HAS_REPOS_OPEN2 1
177 #define PYSNV_HAS_IO_REMOVE_FILE2 1
178 #define PYSVN_HAS_CLIENT_ANNOTATE5 1
179 #define PYSVN_HAS_CLIENT_COMMIT5 1
180 #define PYSVN_HAS_CLIENT_COPY6 1
181 #define PYSVN_HAS_CLIENT_DELETE4 1
182 #define PYSVN_HAS_CLIENT_DIFF5 1
183 #define PYSVN_HAS_CLIENT_DIFF_PEG5 1
184 #define PYSVN_HAS_CLIENT_EXPORT5 QQQ
185 #define PYSVN_HAS_CLIENT_GET_WC_ROOT QQQ
186 #define PYSVN_HAS_CLIENT_IMPORT4 QQQ
187 #define PYSVN_HAS_CLIENT_INFO2_T QQQ
188 #define PYSVN_HAS_CLIENT_INFO3 QQQ
189 #define PYSVN_HAS_CLIENT_INFO_RECEIVER2_T QQQ
190 #define PYSVN_HAS_CLIENT_MERGE4 QQQ
191 #define PYSVN_HAS_CLIENT_MERGEINFO_LOG QQQ
192 #define PYSVN_HAS_CLIENT_MERGE_PEG4 1
193 #define PYSVN_HAS_CLIENT_MIN_MAX_REVISIONS QQQ
194 #define PYSVN_HAS_CLIENT_MKDIR4 1
195 #define PYSVN_HAS_CLIENT_MOVE6 1
196 #define PYSVN_HAS_CLIENT_PATCH QQQ
197 #define PYSVN_HAS_CLIENT_PATCH_FUNC_T QQQ
198 #define PYSVN_HAS_CLIENT_PROPGET4 QQQ
199 #define PYSVN_HAS_CLIENT_PROPSET_LOCAL 1
200 #define PYSVN_HAS_CLIENT_PROPSET_REMOTE 1
201 #define PYSVN_HAS_CLIENT_RELOCATE2 QQQ
202 #define PYSVN_HAS_CLIENT_STATUS5 1
203 #define PYSVN_HAS_CLIENT_STATUS_T 1
204 #define PYSVN_HAS_CLIENT_SWITCH3 1
205 #define PYSVN_HAS_CLIENT_UPDATE4 QQQ
206 #define PYSVN_HAS_CLIENT_UPGRADE QQQ
207 #define PYSVN_HAS_CLIENT_URL_FROM_PATH2 QQQ
208 #define PYSVN_HAS_CLIENT_UUID_FROM_PATH2 QQQ
209 #define PYSVN_HAS_FS_CHANGE_REV_PROP2 QQQ
210 #endif
211 
212 // SVN 1.8 or later
213 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 8) || SVN_VER_MAJOR > 1
214 #define PYSVN_HAS_SVN_1_8
215 #define PYSVN_HAS_CLIENT_ADD5 1
216 #define PYSVN_HAS_CLIENT_COMMIT6 1
217 #define PYSVN_HAS_CLIENT_CLEANUP 1
218 #define PYSVN_HAS_CLIENT_CREATE_CONTEXT2 1
219 #define PYSVN_HAS_CLIENT_DIFF6 QQQ
220 #define PYSVN_HAS_CLIENT_DIFF_PEG6 QQQ
221 #define PYSVN_HAS_CLIENT_GET_MERGING_SUMMARY QQQ
222 #define PYSVN_HAS_CLIENT_GET_REPOS_ROOT 1
223 #define PYSVN_HAS_CLIENT_IMPORT5 QQQ
224 #define PYSVN_HAS_CLIENT_LIST3 1
225 #define PYSVN_HAS_CLIENT_MERGE5 QQQ
226 #define PYSVN_HAS_CLIENT_MERGEINFO_LOG2 QQQ
227 #define PYSVN_HAS_CLIENT_MERGE_PEG5 QQQ
228 #define PYSVN_HAS_CLIENT_MOVE7 1
229 #define PYSVN_HAS_CLIENT_PROPGET5 1
230 #define PYSVN_HAS_CLIENT_PROPLIST4 QQQ
231 #endif
232 
233 // SVN 1.9 or later
234 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 9) || SVN_VER_MAJOR > 1
235 #define PYSVN_HAS_SVN_1_9
236 #define PYSVN_HAS_STREAM_READ_FULL 1
237 #define PYSVN_HAS_CLIENT_CAT3 1
238 #define PYSVN_HAS_CLIENT_CLEANUP2 1
239 #define PYSVN_HAS_CLIENT_COPY7 1
240 #define PYSVN_HAS_CLIENT_INFO4 1
241 #define PYSVN_HAS_CLIENT_REVERT3 1
242 #define PYSVN_HAS_CLIENT_STATUS6 1
243 #define PYSVN_HAS_CLIENT_VACUUM 1
244 #define PYSVN_HAS_REPOS_OPEN3 1
245 #endif
246 
247 // SVN 1.10 or later
248 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 10) || SVN_VER_MAJOR > 1
249 #define PYSVN_HAS_SVN_1_10
250 #define PYSVN_HAS_CLIENT_LIST4 1
251 // Need to support svn_client_conflict_option_id_t
252 #define PYSVN_HAS_CLIENT_conflict_option_get_moved_to_repos_relpath_candidates 1
253 #define PYSVN_HAS_CLIENT_conflict_option_set_moved_to_repos_relpath 1
254 #define PYSVN_HAS_CLIENT_conflict_option_get_moved_to_repos_abspath_candidates 1
255 #define PYSVN_HAS_CLIENT_conflict_option_set_moved_to_repos_abspath 1
256 #endif
257 
258 // SVN 1.11 or later
259 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 11) || SVN_VER_MAJOR > 1
260 #define PYSVN_HAS_SVN_1_11
261 #define PYSVN_HAS_CLIENT_DIFF7 1
262 #define PYSVN_HAS_CLIENT_REVERT4 1
263 // Need to support svn_client_conflict_option_id_t
264 #define PYSVN_HAS_CLIENT_conflict_option_get_moved_to_repos_relpath_candidates2 1
265 #define PYSVN_HAS_CLIENT_conflict_option_set_moved_to_repos_relpath2 1
266 #define PYSVN_HAS_CLIENT_conflict_option_get_moved_to_repos_abspath_candidates2 1
267 #define PYSVN_HAS_CLIENT_conflict_option_set_moved_to_repos_abspath2 1
268 #endif
269 
270 // SVN 1.12 or later
271 #if (SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 12) || SVN_VER_MAJOR > 1
272 #define PYSVN_HAS_SVN_1_12
273 #define PYSVN_HAS_CLIENT_ANNOTATE6 1
274 #endif
275 
276 #if defined( PYSVN_HAS_CLIENT_STATUS3 )
277 typedef svn_wc_status2_t pysvn_wc_status_t;
278 
279 #elif defined( PYSVN_HAS_CLIENT_STATUS2 )
280 typedef svn_wc_status2_t pysvn_wc_status_t;
281 
282 #else
283 typedef svn_wc_status_t pysvn_wc_status_t;
284 #endif
285 
286 #if defined( PYSVN_HAS_SVN_COMMIT_INFO_T )
287 typedef svn_commit_info_t pysvn_commit_info_t;
288 #else
289 typedef svn_client_commit_info_t pysvn_commit_info_t;
290 #endif
291 
292 class SvnPool;
293 class SvnContext;
294 class SvnTransaction;
295 
296 class SvnException
297 {
298 public:
299     SvnException( svn_error_t *error );
300     SvnException( const SvnException &other );
301 
302     virtual ~SvnException();
303 
304     // access methods
305     Py::String &message();
306     Py::Object &pythonExceptionArg( int style );
307     apr_status_t code();
308 
309 private:
310     int                 m_code;
311     Py::String          m_message;
312     Py::Object          m_exception_arg;
313 
314 private:
315     SvnException();
316     SvnException &operator=( const SvnException & );
317 };
318 
319 
320 class SvnPool
321 {
322 public:
323     SvnPool( SvnContext &ctx );
324     SvnPool( SvnTransaction &txn );
325     ~SvnPool();
326 
327     operator apr_pool_t *() const;
328 
329 private:
330     apr_pool_t *m_pool;
331 };
332 
333 class SvnContext
334 {
335 public:
336     SvnContext( const std::string &config_dir="" );
337     virtual ~SvnContext();
338 
339     operator svn_client_ctx_t *();
340     svn_client_ctx_t *ctx();
341 
castBaton(void * baton_)342     static SvnContext *castBaton( void *baton_ ) { return static_cast<SvnContext *>( baton_ ); }
343 
344     // only use this pool for data that has a life time
345     // that matches the life time of the context
346     apr_pool_t          *getContextPool();
347 
348     //
349     // this method will be called to retrieve
350     // authentication information
351     //
352     // WORKAROUND FOR apr_xlate PROBLEM:
353     // STRINGS ALREADY HAVE TO BE UTF8!!!
354     //
355     // @retval true continue
356     //
357     void installGetLogin( bool install );
358     virtual bool contextGetLogin
359         (
360         const std::string &realm,
361         std::string &username,
362         std::string &password,
363         bool &may_save
364         ) = 0;
365 
366     //
367     // this method will be called to notify about
368     // the progress of an ongoing action
369     //
370     void installNotify( bool install );
371 #if defined( PYSVN_HAS_CONTEXT_NOTIFY2 )
372     virtual void contextNotify2
373         (
374         const svn_wc_notify_t *notify,
375         apr_pool_t *pool
376         ) = 0;
377 #else
378     virtual void contextNotify
379         (
380         const char *path,
381         svn_wc_notify_action_t action,
382         svn_node_kind_t kind,
383         const char *mime_type,
384         svn_wc_notify_state_t content_state,
385         svn_wc_notify_state_t prop_state,
386         svn_revnum_t revision
387         ) = 0;
388 #endif
389 
390 
391 #if defined( PYSVN_HAS_CONTEXT_PROGRESS )
392     void installProgress( bool install );
393     virtual void contextProgress
394         (
395         apr_off_t progress,
396         apr_off_t total
397         ) = 0;
398 #endif
399 
400 #if defined( PYSVN_HAS_SVN_CLIENT_CTX_T__CONFLICT_FUNC )
401     void installConflictResolver( bool install );
402     virtual bool contextConflictResolver
403         (
404         svn_wc_conflict_result_t **result,
405         const svn_wc_conflict_description_t *description,
406         apr_pool_t *pool
407         ) = 0;
408 #endif
409 
410     //
411     // this method will be called periodically to allow
412     // the app to cancel long running operations
413     //
414     // @return cancel action?
415     // @retval true cancel
416     //
417     void installCancel( bool install );
418     virtual bool contextCancel
419         (
420         ) = 0;
421 
422     //
423     // this method will be called to retrieve
424     // a log message
425     //
426     virtual bool contextGetLogMessage
427         (
428         std::string &msg
429         ) = 0;
430 
431     //
432     // this method is called if there is ssl server
433     // information, that has to be confirmed by the user
434     //
435     // @param data
436     // @return @a SslServerTrustAnswer
437     //
438     virtual bool contextSslServerTrustPrompt
439         (
440         const svn_auth_ssl_server_cert_info_t &info,
441         const std::string &relam,
442         apr_uint32_t &acceptedFailures,
443         bool &accept_permanent
444         ) = 0;
445 
446     //
447     // this method is called to retrieve client side
448     // information
449     //
450     virtual bool contextSslClientCertPrompt
451         (
452         std::string &cert_file, const std::string &realm, bool &may_save
453         ) = 0;
454 
455     //
456     // this method is called to retrieve the password
457     // for the certificate
458     //
459     // @param password
460     //
461     virtual bool contextSslClientCertPwPrompt
462         (
463         std::string &password,
464         const std::string &realm,
465         bool &may_save
466         ) = 0;
467 
468 private:
469     apr_pool_t          *m_pool;
470     svn_client_ctx_t    *m_context;
471     const char          *m_config_dir;
472 };
473 
474 class SvnTransaction
475 {
476 public:
477     SvnTransaction();
478     ~SvnTransaction();
479 
480     svn_error_t *init( const std::string &repos_path, const std::string &transaction,
481         bool is_revision );
482 
483     operator svn_fs_txn_t *();
484     svn_fs_txn_t *transaction();
485     operator svn_fs_t *();
486     operator svn_repos_t *();
487     svn_revnum_t revision();
is_revision() const488     bool is_revision() const { return m_txn == NULL; };
489     svn_error_t *root( svn_fs_root_t **root, apr_pool_t *pool );
490 
491 private:
492     apr_pool_t          *m_pool;
493     svn_repos_t         *m_repos;
494     svn_fs_t            *m_fs;
495     svn_fs_txn_t        *m_txn;
496     char                *m_txn_name;
497     svn_revnum_t         m_rev_id;
498 };
499 
500 #endif // __PYSVN_SVNENV__
501