mirror of
https://github.com/45Drives/cockpit-navigator.git
synced 2025-09-26 03:08:41 +02:00
Merge branch 'main' into build-package
This commit is contained in:
commit
c633b76e3e
4
.github/workflows/build-packages.yml
vendored
4
.github/workflows/build-packages.yml
vendored
@ -2,7 +2,7 @@ name: Build Packages
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- build-package
|
- build
|
||||||
tags:
|
tags:
|
||||||
- 'v*.*.*'
|
- 'v*.*.*'
|
||||||
jobs:
|
jobs:
|
||||||
@ -107,4 +107,4 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
uses: 45drives/actions/sync-repo@main
|
uses: 45drives/actions/sync-repo@main
|
||||||
with:
|
with:
|
||||||
directory: ${{ github.workspace }}
|
directory: ${{ github.workspace }}
|
@ -5,7 +5,7 @@
|
|||||||
"description": "A File System Browser for Cockpit.",
|
"description": "A File System Browser for Cockpit.",
|
||||||
"version": "0.5.10",
|
"version": "0.5.10",
|
||||||
"build_number": "1",
|
"build_number": "1",
|
||||||
"stable": true,
|
"stable": false,
|
||||||
"author": "Josh Boudreau <jboudreau@45drives.com>",
|
"author": "Josh Boudreau <jboudreau@45drives.com>",
|
||||||
"git_url": "https://github.com/45Drives/cockpit-navigator",
|
"git_url": "https://github.com/45Drives/cockpit-navigator",
|
||||||
"license": "GPL-3.0+",
|
"license": "GPL-3.0+",
|
||||||
@ -14,8 +14,7 @@
|
|||||||
},
|
},
|
||||||
"architecture": {
|
"architecture": {
|
||||||
"rocky": "x86_64",
|
"rocky": "x86_64",
|
||||||
"debian": "amd64",
|
"ubuntu": "all"
|
||||||
"ubuntu": "amd64"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ubuntu_common": [
|
"ubuntu_common": [
|
||||||
@ -24,7 +23,8 @@
|
|||||||
"rsync",
|
"rsync",
|
||||||
"zip",
|
"zip",
|
||||||
"file",
|
"file",
|
||||||
"coreutils"
|
"coreutils",
|
||||||
|
"inotify-tools"
|
||||||
],
|
],
|
||||||
"rocky_common": [
|
"rocky_common": [
|
||||||
"cockpit",
|
"cockpit",
|
||||||
@ -33,7 +33,8 @@
|
|||||||
"zip",
|
"zip",
|
||||||
"file",
|
"file",
|
||||||
"/bin/mkdir",
|
"/bin/mkdir",
|
||||||
"/bin/rmdir"
|
"/bin/rmdir",
|
||||||
|
"inotify-tools"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"builds": [
|
"builds": [
|
||||||
|
@ -100,46 +100,96 @@ export class NavContextMenu {
|
|||||||
}
|
}
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
zip_for_download() {
|
zip_for_download() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var cmd = [
|
const cmd = ["/usr/share/cockpit/navigator/scripts/zip-for-download.py3",
|
||||||
"/usr/share/cockpit/navigator/scripts/zip-for-download.py3",
|
this.nav_window_ref.pwd().path_str()];
|
||||||
this.nav_window_ref.pwd().path_str()
|
for (const entry of this.nav_window_ref.selected_entries) cmd.push(entry.path_str());
|
||||||
];
|
const proc = cockpit.spawn(cmd, { superuser: "try", err: "out" });
|
||||||
for (let entry of this.nav_window_ref.selected_entries) {
|
|
||||||
cmd.push(entry.path_str());
|
const safeParse = (raw) => {
|
||||||
|
const s = (raw || "").trim();
|
||||||
|
const start = s.indexOf("{");
|
||||||
|
const end = s.lastIndexOf("}");
|
||||||
|
if (start === -1 || end === -1 || end < start) {
|
||||||
|
throw new Error("No JSON object in output: " + s.slice(0, 200));
|
||||||
}
|
}
|
||||||
var proc = cockpit.spawn(cmd, {superuser: "try", err: "out"});
|
return JSON.parse(s.slice(start, end + 1));
|
||||||
proc.fail((e, data) => {
|
};
|
||||||
reject(JSON.parse(data));
|
|
||||||
});
|
proc.done((data) => {
|
||||||
proc.done((data) => {
|
|
||||||
resolve(JSON.parse(data));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async download(e) {
|
|
||||||
var download_target = "";
|
|
||||||
if (this.nav_window_ref.selected_entries.size === 1 && !(this.nav_window_ref.selected_entry() instanceof NavDir)) {
|
|
||||||
download_target = this.nav_window_ref.selected_entry();
|
|
||||||
} else {
|
|
||||||
this.nav_window_ref.start_load();
|
|
||||||
var result;
|
|
||||||
try {
|
try {
|
||||||
result = await this.zip_for_download();
|
resolve(safeParse(data));
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
this.nav_window_ref.stop_load();
|
console.error("zip_for_download done(raw):", data);
|
||||||
this.nav_window_ref.modal_prompt.alert(e.message);
|
reject({ message: e.message });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
this.nav_window_ref.stop_load();
|
});
|
||||||
|
|
||||||
|
proc.fail((e, data) => {
|
||||||
|
try {
|
||||||
|
reject(safeParse(data));
|
||||||
|
} catch {
|
||||||
|
console.error("zip_for_download fail(raw):", data);
|
||||||
|
reject({ message: String(data || e || "zip_for_download failed") });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async download(e) {
|
||||||
|
let download_target = "";
|
||||||
|
let result; // function-scoped so we can reference later
|
||||||
|
|
||||||
|
if (this.nav_window_ref.selected_entries.size === 1 &&
|
||||||
|
!(this.nav_window_ref.selected_entry() instanceof NavDir)) {
|
||||||
|
download_target = this.nav_window_ref.selected_entry();
|
||||||
|
} else {
|
||||||
|
this.nav_window_ref.start_load();
|
||||||
|
try {
|
||||||
|
result = await this.zip_for_download();
|
||||||
download_target = new NavFile(result["archive-path"], result["stat"], this.nav_window_ref);
|
download_target = new NavFile(result["archive-path"], result["stat"], this.nav_window_ref);
|
||||||
|
console.log("prepared archive for download:", result["archive-path"]);
|
||||||
|
} catch (err) {
|
||||||
|
this.nav_window_ref.stop_load();
|
||||||
|
this.nav_window_ref.modal_prompt.alert(err.message);
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
this.nav_window_ref.stop_load();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var download = new NavDownloader(download_target);
|
if (result?.["archive-path"]) {
|
||||||
download.download();
|
const unitName = `nav-clean-on-open-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;
|
||||||
}
|
const script = [
|
||||||
|
'set -euo pipefail',
|
||||||
|
'if ! command -v inotifywait >/dev/null 2>&1; then ' +
|
||||||
|
'sleep 300; rm -f -- "$ARCHIVE"; ' +
|
||||||
|
'[ -n "${TEMPDIR:-}" ] && [[ "$TEMPDIR" == /tmp/navigator-* ]] && rm -rf -- "$TEMPDIR"; ' +
|
||||||
|
'exit 0; fi',
|
||||||
|
'inotifywait -q -t 1800 -e open -- "$ARCHIVE" || true',
|
||||||
|
'rm -f -- "$ARCHIVE"',
|
||||||
|
'sleep 3600',
|
||||||
|
'[ -n "${TEMPDIR:-}" ] && [[ "$TEMPDIR" == /tmp/navigator-* ]] && rm -rf -- "$TEMPDIR" || :'
|
||||||
|
].join(' && ');
|
||||||
|
const cmd = [
|
||||||
|
'systemd-run',
|
||||||
|
'--property=CollectMode=inactive-or-failed',
|
||||||
|
'--property=RuntimeMaxSec=90000',
|
||||||
|
'--unit', unitName,
|
||||||
|
'--setenv=ARCHIVE=' + result['archive-path'],
|
||||||
|
...(result['temp-dir'] ? ['--setenv=TEMPDIR=' + result['temp-dir']] : []),
|
||||||
|
'/bin/bash','-lc', script
|
||||||
|
];
|
||||||
|
|
||||||
|
await cockpit.spawn(cmd, { superuser: 'require', err: 'out' }).then(out => console.log(out));
|
||||||
|
console.log("scheduled cleanup:", unitName);
|
||||||
|
console.log("Deleting :", result['archive-path'], "in 30 minutes or after download starts.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloader = new NavDownloader(download_target);
|
||||||
|
downloader.download();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
delete(e) {
|
delete(e) {
|
||||||
this.nav_window_ref.delete_selected();
|
this.nav_window_ref.delete_selected();
|
||||||
|
@ -331,6 +331,19 @@ export class NavWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_selection_info() {
|
update_selection_info() {
|
||||||
|
if (this.selected_entries.size > 1) {
|
||||||
|
// get first element of the Set
|
||||||
|
const it = this.selected_entries.values();
|
||||||
|
const first = it.next().value;
|
||||||
|
const second = it.next().value;
|
||||||
|
if(first.path.length<second.path.length){
|
||||||
|
this.selected_entries.delete(first)
|
||||||
|
}
|
||||||
|
if(first.path.length==second.path.length && first.filename=="/"){
|
||||||
|
this.selected_entries.delete(first)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
if (this.selected_entries.size > 1){
|
if (this.selected_entries.size > 1){
|
||||||
var name_fields = document.getElementsByClassName("nav-info-column-filename");
|
var name_fields = document.getElementsByClassName("nav-info-column-filename");
|
||||||
for (let name_field of name_fields) {
|
for (let name_field of name_fields) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user