22
33#include < fcntl.h>
44#include < string.h>
5-
65#include < unistd.h>
6+
77#include < chrono>
8+ #include < filesystem>
89#include < string_view>
910
11+ namespace fs = std::filesystem;
12+
1013namespace aur {
1114
1215namespace {
@@ -58,7 +61,7 @@ class ResponseHandler {
5861
5962 static size_t BodyCallback (char * ptr, size_t size, size_t nmemb,
6063 void * userdata) {
61- auto * handler = static_cast <ResponseHandler*>(userdata);
64+ auto handler = static_cast <ResponseHandler*>(userdata);
6265
6366 handler->body .append (ptr, size * nmemb);
6467
@@ -67,7 +70,7 @@ class ResponseHandler {
6770
6871 static size_t HeaderCallback (char * buffer, size_t size, size_t nitems,
6972 void * userdata) {
70- auto * handler = static_cast <ResponseHandler*>(userdata);
73+ auto handler = static_cast <ResponseHandler*>(userdata);
7174
7275 // Remove 2 bytes to ignore trailing \r\n
7376 ci_string_view header (buffer, size * nitems - 2 );
@@ -122,8 +125,7 @@ class RpcResponseHandler : public ResponseHandler {
122125 public:
123126 using CallbackType = Aur::RpcResponseCallback;
124127
125- RpcResponseHandler (Aur::RpcResponseCallback callback)
126- : callback_(std::move(callback)) {}
128+ RpcResponseHandler (CallbackType callback) : callback_(std::move(callback)) {}
127129
128130 private:
129131 int Run (const std::string& error) const override {
@@ -146,8 +148,7 @@ class RawResponseHandler : public ResponseHandler {
146148 public:
147149 using CallbackType = Aur::RawResponseCallback;
148150
149- RawResponseHandler (Aur::RawResponseCallback callback)
150- : callback_(std::move(callback)) {}
151+ RawResponseHandler (CallbackType callback) : callback_(std::move(callback)) {}
151152
152153 private:
153154 int Run (const std::string& error) const override {
@@ -161,6 +162,33 @@ class RawResponseHandler : public ResponseHandler {
161162 const CallbackType callback_;
162163};
163164
165+ class CloneResponseHandler : public ResponseHandler {
166+ public:
167+ using CallbackType = Aur::CloneResponseCallback;
168+
169+ CloneResponseHandler (Aur* aur, CallbackType callback)
170+ : aur_(aur), callback_(std::move(callback)) {}
171+
172+ Aur* aur () const { return aur_; }
173+
174+ void SetOperation (std::string operation) {
175+ operation_ = std::move (operation);
176+ }
177+
178+ private:
179+ int Run (const std::string& error) const override {
180+ if (!error.empty ()) {
181+ return callback_ (error);
182+ }
183+
184+ return callback_ (CloneResponse{std::move (operation_)});
185+ }
186+
187+ Aur* aur_;
188+ const CallbackType callback_;
189+ std::string operation_;
190+ };
191+
164192} // namespace
165193
166194Aur::Aur (const std::string& baseurl) : baseurl_(baseurl) {
@@ -175,6 +203,10 @@ Aur::Aur(const std::string& baseurl) : baseurl_(baseurl) {
175203 curl_multi_setopt (curl_, CURLMOPT_TIMERFUNCTION, &Aur::TimerCallback);
176204 curl_multi_setopt (curl_, CURLMOPT_TIMERDATA, this );
177205
206+ sigset_t ss;
207+ sigaddset (&ss, SIGCHLD);
208+ sigprocmask (SIG_BLOCK, &ss, &saved_ss_);
209+
178210 sd_event_default (&event_);
179211}
180212
@@ -183,12 +215,14 @@ Aur::~Aur() {
183215 curl_global_cleanup ();
184216
185217 sd_event_unref (event_);
218+
219+ sigprocmask (SIG_SETMASK, &saved_ss_, nullptr );
186220}
187221
188222// static
189223int Aur::SocketCallback (CURLM* curl, curl_socket_t s, int action,
190224 void * userdata, void *) {
191- Aur* aur = static_cast <Aur*>(userdata);
225+ auto aur = static_cast <Aur*>(userdata);
192226
193227 auto iter = aur->active_io_ .find (s);
194228 sd_event_source* io = iter != aur->active_io_ .end () ? iter->second : nullptr ;
@@ -255,7 +289,7 @@ int Aur::SocketCallback(CURLM* curl, curl_socket_t s, int action,
255289
256290// static
257291int Aur::OnIO (sd_event_source* s, int fd, uint32_t revents, void * userdata) {
258- Aur* aur = static_cast <Aur*>(userdata);
292+ auto aur = static_cast <Aur*>(userdata);
259293 int action, k = 0 ;
260294
261295 // Throwing an exception here would indicate a bug in Aur::SocketCallback.
@@ -275,27 +309,25 @@ int Aur::OnIO(sd_event_source* s, int fd, uint32_t revents, void* userdata) {
275309 return -EINVAL;
276310 }
277311
278- aur->ProcessDoneEvents ();
279- return 0 ;
312+ return aur->ProcessDoneEvents ();
280313}
281314
282315// static
283316int Aur::OnTimer (sd_event_source* s, uint64_t usec, void * userdata) {
284- Aur* aur = static_cast <Aur*>(userdata);
317+ auto aur = static_cast <Aur*>(userdata);
285318 int k = 0 ;
286319
287320 if (curl_multi_socket_action (aur->curl_ , CURL_SOCKET_TIMEOUT, 0 , &k) !=
288321 CURLM_OK) {
289322 return -EINVAL;
290323 }
291324
292- aur->ProcessDoneEvents ();
293- return 0 ;
325+ return aur->ProcessDoneEvents ();
294326}
295327
296328// static
297329int Aur::TimerCallback (CURLM* curl, long timeout_ms, void * userdata) {
298- Aur* aur = static_cast <Aur*>(userdata);
330+ auto aur = static_cast <Aur*>(userdata);
299331
300332 if (timeout_ms < 0 ) {
301333 if (aur->timer_ ) {
@@ -332,7 +364,7 @@ int Aur::TimerCallback(CURLM* curl, long timeout_ms, void* userdata) {
332364
333365void Aur::StartRequest (CURL* curl) {
334366 curl_multi_add_handle (curl_, curl);
335- active_requests_.insert (curl);
367+ active_requests_.Add (curl);
336368}
337369
338370int Aur::FinishRequest (CURL* curl, CURLcode result, bool dispatch_callback) {
@@ -354,7 +386,7 @@ int Aur::FinishRequest(CURL* curl, CURLcode result, bool dispatch_callback) {
354386
355387 auto r = dispatch_callback ? handler->RunCallback (error) : 0 ;
356388
357- active_requests_.erase (curl);
389+ active_requests_.Remove (curl);
358390 curl_multi_remove_handle (curl_, curl);
359391 curl_easy_cleanup (curl);
360392
@@ -383,16 +415,11 @@ int Aur::ProcessDoneEvents() {
383415 return 0 ;
384416}
385417
386- void Aur::Cancel () {
387- while (!active_requests_.empty ()) {
388- FinishRequest (*active_requests_.begin (), CURLE_ABORTED_BY_CALLBACK,
389- /* dispatch_callback = */ false );
390- }
391- }
392-
393418int Aur::Wait () {
394- while (!active_requests_.empty ()) {
395- sd_event_run (event_, 0 );
419+ while (!active_requests_.IsEmpty ()) {
420+ if (sd_event_run (event_, 0 ) < 0 ) {
421+ break ;
422+ }
396423 }
397424
398425 return 0 ;
@@ -473,6 +500,77 @@ void Aur::QueueRequest(
473500 }
474501}
475502
503+ // static
504+ int Aur::OnCloneExit (sd_event_source* s, const siginfo_t * si, void * userdata) {
505+ auto handler = static_cast <CloneResponseHandler*>(userdata);
506+
507+ handler->aur ()->active_requests_ .Remove (s);
508+ sd_event_source_unref (s);
509+
510+ std::string error;
511+ if (si->si_status != 0 ) {
512+ error.assign (" TODO: useful error message for non-zero exit status: " +
513+ std::to_string (si->si_status ));
514+ }
515+
516+ return handler->RunCallback (error);
517+ }
518+
519+ void Aur::QueueCloneRequest (const CloneRequest& request,
520+ const CloneResponseCallback& callback) {
521+ auto response_handler = new CloneResponseHandler (this , callback);
522+
523+ const bool update = fs::exists (fs::path (request.reponame ()) / " .git" );
524+ if (update) {
525+ response_handler->SetOperation (" update" );
526+ } else {
527+ response_handler->SetOperation (" clone" );
528+ }
529+
530+ int pid = fork ();
531+ if (pid < 0 ) {
532+ response_handler->RunCallback (std::string (strerror (errno)));
533+ return ;
534+ }
535+
536+ if (pid == 0 ) {
537+ auto url = request.Build (baseurl_)[0 ];
538+
539+ const char * cmd[] = {
540+ NULL , // git
541+ NULL , // if pulling, -C
542+ NULL , // if pulling, arg to -C
543+ NULL , // 'clone' or 'pull'
544+ NULL , // --quiet
545+ NULL , // --ff-only (if pulling), URL if cloning
546+ NULL ,
547+ };
548+ int idx = 0 ;
549+
550+ cmd[idx++] = " git" ;
551+ if (update) {
552+ cmd[idx++] = " -C" ;
553+ cmd[idx++] = request.reponame ().c_str ();
554+ cmd[idx++] = " pull" ;
555+ cmd[idx++] = " --quiet" ;
556+ cmd[idx++] = " --ff-only" ;
557+ } else {
558+ cmd[idx++] = " clone" ;
559+ cmd[idx++] = " --quiet" ;
560+ cmd[idx++] = url.c_str ();
561+ }
562+
563+ execvp (cmd[0 ], const_cast <char * const *>(cmd));
564+ _exit (127 );
565+ }
566+
567+ sd_event_source* child;
568+ sd_event_add_child (event_, &child, pid, WEXITED, &Aur::OnCloneExit,
569+ response_handler);
570+
571+ active_requests_.Add (child);
572+ }
573+
476574void Aur::QueueRawRpcRequest (const RpcRequest& request,
477575 const RawResponseCallback& callback) {
478576 QueueRequest<RawRpcRequestTraits>(request, callback);
0 commit comments