Eigenständige Linux-Anwendung bereitstellen
Some checks failed
Tests / test (push) Has been cancelled
Some checks failed
Tests / test (push) Has been cancelled
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
/build/
|
/build/
|
||||||
|
/dist/
|
||||||
/**/target/
|
/**/target/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -63,6 +63,23 @@ bash scripts/build-release.sh
|
|||||||
Der Befehl führt die Rust-, Python- und Rauchtests aus, baut alle drei Programme im
|
Der Befehl führt die Rust-, Python- und Rauchtests aus, baut alle drei Programme im
|
||||||
Release-Modus und erzeugt `build/release.json` mit Build-ID und SHA-256-Prüfsummen.
|
Release-Modus und erzeugt `build/release.json` mit Build-ID und SHA-256-Prüfsummen.
|
||||||
|
|
||||||
|
## Eigenständige Anwendung
|
||||||
|
|
||||||
|
Für einen normalen x86-64-Linux-Rechner kann eine einzelne ausführbare Datei gebaut
|
||||||
|
werden. Sie enthält GUI und Hardware-Scanner und verwendet standardmäßig
|
||||||
|
`~/.local/share/csr-intake` für Berichte und Einstellungen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/build-release.sh
|
||||||
|
bash scripts/build-standalone.sh
|
||||||
|
./dist/csr-intake-x86_64.run
|
||||||
|
```
|
||||||
|
|
||||||
|
Ein anderer Datenordner kann mit `--data /pfad/zum/ordner` gewählt werden. Das Paket
|
||||||
|
ist für die Linux-Version des Build-Rechners bestimmt und benötigt Python 3, SQLite,
|
||||||
|
NetworkManager sowie die jeweiligen Diagnoseprogramme. `--check-bundle` prüft die
|
||||||
|
eingebetteten Dateien, ohne die Oberfläche zu starten.
|
||||||
|
|
||||||
## ISO erstellen
|
## ISO erstellen
|
||||||
|
|
||||||
Das Zielverzeichnis muss neu und leer sein:
|
Das Zielverzeichnis muss neu und leer sein:
|
||||||
|
|||||||
@@ -121,6 +121,18 @@ fn setup(data: &Path) -> Result<(), String> {
|
|||||||
fs::remove_file(data.join(".write-test")).map_err(|e| e.to_string())?;
|
fs::remove_file(data.join(".write-test")).map_err(|e| e.to_string())?;
|
||||||
workflow::init_index(data)
|
workflow::init_index(data)
|
||||||
}
|
}
|
||||||
|
fn default_data_dir() -> PathBuf {
|
||||||
|
std::env::var_os("XDG_DATA_HOME")
|
||||||
|
.filter(|value| !value.is_empty())
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.or_else(|| {
|
||||||
|
std::env::var_os("HOME")
|
||||||
|
.filter(|value| !value.is_empty())
|
||||||
|
.map(|home| PathBuf::from(home).join(".local/share"))
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| PathBuf::from("."))
|
||||||
|
.join("csr-intake")
|
||||||
|
}
|
||||||
fn label(key: &str, en: bool) -> String {
|
fn label(key: &str, en: bool) -> String {
|
||||||
match key {
|
match key {
|
||||||
"display" => tr(en, "Bildschirm", "Display"),
|
"display" => tr(en, "Bildschirm", "Display"),
|
||||||
@@ -1845,12 +1857,20 @@ fn main() -> eframe::Result<()> {
|
|||||||
println!("CS-R Intake {} · {BUILD}", env!("CARGO_PKG_VERSION"));
|
println!("CS-R Intake {} · {BUILD}", env!("CARGO_PKG_VERSION"));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
if args.iter().any(|a| a == "--help" || a == "-h") {
|
||||||
|
println!(
|
||||||
|
"CS-R Intake {}\nUsage: intake-gui [--data DIRECTORY] [--version]\nDefault data directory: {}",
|
||||||
|
env!("CARGO_PKG_VERSION"),
|
||||||
|
default_data_dir().display()
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
let data = args
|
let data = args
|
||||||
.iter()
|
.iter()
|
||||||
.position(|a| a == "--data")
|
.position(|a| a == "--data")
|
||||||
.and_then(|i| args.get(i + 1))
|
.and_then(|i| args.get(i + 1))
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.unwrap_or_else(|| PathBuf::from("/mnt/intake-data"));
|
.unwrap_or_else(default_data_dir);
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
"CS-R Intake",
|
"CS-R Intake",
|
||||||
eframe::NativeOptions {
|
eframe::NativeOptions {
|
||||||
|
|||||||
104
scripts/build-standalone.sh
Executable file
104
scripts/build-standalone.sh
Executable file
@@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
||||||
|
OUT=${1:-$ROOT/dist/csr-intake-x86_64.run}
|
||||||
|
GUI="$ROOT/gui/target/release/intake-gui"
|
||||||
|
SCANNER="$ROOT/scanner/target/release/pc-intake"
|
||||||
|
MANIFEST="$ROOT/build/release.json"
|
||||||
|
|
||||||
|
for file in "$GUI" "$SCANNER" "$MANIFEST"; do
|
||||||
|
[[ -f $file ]] || {
|
||||||
|
echo 'Release files are missing. Run bash scripts/build-release.sh first.' >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
BUILD_ID=$(python3 "$ROOT/scripts/release-manifest.py" --source-id)
|
||||||
|
GUI_VERSION=$("$GUI" --version)
|
||||||
|
grep -qF "$BUILD_ID" <<< "$GUI_VERSION" || {
|
||||||
|
echo 'Release binaries are stale. Run bash scripts/build-release.sh first.' >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
VERSION=$(sed -E 's/^CS-R Intake ([^ ]+).*/\1/' <<< "$GUI_VERSION")
|
||||||
|
|
||||||
|
TMP=$(mktemp -d)
|
||||||
|
cleanup() {
|
||||||
|
find "$TMP" -depth -delete 2>/dev/null || true
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
mkdir -p "$TMP/app" "$(dirname "$OUT")"
|
||||||
|
install -m755 "$GUI" "$TMP/app/intake-gui"
|
||||||
|
install -m755 "$SCANNER" "$TMP/app/pc-intake"
|
||||||
|
install -m644 "$MANIFEST" "$TMP/app/release.json"
|
||||||
|
(
|
||||||
|
cd "$TMP/app"
|
||||||
|
sha256sum intake-gui pc-intake release.json > SHA256SUMS
|
||||||
|
)
|
||||||
|
tar -C "$TMP/app" -czf "$TMP/payload.tar.gz" .
|
||||||
|
|
||||||
|
cat > "$TMP/launcher" <<EOF
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
BUILD_ID='$BUILD_ID'
|
||||||
|
VERSION='$VERSION'
|
||||||
|
PAYLOAD_LINE=__PAYLOAD_LINE__
|
||||||
|
|
||||||
|
cache_root=\${XDG_CACHE_HOME:-\${HOME:-\$PWD}/.cache}/csr-intake
|
||||||
|
app_dir=\$cache_root/\$BUILD_ID
|
||||||
|
|
||||||
|
extract_bundle() {
|
||||||
|
bundle_valid() {
|
||||||
|
[ -x "\$app_dir/intake-gui" ] && [ -x "\$app_dir/pc-intake" ] &&
|
||||||
|
(cd "\$app_dir" && sha256sum -c SHA256SUMS >/dev/null 2>&1)
|
||||||
|
}
|
||||||
|
if ! bundle_valid; then
|
||||||
|
if [ -e "\$app_dir" ]; then
|
||||||
|
find "\$app_dir" -depth -delete 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
temp_dir=\$cache_root/.extract-\$BUILD_ID-\$\$
|
||||||
|
mkdir -p "\$temp_dir"
|
||||||
|
trap 'find "\$temp_dir" -depth -delete 2>/dev/null || true' EXIT HUP INT TERM
|
||||||
|
tail -n +"\$PAYLOAD_LINE" "\$0" | gzip -dc | tar -xf - -C "\$temp_dir"
|
||||||
|
(cd "\$temp_dir" && sha256sum -c SHA256SUMS >/dev/null)
|
||||||
|
mkdir -p "\$cache_root"
|
||||||
|
if ! mv -T "\$temp_dir" "\$app_dir" 2>/dev/null; then
|
||||||
|
find "\$temp_dir" -depth -delete 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
trap - EXIT HUP INT TERM
|
||||||
|
fi
|
||||||
|
bundle_valid
|
||||||
|
}
|
||||||
|
|
||||||
|
case \${1:-} in
|
||||||
|
--version)
|
||||||
|
printf 'CS-R Intake %s · %s\n' "\$VERSION" "\$BUILD_ID"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--check-bundle)
|
||||||
|
extract_bundle
|
||||||
|
printf 'Standalone bundle verified: %s\n' "\$BUILD_ID"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
extract_bundle
|
||||||
|
data_dir=\${XDG_DATA_HOME:-\${HOME:-\$PWD}/.local/share}/csr-intake
|
||||||
|
has_data=0
|
||||||
|
for argument in "\$@"; do
|
||||||
|
[ "\$argument" = '--data' ] && has_data=1
|
||||||
|
done
|
||||||
|
export CSR_SCANNER="\$app_dir/pc-intake"
|
||||||
|
if [ "\$has_data" -eq 1 ]; then
|
||||||
|
exec "\$app_dir/intake-gui" "\$@"
|
||||||
|
fi
|
||||||
|
exec "\$app_dir/intake-gui" "\$@" --data "\$data_dir"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
payload_line=$(( $(wc -l < "$TMP/launcher") + 1 ))
|
||||||
|
sed -i "s/__PAYLOAD_LINE__/$payload_line/" "$TMP/launcher"
|
||||||
|
cat "$TMP/launcher" "$TMP/payload.tar.gz" > "$OUT"
|
||||||
|
chmod 755 "$OUT"
|
||||||
|
"$OUT" --check-bundle
|
||||||
|
echo "Standalone executable created: $OUT"
|
||||||
Reference in New Issue
Block a user