private-bower
Version:
A simple private bower registry
390 lines (303 loc) • 11.1 kB
JavaScript
var PackageStore = require('./package-store');
var PublicPackageStore = require('./public-package-store');
var RepoCacheHandler = require('./repo-cache-handler');
var argv = require('optimist').argv;
var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;
var log4js = require('log4js');
var bodyParser = require('body-parser');
var express = require('express');
var app = express();
var logger = require('./logger');
var _config, _configPath, _configDirectory;
var _repoCacheEnabled;
var _packageStore, _publicPackageStore, _repoCacheHandler;
module.exports.run = _init;
function _init() {
if(argv.h || argv.help) {
logger.logHelp();
process.exit();
}
_loadConfig();
_packageStore = new PackageStore({
persistFilePath: _config.registryFile
});
if(!_config.disablePublic) {
_publicPackageStore = new PublicPackageStore(_config);
if(_config.repositoryCache) {
initPublicRepoCache();
}
}
_initService();
function initPublicRepoCache() {
var repoCacheOptions = {};
if(_config.repositoryCache.svn && _config.repositoryCache.svn.enabled) {
repoCacheOptions.svn = {
repoCacheRoot: path.resolve(_config.repositoryCache.svn.cacheDirectory || path.join(_configDirectory, './svnRepoCache')),
hostName: _config.repositoryCache.svn.host || 'localhost',
port: _config.repositoryCache.svn.port || 7891,
refreshTimeout: _config.repositoryCache.svn.refreshTimeout || 10,
parameters: _config.repositoryCache.svn.parameters
};
}
if(_config.repositoryCache.git && _config.repositoryCache.git.enabled) {
repoCacheOptions.git = {
repoCacheRoot: path.resolve(_config.repositoryCache.git.cacheDirectory || path.join(_configDirectory, './gitRepoCache')),
hostName: _config.repositoryCache.git.host || 'localhost',
publicAccessURL: _config.repositoryCache.git.publicAccessURL || null,
port: _config.repositoryCache.git.port || 6789,
refreshTimeout: _config.repositoryCache.git.refreshTimeout || 10,
parameters: _config.repositoryCache.git.parameters
};
}
if(repoCacheOptions.svn || repoCacheOptions.git) {
_repoCacheEnabled = true;
_repoCacheHandler = new RepoCacheHandler(repoCacheOptions);
}
}
}
function _loadConfig() {
var defaultConfigPath = path.join(__dirname, '../bower.conf.json');
_configPath = path.resolve(argv.config || defaultConfigPath);
if(!fs.existsSync(_configPath)) {
logger.error('config file not found at ' + _configPath);
}
_configDirectory = path.join(_configPath, '../');
var json = fs.readFileSync(_configPath).toString();
_config = JSON.parse(json);
//defaults
_config.port = _config.port || 5678;
_config.registryFile = path.resolve(_config.registryFile || path.join(_configDirectory, './bowerRepository.json'));
_config.timeout = _config.timeout || 2 * 60 * 1200;
if(_config.log4js && _config.log4js.enabled) {
log4js.configure(_config.log4js.configPath);
}
}
function _initService() {
app.use(bodyParser());
app.use(express.static(path.join(__dirname, '../site')));
app.post('/registerPackage', function(req, res) {
if(!authenticate(req, res)) {
return;
}
_packageStore.registerPackages([
{
name: req.body.name,
repo: req.body.repo
}
]);
res.send('ok');
});
app.post('/packages', function(req, res) {
if(!authenticate(req, res)) {
return;
}
_packageStore.registerPackages([
{
name: req.body.name,
repo: req.body.url
}
]);
res.send(201);
});
app.post('/registerPackages', function(req, res) {
if(!authenticate(req, res)) {
return;
}
_packageStore.registerPackages(req.body.packages);
res.send('ok');
});
app.post('/removePackage', function(req, res) {
if(!authenticate(req, res)) {
return;
}
var packages = [ req.body.name ];
_packageStore.removePackages(packages);
if(_repoCacheHandler) {
_removePackagesFromRepoCaches(packages);
}
res.send('ok');
});
app.post('/removePackages', function(req, res) {
if(!authenticate(req, res)) {
return;
}
var packages = req.body.packages;
_packageStore.removePackages(packages);
if(_repoCacheHandler) {
_removePackagesFromRepoCaches(packages);
}
res.send('ok');
});
function _removePackagesFromRepoCaches(packages) {
var repoCaches = _repoCacheHandler.getRepoAllCaches();
repoCaches.forEach(function(repoCache) {
packages.forEach(function(packageName) {
repoCache.removeRepo(packageName);
});
});
}
app.get('/packages', function(req, res) {
var packages = [];
for(var packageName in _packageStore.packages) {
if(_packageStore.packages.hasOwnProperty(packageName)) {
var item = _packageStore.packages[packageName];
packages.push({
name: packageName,
repo: item.repo,
hits: item.hits
});
}
}
res.send(packages);
});
app.get('/packages/search/:name', function(req, res) {
var searchName = req.params.name;
var packages = _packageStore.searchPackage(searchName);
if(!_config.disablePublic) {
Array.prototype.push.apply(packages, _publicPackageStore.searchPackage(searchName));
}
res.send(packages);
});
//bower service
app.get('/packages/:name', function(req, res) {
var packageName = req.params.name;
var privatePackage = _packageStore.getPackage(packageName);
if(privatePackage) {
handlePrivatePackage();
}
else if(!_config.disablePublic) {
handlePublicPackage();
}
else {
res.status(404).send('Not found');
}
function handlePrivatePackage() {
if(_config.repositoryCache && _config.repositoryCache.cachePrivate) {
if(privatePackage.cachedRepo) {
res.send({
name: packageName,
url: privatePackage.cachedRepo,
hits: privatePackage.hits
});
}
else if(_repoCacheHandler) {
cachePrivateRepoAndSend();
}
else {
sendPrivatePackage();
}
}
else {
sendPrivatePackage();
}
function cachePrivateRepoAndSend() {
var repoCache = _repoCacheHandler.getRepoCache(privatePackage.repo);
repoCache.cacheRepo(packageName, privatePackage.repo)
.then(function(pack) {
privatePackage.cachedRepo = pack.repo;
_packageStore.persistPackages();
res.send({
name: packageName,
url: privatePackage.cachedRepo,
hits: privatePackage.hits
});
})
.fail(sendPrivatePackage);
}
function sendPrivatePackage() {
res.send({
name: packageName,
url: privatePackage.repo,
hits: privatePackage.hits
});
}
}
function handlePublicPackage() {
var publicPackage = _publicPackageStore.getPackage(packageName);
if(publicPackage) {
if(_repoCacheEnabled) {
cachePublicRepo();
}
else {
res.send(publicPackage);
}
}
else {
res.status(404).send('Not found');
}
function cachePublicRepo() {
var repoCache = _repoCacheHandler.getRepoCache(publicPackage.url);
repoCache.cacheRepo(packageName, publicPackage.url)
.then(function(pack) {
var privatePackage = {
name: packageName,
repo: pack.repo,
hits: publicPackage.hits
};
_packageStore.registerPackages([ privatePackage ]);
res.send({
name: privatePackage.name,
url: privatePackage.repo,
hits: privatePackage.hits
});
})
.fail(function() {
res.send(publicPackage);
});
}
}
});
app.post('/restart', function(req, res) {
if(!authenticate(req, res)) {
return;
}
logger.log('Shutting down server for restart');
res.send('ok');
server.close();
logger.log('Restarting private-bower with config set to ' + _configPath);
_shutDown();
_startDetachedChildProcess('private-bower', ['--config', _configPath]);
});
var server = app.listen(_config.port, function() {
logger.log('Bower server started on port ' + _config.port);
});
server.timeout = _config.timeout;
process.on('SIGINT', _doShutDown);
function authenticate(req, res) {
if(!_config.authentication || !_config.authentication.enabled) {
return true;
}
if(req.get('Auth-Key') === _config.authentication.key) {
return true;
}
res.status(401);
res.send('Unauthorized');
return false;
}
}
function _startDetachedChildProcess(command, args) {
var child = spawn(command, args, {
detached: true
});
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
child.unref();
}
function _doShutDown() {
_shutDown();
process.exit();
}
function _shutDown() {
logger.log('Shutting down private-bower');
if(_repoCacheHandler) {
_repoCacheHandler.getRepoAllCaches().forEach(function(repoCache) {
repoCache.shutDown();
});
}
}
process.on('uncaughtException', function(err) {
logger.log('Exception message:' + (err.stack || err.message));
_shutDown();
});