Commit f7a4f04a authored by Leo Iannacone's avatar Leo Iannacone

Merge branch 'master' into portable

parents 04380791 43903d3a
...@@ -19,6 +19,11 @@ var express = require('express'), ...@@ -19,6 +19,11 @@ var express = require('express'),
Broadcaster = require('./lib/broadcaster.js'); Broadcaster = require('./lib/broadcaster.js');
// serve dsc files as octet-stream
serve_static.mime.define({
'application/octet-stream': ['dsc']
});
app.set('views', __dirname + '/views'); app.set('views', __dirname + '/views');
app.set('view engine', 'ejs'); app.set('view engine', 'ejs');
app.use(serve_static(__dirname + '/public')); app.use(serve_static(__dirname + '/public'));
......
var config = require('./config.js') 'use strict';
, fs = require('fs')
, Tail = require('./tail.js')
function __watch_status_check_same_obj (obj1, obj2) { var config = require('./config.js'),
if (obj1.status == obj2.status) { fs = require('fs'),
if (obj1.distribution == obj2.distribution) { utils = require('./utils.js'),
if (obj1.hasOwnProperty('package') && Tail = require('./tail.js');
obj2.hasOwnProperty('package'))
{ function __watch_status_check_same_obj(obj1, obj2) {
if (obj1.package == obj2.package) if (obj1.status == obj2.status) {
return true; if (obj1.distribution == obj2.distribution) {
return false if (obj1.hasOwnProperty('package') &&
} obj2.hasOwnProperty('package')) {
return true if (obj1.package == obj2.package)
return true;
return false;
}
return true;
}
} }
} return false;
return false
} }
// watcher on build_status // watcher on build_status
function __watch_status (socket, status) { function __watch_status(socket, status) {
var watcher = new Tail(config.debomatic.jsonfile) var watcher = new Tail(config.debomatic.jsonfile);
watcher.on('line', function(new_content) { watcher.on('line', function (new_content) {
var data = null var data = null;
try { try {
data = JSON.parse(new_content) data = JSON.parse(new_content);
} catch (err) { } catch (err) {
utils.errors_handler('Broadcaster:__watch_status:JSON.parse(new_content) - ', err, socket) utils.errors_handler('Broadcaster:__watch_status:JSON.parse(new_content) - ', err, socket);
return return;
}
// looking for same status already in statuses lists
if (data.hasOwnProperty('success')) {
for(i = 0; i < status.length; i++) {
if (__watch_status_check_same_obj(data, status[i])) {
status.splice(i, 1)
break;
} }
else // looking for same status already in statuses lists
continue; if (data.hasOwnProperty('success')) {
} for (var i = 0; i < status.length; i++) {
} if (__watch_status_check_same_obj(data, status[i])) {
else { status.splice(i, 1);
status.push(data) break;
} } else
socket.emit(config.events.broadcast.status_update, data) continue;
}) }
watcher.on('error', function(msg) { } else {
socket.emit(config.events.error, msg) status.push(data);
}) }
socket.emit(config.events.broadcast.status_update, data);
});
watcher.on('error', function (msg) {
socket.emit(config.events.error, msg);
});
} }
// watcher on new distributions // watcher on new distributions
function __watch_distributions (socket) { function __watch_distributions(socket) {
fs.watch(config.debomatic.path, { persistent: true }, function (event, fileName) { fs.watch(config.debomatic.path, {
// wait half a second to get pool subdir created persistent: true
setTimeout(function() { }, function (event, fileName) {
utils.send_distributions(socket) // wait half a second to get pool subdir created
}, 500) setTimeout(function () {
}) utils.send_distributions(socket);
}, 500);
});
} }
function Broadcaster (sockets, status) { function Broadcaster(sockets, status) {
var sockets = sockets
__watch_status(sockets, status) __watch_status(sockets, status);
__watch_distributions(sockets) __watch_distributions(sockets);
return { return {
} };
} }
module.exports = Broadcaster module.exports = Broadcaster;
This diff is collapsed.
'use strict';
/* /*
* Please DO NOT edit this file. * Please DO NOT edit this file.
* *
* Edit auto-generated "user.config.js" file instead. * Edit auto-generated 'user.config.js' file instead.
* *
*/ */
// #start config-auto-export // #start config-auto-export
var config = {} var config = {};
/* /*
* Configure host and port. * Configure host and port.
* Please for ports < 1000 use authbind. DO NOT RUN nodejs as root. * Please for ports < 1000 use authbind. DO NOT RUN nodejs as root.
* $ authbind nodejs index.js * $ authbind nodejs index.js
*/ */
config.host = 'localhost' config.host = 'localhost';
config.port = 3000 config.port = 3000;
config.socket = {} config.socket = {};
config.socket.log = false config.socket.log = false;
config.debomatic = {} config.debomatic = {};
config.debomatic.path = '/srv/debomatic-amd64' config.debomatic.path = '/srv/debomatic-amd64';
config.debomatic.jsonfile = '/var/log/debomatic-json.log' config.debomatic.jsonfile = '/var/log/debomatic-json.log';
config.routes = {} config.routes = {};
config.routes.debomatic = '/debomatic' config.routes.debomatic = '/debomatic';
config.routes.distribution = '/distribution' config.routes.distribution = '/distribution';
config.routes.preferences = '/preferences' config.routes.preferences = '/preferences';
config.web = {} config.web = {};
config.web.title = "Deb-o-Matic web.ui" config.web.title = 'Deb-o-Matic web.ui';
config.web.description = "This is a web interface for debomatic" config.web.description = 'This is a web interface for debomatic';
// debomatic configuration exportable for web // debomatic configuration exportable for web
config.web.debomatic = {} config.web.debomatic = {};
config.web.debomatic.admin = {} config.web.debomatic.admin = {};
config.web.debomatic.admin.name = "Your Name" config.web.debomatic.admin.name = 'Your Name';
config.web.debomatic.admin.email = "you AT debian DOT org" // please use this SPAMFREE form - it will be converted client side by javascript config.web.debomatic.admin.email = 'you AT debian DOT org'; // please use this SPAMFREE form - it will be converted client side by javascript
config.web.debomatic.architecture = 'amd64' config.web.debomatic.architecture = 'amd64';
config.web.debomatic.dput = {} config.web.debomatic.dput = {};
config.web.debomatic.dput.incoming = config.debomatic.path config.web.debomatic.dput.incoming = config.debomatic.path;
config.web.debomatic.dput.host = config.host config.web.debomatic.dput.host = config.host;
config.web.debomatic.dput.login = "debomatic" config.web.debomatic.dput.login = 'debomatic';
config.web.debomatic.dput.method = "scp" config.web.debomatic.dput.method = 'scp';
config.web.debomatic.dput.unsigned_uploads = false config.web.debomatic.dput.unsigned_uploads = false;
// default ui settings // default ui settings
config.web.preferences = {} config.web.preferences = {};
config.web.preferences.autoscroll = true config.web.preferences.autoscroll = true;
config.web.preferences.header = true config.web.preferences.header = true;
config.web.preferences.sidebar = true config.web.preferences.sidebar = true;
config.web.preferences.glossy_theme = true config.web.preferences.glossy_theme = true;
config.web.preferences.file_background = true config.web.preferences.file_background = true;
config.web.preferences.file_fontsize = 13 // valid values are [13..16] config.web.preferences.file_fontsize = 13; // valid values are [13..16]
config.web.preferences.debug = 0 // debug level - 0 means disabled config.web.preferences.debug = 0; // debug level - 0 means disabled
// #end config-auto-export // #end config-auto-export
// DO NOT TOUCH these ones // DO NOT TOUCH these ones
config.version = '0.2.2' config.version = '0.2.3';
// A simple function to quickly have // A simple function to quickly have
// get and set strings for client events // get and set strings for client events
function _event_get_set(event_name) { function _event_get_set(event_name) {
return { return {
set: event_name, set: event_name,
get: 'get_' + event_name get: 'get_' + event_name
} };
} }
config.events = {} config.events = {};
config.events.error = 'error' config.events.error = 'error';
config.events.broadcast = {} config.events.broadcast = {};
config.events.broadcast.distributions = 'distributions' config.events.broadcast.distributions = 'distributions';
config.events.broadcast.status_update = 'status_update' config.events.broadcast.status_update = 'status_update';
config.events.client = {} config.events.client = {};
config.events.client.distribution_packages = _event_get_set('distribution_packages') config.events.client.distribution_packages = _event_get_set('distribution_packages');
config.events.client.distribution_packages.status = 'package_status' config.events.client.distribution_packages.status = 'package_status';
config.events.client.package_files_list = _event_get_set('package_files_list') config.events.client.package_files_list = _event_get_set('package_files_list');
config.events.client.file = _event_get_set('file') config.events.client.file = _event_get_set('file');
config.events.client.file_newcontent = 'file_newcontent' config.events.client.file_newcontent = 'file_newcontent';
config.events.client.status = 'status' config.events.client.status = 'status';
// debomatic status according with JSONLogger.py module // debomatic status according with JSONLogger.py module
config.status = {} config.status = {};
config.status.build = 'build' config.status.build = 'build';
config.status.create = 'create' config.status.create = 'create';
config.status.update = 'update' config.status.update = 'update';
config.status.success = true config.status.success = true;
config.status.fail = false config.status.fail = false;
// read user configuration and merge it // read user configuration and merge it
/* /*
* update object1 with object2 values * update object1 with object2 values
*/ */
function _merge(object1, object2) { function _merge(object1, object2) {
var result = {} var result = {};
for (p in object1) { for (var p in object1) {
if (object2.hasOwnProperty(p)) { if (object2.hasOwnProperty(p)) {
if (typeof object1[p] === 'object' && typeof object2[p] === 'object') { if (typeof object1[p] === 'object' && typeof object2[p] === 'object') {
result[p] = _merge(object1[p], object2[p]) result[p] = _merge(object1[p], object2[p]);
} } else {
else { result[p] = object2[p];
result[p] = object2[p] }
} } else {
result[p] = object1[p];
}
} }
else { return result;
result[p] = object1[p]
}
}
return result
} }
try { try {
var Parser = require('./parser.js') var Parser = require('./parser.js');
var parser = new Parser() var parser = new Parser();
var user_config = parser.getUserConfig() var user_config = parser.getUserConfig();
if (user_config) { if (user_config) {
console.log("Reading user configutation ...") console.log('Reading user configutation ...');
config = _merge(config, require(user_config)) config = _merge(config, require(user_config));
} } else {
else { console.log('No user config specified. Using global settings.');
console.log("No user config specified. Using global settings.") }
}
} catch (err) { } catch (err) {
if (err.code == 'MODULE_NOT_FOUND') { if (err.code == 'MODULE_NOT_FOUND') {
console.log("File %s not found.", user_config) console.log('File %s not found.', user_config);
process.exit(1) process.exit(1);
} } else {
else { console.error('Error reading user configutation', err);
console.error("Error reading user configutation", err); process.exit(1);
process.exit(1) }
}
} finally { } finally {
// export some variable // export some variable
config.web.paths = config.routes config.web.paths = config.routes;
config.web.events = config.events config.web.events = config.events;
config.web.status = config.status config.web.status = config.status;
config.web.host = config.host config.web.host = config.host;
module.exports = config module.exports = config;
} }
function Parser() 'use strict';
{
var args = process.argv.slice(2); function Parser() {
var help = function() { var args = process.argv.slice(2);
console.log("\
var help = function () {
console.log('\
Usage: %s [-c config]\n\ Usage: %s [-c config]\n\
-h print this help \n\ -h print this help \n\
-c set user configuration file", -c set user configuration file',
process.argv[1].split('/').pop()); process.argv[1].split('/').pop());
process.exit(0);
}
this.getUserConfig = function() { process.exit(0);
var configFile = null; };
args.forEach(function (val, index) {
if (val == '-c') {
configFile = args[index+1]
return
}
})
if (configFile)
return process.cwd() + '/' + configFile;
else
return null
}
args.forEach(function (val, index) { this.getUserConfig = function () {
if (val == '-h') { var configFile = null;
help() args.forEach(function (val, index) {
} if (val == '-c') {
}) configFile = args[index + 1];
return;
}
});
if (configFile)
return process.cwd() + '/' + configFile;
else
return null;
};
args.forEach(function (val, index) {
if (val == '-h') {
help();
}
});
} }
module.exports = Parser module.exports = Parser
\ No newline at end of file
var fs =require('fs') 'use strict';
, Tail = require('tail').Tail
Tail.prototype.watchEvent = function(e) { var fs = require('fs'),
var _this = this; Tail = require('tail').Tail;
if (e === 'change') { Tail.prototype.watchEvent = function (e) {
return fs.stat(this.filename, function(err, stats) { var _this = this;
if (err) {
_this.emit('error', err); if (e === 'change') {
} return fs.stat(this.filename, function (err, stats) {
if (stats.size < _this.pos) { if (err) {
_this.pos = stats.size; _this.emit('error', err);
} }
if (stats.size > _this.pos) { if (stats.size < _this.pos) {
_this.queue.push({ _this.pos = stats.size;
start: _this.pos, }
end: stats.size if (stats.size > _this.pos) {
_this.queue.push({
start: _this.pos,
end: stats.size
});
_this.pos = stats.size;
if (_this.queue.length === 1) {
return _this.internalDispatcher.emit('next');
}
}
}); });
_this.pos = stats.size; } else if (e === 'rename') {
if (_this.queue.length === 1) { this.unwatch();
return _this.internalDispatcher.emit("next"); _this.emit('error', 'File ' + this.filename + ' deleted.');
} }
}
});
} else if (e === 'rename') {
this.unwatch();
_this.emit('error', "File " + this.filename + " deleted.");
}
}; };
Tail.prototype.close = function() { Tail.prototype.close = function () {
this.unwatch() this.unwatch();
} };
module.exports = Tail module.exports = Tail;
\ No newline at end of file
This diff is collapsed.
"use strict";
/* /*
General information about debugging: General information about debugging:
...@@ -10,18 +11,18 @@ ...@@ -10,18 +11,18 @@
3 - socket emit data 3 - socket emit data
4 - socket received data 4 - socket received data
*/ */
var debug = function() { var debug = function () {
if (arguments.length < 2) { if (arguments.length < 2) {
return return;
} }
var level = arguments[0] var level = arguments[0];
arguments[0] = "debug [" + level + "]:" arguments[0] = "debug [" + level + "]:";
if (level <= config.preferences.debug) { if (level <= config.preferences.debug) {
if (console.debug) if (console.debug)
console.debug.apply(console, arguments) console.debug.apply(console, arguments);
else else
console.log.apply(console, arguments) console.log.apply(console, arguments);
} }
} }
/* /*
...@@ -30,11 +31,11 @@ var debug = function() { ...@@ -30,11 +31,11 @@ var debug = function() {
usage: debug_socket("emit"|"received", event_name, data) usage: debug_socket("emit"|"received", event_name, data)
*/ */
var debug_socket = function() { var debug_socket = function () {
if (arguments.length != 3) if (arguments.length != 3)
return return;
var level = 3; var level = 3;
if (arguments[0] == "received") if (arguments[0] == "received")
level = 4 level = 4;
debug(level, "socket", arguments[0], "event:", arguments[1], "data:", arguments[2]) debug(level, "socket", arguments[0], "event:", arguments[1], "data:", arguments[2]);
} }
\ No newline at end of file
// main client javascript // main client javascript
'use strict';
var preferences = new Preferences() var preferences = new Preferences();
var page_generic = new Page_Generic() var page_generic = new Page_Generic();
if (window.location.pathname == config.paths.preferences) { if (window.location.pathname == config.paths.preferences) {
preferences.initPage() preferences.initPage();
} }
if (window.location.pathname == '/') { if (window.location.pathname == '/') {
// convert email addresses in the right format // convert email addresses in the right format
var emails = $(".email") var emails = $('.email');
$.each(emails, function (){ $.each(emails, function () {
var subject = '' var subject = '';
if ($(this).attr('subject')) { if ($(this).attr('subject')) {
subject = '?subject=' + $(this).attr('subject') subject = '?subject=' + $(this).attr('subject');
} }
var real_email = $(this).attr('address').replace('AT','@').replace('DOT','.').replace(/ /g,'') var real_email = $(this).attr('address').replace('AT', '@').replace('DOT', '.').replace(/ /g, '');
var label = real_email var label = real_email;
if (config.debomatic.admin.name && config.debomatic.admin.name != 'Your Name') if (config.debomatic.admin.name && config.debomatic.admin.name != 'Your Name');
label = config.debomatic.admin.name label = config.debomatic.admin.name;
real_email = '<a href="mailto:' + real_email + subject + '">' + label + '</a>' real_email = '<a href="mailto:' + real_email + subject + '">' + label + '</a>';
$(this).html(real_email) $(this).html(real_email);
}) })
} }
var socket = io.connect('/'); var socket = io.connect('/');
page_generic.start(socket) page_generic.start(socket);
if (window.location.pathname == config.paths.distribution) { if (window.location.pathname == config.paths.distribution) {
new Page_Distrubion(socket).start() new Page_Distrubion(socket).start();
} }
'use strict';
function Preferences() { function Preferences() {
// update config.preferences according with user choices // update config.preferences according with user choices
var load = function () { var load = function () {
for (key in config.preferences) { for (var key in config.preferences) {
if ((value = localStorage.getItem(key))) { var value = localStorage.getItem(key);
debug(2, 'loading preference', key, value) if (value) {
config.preferences[key] = JSON.parse(value) debug(2, 'loading preference', key, value);
} config.preferences[key] = JSON.parse(value);
} }
} }
};
// set prefence
var set = function (key, value) { // set prefence
if (config.preferences.hasOwnProperty(key)) { var set = function (key, value) {
debug(1, 'setting preference', key, value) if (config.preferences.hasOwnProperty(key)) {
localStorage.setItem(key, value) debug(1, 'setting preference', key, value);
config.preferences[key] = JSON.parse(value) localStorage.setItem(key, value);
} config.preferences[key] = JSON.parse(value);
} }
};
// init prefence page
this.initPage = function() { // init prefence page
this.initPage = function () {
page_generic.set_window_title("Preferences")
page_generic.set_window_title('Preferences');
// set view according with config.preferences
for (key in config.preferences) { // set view according with config.preferences
var element = $("#preferences #" + key) for (var key in config.preferences) {
if (element.attr('type') == "checkbox") { var element = $('#preferences #' + key);
element.prop('checked', config.preferences[key]) if (element.attr('type') == 'checkbox') {
} element.prop('checked', config.preferences[key]);
else { } else {
element.val(config.preferences[key]) element.val(config.preferences[key]);
} }
} }
// on input change, set prefence // on input change, set prefence
$("#preferences input, #preferences select").change(function() { $('#preferences input, #preferences select').change(function () {
var key = $(this).attr('id') var key = $(this).attr('id');
var value = $(this).val() var value = $(this).val();
if ($(this).attr('type') == 'checkbox') if ($(this).attr('type') == 'checkbox')
value = $(this).is(':checked') value = $(this).is(':checked');
set(key,value) set(key, value);
// give to user an immediate feedback changing preferences // give to user an immediate feedback changing preferences
page_generic.preferences() page_generic.preferences();
}) });
} };
load() load();
} }
\ No newline at end of file
'use strict';
var Utils = { var Utils = {
from_hash_to_view: function (hash) { from_hash_to_view: function (hash) {
if (! hash ) if (!hash)
hash = window.location.hash hash = window.location.hash;
hash = hash.replace('#', '') hash = hash.replace('#', '');
info = hash.split('/'); var info = hash.split('/');
var view = {} var view = {};
view.distribution = {} view.distribution = {};
view.packages = {} view.packages = {};
view.package = {} view.package = {};
view.file = {} view.file = {};
if (info.length >= 1) { if (info.length >= 1) {
view.distribution.name = info[0]; view.distribution.name = info[0];
} }
if (info.length >= 3){ if (info.length >= 3) {
view.package.name = info[1]; view.package.name = info[1];
view.package.version = info[2]; view.package.version = info[2];
view.package.orig_name = view.package.name + '_' + view.package.version view.package.orig_name = view.package.name + '_' + view.package.version;
} }
if (info.length >= 4) { if (info.length >= 4) {
view.file.name = info[3] view.file.name = info[3];
view.file.orig_name = view.package.orig_name + '.' + view.file.name view.file.orig_name = view.package.orig_name + '.' + view.file.name;
} }
return view return view;
}, },
from_view_to_hash: function (view) {
hash = "#"
if (Utils.check_view_distribution(view)) {
hash = hash + view.distribution.name
if (Utils.check_view_package(view)) {
hash = hash + '/' + view.package.name + "/" + view.package.version
if (Utils.check_view_file(view))
hash = hash + '/' + view.file.name
}
}
return hash
},
check_view_distribution: function(view) {
return view && view.distribution && view.distribution.name
},
check_view_package: function(view) {
return Utils.check_view_distribution(view) && view.package && view.package.name && view.package.version && view.package.orig_name
},
check_view_file: function(view) {
return Utils.check_view_package(view) && view.file && view.file.name
},
get_status_icon_and_class: function (status_data) { from_view_to_hash: function (view) {
var _c = config.status.className var hash = '#';
var _i = config.status.icons if (Utils.check_view_distribution(view)) {
var _s = status_data hash = hash + view.distribution.name;
var className = null if (Utils.check_view_package(view)) {
var icon = null hash = hash + '/' + view.package.name + '/' + view.package.version;
if (_s.hasOwnProperty('success')) { if (Utils.check_view_file(view))
if (_s.success == true) { hash = hash + '/' + view.file.name;
className = _c.success }
icon = _i.success }
} return hash;
else { },
className = _c.fail
icon = _i.fail
}
}
else {
className = _c[_s.status]
icon = _i[_s.status]
}
// do not change color if update or create and successed check_view_distribution: function (view) {
if (_s.success == true && return view && view.distribution && view.distribution.name;
_s.status != config.status.build) },
{
className = _c[_s.status]
}
return { check_view_package: function (view) {
className: className, return Utils.check_view_distribution(view) && view.package && view.package.name && view.package.version && view.package.orig_name;
icon: icon },
}
}, check_view_file: function (view) {
return Utils.check_view_package(view) && view.file && view.file.name;
},
get_status_icon_and_class: function (status_data) {
var _c = config.status.className;
var _i = config.status.icons;
var _s = status_data;
var className = null;
var icon = null;
if (_s.hasOwnProperty('success')) {
if (_s.success === true) {
className = _c.success;
icon = _i.success;
} else {
className = _c.fail;
icon = _i.fail;
}
} else {
className = _c[_s.status];
icon = _i[_s.status];
}
get_status_icon_html: function (status_data) { // do not change color if update or create and successed
info = Utils.get_status_icon_and_class(status_data) if (_s.success === true &&
return '<span class="icon glyphicon glyphicon-' + info.icon + '"></span>' _s.status != config.status.build) {
}, className = _c[_s.status];
}
// clone an object via JSON return {
clone: function (object) { className: className,
return JSON.parse(JSON.stringify(object)); icon: icon
} };
} },
get_status_icon_html: function (status_data) {
var info = Utils.get_status_icon_and_class(status_data);
return '<span class="icon glyphicon glyphicon-' + info.icon + '"></span>';
},
// clone an object via JSON
clone: function (object) {
return JSON.parse(JSON.stringify(object));
}
};
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<h2>Packages</h2> <h2>Packages</h2>
<ul class="nav nav-pills nav-stacked"></ul> <ul class="nav nav-pills nav-stacked"></ul>
</nav> </nav>
<div id="sticky" > <div id="sticky" >
<section id="files"> <section id="files">
<nav id="logs"> <nav id="logs">
...@@ -24,7 +24,11 @@ ...@@ -24,7 +24,11 @@
</nav> </nav>
<div class="others"> <div class="others">
<nav id="sources"> <nav id="sources">
<h4>Sources</h4> <h4>Sources
<a class="btn btn-link" title="Get all sources in one click" onclick="download_all('#sources')">
<span class="glyphicon glyphicon-download-alt"></span>
</a>
</h4>
<ul></ul> <ul></ul>
</nav> </nav>
<nav id="debs"> <nav id="debs">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment