mirror of
https://github.com/srlabs/blue-merle.git
synced 2024-12-22 21:59:25 -05:00
initial PoC for a Web interface
This commit is contained in:
parent
da1a2f071c
commit
61a7466117
3
srl-blue-merle/usr/libexec/blue-merle
Executable file
3
srl-blue-merle/usr/libexec/blue-merle
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo Hello, World!
|
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"admin/system/opkg2": {
|
"admin/network/blue-merle": {
|
||||||
"title": "Software",
|
"title": "Blue Merle",
|
||||||
"order": 30,
|
"order": 30,
|
||||||
"action": {
|
"action": {
|
||||||
"type": "view",
|
"type": "view",
|
||||||
"path": "opkg2"
|
"path": "opkg2"
|
||||||
},
|
},
|
||||||
"depends": {
|
"depends": {
|
||||||
"acl": [ "luci-app-opkg2" ]
|
"acl": [ "luci-app-blue-merle" ]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
srl-blue-merle/usr/share/rpcd/acl.d/luci-app-blue-merle.json
Normal file
26
srl-blue-merle/usr/share/rpcd/acl.d/luci-app-blue-merle.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"luci-app-blue-merle": {
|
||||||
|
"description": "Grant access to opkg management",
|
||||||
|
"read": {
|
||||||
|
"cgi-io": [ "exec" ],
|
||||||
|
"file": {
|
||||||
|
"/usr/libexec/blue-merle": [ "exec" ],
|
||||||
|
"/usr/libexec/blue-merle shred": [ "exec" ],
|
||||||
|
"/usr/libexec/blue-merle *": [ "exec" ],
|
||||||
|
"/etc/opkg.conf": [ "read" ],
|
||||||
|
"/etc/opkg/*.conf": [ "read" ]
|
||||||
|
},
|
||||||
|
"ubus": {
|
||||||
|
"luci": [ "getMountPoints" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"write": {
|
||||||
|
"file": {
|
||||||
|
"/usr/libexec/blue-merle": [ "exec" ],
|
||||||
|
"/usr/libexec/blue-merle shred": [ "exec" ],
|
||||||
|
"/usr/libexec/blue-merle *": [ "exec" ],
|
||||||
|
"/tmp/upload.ipk": [ "write" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"luci-app-opkg2": {
|
|
||||||
"description": "Grant access to opkg management",
|
|
||||||
"read": {
|
|
||||||
"cgi-io": [ "exec" ],
|
|
||||||
"file": {
|
|
||||||
"/usr/libexec/opkg-list installed": [ "exec" ],
|
|
||||||
"/usr/libexec/opkg-list available": [ "exec" ],
|
|
||||||
"/usr/libexec/opkg-call list-installed": [ "exec" ],
|
|
||||||
"/usr/libexec/opkg-call list-available": [ "exec" ],
|
|
||||||
"/etc/opkg.conf": [ "read" ],
|
|
||||||
"/etc/opkg/*.conf": [ "read" ]
|
|
||||||
},
|
|
||||||
"ubus": {
|
|
||||||
"luci": [ "getMountPoints" ]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"write": {
|
|
||||||
"file": {
|
|
||||||
"/usr/libexec/opkg-call install *": [ "exec" ],
|
|
||||||
"/usr/libexec/opkg-call remove *": [ "exec" ],
|
|
||||||
"/usr/libexec/opkg-call update *": [ "exec" ],
|
|
||||||
"/etc/opkg.conf": [ "write" ],
|
|
||||||
"/etc/opkg/*.conf": [ "write" ],
|
|
||||||
"/tmp/upload.ipk": [ "write" ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -199,140 +199,6 @@ function parseList(s, dest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function display(pattern)
|
|
||||||
{
|
|
||||||
var src = packages[currentDisplayMode === 'updates' ? 'installed' : currentDisplayMode],
|
|
||||||
table = document.querySelector('#packages'),
|
|
||||||
pagers = document.querySelectorAll('.controls > .pager'),
|
|
||||||
i18n_filter = null;
|
|
||||||
|
|
||||||
currentDisplayRows.length = 0;
|
|
||||||
|
|
||||||
if (typeof(pattern) === 'string' && pattern.length > 0)
|
|
||||||
pattern = new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'ig');
|
|
||||||
|
|
||||||
switch (document.querySelector('input[name="filter_i18n"]:checked').value) {
|
|
||||||
case 'all':
|
|
||||||
i18n_filter = /^luci-i18n-/;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'lang':
|
|
||||||
i18n_filter = new RegExp('^luci-i18n-(base-.+|.+-(' + languages.join('|') + '))$');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var name in src.pkgs) {
|
|
||||||
var pkg = src.pkgs[name],
|
|
||||||
desc = pkg.description || '',
|
|
||||||
altsize = null;
|
|
||||||
|
|
||||||
if (!pkg.size && packages.available.pkgs[name])
|
|
||||||
altsize = packages.available.pkgs[name].size;
|
|
||||||
|
|
||||||
if (!desc && packages.available.pkgs[name])
|
|
||||||
desc = packages.available.pkgs[name].description || '';
|
|
||||||
|
|
||||||
desc = desc.split(/\n/);
|
|
||||||
desc = desc[0].trim() + (desc.length > 1 ? '…' : '');
|
|
||||||
|
|
||||||
if ((pattern instanceof RegExp) &&
|
|
||||||
!name.match(pattern) && !desc.match(pattern))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (name.indexOf('luci-i18n-') === 0 && (!(i18n_filter instanceof RegExp) || !name.match(i18n_filter)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var btn, ver;
|
|
||||||
|
|
||||||
if (currentDisplayMode === 'updates') {
|
|
||||||
var avail = packages.available.pkgs[name],
|
|
||||||
inst = packages.installed.pkgs[name];
|
|
||||||
|
|
||||||
if (!inst || !inst.installed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!avail || compareVersion(avail.version, pkg.version) <= 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ver = '%s » %s'.format(
|
|
||||||
truncateVersion(pkg.version || '-'),
|
|
||||||
truncateVersion(avail.version || '-'));
|
|
||||||
|
|
||||||
btn = E('div', {
|
|
||||||
'class': 'btn cbi-button-positive',
|
|
||||||
'data-package': name,
|
|
||||||
'click': handleInstall
|
|
||||||
}, _('Upgrade…'));
|
|
||||||
}
|
|
||||||
else if (currentDisplayMode === 'installed') {
|
|
||||||
if (!pkg.installed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ver = truncateVersion(pkg.version || '-');
|
|
||||||
btn = E('div', {
|
|
||||||
'class': 'btn cbi-button-negative',
|
|
||||||
'data-package': name,
|
|
||||||
'click': handleRemove
|
|
||||||
}, _('Remove…'));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var inst = packages.installed.pkgs[name];
|
|
||||||
|
|
||||||
ver = truncateVersion(pkg.version || '-');
|
|
||||||
|
|
||||||
if (!inst || !inst.installed)
|
|
||||||
btn = E('div', {
|
|
||||||
'class': 'btn cbi-button-action',
|
|
||||||
'data-package': name,
|
|
||||||
'click': handleInstall
|
|
||||||
}, _('Install…'));
|
|
||||||
else if (inst.installed && inst.version != pkg.version)
|
|
||||||
btn = E('div', {
|
|
||||||
'class': 'btn cbi-button-positive',
|
|
||||||
'data-package': name,
|
|
||||||
'click': handleInstall
|
|
||||||
}, _('Upgrade…'));
|
|
||||||
else
|
|
||||||
btn = E('div', {
|
|
||||||
'class': 'btn cbi-button-neutral',
|
|
||||||
'disabled': 'disabled'
|
|
||||||
}, _('Installed'));
|
|
||||||
}
|
|
||||||
|
|
||||||
name = '%h'.format(name);
|
|
||||||
desc = '%h'.format(desc || '-');
|
|
||||||
|
|
||||||
if (pattern) {
|
|
||||||
name = name.replace(pattern, '<ins>$&</ins>');
|
|
||||||
desc = desc.replace(pattern, '<ins>$&</ins>');
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDisplayRows.push([
|
|
||||||
name,
|
|
||||||
ver,
|
|
||||||
pkg.size ? '%1024mB'.format(pkg.size)
|
|
||||||
: (altsize ? '~%1024mB'.format(altsize) : '-'),
|
|
||||||
desc,
|
|
||||||
btn
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDisplayRows.sort(function(a, b) {
|
|
||||||
if (a[0] < b[0])
|
|
||||||
return -1;
|
|
||||||
else if (a[0] > b[0])
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
for (var i = 0; i < pagers.length; i++) {
|
|
||||||
pagers[i].parentNode.style.display = '';
|
|
||||||
pagers[i].setAttribute('data-offset', 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePage({ target: pagers[0].querySelector('.prev') });
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePage(ev)
|
function handlePage(ev)
|
||||||
{
|
{
|
||||||
@ -852,9 +718,48 @@ function handleConfig(ev)
|
|||||||
{
|
{
|
||||||
var conf = {};
|
var conf = {};
|
||||||
|
|
||||||
ui.showModal(_('OPKG Configuration'), [
|
var cmd = "/usr/libexec/blue-merle";
|
||||||
E('p', { 'class': 'spinning' }, _('Loading configuration data…'))
|
var dlg = ui.showModal(_('Executing blue merle'), [
|
||||||
]);
|
E('p', { 'class': 'spinning' },
|
||||||
|
_('Waiting for the <em>%h</em> command to complete…').format(cmd))
|
||||||
|
]);
|
||||||
|
|
||||||
|
var argv = []; //["shred"];
|
||||||
|
fs.exec_direct('/usr/libexec/blue-merle', argv, 'json').then(function(res) {
|
||||||
|
|
||||||
|
if (res.stdout)
|
||||||
|
dlg.appendChild(E('pre', [ res.stdout ]));
|
||||||
|
|
||||||
|
if (res.stderr) {
|
||||||
|
dlg.appendChild(E('h5', _('Errors')));
|
||||||
|
dlg.appendChild(E('pre', { 'class': 'errors' }, [ res.stderr ]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.code !== 0)
|
||||||
|
dlg.appendChild(E('p', _('The <em>opkg %h</em> command failed with code <code>%d</code>.').format(cmd, (res.code & 0xff) || -1)));
|
||||||
|
|
||||||
|
dlg.appendChild(E('div', { 'class': 'right' },
|
||||||
|
E('div', {
|
||||||
|
'class': 'btn',
|
||||||
|
'click': L.bind(function(res) {
|
||||||
|
if (ui.menu && ui.menu.flushCache)
|
||||||
|
ui.menu.flushCache();
|
||||||
|
|
||||||
|
ui.hideModal();
|
||||||
|
updateLists();
|
||||||
|
|
||||||
|
if (res.code !== 0)
|
||||||
|
rejectFn(new Error(res.stderr || 'opkg error %d'.format(res.code)));
|
||||||
|
else
|
||||||
|
resolveFn(res);
|
||||||
|
}, this, res)
|
||||||
|
}, _('Dismiss'))));
|
||||||
|
}).catch(function(err) {
|
||||||
|
ui.addNotification(null, E('p', _('Unable to execute <em>opkg %s</em> command: %s').format(cmd, err)));
|
||||||
|
ui.hideModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fs.list('/etc/opkg').then(function(partials) {
|
fs.list('/etc/opkg').then(function(partials) {
|
||||||
var files = [ '/etc/opkg.conf' ];
|
var files = [ '/etc/opkg.conf' ];
|
||||||
@ -914,7 +819,7 @@ function handleConfig(ev)
|
|||||||
}, _('Save')),
|
}, _('Save')),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
ui.showModal(_('OPKG Configuration'), body);
|
//ui.showModal(_('OPKG Configuration'), body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user