@@ -65,6 +65,8 @@ class RefreshedRefModel {
6565 message (NULL ),
6666 sha (new char [GIT_OID_HEXSZ + 1 ]),
6767 shorthand (strdup(git_reference_shorthand(ref))),
68+ tagOdbBuffer (NULL ),
69+ tagOdbBufferLength (0 ),
6870 type (NULL )
6971 {
7072 if (git_reference_is_branch (ref)) {
@@ -76,33 +78,89 @@ class RefreshedRefModel {
7678 }
7779 }
7880
79- static int fromReference (RefreshedRefModel **out, git_reference *ref) {
81+ static int fromReference (RefreshedRefModel **out, git_reference *ref, git_odb *odb ) {
8082 RefreshedRefModel *refModel = new RefreshedRefModel (ref);
81- git_oid referencedTargetOid;
83+ const git_oid * referencedTargetOid = git_reference_target (ref) ;
8284
83- int result = getOidOfReferenceCommit (&referencedTargetOid, ref);
84- if (result != GIT_OK ) {
85- delete refModel;
86- return result;
85+ if (!git_reference_is_tag (ref)) {
86+ git_oid_tostr (refModel->sha , GIT_OID_HEXSZ + 1 , referencedTargetOid);
87+
88+ *out = refModel;
89+ return GIT_OK ;
8790 }
91+ git_repository *repo = git_reference_owner (ref);
8892
89- if (git_reference_is_tag (ref)) {
90- git_repository *repo = git_reference_owner (ref);
93+ git_tag *referencedTag;
94+ if (git_tag_lookup (&referencedTag, repo, referencedTargetOid) == GIT_OK ) {
95+ refModel->message = strdup (git_tag_message (referencedTag));
9196
92- git_tag *referencedTag;
93- if (git_tag_lookup (&referencedTag, repo, &referencedTargetOid) == GIT_OK ) {
94- refModel->message = strdup (git_tag_message (referencedTag));
95- git_tag_free (referencedTag);
97+ git_odb_object *tagOdbObject;
98+ if (git_odb_read (&tagOdbObject, odb, git_tag_id (referencedTag)) == GIT_OK ) {
99+ refModel->tagOdbBufferLength = git_odb_object_size (tagOdbObject);
100+ refModel->tagOdbBuffer = new char [refModel->tagOdbBufferLength ];
101+ std::memcpy (refModel->tagOdbBuffer , git_odb_object_data (tagOdbObject), refModel->tagOdbBufferLength );
102+ git_odb_object_free (tagOdbObject);
96103 }
104+
105+ git_tag_free (referencedTag);
106+ }
107+
108+ git_oid peeledReferencedTargetOid;
109+ int error = getOidOfReferenceCommit (&peeledReferencedTargetOid, ref);
110+ if (error != GIT_OK ) {
111+ delete refModel;
112+ return error;
97113 }
98114
99- git_oid_tostr (refModel->sha , GIT_OID_HEXSZ + 1 , &referencedTargetOid );
115+ git_oid_tostr (refModel->sha , GIT_OID_HEXSZ + 1 , &peeledReferencedTargetOid );
100116
101117 *out = refModel;
102118 return GIT_OK ;
103119 }
104120
105- v8::Local<v8::Object> toJavascript () {
121+ static void ensureSignatureRegexes () {
122+ if (!signatureRegexesBySignatureType.IsEmpty ()) {
123+ return ;
124+ }
125+
126+ v8::Local<v8::Array> gpgsigArray = Nan::New<v8::Array>(2 ),
127+ x509Array = Nan::New<v8::Array>(1 );
128+
129+ Nan::Set (
130+ gpgsigArray,
131+ Nan::New<Number>(0 ),
132+ Nan::New<v8::RegExp>(
133+ Nan::New (" -----BEGIN PGP SIGNATURE-----[\\ s\\ S]+?-----END PGP SIGNATURE-----" ).ToLocalChecked (),
134+ static_cast <v8::RegExp::Flags>(v8::RegExp::Flags::kGlobal | v8::RegExp::Flags::kMultiline )
135+ ).ToLocalChecked ()
136+ );
137+
138+ Nan::Set (
139+ gpgsigArray,
140+ Nan::New<Number>(1 ),
141+ Nan::New<v8::RegExp>(
142+ Nan::New (" -----BEGIN PGP MESSAGE-----[\\ s\\ S]+?-----END PGP MESSAGE-----" ).ToLocalChecked (),
143+ static_cast <v8::RegExp::Flags>(v8::RegExp::Flags::kGlobal | v8::RegExp::Flags::kMultiline )
144+ ).ToLocalChecked ()
145+ );
146+
147+ Nan::Set (
148+ x509Array,
149+ Nan::New<Number>(0 ),
150+ Nan::New<v8::RegExp>(
151+ Nan::New (" -----BEGIN SIGNED MESSAGE-----[\s\S]+?-----END SIGNED MESSAGE-----" ).ToLocalChecked (),
152+ static_cast <v8::RegExp::Flags>(v8::RegExp::Flags::kGlobal | v8::RegExp::Flags::kMultiline )
153+ ).ToLocalChecked ()
154+ );
155+
156+ v8::Local<v8::Object> result = Nan::New<Object>();
157+ Nan::Set (result, Nan::New (" gpgsig" ).ToLocalChecked (), gpgsigArray);
158+ Nan::Set (result, Nan::New (" x509" ).ToLocalChecked (), x509Array);
159+
160+ signatureRegexesBySignatureType.Reset (result);
161+ }
162+
163+ v8::Local<v8::Object> toJavascript (v8::Local<v8::String> signatureType) {
106164 v8::Local<v8::Object> result = Nan::New<Object>();
107165
108166 v8::Local<v8::Value> jsFullName;
@@ -135,6 +193,34 @@ class RefreshedRefModel {
135193 }
136194 Nan::Set (result, Nan::New (" shorthand" ).ToLocalChecked (), jsShorthand);
137195
196+ v8::Local<v8::Value> jsTagSignature = Nan::Null ();
197+ if (tagOdbBuffer != NULL && tagOdbBufferLength != 0 ) {
198+ // tagOdbBuffer is already a copy, so we'd like to use NewBuffer instead,
199+ // but we were getting segfaults and couldn't easily figure out why. :(
200+ // We tried passing the tagOdbBuffer directly to NewBuffer and then nullifying tagOdbBuffer so that
201+ // the destructor didn't double free, but that still segfaulted internally in Node.
202+ v8::Local<v8::Object> buffer = Nan::CopyBuffer (tagOdbBuffer, tagOdbBufferLength).ToLocalChecked ();
203+ v8::Local<v8::Value> toStringProp = Nan::Get (buffer, Nan::New (" toString" ).ToLocalChecked ()).ToLocalChecked ();
204+ v8::Local<v8::Object> jsTagOdbObjectString = Nan::CallAsFunction (toStringProp->ToObject (), buffer, 0 , NULL ).ToLocalChecked ()->ToObject ();
205+
206+ v8::Local<v8::Object> _signatureRegexesBySignatureType = Nan::New (signatureRegexesBySignatureType);
207+ v8::Local<v8::Array> signatureRegexes = v8::Local<v8::Array>::Cast (Nan::Get (_signatureRegexesBySignatureType, signatureType).ToLocalChecked ());
208+
209+ for (uint32_t i = 0 ; i < signatureRegexes->Length (); ++i) {
210+ v8::Local<v8::Value> argv[] = {
211+ Nan::Get (signatureRegexes, Nan::New (i)).ToLocalChecked ()
212+ };
213+
214+ v8::Local<v8::Value> matchProp = Nan::Get (jsTagOdbObjectString, Nan::New (" match" ).ToLocalChecked ()).ToLocalChecked ();
215+ v8::Local<v8::Value> match = Nan::CallAsFunction (matchProp->ToObject (), jsTagOdbObjectString, 1 , argv).ToLocalChecked ();
216+ if (match->IsArray ()) {
217+ jsTagSignature = Nan::Get (match->ToObject (), 0 ).ToLocalChecked ();
218+ break ;
219+ }
220+ }
221+ }
222+ Nan::Set (result, Nan::New (" tagSignature" ).ToLocalChecked (), jsTagSignature);
223+
138224 v8::Local<v8::Value> jsType;
139225 if (type == NULL ) {
140226 jsType = Nan::Null ();
@@ -151,12 +237,17 @@ class RefreshedRefModel {
151237 if (message != NULL ) { delete[] message; }
152238 delete[] sha;
153239 if (shorthand != NULL ) { delete[] shorthand; }
240+ if (tagOdbBuffer != NULL ) { delete[] tagOdbBuffer; }
154241 }
155242
156- char *fullName, *message, *sha, *shorthand;
243+ char *fullName, *message, *sha, *shorthand, *tagOdbBuffer;
244+ size_t tagOdbBufferLength;
157245 const char *type;
246+ static Nan::Persistent<v8::Object> signatureRegexesBySignatureType;
158247};
159248
249+ Nan::Persistent<v8::Object> RefreshedRefModel::signatureRegexesBySignatureType;
250+
160251class UpstreamModel {
161252public:
162253 UpstreamModel (const char *inputDownstreamFullName, const char *inputUpstreamFullName):
@@ -277,7 +368,25 @@ class RefreshReferencesData {
277368
278369NAN_METHOD (GitRepository::RefreshReferences)
279370{
280- if (info.Length () == 0 || !info[0 ]->IsFunction ()) {
371+ v8::Local<v8::String> signatureType;
372+ if (info.Length () == 2 ) {
373+ if (!info[0 ]->IsString ()) {
374+ return Nan::ThrowError (" Signature type must be \" gpgsig\" or \" x509\" ." );
375+ }
376+
377+ v8::Local<v8::String> signatureTypeParam = info[0 ]->ToString ();
378+ if (
379+ Nan::Equals (signatureTypeParam, Nan::New (" gpgsig" ).ToLocalChecked ()) != Nan::Just (true )
380+ && Nan::Equals (signatureTypeParam, Nan::New (" x509" ).ToLocalChecked ()) != Nan::Just (true )
381+ ) {
382+ return Nan::ThrowError (" Signature type must be \" gpgsig\" or \" x509\" ." );
383+ }
384+ signatureType = signatureTypeParam;
385+ } else {
386+ signatureType = Nan::New (" gpgsig" ).ToLocalChecked ();
387+ }
388+
389+ if (info.Length () == 0 || (info.Length () == 1 && !info[0 ]->IsFunction ()) || (info.Length () == 2 && !info[1 ]->IsFunction ())) {
281390 return Nan::ThrowError (" Callback is required and must be a Function." );
282391 }
283392
@@ -291,6 +400,7 @@ NAN_METHOD(GitRepository::RefreshReferences)
291400 Nan::Callback *callback = new Nan::Callback (Local<Function>::Cast (info[0 ]));
292401 RefreshReferencesWorker *worker = new RefreshReferencesWorker (baton, callback);
293402 worker->SaveToPersistent (" repo" , info.This ());
403+ worker->SaveToPersistent (" signatureType" , signatureType);
294404 Nan::AsyncQueueWorker (worker);
295405 return ;
296406}
@@ -302,6 +412,18 @@ void GitRepository::RefreshReferencesWorker::Execute()
302412 LockMaster lockMaster (true , baton->repo );
303413 git_repository *repo = baton->repo ;
304414 RefreshReferencesData *refreshData = (RefreshReferencesData *)baton->out ;
415+ git_odb *odb;
416+
417+ baton->error_code = git_repository_odb (&odb, repo);
418+ if (baton->error_code != GIT_OK ) {
419+ if (giterr_last () != NULL ) {
420+ baton->error = git_error_dup (giterr_last ());
421+ }
422+ git_odb_free (odb);
423+ delete refreshData;
424+ baton->out = NULL ;
425+ return ;
426+ }
305427
306428 // START Refresh HEAD
307429 git_reference *headRef = NULL ;
@@ -311,17 +433,19 @@ void GitRepository::RefreshReferencesWorker::Execute()
311433 if (giterr_last () != NULL ) {
312434 baton->error = git_error_dup (giterr_last ());
313435 }
436+ git_odb_free (odb);
314437 delete refreshData;
315438 baton->out = NULL ;
316439 return ;
317440 }
318441
319442 RefreshedRefModel *headModel;
320- baton->error_code = RefreshedRefModel::fromReference (&headModel, headRef);
443+ baton->error_code = RefreshedRefModel::fromReference (&headModel, headRef, odb );
321444 if (baton->error_code != GIT_OK ) {
322445 if (giterr_last () != NULL ) {
323446 baton->error = git_error_dup (giterr_last ());
324447 }
448+ git_odb_free (odb);
325449 git_reference_free (headRef);
326450 delete refreshData;
327451 baton->out = NULL ;
@@ -336,7 +460,7 @@ void GitRepository::RefreshReferencesWorker::Execute()
336460 // START Refresh CHERRY_PICK_HEAD
337461 git_reference *cherrypickRef = NULL ;
338462 if (lookupDirectReferenceByShorthand (&cherrypickRef, repo, " CHERRY_PICK_HEAD" ) == GIT_OK ) {
339- baton->error_code = RefreshedRefModel::fromReference (&refreshData->cherrypick , cherrypickRef);
463+ baton->error_code = RefreshedRefModel::fromReference (&refreshData->cherrypick , cherrypickRef, odb );
340464 git_reference_free (cherrypickRef);
341465 } else {
342466 cherrypickRef = NULL ;
@@ -347,7 +471,7 @@ void GitRepository::RefreshReferencesWorker::Execute()
347471 git_reference *mergeRef = NULL ;
348472 // fall through if cherry pick failed
349473 if (baton->error_code == GIT_OK && lookupDirectReferenceByShorthand (&mergeRef, repo, " MERGE_HEAD" ) == GIT_OK ) {
350- baton->error_code = RefreshedRefModel::fromReference (&refreshData->merge , mergeRef);
474+ baton->error_code = RefreshedRefModel::fromReference (&refreshData->merge , mergeRef, odb );
351475 git_reference_free (mergeRef);
352476 } else {
353477 mergeRef = NULL ;
@@ -358,6 +482,7 @@ void GitRepository::RefreshReferencesWorker::Execute()
358482 if (giterr_last () != NULL ) {
359483 baton->error = git_error_dup (giterr_last ());
360484 }
485+ git_odb_free (odb);
361486 delete refreshData;
362487 baton->out = NULL ;
363488 return ;
@@ -371,6 +496,7 @@ void GitRepository::RefreshReferencesWorker::Execute()
371496 if (giterr_last () != NULL ) {
372497 baton->error = git_error_dup (giterr_last ());
373498 }
499+ git_odb_free (odb);
374500 delete refreshData;
375501 baton->out = NULL ;
376502 return ;
@@ -383,6 +509,7 @@ void GitRepository::RefreshReferencesWorker::Execute()
383509 if (giterr_last () != NULL ) {
384510 baton->error = git_error_dup (giterr_last ());
385511 }
512+ git_odb_free (odb);
386513 git_strarray_free (&referenceNames);
387514 delete refreshData;
388515 baton->out = NULL ;
@@ -424,14 +551,15 @@ void GitRepository::RefreshReferencesWorker::Execute()
424551 }
425552
426553 RefreshedRefModel *refreshedRefModel;
427- baton->error_code = RefreshedRefModel::fromReference (&refreshedRefModel, reference);
554+ baton->error_code = RefreshedRefModel::fromReference (&refreshedRefModel, reference, odb );
428555 git_reference_free (reference);
429556
430557 if (baton->error_code == GIT_OK ) {
431558 refreshData->refs .push_back (refreshedRefModel);
432559 }
433560 }
434561
562+ git_odb_free (odb);
435563 git_strarray_free (&remoteNames);
436564 git_strarray_free (&referenceNames);
437565
@@ -449,6 +577,7 @@ void GitRepository::RefreshReferencesWorker::HandleOKCallback()
449577{
450578 if (baton->out != NULL )
451579 {
580+ RefreshedRefModel::ensureSignatureRegexes ();
452581 RefreshReferencesData *refreshData = (RefreshReferencesData *)baton->out ;
453582 v8::Local<v8::Object> result = Nan::New<Object>();
454583
@@ -458,27 +587,29 @@ void GitRepository::RefreshReferencesWorker::HandleOKCallback()
458587 Nan::New<String>(refreshData->headRefFullName ).ToLocalChecked ()
459588 );
460589
590+ v8::Local<v8::String> signatureType = GetFromPersistent (" signatureType" )->ToString ();
591+
461592 unsigned int numRefs = refreshData->refs .size ();
462- v8::Local<v8::Array> refs = Nan::New<Array>(numRefs);
593+ v8::Local<v8::Array> refs = Nan::New<v8:: Array>(numRefs);
463594 for (unsigned int i = 0 ; i < numRefs; ++i) {
464595 RefreshedRefModel *refreshedRefModel = refreshData->refs [i];
465- Nan::Set (refs, Nan::New<Number> (i), refreshedRefModel->toJavascript ());
596+ Nan::Set (refs, Nan::New (i), refreshedRefModel->toJavascript (signatureType ));
466597 }
467598 Nan::Set (result, Nan::New (" refs" ).ToLocalChecked (), refs);
468599
469600 unsigned int numUpstreamInfo = refreshData->upstreamInfo .size ();
470- v8::Local<v8::Array> upstreamInfo = Nan::New<Array>(numUpstreamInfo);
601+ v8::Local<v8::Array> upstreamInfo = Nan::New<v8:: Array>(numUpstreamInfo);
471602 for (unsigned int i = 0 ; i < numUpstreamInfo; ++i) {
472603 UpstreamModel *upstreamModel = refreshData->upstreamInfo [i];
473- Nan::Set (upstreamInfo, Nan::New<Number> (i), upstreamModel->toJavascript ());
604+ Nan::Set (upstreamInfo, Nan::New (i), upstreamModel->toJavascript ());
474605 }
475606 Nan::Set (result, Nan::New (" upstreamInfo" ).ToLocalChecked (), upstreamInfo);
476607
477608 if (refreshData->cherrypick != NULL ) {
478609 Nan::Set (
479610 result,
480611 Nan::New (" cherrypick" ).ToLocalChecked (),
481- refreshData->cherrypick ->toJavascript ()
612+ refreshData->cherrypick ->toJavascript (signatureType )
482613 );
483614 } else {
484615 Nan::Set (result, Nan::New (" cherrypick" ).ToLocalChecked (), Nan::Null ());
@@ -488,7 +619,7 @@ void GitRepository::RefreshReferencesWorker::HandleOKCallback()
488619 Nan::Set (
489620 result,
490621 Nan::New (" merge" ).ToLocalChecked (),
491- refreshData->merge ->toJavascript ()
622+ refreshData->merge ->toJavascript (signatureType )
492623 );
493624 } else {
494625 Nan::Set (result, Nan::New (" merge" ).ToLocalChecked (), Nan::Null ());
0 commit comments