我最終使用了類似的方法找到了一個我發現有人用於Python的方法。
我創建了一個C#控制檯應用程序如下:
using System;
using System.Diagnostics;
using System.IO;
namespace GitNodeRunner
{
class Program
{
static int Main(string[] args)
{
if (args == null || args.Length == 0)
{
Console.Error.WriteLine("Path to script file not specified");
return -1;
}
string argString = string.Join(" ", args);
Console.WriteLine("Node.js arguments received: {0}", argString);
string nodePath = Environment.GetEnvironmentVariable("NODE_HOME",
EnvironmentVariableTarget.Machine); // without "Machine" Git's Bash loses it
if (string.IsNullOrWhiteSpace(nodePath))
{
Console.Error.WriteLine("NODE_HOME global envirnoment variable not found");
return -1;
}
nodePath = Path.Combine(nodePath, "node.exe");
ProcessStartInfo start = new ProcessStartInfo
{
UseShellExecute = false,
Arguments = argString,
FileName = nodePath,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
Process process = new Process();
process.StartInfo = start;
process.EnableRaisingEvents = true;
process.OutputDataReceived += process_OutputDataReceived;
process.ErrorDataReceived += process_OutputDataReceived;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
return process.ExitCode;
}
static void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
string s = e.Data;
Console.Out.WriteLine(s);
}
static void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
string s = e.Data;
Console.Error.WriteLine(s);
}
}
}
我編譯它作爲混帳nodejs.exe,投入Git的bin
文件夾,確保我已經定義NODE_HOME
環境變量,現在我可以使用node.js腳本。作爲一個例子,我提供了我的node.js更新鉤子,它拒絕推送格式錯誤的註釋消息:
#!/bin/git-nodejs
// bin/git-nodejs is our custom C# programmed node launcher
// the following code is ported from http://git-scm.com/book/en/Customizing-Git-An-Example-Git-Enforced-Policy
// we have some offset from standard Git args here:
// 0 is path to node
// 1 is path to this script
var exec = require('child_process').exec,
refname = process.argv[2],
oldrev = process.argv[3],
newrev = process.argv[4],
regexMatch = /^REF #\d* /; // in my case I require strict start with "REF #number "
console.log("Enforcing policies in branch " + refname + " for commits between revisions " + oldrev + " and " + newrev);
// we have a special case - if this is a new branch, oldrev..newrev will cause git to throw an error,
// that's why we check for empty branch commit ID
var revListCmd = (oldrev === "0000000000000000000000000000000000000000") ?
"git rev-list " + newrev + " --not --branches=*" :
"git rev-list " + oldrev + ".." + newrev;
exec(revListCmd,
function (error, stdout, stderr) {
if (error !== null) {
console.error("Exec error: " + error);
exitError();
}
var missedRevs = stdout.split("\n");
missedRevs.forEach(function(rev){
// there is a redundant empty entry at the end after split()
if (rev.length === 0) {
return;
}
console.log("Verifying policy for revision " + rev);
// | sed '1,/^$/d' does not quite work as expected on Windows
// - it returns all commit details instead of comment
// thus we complete the processing from JavaScript
exec("git cat-file commit " + rev,
function (error, stdout, stderr) {
if (error !== null) {
console.error("Exec error: " + error);
exitError();
}
// we skip the blank line (two sequential newlines) and take everything that follows
// not sure if this is the best solution but "it works on my machine"
var commitMessage = stdout.split("\n\n")[1];
// notice: if commit message missing, git will report it as "no message"
if (commitMessage.match(regexMatch) === null) {
console.error("Commit message '" + commitMessage + "' does not match the required pattern " + regexMatch);
exitError();
}
});
});
});
//////////////////////////
// some helpers
function exitError()
{
// hack for bug https://github.com/joyent/node/issues/3584
// delay exit until stdout on Windows has had some time to flush
setTimeout(function() {
console.error("Exiting with error status 1");
process.exit(1);
}, 1000);
}