Skip to content

Commit 888e34c

Browse files
authored
Merge pull request nodegit#1624 from stevex86/feature/sign-init-commit-on-bare-repo
Fix non-existent / dangling refs cause Repository.prototype.createCommitWithSignature to fail
2 parents 299414f + 6e7032b commit 888e34c

10 files changed

Lines changed: 494 additions & 199 deletions

File tree

generate/input/descriptor.json

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2269,13 +2269,14 @@
22692269
"ignore": true
22702270
},
22712271
"git_oid_fromstr": {
2272-
"isAsync": false
2272+
"ignore": true
22732273
},
22742274
"git_oid_fromstrn": {
22752275
"ignore": true
22762276
},
22772277
"git_oid_fromstrp": {
2278-
"ignore": true
2278+
"isAsync": false,
2279+
"jsFunctionName": "fromString"
22792280
},
22802281
"git_oid_nfmt": {
22812282
"ignore": true
@@ -3067,7 +3068,15 @@
30673068
"ignore": true
30683069
},
30693070
"git_repository_ident": {
3070-
"ignore": true
3071+
"args": {
3072+
"name": {
3073+
"isReturn": true
3074+
},
3075+
"email": {
3076+
"isReturn": true
3077+
}
3078+
},
3079+
"isAsync": false
30713080
},
30723081
"git_repository_init_init_options": {
30733082
"ignore": true
@@ -3251,7 +3260,10 @@
32513260
"dupFunction": "git_signature_dup",
32523261
"functions": {
32533262
"git_signature_default": {
3254-
"isAsync": false
3263+
"isAsync": true,
3264+
"return": {
3265+
"isErrorCode": true
3266+
}
32553267
},
32563268
"git_signature_dup": {
32573269
"ignore": true
@@ -3263,7 +3275,15 @@
32633275
"isAsync": false
32643276
},
32653277
"git_signature_now": {
3266-
"isAsync": false
3278+
"isAsync": false,
3279+
"args": {
3280+
"sig_out": {
3281+
"isReturn": true
3282+
}
3283+
},
3284+
"return": {
3285+
"isErrorCode": true
3286+
}
32673287
}
32683288
}
32693289
},

generate/templates/partials/sync_function.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) {
5050
{%endeach%}
5151
);
5252

53-
{%if .|hasReturnValue %} {{ return.cType }} result = {%endif%}
53+
{%if .|hasReturnType %} {{ return.cType }} result = {%endif%}
5454
{{ cFunctionName }}(
5555
{%each args|argsInfo as arg %}
5656
{%if arg.isReturn %}
@@ -67,15 +67,15 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) {
6767
{%endeach%}
6868
);
6969

70-
{%if .|hasReturnValue |and return.isErrorCode %}
70+
{%if .|hasReturnType |and return.isErrorCode %}
7171
if (result != GIT_OK) {
7272
{%each args|argsInfo as arg %}
73-
{%if arg.shouldAlloc %}
74-
free({{ arg.name }});
75-
{%elsif arg | isOid %}
73+
{%if arg | isOid %}
7674
if (info[{{ arg.jsArg }}]->IsString()) {
77-
free({{ arg.name }});
75+
free((void *)from_{{ arg.name }});
7876
}
77+
{%elsif arg.shouldAlloc %}
78+
free({{ arg.name }});
7979
{%endif%}
8080
{%endeach%}
8181

lib/reference.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,123 @@ Reference.prototype.isValid = function() {
6363
Reference.prototype.toString = function() {
6464
return this.name();
6565
};
66+
67+
const getTerminal = (repo, refName, depth = 10, prevRef = null) => {
68+
if (depth <= 0) {
69+
return Promise.resolve({
70+
error: NodeGit.Error.CODE.ENOTFOUND,
71+
out: prevRef
72+
});
73+
}
74+
75+
return NodeGit.Reference.lookup(repo, refName)
76+
.then((ref) => {
77+
if (ref.type() === NodeGit.Reference.TYPE.OID) {
78+
return {
79+
error: NodeGit.Error.CODE.OK,
80+
out: ref
81+
};
82+
} else {
83+
return getTerminal(repo, ref.symbolicTarget(), depth - 1, ref)
84+
.then(({ error, out }) => {
85+
if (error === NodeGit.Error.CODE.ENOTFOUND && !out) {
86+
return { error, out: ref };
87+
} else {
88+
return { error, out };
89+
}
90+
});
91+
}
92+
})
93+
.catch((error) => {
94+
return {
95+
error: error.errno,
96+
out: null
97+
};
98+
});
99+
};
100+
101+
const getSignatureForReflog = (repo) => {
102+
const { email, name } = repo.ident();
103+
if (email && name) {
104+
return Promise.resolve(NodeGit.Signature.now(name, email));
105+
}
106+
107+
return NodeGit.Signature.default(repo)
108+
.catch(() => NodeGit.Signature.now("unknown", "unknown"));
109+
};
110+
111+
/**
112+
* Given a reference name, follows symbolic links and updates the direct
113+
* reference to point to a given OID. Updates the reflog with a given message.
114+
*
115+
* @async
116+
* @param {Repository} repo The repo where the reference and objects live
117+
* @param {String} refName The reference name to update
118+
* @param {Oid} oid The target OID that the reference will point to
119+
* @param {String} logMessage The reflog message to be writted
120+
* @param {Signature} signature Optional signature to use for the reflog entry
121+
*/
122+
Reference.updateTerminal = function (
123+
repo,
124+
refName,
125+
oid,
126+
logMessage,
127+
signature
128+
) {
129+
let signatureToUse;
130+
let promiseChain = Promise.resolve();
131+
132+
if (!signature) {
133+
promiseChain = promiseChain
134+
.then(() => getSignatureForReflog(repo))
135+
.then((sig) => {
136+
signatureToUse = sig;
137+
return Promise.resolve();
138+
});
139+
} else {
140+
signatureToUse = signature;
141+
}
142+
143+
return promiseChain
144+
.then(() => getTerminal(repo, refName))
145+
.then(({ error, out }) => {
146+
if (error === NodeGit.Error.CODE.ENOTFOUND && out) {
147+
return NodeGit.Reference.create(
148+
repo,
149+
out.symbolicTarget(),
150+
oid,
151+
0,
152+
logMessage
153+
);
154+
} else if (error === NodeGit.Error.CODE.ENOTFOUND) {
155+
return NodeGit.Reference.create(
156+
repo,
157+
refName,
158+
oid,
159+
0,
160+
logMessage
161+
);
162+
} else {
163+
return NodeGit.Reference.createMatching(
164+
repo,
165+
out.name(),
166+
oid,
167+
1,
168+
out.target(),
169+
logMessage
170+
);
171+
}
172+
})
173+
.then(() => NodeGit.Reflog.read(repo, refName))
174+
.then((reflog) => {
175+
// Janky, but works. Ideally, we would want to generate the correct reflog
176+
// entry in the first place, rather than drop the most recent entry and
177+
// write the correct one.
178+
// NOTE: There is a theoretical race condition that could happen here.
179+
// We may want to consider some kind of transactional logic to make sure
180+
// that the reflog on disk isn't modified before we can write back.
181+
reflog.drop(0, 1);
182+
reflog.append(oid, signatureToUse, logMessage);
183+
return reflog.write();
184+
});
185+
};

0 commit comments

Comments
 (0)