Rework auto-availability of binaries

This commit is contained in:
Rudra Saraswat 2023-05-02 23:54:00 +05:30
parent 956e8eb1b5
commit eea89f26cc
5 changed files with 154 additions and 107 deletions

View file

@ -24,7 +24,7 @@ function createWindow() {
autoHideMenuBar: true
})
mainWindow.setMenu(null)
// mainWindow.setMenu(null)
mainWindow.loadFile('src/index.html')
}
@ -75,6 +75,7 @@ function loadTerminalWindow(title, cmd) {
terminalWindow.show()
ipcMain.removeAllListeners('terminal.reset')
ipcMain.removeAllListeners('terminal.resize')
ipcMain.removeAllListeners('terminal.keystroke')
ipcMain.removeAllListeners('terminal.incomingData')
ipcMain.removeAllListeners('title')

View file

@ -7,9 +7,9 @@ function init_waydroid() {
require('child_process').spawnSync('pkexec', ['systemctl', 'enable', '--now', 'waydroid-container'])
require('child_process').spawn('sh', ['-c', 'waydroid session start & disown'])
setTimeout(() => {
require('child_process').spawnSync('waydroid', ['prop', 'set', 'persist.waydroid.multi_windows', 'true'])
require('child_process').spawnSync('sh', ['-c', 'echo "persist.waydroid.multi_windows=true" | pkexec tee -a /var/lib/waydroid/waydroid_base.prop'])
require('child_process').spawnSync('pkexec', ['waydroid', 'shell', 'pm', 'disable', 'com.android.inputmethod.latin'])
if (require('child_process').spawnSync('sh', ['-c', 'LC_ALL=C glxinfo | grep "^OpenGL renderer string: "']).stdout.includes('NVIDIA')) {
if (require('child_process').spawnSync('sh', ['-c', 'LC_ALL=C glxinfo | grep "^OpenGL renderer string: "']).stdout.includes('NVIDIA') || require('child_process').spawnSync('cat', ['/proc/cpuinfo']).stdout.includes('hypervisor')) {
require('child_process').spawnSync('sh', ['-c', 'echo "ro.hardware.gralloc=default" | pkexec tee -a /var/lib/waydroid/waydroid.cfg'])
require('child_process').spawnSync('sh', ['-c', 'echo "ro.hardware.egl=swiftshader" | pkexec tee -a /var/lib/waydroid/waydroid.cfg'])
}

View file

@ -1,21 +1,27 @@
var term
function open_container(name) {
ipc.send("create-term", { 'title': `Container: ${name}`, 'cmd': `blend enter -cn ${name}` });
ipc.send("create-term", { 'title': `Container: ${name}`, 'cmd': `BLEND_NO_CHECK=true blend enter -cn ${name}` });
}
function create_container () {
function create_container() {
$('#inputContainerName').on('input', () => {
$('#inputContainerName').get(0).setCustomValidity('')
$('#inputContainerName').get(0).reportValidity();
})
container_name = $('#inputContainerName').val()
if (!(/^[\w\-\.]+$/.test(container_name))) {
$('#inputContainerName').get(0).setCustomValidity('Container name can only contain alphanumeric characters and dashes (no spaces allowed).')
if (!(/^[\w\-]+$/.test(container_name))) {
$('#inputContainerName').get(0).setCustomValidity('Container name may only contain alphanumeric characters and dashes (no spaces allowed).')
$('#inputContainerName').get(0).reportValidity();
return
}
container_distro = $('#inputContainerDistro').val().toLowerCase().replace(' ', '-')
ipc.send("create-term", { 'title': `Creating container: ${container_name}`,
'cmd': `blend create-container -cn ${container_name} -d ${container_distro} \
&& echo 'created container successfully (exiting automatically in 5 seconds)' \
|| echo 'container creation failed (exiting automatically in 5 seconds)';
ipc.send("create-term", {
'title': `Creating container: ${container_name}`,
'cmd': `blend create-container -cn ${container_name} -d ${container_distro} \
&& echo -e '\nExiting automatically in 5 seconds.' \
|| echo -e '\nContainer creation failed. Exiting automatically in 5 seconds.';
sleep 5` })
$('#inputContainerName').val('')
ipc.on('container-created', () => {
@ -23,7 +29,7 @@ function create_container () {
})
}
async function remove_container (name) {
async function remove_container(name) {
let rm_worker = new Worker(
`data:text/javascript,
require('child_process').spawnSync('podman', ['stop', '-t', '0', '${name}'], { encoding: 'utf8' })
@ -37,47 +43,7 @@ async function remove_container (name) {
window.worker = new Worker(
`data:text/javascript,
function list_containers() {
let container_list = require('child_process').spawnSync('podman', ['ps', '-a', '--no-trunc', '--size', '--format', '{{.Names}}'], { encoding: 'utf8' }).stdout.split(/\\r?\\n/).filter(Boolean).reverse();
if (require('fs').existsSync(require('path').join(require('os').homedir(), '.config/blend/config.yaml'), 'utf8')) {
try {
let fileContents = require('fs').readFileSync(require('path').join(require('os').homedir(), '.config/blend/config.yaml'), 'utf8')
let data = require('js-yaml').load(fileContents);
new_container_list = data['container_order']
container_list.forEach(container => {
if (!new_container_list.includes(container)) {
new_container_list.push(container)
}
});
new_container_list = new_container_list.filter(container => container_list.includes(container))
new_container_list.filter((item, index) => arr.indexOf(item) === index)
data = {
container_order: [...new_container_list],
use_container_bins: []
};
contents = require('js-yaml').dump(data)
require('fs').writeFileSync(require('path').join(require('os').homedir(), '.config/blend/config.yaml'), contents, 'utf8')
return new_container_list
} catch (e) {
let data = {
container_order: [...container_list],
use_container_bins: []
};
contents = require('js-yaml').dump(data)
require('fs').writeFileSync(require('path').join(require('os').homedir(), '.config/blend/config.yaml'), contents, 'utf8')
return container_list
}
} else {
let data = {
container_order: [...container_list],
use_container_bins: []
};
require('fs').mkdirSync(require('path').join(require('os').homedir(), '.config/blend'), { recursive: true });
contents = require('js-yaml').dump(data)
require('fs').writeFileSync(require('path').join(require('os').homedir(), '.config/blend/config.yaml'), contents, 'utf8')
return container_list
}
return require('child_process').spawnSync('podman', ['ps', '-a', '--no-trunc', '--size', '--format', '{{.Names}}'], { encoding: 'utf8' }).stdout.split(/\\r?\\n/).filter(Boolean).reverse();
}
function truncateText(text, maxLength=30) {
@ -98,7 +64,7 @@ window.worker = new Worker(
<div class="row align-items-center">
<div class="col">
<strong class="mb-0">No containers present.</strong>
<p class="text-muted mb-0">Create one from below.</p>
<p class="text-muted mb-0">Create one from above.</p>
</div>
</div>
</div>
@ -108,25 +74,19 @@ window.worker = new Worker(
container_list.forEach(container => {
container_list_html += \`
<div class="list-group-item" style="padding-top: 10px; padding-bottom: 10px; border: 0.5px solid rgba(255, 255, 255, 0.05);">
<div class="row align-items-center" style="cursor: grab;">
<div class="list-group-item" style="padding: 11px 20px 11px 20px; border: 0.5px solid rgba(255, 255, 255, 0.05);">
<div class="row align-items-center">
<div class="col">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-grip-vertical" viewBox="0 0 16 16" style="margin-right: 12px;">
<path d="M7 2a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM7 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM7 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
</svg>
<strong class="mb-0 container_name">\${container}</strong>
</div>
<div class="col-auto">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-play" viewBox="0 0 16 16" onclick="open_container('\${container}')" style="cursor: pointer; margin-right: 8px;">
<path d="M10.804 8 5 4.633v6.734L10.804 8zm.792-.696a.802.802 0 0 1 0 1.392l-6.363 3.692C4.713 12.69 4 12.345 4 11.692V4.308c0-.653.713-.998 1.233-.696l6.363 3.692z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16" onclick="remove_container('\${container}')" style="cursor: pointer; margin-right: 20px; z-index: 10;">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16" onclick="remove_container('\${container}')" style="cursor: pointer; z-index: 10;">
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
<path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-grip-vertical" viewBox="0 0 16 16">
<path d="M7 2a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM7 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM7 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
</svg>
</div>
</div>
</div>
@ -155,31 +115,98 @@ worker.postMessage('update-list')
worker.onmessage = function (event) {
window.data = event.data
if (event.data.includes('bi-grip-vertical')) {
$('#container-list').addClass('sortable')
$('#container-list').html(event.data)
} else {
$('#container-list').removeClass('sortable')
$('#container-list').html(event.data)
$('#container-list').html(event.data)
}
function create_association() {
$('#inputAssociationContainerName').on('input', () => {
$('#inputAssociationContainerName').get(0).setCustomValidity('')
$('#inputAssociationContainerName').get(0).reportValidity();
})
$('#inputAssociationBinaryName').on('input', () => {
$('#inputAssociationBinaryName').get(0).setCustomValidity('')
$('#inputAssociationBinaryName').get(0).reportValidity();
})
if (!(/^[\w\-]+$/.test($('#inputAssociationContainerName').val()))) {
$('#inputAssociationContainerName').get(0).setCustomValidity('Container name may only contain alphanumeric characters and dashes (no spaces allowed).')
$('#inputAssociationContainerName').get(0).reportValidity();
return
}
$('.sortable').each((i, e) => {
Sortable.create(e, {
animation: 100,
onEnd: () => {
let container_list = []
$('.container_name').each((i, e) => {
container_list.push(e.innerText)
})
let data = {
container_order: [...container_list],
use_container_bins: []
};
require('fs').mkdirSync(require('path').join(require('os').homedir(), '.config/blend'), { recursive: true });
contents = require('js-yaml').dump(data)
require('fs').writeFileSync(require('path').join(require('os').homedir(), '.config/blend/config.yaml'), contents, 'utf8')
}
});
e.addEventListener("dragstart", e => e.dataTransfer.setDragImage(new Image(), 0, 0), false);
if (!(/^[\w\-]+$/.test($('#inputAssociationBinaryName').val()))) {
$('#inputAssociationBinaryName').get(0).setCustomValidity('Binary name may only contain alphanumeric characters and dashes (no spaces allowed).')
$('#inputAssociationBinaryName').get(0).reportValidity();
return
}
if (binary_names.includes($('#inputAssociationBinaryName').val())) {
$('#inputAssociationBinaryName').get(0).setCustomValidity('Association already exists.')
$('#inputAssociationBinaryName').get(0).reportValidity();
return
}
fs.appendFile(require('os').homedir() + '/.local/bin/blend_bin/.associations', `${$('#inputAssociationBinaryName').val()}\0${$('#inputAssociationContainerName').val()}\n`, err => {
require('child_process').spawnSync('ln', ['-sf', $('#inputAssociationBinaryName').val() + '.' + $('#inputAssociationContainerName').val(), require('os').homedir() + '/.local/bin/blend_bin/' + $('#inputAssociationBinaryName').val()])
update_association_list()
$('#inputAssociationContainerName').val('')
$('#inputAssociationBinaryName').val('')
})
}
function remove_association(binary_name) {
require('child_process').spawnSync('bash', ['-c', `sed -i 's/^${binary_name}\\x0//g' ~/.local/bin/blend_bin/.associations`])
require('child_process').spawnSync('rm', ['-f', require('os').homedir() + '/.local/bin/blend_bin/' + binary_name])
update_association_list()
}
var binary_names = []
function update_association_list() {
require('fs').readFile(require('os').homedir() + '/.local/bin/blend_bin/.associations', 'utf8', (err, data) => {
let association_list_html = ''
binary_names = []
data.split('\n').forEach(line => {
if (line.includes('\0')) {
let binary_name = line.split('\0')[0]
binary_names.push(binary_name)
let container_name = line.split('\0')[1]
console.log(binary_name, container_name)
association_list_html += `
<div class="list-group-item" style="padding: 11px 20px 11px 20px; border: 0.5px solid rgba(255, 255, 255, 0.05);">
<div class="row align-items-center">
<div class="col">
<strong class="mb-0 container_name">${binary_name} <span style="padding-left: 20px; padding-right: 20px;">&rarr;</span> ${container_name}</strong>
</div>
<div class="col-auto">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16" onclick="remove_association('${binary_name}')" style="cursor: pointer; z-index: 10;">
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
<path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
</svg>
</div>
</div>
</div>
`
}
})
if (association_list_html != '') {
$('#association-list').html(association_list_html)
} else {
$('#association-list').html(`
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<strong class="mb-0">No associations.</strong>
<p class="text-muted mb-0">Add one from above. It's recommended to add associations for each of the supported package managers for easier usage (apt, pacman and dnf).</p>
</div>
</div>
</div>
`)
}
})
}
update_association_list()

View file

@ -1,7 +1,28 @@
<div class="container-fluid d-flex justify-content-center">
<div class="col-12 col-lg-10 col-xl-8 mx-auto">
<strong class="mb-0">Containers</strong>
<p>You can install any app from any of the supported distributions (<b>Arch</b>, <b>Fedora</b>, and <b>Ubuntu</b>). Apps you install will appear as regular applications on your system (as well as binaries and package managers). You can override the priority in which common binaries are made available on the system by rearranging (dragging) the containers below to select the priority that should be assigned to each container.</p>
<p>Installed apps will appear in the application launcher. Binaries can be executed with the container's name as a suffix. For example, <b>apt</b> -> <b>apt.ubuntu</b>, in a container named 'ubuntu'.</p>
<form onsubmit="create_container(); return false">
<div class="form-group row">
<div class="col-sm-4"></div>
<div class="col-sm-3">
<input type="text" class="form-control" id="inputContainerName" placeholder="Container name" required>
</div>
<div class="col-sm-4">
<select class="form-control" id="inputContainerDistro">
<option selected>Arch</option>
<option>Fedora Rawhide</option>
<option>Ubuntu 22.04</option>
<option>Ubuntu 22.10</option>
</select>
</div>
<div class="col-sm-1">
<button type="submit" class="btn btn-primary"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-plus" viewBox="0 0 16 16">
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
</svg></button>
</div>
</div>
</form>
<div class="list-group mb-4 shadow" id="container-list">
<div class="list-group-item">
<div class="row align-items-center">
@ -17,29 +38,26 @@
<div class="container-fluid d-flex justify-content-center">
<div class="col-12 col-lg-10 col-xl-8 mx-auto">
<strong class="mb-0">Create new container</strong>
<p>Create a container for each distribution to be able to use their package managers and other binaries directly from a terminal.</p>
<form onsubmit="create_container(); return false">
<strong class="mb-0">Associations</strong>
<p>You can associate a binary to a container so as to use it without a suffix.</p>
<form onsubmit="create_association(); return false">
<div class="form-group row">
<label for="inputContainerName" class="col-sm-3 col-form-label">Container name</label>
<div class="col-sm-4"></div>
<div class="col-sm-3">
<input type="text" class="form-control" id="inputAssociationBinaryName" placeholder="Binary name" required>
</div>
<div class="col-sm-4">
<input type="text" class="form-control" id="inputContainerName" placeholder="Container name" required>
<input type="text" class="form-control" id="inputAssociationContainerName" placeholder="Container name" required>
</div>
<div class="col-sm-1">
<button type="submit" class="btn btn-primary"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-plus" viewBox="0 0 16 16">
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
</svg></button>
</div>
</div>
<div class="form-group row">
<label for="inputContainerDistro" class="col-sm-3 col-form-label">Distribution</label>
<div class="col-sm-4">
<select class="form-control" id="inputContainerDistro">
<option selected>Arch</option>
<option>Fedora Rawhide</option>
<option>Ubuntu 22.04</option>
<option>Ubuntu 22.10</option>
</select>
</div>
</div>
<br>
<button type="submit" id="publish-button" class="btn btn-primary">Create container</button>
</form>
<div class="list-group mb-4 shadow" id="association-list">
</div>
</div>
</div>

View file

@ -54,6 +54,7 @@
function create_term() {
ipc.removeAllListeners('terminal.reset')
ipc.removeAllListeners('terminal.resize')
ipc.removeAllListeners('terminal.keystroke')
ipc.removeAllListeners('terminal.incomingData')
ipc.removeAllListeners('title')