Apache Mesos
svn.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_SVN_HPP__
14 #define __STOUT_SVN_HPP__
15 
16 #include <apr_pools.h>
17 
18 #include <stdlib.h>
19 
20 #include <svn_delta.h>
21 #include <svn_error.h>
22 #include <svn_pools.h>
23 #include <svn_version.h>
24 
25 #include <string>
26 
27 #include <stout/try.hpp>
28 
29 namespace svn {
30 
31 struct Diff
32 {
33  Diff(const std::string& data) : data(data) {}
34 
35  std::string data;
36 };
37 
38 
39 // Note, this function is exposed publicly in the event that someone
40 // wants to coordinate the intialization of APR done automatically by
41 // calls to svn::diff, svn::patch, etc. That is, if you're using the
42 // svn::* functions in your code and you're also using APR you can
43 // initialize the APR before you start doing things with threads that
44 // might call svn::* functions.
45 inline void initialize()
46 {
47  // We use a static variable to initialize the Apache Portable
48  // Runtime (APR) library in a thread-safe way (at least with respect
49  // to calls within svn::* since there is no way to guarantee that
50  // another library isn't concurrently initializing the APR). Thread
51  // safety is provided by the fact that the static variable 'apr'
52  // should get constructed (i.e., the APR constructor invoked) and
53  // destructed in a thread safe way (as of GCC 4.3 and required for
54  // C++11).
55  struct APR
56  {
57  APR()
58  {
59  apr_initialize();
60  }
61 
62  ~APR()
63  {
64  apr_terminate();
65  }
66  };
67 
68  static APR apr;
69 }
70 
71 
72 inline Try<Diff> diff(const std::string& from, const std::string& to)
73 {
74  // Initialize the Apache Portable Runtime subsystem, as necessary
75  // for using the svn library.
76  initialize();
77 
78  // Note that svn_pool_create wraps apr_pool_create_ex, which is
79  // thread safe, see: http://goo.gl/NX0hps.
80  apr_pool_t* pool = svn_pool_create(nullptr);
81 
82  // First we need to produce a text delta stream by diffing 'source'
83  // against 'target'.
84  svn_string_t source;
85  source.data = from.data();
86  source.len = from.length();
87 
88  svn_string_t target;
89  target.data = to.data();
90  target.len = to.length();
91 
92  svn_txdelta_stream_t* delta;
93 
94 #if SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 8
95  svn_txdelta2(
96  &delta,
97  svn_stream_from_string(&source, pool),
98  svn_stream_from_string(&target, pool),
99  false,
100  pool);
101 #else
102  svn_txdelta(
103  &delta,
104  svn_stream_from_string(&source, pool),
105  svn_stream_from_string(&target, pool),
106  pool);
107 #endif
108 
109  // Now we want to convert this text delta stream into an svndiff
110  // format based diff. Setup the handler that will consume the text
111  // delta and produce the svndiff.
112  svn_txdelta_window_handler_t handler;
113  void* baton = nullptr;
114  svn_stringbuf_t* diff = svn_stringbuf_create_ensure(1024, pool);
115 
116 #if SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 7
117  svn_txdelta_to_svndiff3(
118  &handler,
119  &baton,
120  svn_stream_from_stringbuf(diff, pool),
121  0,
122  SVN_DELTA_COMPRESSION_LEVEL_DEFAULT,
123  pool);
124 #elif SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 4
125  svn_txdelta_to_svndiff2(
126  &handler,
127  &baton,
128  svn_stream_from_stringbuf(diff, pool),
129  0,
130  pool);
131 #else
132  svn_txdelta_to_svndiff(
133  svn_stream_from_stringbuf(diff, pool),
134  pool,
135  &handler,
136  &baton);
137 #endif
138 
139  // Now feed the text delta to the handler.
140  svn_error_t* error = svn_txdelta_send_txstream(delta, handler, baton, pool);
141 
142  if (error != nullptr) {
143  char buffer[1024];
144  std::string message(svn_err_best_message(error, buffer, 1024));
145  svn_pool_destroy(pool);
146  return Error(message);
147  }
148 
149  Diff d(std::string(diff->data, diff->len));
150 
151  svn_pool_destroy(pool);
152 
153  return d;
154 }
155 
156 
157 inline Try<std::string> patch(const std::string& s, const Diff& diff)
158 {
159  // Initialize the Apache Portable Runtime subsystem, as necessary
160  // for using the svn library.
161  initialize();
162 
163  // Note that svn_pool_create wraps apr_pool_create_ex, which is
164  // thread safe, see: http://goo.gl/NX0hps.
165  apr_pool_t* pool = svn_pool_create(nullptr);
166 
167  // We want to apply the svndiff format diff to the source trying to
168  // produce a result. First setup a handler for applying a text delta
169  // to the source stream.
170  svn_string_t source;
171  source.data = s.data();
172  source.len = s.length();
173 
174  svn_txdelta_window_handler_t handler;
175  void* baton = nullptr;
176 
177  svn_stringbuf_t* patched = svn_stringbuf_create_ensure(s.length(), pool);
178 
179  svn_txdelta_apply(
180  svn_stream_from_string(&source, pool),
181  svn_stream_from_stringbuf(patched, pool),
182  nullptr,
183  nullptr,
184  pool,
185  &handler,
186  &baton);
187 
188  // Setup a stream that converts an svndiff format diff to a text
189  // delta, so that we can use our handler to patch the source string.
190  svn_stream_t* stream = svn_txdelta_parse_svndiff(
191  handler,
192  baton,
193  TRUE,
194  pool);
195 
196  // Now feed the diff into the stream to compute the patched result.
197  const char* data = diff.data.data();
198  apr_size_t length = diff.data.length();
199 
200  svn_error_t* error = svn_stream_write(stream, data, &length);
201 
202  if (error != nullptr) {
203  char buffer[1024];
204  std::string message(svn_err_best_message(error, buffer, 1024));
205  svn_pool_destroy(pool);
206  return Error(message);
207  }
208 
209  std::string result(patched->data, patched->len);
210 
211  svn_pool_destroy(pool);
212 
213  return result;
214 }
215 
216 } // namespace svn {
217 
218 #endif // __STOUT_SVN_HPP__
Try< Diff > diff(const std::string &from, const std::string &to)
Definition: svn.hpp:72
void initialize()
Definition: svn.hpp:45
Definition: errorbase.hpp:36
Try< std::string > patch(const std::string &s, const Diff &diff)
Definition: svn.hpp:157
Definition: check.hpp:33
std::string data
Definition: svn.hpp:35
Definition: svn.hpp:29
Diff(const std::string &data)
Definition: svn.hpp:33
Definition: svn.hpp:31
std::string error(const std::string &msg, uint32_t code)