source: trunk/lib/SVN.cc @ 164

Last change on this file since 164 was 164, checked in by Jari Häkkinen, 17 years ago

Fixes #33. Added configure checks for APR and subversion APIs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.1 KB
Line 
1// $Id: SVN.cc 164 2006-08-23 22:51:01Z jari $
2
3/*
4  Copyright (C) 2006 Jari Häkkinen
5
6  This file is part of svndigest, http://lev.thep.lu.se/trac/svndigest
7
8  svndigest is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  svndigest is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  02111-1307, USA.
22*/
23
24#include "SVN.h"
25
26#include <string>
27
28#include <apr_allocator.h>
29#include <apr_hash.h>
30#include <subversion-1/svn_client.h>
31#include <subversion-1/svn_cmdline.h>
32#include <subversion-1/svn_path.h>
33#include <subversion-1/svn_pools.h>
34#include <subversion-1/svn_wc.h>
35
36namespace theplu {
37namespace svndigest {
38
39
40  SVN* SVN::instance_=NULL;
41
42
43  SVN::SVN(void)
44    : adm_access_(NULL), allocator_(NULL), context_(NULL), pool_(NULL)
45  {
46    svn_error_t* err=NULL;
47
48    // initialize something (APR subsystem and more). The APR
49    // subsystem is automatically destroyed at program exit. In case
50    // of several calls to svn_cmdline_init (ie. several exceptions
51    // thrown and caught with subsequent reinitializatios is safe
52    // memorywise but what about APR internal counters?)
53    if (svn_cmdline_init("svndigest",stderr) != EXIT_SUCCESS)
54      throw SVNException("SVN(void): svn_cmdline_init failed");
55
56    /// create top-level pool
57    if (apr_allocator_create(&allocator_))
58      throw SVNException("SVN(void): apr_allocator_create failed");
59    apr_allocator_max_free_set(allocator_,SVN_ALLOCATOR_RECOMMENDED_MAX_FREE);
60    pool_ = svn_pool_create_ex(NULL, allocator_);
61    apr_allocator_owner_set(allocator_, pool_);
62
63    // initialize the repository access library
64    if ((err=svn_ra_initialize(pool_))) {
65      cleanup_failed_initialization(err);
66      throw SVNException("SVN(void): svn_ra_initialize failed");
67    }
68
69    // Check that users .subversion exist. Should this really be done?
70    // If this check is to be done, we might be forced to support a
71    // command line option to change the location of the .subversion
72    // stuff (compare with the svn binary).
73    if ((err=svn_config_ensure(NULL, pool_))) {
74      cleanup_failed_initialization(err);
75      throw SVNException("SVN(void): svn_config_ensure failed");
76    }
77
78    // create a client context object
79    if ((err=svn_client_create_context(&context_, pool_))) {
80      cleanup_failed_initialization(err);
81      throw SVNException("SVN(void): svn_client_create_context failed");
82    }
83
84    if ((err=svn_config_get_config(&(context_->config), NULL, pool_))) {
85      cleanup_failed_initialization(err);
86      throw SVNException("SVN(void): svn_config_get_config failed");
87    }
88
89    // set up authentication stuff
90    if ((err=svn_cmdline_setup_auth_baton(&(context_->auth_baton), false, NULL,
91                                          NULL, NULL, false,
92            static_cast<svn_config_t*>(apr_hash_get(context_->config,
93                                                    SVN_CONFIG_CATEGORY_CONFIG,
94                                                    APR_HASH_KEY_STRING)),
95                                          context_->cancel_func,
96                                          context_->cancel_baton, pool_))) {
97      cleanup_failed_initialization(err);
98      throw SVNException("SVN(void): svn_cmdline_setup_auth_baton failed");
99    }
100  }
101
102
103  SVN::~SVN(void)
104  {
105    if (adm_access_)
106      svn_error_clear(svn_wc_adm_close(adm_access_));
107    svn_pool_destroy(pool_);
108    apr_allocator_destroy(allocator_);
109    // other apr resources acquired in svn_cmdline_init are destroyed
110    // at program exit, ok since SVN is a singleton
111    delete instance_;
112  }
113
114
115  svn_error_t* SVN::client_blame(const std::string& path,
116                                 svn_client_blame_receiver_t receiver,
117                                 void *baton)
118  {
119    // Setup to use all revisions
120    svn_opt_revision_t peg, start, head;
121    peg.kind=svn_opt_revision_unspecified;
122    start.kind=svn_opt_revision_number;
123    start.value.number=0;
124    head.kind=svn_opt_revision_head;
125    apr_pool_t *subpool = svn_pool_create(pool_);
126    svn_error_t* err=svn_client_blame3(path.c_str(), &peg, &start, &head,
127                                       svn_diff_file_options_create(subpool),
128                                       false, receiver, baton, context_,
129                                       subpool);
130    if (err && err->apr_err!=SVN_ERR_CLIENT_IS_BINARY_FILE) {
131      svn_handle_error2(err, stderr, false, "svndigest: ");
132      svn_error_clear(err);
133      svn_pool_destroy(subpool);
134      throw SVNException("SVN::client_blame: svn_client_blame3 failed");
135    }
136    svn_pool_destroy(subpool);
137    return err;
138  }
139
140
141  void SVN::client_info(const std::string& path, svn_info_receiver_t receiver,
142                        void *baton)
143  {
144    apr_pool_t *subpool = svn_pool_create(pool_);
145    if (svn_error_t *err=svn_client_info(path.c_str(), NULL, NULL, receiver,
146                                         baton, false, context_, subpool)) {
147      svn_handle_error2(err, stderr, false, "svndigest: ");
148      svn_error_clear(err);
149      svn_pool_destroy(subpool);
150      throw SVNException("repository: svn_client_info failed");
151    }
152    svn_pool_destroy(subpool);
153  }
154
155
156  std::vector<std::string> SVN::commit_dates(const std::string& path)
157  {
158    // Allocate space in subpool to pool_ for apr_path (here a string).
159    apr_pool_t *subpool = svn_pool_create(pool_);
160    apr_array_header_t* apr_path=apr_array_make(subpool,1,4);
161    // Copy path to apr_path.
162    (*((const char **) apr_array_push(apr_path))) =
163      apr_pstrdup(subpool, svn_path_internal_style(path.c_str(),subpool));
164
165    // Setup to retrieve all commit logs.
166    svn_opt_revision_t peg, start, head;
167    peg.kind=svn_opt_revision_unspecified;
168    start.kind=svn_opt_revision_number;
169    start.value.number=0;
170    head.kind=svn_opt_revision_head;
171    svn_error_t* err=NULL;
172    // Retrieving the last revision is only needed for the reserve
173    // call below, not needed for the functionality here.
174    if ((err=svn_ra_get_latest_revnum(ra_session_, &(head.value.number),
175                                      subpool))) {
176      svn_handle_error2(err, stderr, false, "svndigest: ");
177      svn_error_clear(err);
178      svn_pool_destroy(subpool);
179      throw SVNException("commit_dates: svn_ra_get_latest_revnum failed");
180    }
181    // The struct we want to pass through to all log_message_receiver
182    // calls, here we only want to push all commit dates into a
183    // std::vector<std::string>.
184    struct log_receiver_baton lb;
185    lb.commit_dates.reserve(head.value.number+1); // revision 0 is also stored.
186    if ((err=svn_client_log3(apr_path, &peg, &start, &head, 0, false, true,
187                             log_message_receiver, static_cast<void*>(&lb),
188                             context_, subpool))) {
189      svn_handle_error2(err, stderr, false, "svndigest: ");
190      svn_error_clear(err);
191      svn_pool_destroy(subpool);
192      throw SVNException("commit_dates: svn_client_log3 failed");
193    }
194    svn_pool_destroy(subpool);
195    return lb.commit_dates;
196  }
197
198
199  void SVN::cleanup_failed_initialization(svn_error_t *err)
200  {
201    svn_handle_error2(err,stderr,false,"svndigest:");
202    svn_error_clear(err);
203    svn_pool_destroy(pool_);
204    apr_allocator_destroy(allocator_);
205  }
206
207
208  svn_error_t *
209  SVN::log_message_receiver(void *baton, apr_hash_t *changed_paths,
210                            svn_revnum_t rev, const char *author,
211                            const char *date, const char *msg, apr_pool_t *pool)
212  {
213    struct log_receiver_baton *lb=static_cast<struct log_receiver_baton*>(baton);
214    if (date && date[0])
215      lb->commit_dates.push_back(date);
216    else
217      throw SVNException("No date defined for revision: " + rev); 
218    return SVN_NO_ERROR;
219  }
220
221
222  void SVN::setup_ra_session(const std::string& path) {
223    // get a session to the repository
224    if (svn_error_t *err=svn_client_open_ra_session(&ra_session_, path.c_str(),
225                                                    context_,pool_)) {
226      svn_handle_error2(err,stderr,false,"svndigest:");
227      svn_error_clear(err);
228      throw SVNException("setup_ra_session: svn_client_open_ra_session failed");
229    }
230  }
231
232
233  void SVN::setup_wc_adm_access(const std::string& path)
234  {
235    // Set up svn administration area access. The whole structure is
236    // setup, maybe this is unnecessary?
237    const char* canonical_path=svn_path_internal_style(path.c_str(), pool_);
238    if (svn_error_t *err=svn_wc_adm_open3(&adm_access_, NULL, canonical_path,
239                                          false, -1, context_->cancel_func,
240                                          context_->cancel_baton, pool_)) {
241      svn_handle_error2(err,stderr,false,"svndigest:");
242      svn_error_clear(err);
243      throw SVNException("setup_wc_adm_access: svn_wc_adm_open3 failed");
244    }
245  }
246
247
248  SVN::vc_status SVN::version_controlled(const std::string& path)
249  {
250    svn_wc_status2_t* status=NULL;
251    apr_pool_t *subpool = svn_pool_create(pool_);
252    if (svn_error_t *err=
253        svn_wc_status2(&status,svn_path_internal_style(path.c_str(), subpool),
254                       adm_access_, subpool)) {
255      svn_handle_error2(err,stderr,false,"svndigest:");
256      svn_error_clear(err);
257      svn_pool_destroy(subpool);
258      throw SVNException("version_controlled(): svn_config_get_config failed");
259    }
260    svn_pool_destroy(subpool);
261
262    if ((status->text_status==svn_wc_status_none) ||
263        (status->text_status==svn_wc_status_unversioned))
264      return unversioned;
265    else if (status->text_status==svn_wc_status_normal)
266      return uptodate;
267
268    return unresolved;
269  }
270
271
272}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.