Commit 75862dc7 authored by Leo Iannacone's avatar Leo Iannacone

Merge remote-tracking branch 'github/master' into portable

parents 6cb54923 aef06a26
# 0.5.1 (2015-06-17) # 0.6.0 (2014-07-10)
* [new] [module] write a JSON file about package status in its own directory
* [new] update to socket.io 1.x
* [new] enable icons and details in static debomatic directory listening
* [new] get status of package via socket instead of making a GET request
* [new] add clean button to package search
* [new] double click on a package in the list make an automatic search
* [new] add slide up and down effect while searching packages
* [new] set files list to not send to client as configurable
* [fix] prevent crashes filtering out request to chroots - send back 403 HTTP status
* [fix] escape correctly HTML in file content
* [fix] auto-populate page on socket connect instead of on page loads
* [fix] preferences does not set correctly if value is false
* [fix] better and smaller error messages
* [fix] fix some style issues
# 0.5.1 (2014-06-17)
* [fix] recursive call on receive file new_content while view the whole file * [fix] recursive call on receive file new_content while view the whole file
* [fix] improved style for file view and datestamp * [fix] improved style for file view and datestamp
* [fix] documentation set porter command instead of rebuild * [fix] documentation set porter command instead of rebuild
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
import os import os
from time import time from time import time
from json import dumps as toJSON from json import dumps as toJSON
from json import load as fileToJSON
class DebomaticModule_JSONLogger: class DebomaticModule_JSONLogger:
...@@ -34,58 +35,88 @@ class DebomaticModule_JSONLogger: ...@@ -34,58 +35,88 @@ class DebomaticModule_JSONLogger:
def __init__(self): def __init__(self):
self.jsonfile = '/var/log/debomatic-json.log' self.jsonfile = '/var/log/debomatic-json.log'
def _set_jsonfile(self, args): def _set_json_logfile_name(self, args):
"""If debomatic config file has section [jsonlogger] try to get """If debomatic config file has section [jsonlogger] try to get
'jsonfile' option and override the default value.""" 'jsonfile' option and override the default value."""
if 'opts' in args and args['opts'].has_section('jsonlogger'): if 'opts' in args and args['opts'].has_section('jsonlogger'):
self.jsonfile = args['opts'].get('jsonlogger', 'jsonfile').strip() self.jsonfile = args['opts'].get('jsonlogger', 'jsonfile').strip()
def _append_info_to_logfile(self, args, info): def _write_json_logfile(self, args, status):
"""Write info to jsonfile converted in JSON format.""" """Write status to jsonfile in JSON format."""
self._set_jsonfile(args) self._set_json_logfile_name(args)
info['time'] = int(time()) status['time'] = int(time())
with open(self.jsonfile, 'a') as logfd: with open(self.jsonfile, 'a') as logfd:
json = toJSON(info) json = toJSON(status)
logfd.write(json + '\n') logfd.write(json + '\n')
def _get_distribution_info(self, args): def _get_package_json(self, args):
"""From args to distribution info.""" """Get the path of package JSON file"""
info = {} return '%(directory)s/pool/%(package)s/%(package)s.json' % args
info['status'] = args['cmd']
info['distribution'] = args['distribution'] def _write_package_json(self, args, status):
"""Write package status to a JSON file."""
package_json = self._get_package_json(args)
if os.path.isfile(package_json):
with open(package_json, 'r') as infofd:
try:
info = fileToJSON(infofd)
info['end'] = int(time())
except:
return
else:
info = {'start': int(time())}
for key in status:
if key not in info:
info[key] = status[key]
with open(package_json, 'w') as infofd:
json = toJSON(info, indent=4)
infofd.write(json + '\n')
def _get_distribution_status(self, args):
"""From args to distribution status"""
status = {}
status['status'] = args['cmd']
status['distribution'] = args['distribution']
if 'success' in args: if 'success' in args:
info['success'] = args['success'] status['success'] = args['success']
return info return status
def _get_package_info(self, args): def _get_package_status(self, args):
"""From args to package info.""" """From args to package status"""
keys = ['package', 'distribution', 'uploader'] keys = ['package', 'distribution', 'uploader']
info = {} status = {}
for k in keys: for k in keys:
if k in args: if k in args:
info[k] = args[k] status[k] = args[k]
return info return status
def pre_chroot(self, args): def pre_chroot(self, args):
distribution = self._get_distribution_info(args) distribution = self._get_distribution_status(args)
self._append_info_to_logfile(args, distribution) self._write_json_logfile(args, distribution)
def post_chroot(self, args): def post_chroot(self, args):
distribution = self._get_distribution_info(args) distribution = self._get_distribution_status(args)
self._append_info_to_logfile(args, distribution) self._write_json_logfile(args, distribution)
def pre_build(self, args): def pre_build(self, args):
package = self._get_package_info(args) package = self._get_package_status(args)
package['status'] = 'build' package['status'] = 'build'
self._append_info_to_logfile(args, package) package_json = self._get_package_json(args)
if os.path.isfile(package_json):
os.remove(package_json)
self._write_package_json(args, package)
self._write_json_logfile(args, package)
def post_build(self, args): def post_build(self, args):
package = self._get_package_info(args) status = self._get_package_status(args)
package['status'] = 'build' status['status'] = 'build'
package['success'] = False status['success'] = False
resultdir = os.path.join(args['directory'], 'pool', args['package']) resultdir = os.path.join(args['directory'], 'pool', args['package'])
for filename in os.listdir(resultdir): for filename in os.listdir(resultdir):
if filename.endswith('.dsc'): if filename.endswith('.dsc'):
package['success'] = True status['success'] = True
break break
self._append_info_to_logfile(args, package) self._write_package_json(args, status)
self._write_json_logfile(args, status)
...@@ -18,6 +18,8 @@ function __get_files_list_from_package(data, callback) { ...@@ -18,6 +18,8 @@ function __get_files_list_from_package(data, callback) {
file.orig_name = f; file.orig_name = f;
file.name = f.split('_')[0]; file.name = f.split('_')[0];
file.extension = f.split('.').pop(); file.extension = f.split('.').pop();
if (config.debomatic.excluded_files.indexOf(file.extension) >= 0)
return;
if (file.extension == 'deb' || file.extension == 'ddeb' || file.extension == 'udeb') { if (file.extension == 'deb' || file.extension == 'ddeb' || file.extension == 'udeb') {
data.package.debs.push(file); data.package.debs.push(file);
} else if (f.indexOf('.tar') >= 0 || file.extension == 'changes' || file.extension == 'dsc') { } else if (f.indexOf('.tar') >= 0 || file.extension == 'changes' || file.extension == 'dsc') {
...@@ -42,50 +44,35 @@ function __send_package_files_list(event_name, socket, data) { ...@@ -42,50 +44,35 @@ function __send_package_files_list(event_name, socket, data) {
}); });
} }
function __send_package_status(socket, data, package_data) { function __read_package_status(data, cb) {
var package_path = utils.get_package_path(data);
var event_name = config.events.client.distribution_packages_status; var package_json = path.join(package_path, data.package.orig_name + '.json');
fs.readFile(package_json, {
var new_data = {}; encoding: 'utf8'
new_data.distribution = data.distribution; }, function (err, content) {
new_data.package = package_data; if (err) {
utils.errors_handler('Client:__read_package_status:', err);
var status_data = {}; return;
status_data.status = config.status.build;
status_data.distribution = data.distribution.name;
status_data.package = package_data.orig_name;
var package_path = utils.get_package_path(new_data);
// status policy:
// + successed: exists .dsc
// + building: wc -l .datestamp == 1 (FIX_ME)
// + failed: else
var base_path = path.join(package_path, package_data.orig_name);
fs.exists(base_path + '.dsc', function (dsc_exists) {
if (dsc_exists) {
status_data.success = config.status.success;
socket.emit(event_name, status_data);
} else {
// emulate wc -l .datestamp in nodejs
var count = 0;
var datestamp = base_path + '.datestamp';
fs.exists(datestamp, function (datestamp_exists) {
if (datestamp_exists) {
// count lines
fs.createReadStream(datestamp)
.on('data', function (chunk) {
for (var i = 0; i < chunk.length; ++i)
if (chunk[i] == 10) count++;
})
.on('end', function () {
if (count > 1)
status_data.success = config.status.fail;
socket.emit(event_name, status_data);
});
}
});
} }
try {
content = JSON.parse(content);
} catch (parse_err) {
utils.errors_handler('Client:__read_package_status:parse_err:', parse_err);
return;
}
cb(content);
});
}
function __send_package_info(socket, data) {
__read_package_status(data, function (content) {
socket.emit(_e.package_info, content);
});
}
function __send_package_status(socket, data) {
__read_package_status(data, function (content) {
socket.emit(_e.distribution_packages_status, content);
}); });
} }
...@@ -99,8 +86,11 @@ function __send_distribution_packages(event_name, socket, data) { ...@@ -99,8 +86,11 @@ function __send_distribution_packages(event_name, socket, data) {
pack.name = info[0]; pack.name = info[0];
pack.version = info[1]; pack.version = info[1];
pack.orig_name = p; pack.orig_name = p;
__send_package_status(socket, {
distribution: data.distribution,
package: pack
});
data.distribution.packages.push(pack); data.distribution.packages.push(pack);
__send_package_status(socket, data, pack);
}); });
socket.emit(event_name, data); socket.emit(event_name, data);
}); });
...@@ -162,6 +152,12 @@ function Client(socket) { ...@@ -162,6 +152,12 @@ function Client(socket) {
__handler_get_file(socket, data); __handler_get_file(socket, data);
}); });
socket.on(_e.package_info, function (data) {
if (!utils.check_data_package(data))
return;
__send_package_info(socket, data);
});
// on client disconnection close all watchers // on client disconnection close all watchers
socket.on('disconnect', function () { socket.on('disconnect', function () {
......
...@@ -68,7 +68,9 @@ config.web.preferences.debug = 0; // debug level - 0 means disabled ...@@ -68,7 +68,9 @@ config.web.preferences.debug = 0; // debug level - 0 means disabled
// DO NOT TOUCH these ones // DO NOT TOUCH these ones
config.version = '0.5.1'; config.version = '0.6.0';
config.debomatic.excluded_files = ['datestamp', 'json'];
config.events = {}; config.events = {};
config.events.error = 'server-error'; config.events.error = 'server-error';
...@@ -81,6 +83,7 @@ config.events.client = {}; ...@@ -81,6 +83,7 @@ config.events.client = {};
config.events.client.distribution_packages = 'c.distribution_packages'; config.events.client.distribution_packages = 'c.distribution_packages';
config.events.client.distribution_packages_status = 'c.distribution_packages_status'; config.events.client.distribution_packages_status = 'c.distribution_packages_status';
config.events.client.package_files_list = 'c.package_files_list'; config.events.client.package_files_list = 'c.package_files_list';
config.events.client.package_info = 'c.package_info';
config.events.client.file = 'c.file'; config.events.client.file = 'c.file';
config.events.client.file_newcontent = 'c.file_newcontent'; config.events.client.file_newcontent = 'c.file_newcontent';
config.events.client.status = 'c.status'; config.events.client.status = 'c.status';
......
...@@ -8,7 +8,7 @@ var path = require('path'), ...@@ -8,7 +8,7 @@ var path = require('path'),
function __errors_handler(from, err, socket) { function __errors_handler(from, err, socket) {
if (!socket) if (!socket)
from = 'NO SOCKET: ' + from; from = 'NO SOCKET: ' + from;
console.error(from, err); console.error(from, err.message);
if (socket) if (socket)
socket.emit(config.events.error, err.message); socket.emit(config.events.error, err.message);
} }
......
...@@ -317,27 +317,6 @@ function Page_Distrubion(socket) { ...@@ -317,27 +317,6 @@ function Page_Distrubion(socket) {
query_data.package = view.package; query_data.package = view.package;
debug_socket('emit', _e.package_files_list, query_data); debug_socket('emit', _e.package_files_list, query_data);
socket.emit(_e.package_files_list, query_data); socket.emit(_e.package_files_list, query_data);
files.get_datestamp();
}
},
get_datestamp: function (socket_data) {
if (Utils.check_view_package(view)) {
if (socket_data && socket_data.package != view.package.orig_name)
return;
var url = config.paths.debomatic + '/' +
view.distribution.name + '/pool/' +
view.package.orig_name + '/' +
view.package.orig_name + '.datestamp';
debug(2, 'getting datestamp');
$.get(url, function (data) {
data = data.replace(/ (\d+:\d+(:\d+)?)$/mg, ' <b>$1</b>');
data = data.replace('Build finished', 'finished');
data = data.replace('Elapsed', 'elapsed');
data = data.replace(/\n$/g, '');
data = data.replace(/\n/g, ' - ');
data = data.replace(/at /g, '');
$("#file .datestamp").html(data);
});
} }
}, },
select: function () { select: function () {
...@@ -358,6 +337,56 @@ function Page_Distrubion(socket) { ...@@ -358,6 +337,56 @@ function Page_Distrubion(socket) {
}, },
}; };
var package_info = {
set: function (socket_data) {
if (!Utils.check_view_package(view) || socket_data.package != view.package.orig_name) {
return;
}
function _get_time(timestamp) {
var date = new Date(timestamp * 1000);
var locale = navigator.language || 'en-US';
var options = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
};
var result = date.toLocaleDateString(locale, options);
result += ' <b>' + date.getHours() + ':' + date.getMinutes() + '</b>';
return result;
}
var info = "";
if (socket_data.uploader)
info += "Uploaded by " + socket_data.uploader + ' - ';
info += "Build started " + _get_time(socket_data.start);
if (socket_data.end) {
info += ' - finished ' + _get_time(socket_data.end);
info += ' - elapsed time: <b>';
var elapsed = new Date((socket_data.end - socket_data.start) * 1000);
info += ("0" + elapsed.getUTCHours()).slice(-2) + ':';
info += ("0" + elapsed.getUTCMinutes()).slice(-2) + ':';
info += ("0" + elapsed.getUTCSeconds()).slice(-2);
}
$("#package_info").html(info);
},
get: function () {
if (Utils.check_view_package(view)) {
var query_data = {};
query_data.distribution = view.distribution;
query_data.package = view.package;
debug_socket('emit', _e.package_info, query_data);
socket.emit(_e.package_info, query_data);
$("#package_info").html('...');
}
}
};
var file = { var file = {
set: function (socket_data) { set: function (socket_data) {
var new_content = Utils.escape_html(socket_data.file.content); var new_content = Utils.escape_html(socket_data.file.content);
...@@ -628,6 +657,7 @@ function Page_Distrubion(socket) { ...@@ -628,6 +657,7 @@ function Page_Distrubion(socket) {
return; return;
} else if (!Utils.check_view_package(old_view) || !Utils.check_view_package(view) || } else if (!Utils.check_view_package(old_view) || !Utils.check_view_package(view) ||
view.package.orig_name != old_view.package.orig_name) { // new package view view.package.orig_name != old_view.package.orig_name) { // new package view
package_info.get();
files.get(); files.get();
file.get(); file.get();
} else if (!Utils.check_view_file(old_view) || !Utils.check_view_file(view) || } else if (!Utils.check_view_file(old_view) || !Utils.check_view_file(view) ||
...@@ -650,6 +680,7 @@ function Page_Distrubion(socket) { ...@@ -650,6 +680,7 @@ function Page_Distrubion(socket) {
var populate = function () { var populate = function () {
clean(); clean();
packages.get(); packages.get();
package_info.get();
files.get(); files.get();
file.get(); file.get();
update.view(); update.view();
...@@ -687,7 +718,9 @@ function Page_Distrubion(socket) { ...@@ -687,7 +718,9 @@ function Page_Distrubion(socket) {
socket.on(config.events.broadcast.status_update, function (socket_data) { socket.on(config.events.broadcast.status_update, function (socket_data) {
packages.set_status(socket_data); packages.set_status(socket_data);
sticky.set_status(socket_data); sticky.set_status(socket_data);
files.get_datestamp(socket_data); if (socket_data.distribution == view.distribution.name && socket_data.package == view.package.orig_name) {
package_info.get();
}
}); });
socket.on(_e.package_files_list, function (socket_data) { socket.on(_e.package_files_list, function (socket_data) {
...@@ -705,6 +738,11 @@ function Page_Distrubion(socket) { ...@@ -705,6 +738,11 @@ function Page_Distrubion(socket) {
new_lines.push(socket_data.file.new_content); new_lines.push(socket_data.file.new_content);
}); });
socket.on(_e.package_info, function (socket_data) {
debug_socket('received', _e.package_info, socket_data);
package_info.set(socket_data);
});
$(window).on('hashchange', function () { $(window).on('hashchange', function () {
if (!__check_hash_makes_sense()) if (!__check_hash_makes_sense())
return; return;
......
...@@ -169,10 +169,6 @@ footer .info { ...@@ -169,10 +169,6 @@ footer .info {
display: none; display: none;
} }
#files li[id$='datestamp'] {
display: none;
}
#preferences .select label { #preferences .select label {
font-weight: normal; font-weight: normal;
line-height: 35px; line-height: 35px;
...@@ -189,15 +185,6 @@ footer .info { ...@@ -189,15 +185,6 @@ footer .info {
color: #101010; color: #101010;
} }
#file .datestamp {
display: inline-block;
background: #f4f4f4;
padding: 4px 10px;
margin-bottom: 10px;
border-radius: 4px;
font-size: 75%;
}
#file .preview { #file .preview {
overflow:hidden; overflow:hidden;
} }
...@@ -206,3 +193,12 @@ footer .info { ...@@ -206,3 +193,12 @@ footer .info {
padding: 10px 12px; padding: 10px 12px;
float: right; float: right;
} }
#package_info {
display: inline-block;
background: #f4f4f4;
padding: 4px 10px;
margin-bottom: 10px;
border-radius: 4px;
font-size: 75%;
}
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
export SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" export SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
bash ${SCRIPTS_DIR}/install/patch_css_directory_listing.sh
bash ${SCRIPTS_DIR}/install/download_external_libs.sh bash ${SCRIPTS_DIR}/install/download_external_libs.sh
python ${SCRIPTS_DIR}/install/create-user-config.py python ${SCRIPTS_DIR}/install/create-user-config.py
#!/bin/bash
CSS="${SCRIPTS_DIR}/../node_modules/serve-index/public/style.css"
if [ "`grep debomatic-webui $CSS`" == "" ] ; then
echo "Patching directory listing style.css"
cp $CSS $CSS.orig
echo "
/* debomatic-webui style patch */
ul#files li {
float: none;
}
/* end debomatic-webui patch */
" >> $CSS
fi
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
</header> </header>
<div id="welcome"></div> <div id="welcome"></div>
<div id="file"> <div id="file">
<div class="datestamp"></div> <div id="package_info"></div>
<pre class="content"></pre> <pre class="content"></pre>
<div id="fileOffset"></div> <div id="fileOffset"></div>
</div> </div>
......
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