source: trunk/lib/SVN.cc @ 129

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

Addresses ticket:23. Changed usage of 'svn info' to API calls.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.3 KB
Line 
1// $Id: SVN.cc 129 2006-08-02 17:56:18Z jari $
2
3/*
4  Copyright (C) 2006 Jari Häkkinen
5
6  This file is part of svnstat, http://lev.thep.lu.se/trac/svnstat
7
8  svnstat 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  svnstat 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#include <apr_hash.h>
28#include <svn_cmdline.h>
29#include <svn_path.h>
30#include <svn_pools.h>
31#include <svn_wc.h>
32
33namespace theplu {
34namespace svnstat {
35
36
37  SVN* SVN::instance_=NULL;
38
39
40  SVN::SVN(void)
41    : adm_access_(NULL), allocator_(NULL), context_(NULL), pool_(NULL)
42  {
43    // To be honest, I (Jari) am not perfectly sure of what I am
44    // doing, most bits here are stolen from subversion source for the
45    // svn command line binary (subverion/svn/main.c)
46
47    svn_error_t* err=NULL;
48
49    // initialize something (APR subsystem and more). The APR
50    // subsystem is automatically destroyed at program exit. In case
51    // of several calls to svn_cmdline_init (ie. several exceptions
52    // thrown and caught with subsequent reinitializatios is safe
53    // memorywise but what about APR internal counters?)
54    if (svn_cmdline_init("svnstat",stderr) != EXIT_SUCCESS)
55      throw SVNException("SVN(void): svn_cmdline_init failed");
56
57    /// create top-level pool
58    if (apr_allocator_create(&allocator_))
59      throw SVNException("SVN(void): apr_allocator_create failed");
60    apr_allocator_max_free_set(allocator_,SVN_ALLOCATOR_RECOMMENDED_MAX_FREE);
61    pool_ = svn_pool_create_ex(NULL, allocator_);
62    apr_allocator_owner_set(allocator_, pool_);
63
64    // initialize the repository access library
65    if ((err=svn_ra_initialize(pool_))) {
66      // destroys pool and clears err
67      svn_cmdline_handle_exit_error(err, pool_, "svnstat: ");
68      apr_allocator_destroy(allocator_);
69      throw SVNException("SVN(void): svn_ra_initialize failed");
70    }
71
72    // Check that users .subversion exist. Should this really be done?
73    // If this check is to be done, we might be forced to support a
74    // command line option to change the location of the .subversion
75    // stuff (compare with the svn binary).
76    if ((err=svn_config_ensure(NULL, pool_))) {
77      // destroys pool and clears err
78      svn_cmdline_handle_exit_error(err, pool_, "svnstat: ");
79      apr_allocator_destroy(allocator_);
80      throw SVNException("SVN(void): svn_config_ensure failed");
81    }
82
83    // create a client context object
84    if ((err=svn_client_create_context(&context_, pool_))) {
85      // destroys pool and clears err
86      svn_cmdline_handle_exit_error(err, pool_, "svnstat: ");
87      apr_allocator_destroy(allocator_);
88      throw SVNException("SVN(void): svn_client_create_context failed");
89    }
90
91    if ((err=svn_config_get_config(&(context_->config), NULL, pool_))) {
92      // destroys pool and clears err
93      svn_cmdline_handle_exit_error(err, pool_, "svnstat: ");
94      apr_allocator_destroy(allocator_);
95      throw SVNException("SVN(void): svn_config_get_config failed");
96    }
97
98    // set up authentication stuff
99    if ((err=svn_cmdline_setup_auth_baton(&(context_->auth_baton), false, NULL,
100                                          NULL, NULL, false,
101            static_cast<svn_config_t*>(apr_hash_get(context_->config,
102                                                    SVN_CONFIG_CATEGORY_CONFIG,
103                                                    APR_HASH_KEY_STRING)),
104                                          context_->cancel_func,
105                                          context_->cancel_baton, pool_)))
106      svn_handle_error2(err, stderr, TRUE, "svnstat: ");
107  }
108
109
110  SVN::~SVN(void)
111  {
112    svn_pool_destroy(pool_);
113    apr_allocator_destroy(allocator_);
114    // other apr resources acquired in svn_cmdline_init are destroyed
115    // at program exit, ok since SVN is a singleton
116    delete instance_;
117  }
118
119
120  std::vector<std::string> SVN::commit_dates(const std::string& path)
121  {
122    // Allocate space in pool_ for apr_path (here a string).
123    apr_array_header_t* apr_path=apr_array_make(pool_,1,4);
124    // Copy path to apr_path.
125    (*((const char **) apr_array_push(apr_path))) =
126      apr_pstrdup(pool_, svn_path_internal_style(path.c_str(),pool_));
127
128    // Setup to retrieve all commit logs.
129    svn_opt_revision_t peg, start, head;
130    peg.kind=svn_opt_revision_unspecified;
131    start.kind=svn_opt_revision_number;
132    start.value.number=0;
133    head.kind=svn_opt_revision_head;
134    svn_error_t* err=NULL;
135    // Retrieving the last revision is only needed for the reserve
136    // call below, not needed for the functionality here.
137    if ((err=svn_ra_get_latest_revnum(ra_session_,&(head.value.number),pool_))) {
138      svn_cmdline_handle_exit_error(err, pool_, "svnstat: ");
139      throw SVNException("commit_dates: svn_ra_get_latest_revnum failed");
140    }
141    // The struct we want to pass through to all log_message_receiver
142    // calls, here we only want to push all commit dates into a
143    // std::vector<std::string>.
144    struct log_receiver_baton lb;
145    lb.commit_dates.reserve(head.value.number+1); // revision 0 is also stored.
146    if ((err=svn_client_log3(apr_path, &peg, &start, &head, 0, false, true,
147                             log_message_receiver, static_cast<void*>(&lb),
148                             context_, pool_))) {
149      svn_cmdline_handle_exit_error(err, pool_, "svnstat: ");
150      throw SVNException("commit_dates: svn_client_log3 failed");
151    }
152    return lb.commit_dates;
153  }
154
155
156  svn_error_t *
157  SVN::log_message_receiver(void *baton, apr_hash_t *changed_paths,
158                            svn_revnum_t rev, const char *author,
159                            const char *date, const char *msg, apr_pool_t *pool)
160  {
161    struct log_receiver_baton *lb=static_cast<struct log_receiver_baton*>(baton);
162    if (date && date[0])
163      lb->commit_dates.push_back(date);
164    else
165      throw SVNException("No date defined for revision: " + rev); 
166    return SVN_NO_ERROR;
167  }
168
169
170  void SVN::setup_ra_session(const std::string& path) {
171    // get a session to the repository
172    if (svn_client_open_ra_session(&ra_session_, path.c_str(), context_,pool_)) {
173      // Jari, should the error space be cleared?
174      throw SVNException("setup_ra_session: svn_client_open_ra_session failed");
175    }
176  }
177
178
179  void SVN::setup_wc_adm_access(const std::string& path)
180  {
181    // Set up svn administration area access. The whole structure is
182    // setup, maybe this should not be done?
183    const char* canonical_path=svn_path_internal_style(path.c_str(), pool_);
184    if (svn_wc_adm_open3(&adm_access_, NULL, canonical_path, false, -1,
185                         context_->cancel_func,context_->cancel_baton, pool_))
186      // Jari, should the error space be cleared?
187      throw SVNException("setup_wc_adm_access: svn_wc_adm_open3 failed");
188  }
189
190
191  SVN::vc_status SVN::version_controlled(const std::string& path)
192  {
193    svn_wc_status2_t* status=NULL;
194    if (svn_wc_status2(&status,svn_path_internal_style(path.c_str(), pool_),
195                       adm_access_, pool_))
196      throw SVNException("version_controlled(): svn_config_get_config failed");
197
198    if ((status->text_status==svn_wc_status_none) ||
199        (status->text_status==svn_wc_status_unversioned))
200      return unversioned;
201    else if (status->text_status==svn_wc_status_normal)
202      return uptodate;
203
204    return unresolved;
205  }
206
207
208}} // end of namespace svnstat and namespace theplu
Note: See TracBrowser for help on using the repository browser.