-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgit_http_backend.js
123 lines (106 loc) · 4.43 KB
/
git_http_backend.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
git-angler: a Git event bus
Copyright (C) 2014 Nick Hynes -- MIT
*/
'use strict';
var fs = require('fs'),
gitHttpBackend = require('git-http-backend'),
path = require('path'),
spawn = require('child_process').spawn,
stream = require('stream'),
utils = require('./utils'),
zlib = require('zlib');
module.exports = function( opts ) {
opts = opts || {};
if ( !opts.pathToRepos || !opts.eventBus ) {
throw Error('git-angler backend requires both a path to repos and an EventBus');
}
var eventBus = opts.eventBus,
pathToRepos = opts.pathToRepos,
authenticator = opts.authenticator || function( _, cb ) { cb({ ok: true }); },
handlerTimeoutLen = opts.handlerTimeoutLen || 30000;
return function( req, res ) {
var repoPath = utils.getRepoPath( req.url ),
repoPathStr = '/' + repoPath.join('/'),
repoFullPath = path.resolve.bind( null, pathToRepos ).apply( null, repoPath ),
backend,
gitService,
encoding = req.headers['content-encoding'],
decompress = ( encoding === 'gzip' || encoding === 'deflate' ?
zlib.createUnzip() : stream.PassThrough() ),
callHandlerSync = utils.callHandlerSync
.bind( null, eventBus, handlerTimeoutLen, repoPathStr );
function createBackend( serviceHook ) {
return gitHttpBackend( req.url, function( err, service ) {
var ps,
authParams;
if ( err ) {
res.writeHead( 400 );
res.end();
return;
}
authParams = {
request: {
url: req.url,
method: req.method,
headers: req.headers
},
service: {
action: service.action,
fields: service.fields
},
repoPath: repoPath
};
authenticator( authParams, function( auth ) {
if ( !auth.ok ) {
res.writeHead( auth.status || 401 );
res.end( auth.message );
return;
}
res.setHeader( 'Content-Type', service.type );
gitService = service;
res.on( 'finish', function() {
eventBus.trigger( repoPathStr, gitService.action, [ gitService.fields ] );
});
serviceHook( service, function() {
ps = spawn( service.cmd, service.args.concat( repoFullPath ) );
ps.stdout.pipe( service.createStream() ).pipe( ps.stdin );
ps.stderr.on( 'data', function( data ) {
eventBus.trigger( repoPathStr, 'err', [ data.toString() ] );
});
});
});
});
}
fs.stat( repoFullPath, function( err ) {
if ( err ) {
if ( err.code !== 'ENOENT' ) { return eventBus.trigger( 'error', err ); }
callHandlerSync( '404', [ {} ], function( clonable ) {
if ( !clonable ) {
res.writeHead( 404 );
res.end();
return;
}
backend = createBackend( function( service, done ) {
eventBus.triggerListeners( repoPathStr, '404' );
done();
});
req.pipe( decompress ).pipe( backend ).pipe( res );
});
return;
}
backend = createBackend( function( service, done ) {
var action = service.action,
cbArgs = [ service.fields ];
callHandlerSync( 'pre-' + action, cbArgs, function( responseText ) {
if ( action !== 'info' && responseText ) {
service.createBand().end( responseText + '\n' );
}
eventBus.triggerListeners( repoPathStr, 'pre-' + action, [ service.fields ] );
done();
});
});
req.pipe( decompress ).pipe( backend ).pipe( res );
});
};
};