Feature: Shell-Completion wird automatisch mitpaketiert statt über eigenen Befehl
Entfernt den 'smart-mount completions'-Befehl komplett - Shell-Completion (bash/zsh/fish) wird stattdessen beim Bauen des .deb/.rpm/.pkg.tar.zst-Pakets generiert und als normales Paket-Asset ausgeliefert, sodass sie beim Installieren automatisch mit installiert und beim Entfernen automatisch mit entfernt wird, ganz ohne Zutun des Nutzers. Das 'cli'-Modul ist dafür Teil der Library geworden (pub mod cli), damit ein neues, separates Build-Hilfsprogramm (src/bin/generate-completions.rs) die bestehende Cli-Definition als einzige Quelle wiederverwenden kann, statt sie zu duplizieren. Die Gitea-Workflows rufen es nach dem Release-Build auf; Cargo.toml und scripts/package-arch.py bündeln die erzeugten Dateien für alle drei Paketformate an den jeweils distributionsüblichen Pfaden. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,7 +59,7 @@ jobs:
|
|||||||
cargo-${{ runner.os }}-
|
cargo-${{ runner.os }}-
|
||||||
|
|
||||||
- name: Alte Paketierungs-Ausgaben aus dem Cache entfernen
|
- name: Alte Paketierungs-Ausgaben aus dem Cache entfernen
|
||||||
run: rm -rf target/debian target/generate-rpm target/arch
|
run: rm -rf target/debian target/generate-rpm target/arch target/completions
|
||||||
|
|
||||||
- name: Install Cross-Compilation Toolchains (apt)
|
- name: Install Cross-Compilation Toolchains (apt)
|
||||||
run: |
|
run: |
|
||||||
@@ -111,6 +111,11 @@ jobs:
|
|||||||
cargo build --release --target x86_64-unknown-linux-gnu
|
cargo build --release --target x86_64-unknown-linux-gnu
|
||||||
cargo build --release --target aarch64-unknown-linux-gnu
|
cargo build --release --target aarch64-unknown-linux-gnu
|
||||||
|
|
||||||
|
- name: Generate Shell Completions
|
||||||
|
run: |
|
||||||
|
cargo build --release --bin generate-completions
|
||||||
|
./target/release/generate-completions target/completions
|
||||||
|
|
||||||
- name: Determine Build Number
|
- name: Determine Build Number
|
||||||
id: build_num
|
id: build_num
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ jobs:
|
|||||||
cargo-${{ runner.os }}-
|
cargo-${{ runner.os }}-
|
||||||
|
|
||||||
- name: Alte Paketierungs-Ausgaben aus dem Cache entfernen
|
- name: Alte Paketierungs-Ausgaben aus dem Cache entfernen
|
||||||
run: rm -rf target/debian target/generate-rpm target/arch
|
run: rm -rf target/debian target/generate-rpm target/arch target/completions
|
||||||
|
|
||||||
- name: Install Cross-Compilation Toolchains (apt)
|
- name: Install Cross-Compilation Toolchains (apt)
|
||||||
run: |
|
run: |
|
||||||
@@ -111,6 +111,11 @@ jobs:
|
|||||||
cargo build --release --target x86_64-unknown-linux-gnu
|
cargo build --release --target x86_64-unknown-linux-gnu
|
||||||
cargo build --release --target aarch64-unknown-linux-gnu
|
cargo build --release --target aarch64-unknown-linux-gnu
|
||||||
|
|
||||||
|
- name: Generate Shell Completions
|
||||||
|
run: |
|
||||||
|
cargo build --release --bin generate-completions
|
||||||
|
./target/release/generate-completions target/completions
|
||||||
|
|
||||||
- name: Determine Build Number
|
- name: Determine Build Number
|
||||||
id: build_num
|
id: build_num
|
||||||
env:
|
env:
|
||||||
|
|||||||
+12
@@ -68,6 +68,13 @@ assets = [
|
|||||||
["packaging/systemd/smart-mount-mount.service", "usr/lib/systemd/system/smart-mount-mount.service", "644"],
|
["packaging/systemd/smart-mount-mount.service", "usr/lib/systemd/system/smart-mount-mount.service", "644"],
|
||||||
["packaging/systemd/smart-mount-watch.service", "usr/lib/systemd/system/smart-mount-watch.service", "644"],
|
["packaging/systemd/smart-mount-watch.service", "usr/lib/systemd/system/smart-mount-watch.service", "644"],
|
||||||
["packaging/systemd/smart-mount-watch.timer", "usr/lib/systemd/system/smart-mount-watch.timer", "644"],
|
["packaging/systemd/smart-mount-watch.timer", "usr/lib/systemd/system/smart-mount-watch.timer", "644"],
|
||||||
|
# Von 'cargo build --bin generate-completions' erzeugt (siehe .gitea/workflows/main.yaml) -
|
||||||
|
# kein 'smart-mount completions'-Subcommand mehr, Shell-Completion wird stattdessen wie jedes
|
||||||
|
# andere Paket-Asset automatisch mit installiert/entfernt. Debian/Ubuntu laden Zsh-Completions
|
||||||
|
# aus 'vendor-completions' (anders als Fedora/Arch, siehe [package.metadata.generate-rpm]).
|
||||||
|
["target/completions/smart-mount.bash", "usr/share/bash-completion/completions/smart-mount", "644"],
|
||||||
|
["target/completions/_smart-mount", "usr/share/zsh/vendor-completions/_smart-mount", "644"],
|
||||||
|
["target/completions/smart-mount.fish", "usr/share/fish/vendor_completions.d/smart-mount.fish", "644"],
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata.generate-rpm]
|
[package.metadata.generate-rpm]
|
||||||
@@ -78,6 +85,11 @@ assets = [
|
|||||||
{ source = "packaging/systemd/smart-mount-mount.service", dest = "/usr/lib/systemd/system/smart-mount-mount.service", mode = "644" },
|
{ source = "packaging/systemd/smart-mount-mount.service", dest = "/usr/lib/systemd/system/smart-mount-mount.service", mode = "644" },
|
||||||
{ source = "packaging/systemd/smart-mount-watch.service", dest = "/usr/lib/systemd/system/smart-mount-watch.service", mode = "644" },
|
{ source = "packaging/systemd/smart-mount-watch.service", dest = "/usr/lib/systemd/system/smart-mount-watch.service", mode = "644" },
|
||||||
{ source = "packaging/systemd/smart-mount-watch.timer", dest = "/usr/lib/systemd/system/smart-mount-watch.timer", mode = "644" },
|
{ source = "packaging/systemd/smart-mount-watch.timer", dest = "/usr/lib/systemd/system/smart-mount-watch.timer", mode = "644" },
|
||||||
|
# Fedora/RHEL (wie Arch, siehe scripts/package-arch.py) laden Zsh-Completions aus
|
||||||
|
# 'site-functions' statt Debians 'vendor-completions' (siehe [package.metadata.deb]).
|
||||||
|
{ source = "target/completions/smart-mount.bash", dest = "/usr/share/bash-completion/completions/smart-mount", mode = "644" },
|
||||||
|
{ source = "target/completions/_smart-mount", dest = "/usr/share/zsh/site-functions/_smart-mount", mode = "644" },
|
||||||
|
{ source = "target/completions/smart-mount.fish", dest = "/usr/share/fish/vendor_completions.d/smart-mount.fish", mode = "644" },
|
||||||
]
|
]
|
||||||
requires = { "mac2ip" = "*" }
|
requires = { "mac2ip" = "*" }
|
||||||
suggests = { "davfs2" = "*", "cifs-utils" = "*", "nfs-utils" = "*" }
|
suggests = { "davfs2" = "*", "cifs-utils" = "*", "nfs-utils" = "*" }
|
||||||
|
|||||||
@@ -88,12 +88,12 @@ sudo smart-mount service crontab --remove
|
|||||||
# einzeln beim Mount-Fehlschlag entdecken würde
|
# einzeln beim Mount-Fehlschlag entdecken würde
|
||||||
smart-mount doctor
|
smart-mount doctor
|
||||||
smart-mount doctor --json
|
smart-mount doctor --json
|
||||||
|
|
||||||
# Shell-Completion-Skript ausgeben (bash/zsh/fish/elvish/powershell)
|
|
||||||
smart-mount completions bash > /etc/bash_completion.d/smart-mount
|
|
||||||
smart-mount completions zsh > "${fpath[1]}/_smart-mount"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Shell-Completion (bash/zsh/fish) wird beim Installieren des .deb/.rpm/.pkg.tar.zst-Pakets
|
||||||
|
automatisch mit installiert (und beim Entfernen des Pakets automatisch mit entfernt) - dafür ist
|
||||||
|
kein eigenes `smart-mount`-Subcommand nötig.
|
||||||
|
|
||||||
Die Konfiguration liegt immer unter `/etc/smart-mount/config.toml`, unabhängig davon, ob
|
Die Konfiguration liegt immer unter `/etc/smart-mount/config.toml`, unabhängig davon, ob
|
||||||
`smart-mount` selbst mit oder ohne Root-Rechte aufgerufen wird (siehe oben). Die verschlüsselte
|
`smart-mount` selbst mit oder ohne Root-Rechte aufgerufen wird (siehe oben). Die verschlüsselte
|
||||||
Zugangsdaten-Datenbank (`smart-mount.db`) liegt im selben Verzeichnis.
|
Zugangsdaten-Datenbank (`smart-mount.db`) liegt im selben Verzeichnis.
|
||||||
|
|||||||
@@ -61,6 +61,27 @@ def collect_systemd_units(systemd_src_dir="packaging/systemd"):
|
|||||||
return unit_files, installable
|
return unit_files, installable
|
||||||
|
|
||||||
|
|
||||||
|
def collect_completions(completions_dir="target/completions"):
|
||||||
|
"""Findet die von 'cargo build --bin generate-completions' erzeugten Shell-Completion-
|
||||||
|
Skripte (siehe src/bin/generate-completions.rs), falls vorhanden, und ordnet sie generisch -
|
||||||
|
ohne den Anwendungsnamen zu kennen - allein anhand ihrer clap_complete-Namenskonvention
|
||||||
|
(Bash: '<name>.bash', Zsh: '_<name>', Fish: '<name>.fish') dem jeweiligen
|
||||||
|
System-Verzeichnis zu. Gibt eine Liste aus (Quellpfad, Zielverzeichnis, Zieldateiname) zurück."""
|
||||||
|
if not os.path.isdir(completions_dir):
|
||||||
|
return []
|
||||||
|
|
||||||
|
mapping = []
|
||||||
|
for f in sorted(os.listdir(completions_dir)):
|
||||||
|
src = os.path.join(completions_dir, f)
|
||||||
|
if f.endswith(".bash"):
|
||||||
|
mapping.append((src, "usr/share/bash-completion/completions", f[: -len(".bash")]))
|
||||||
|
elif f.endswith(".fish"):
|
||||||
|
mapping.append((src, "usr/share/fish/vendor_completions.d", f))
|
||||||
|
elif f.startswith("_"):
|
||||||
|
mapping.append((src, "usr/share/zsh/site-functions", f))
|
||||||
|
return mapping
|
||||||
|
|
||||||
|
|
||||||
def build_install_scriptlet(installable, all_units):
|
def build_install_scriptlet(installable, all_units):
|
||||||
"""Erzeugt den Inhalt einer Arch-'.INSTALL'-Datei (siehe `man PKGBUILD`, Abschnitt
|
"""Erzeugt den Inhalt einer Arch-'.INSTALL'-Datei (siehe `man PKGBUILD`, Abschnitt
|
||||||
'install'), die den paketierten systemd-Dienst beim Installieren aktiviert/startet und beim
|
'install'), die den paketierten systemd-Dienst beim Installieren aktiviert/startet und beim
|
||||||
@@ -155,6 +176,14 @@ def build_package(target_triple=None, target_arch=None, pkgrel=None):
|
|||||||
check=True,
|
check=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for src, dest_dir, dest_name in collect_completions():
|
||||||
|
target_dir = os.path.join(build_dir, dest_dir)
|
||||||
|
os.makedirs(target_dir, exist_ok=True)
|
||||||
|
subprocess.run(
|
||||||
|
["install", "-m", "644", src, os.path.join(target_dir, dest_name)],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
|
||||||
installed_size = subprocess.check_output(["du", "-sb", build_dir]).decode().split()[0]
|
installed_size = subprocess.check_output(["du", "-sb", build_dir]).decode().split()[0]
|
||||||
builddate = str(int(time.time()))
|
builddate = str(int(time.time()))
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
//! Erzeugt die Shell-Completion-Skripte (bash/zsh/fish) für `smart-mount` als Dateien in einem
|
||||||
|
//! Ausgabeverzeichnis - kein `smart-mount`-Subcommand mehr (siehe `smart_mount::cli::Commands`),
|
||||||
|
//! sondern ein separates Build-Hilfsprogramm, das ausschließlich während der CI-Paketierung
|
||||||
|
//! aufgerufen wird (siehe `.gitea/workflows/main.yaml`/`testing.yaml`): die erzeugten Dateien
|
||||||
|
//! werden dort als normale Paket-Assets gebündelt, sodass sie beim Installieren des .deb/.rpm/
|
||||||
|
//! .pkg.tar.zst-Pakets automatisch mit installiert und beim Entfernen automatisch mit entfernt
|
||||||
|
//! werden - ganz ohne Zutun des Nutzers.
|
||||||
|
//!
|
||||||
|
//! Nutzt `smart_mount::cli::Cli` als einzige Quelle der CLI-Definition (kein separat gepflegtes
|
||||||
|
//! Duplikat), da `cli` als `pub mod` Teil der Library ist und so auch von diesem zusätzlichen
|
||||||
|
//! Binary-Target aus der Cargo-eigenen `src/bin/`-Autodiscovery erreichbar ist.
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use clap::CommandFactory;
|
||||||
|
use clap_complete::Shell;
|
||||||
|
use smart_mount::cli::Cli;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let Some(out_dir) = std::env::args_os().nth(1).map(PathBuf::from) else {
|
||||||
|
eprintln!("usage: generate-completions <output-dir>");
|
||||||
|
std::process::exit(1);
|
||||||
|
};
|
||||||
|
std::fs::create_dir_all(&out_dir)
|
||||||
|
.unwrap_or_else(|e| panic!("could not create '{}': {e}", out_dir.display()));
|
||||||
|
|
||||||
|
let mut cmd = Cli::command();
|
||||||
|
let bin_name = cmd.get_name().to_string();
|
||||||
|
for shell in [Shell::Bash, Shell::Zsh, Shell::Fish] {
|
||||||
|
let path = clap_complete::generate_to(shell, &mut cmd, &bin_name, &out_dir)
|
||||||
|
.unwrap_or_else(|e| panic!("could not generate {shell} completions: {e}"));
|
||||||
|
println!("generated: {}", path.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
//! `smart-mount doctor` - prüft die im Laufe der Entwicklung angesammelten Voraussetzungen
|
//! `smart-mount doctor` - prüft die im Laufe der Entwicklung angesammelten Voraussetzungen
|
||||||
//! (Binaries, Gruppenmitgliedschaft, fstab-Setup, Scheduler) gebündelt an einer Stelle.
|
//! (Binaries, Gruppenmitgliedschaft, fstab-Setup, Scheduler) gebündelt an einer Stelle.
|
||||||
|
|
||||||
use smart_mount::config;
|
use crate::config;
|
||||||
use smart_mount::doctor::{self, CheckStatus};
|
use crate::doctor::{self, CheckStatus};
|
||||||
|
|
||||||
pub async fn run(json: bool) -> anyhow::Result<()> {
|
pub async fn run(json: bool) -> anyhow::Result<()> {
|
||||||
let cfg = config::pairs::load()?;
|
let cfg = config::pairs::load()?;
|
||||||
|
|||||||
+8
-10
@@ -12,10 +12,8 @@ use std::str::FromStr;
|
|||||||
use clap::{Args, Subcommand};
|
use clap::{Args, Subcommand};
|
||||||
use dialoguer::{Confirm, Input, Password, Select};
|
use dialoguer::{Confirm, Input, Password, Select};
|
||||||
|
|
||||||
use smart_mount::config::{
|
use crate::config::{self, AppConfig, CloudSide, DrivePair, LocalAddress, LocalSide, MountKind};
|
||||||
self, AppConfig, CloudSide, DrivePair, LocalAddress, LocalSide, MountKind,
|
use crate::db::credentials::{Credential, CredentialStore, Side};
|
||||||
};
|
|
||||||
use smart_mount::db::credentials::{Credential, CredentialStore, Side};
|
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub enum DriveAction {
|
pub enum DriveAction {
|
||||||
@@ -145,7 +143,7 @@ async fn remove(id: &str) -> anyhow::Result<()> {
|
|||||||
|
|
||||||
// Vor dem Entfernen aus der Config nachschlagen, damit wir hinterher noch wissen, welche
|
// Vor dem Entfernen aus der Config nachschlagen, damit wir hinterher noch wissen, welche
|
||||||
// Mount-Typen/Adressen betroffen sind - nötig, um die passenden Klartext-Zugangsdaten
|
// Mount-Typen/Adressen betroffen sind - nötig, um die passenden Klartext-Zugangsdaten
|
||||||
// (davfs2 secrets, .cred-Datei) aufzuräumen, siehe smart_mount::mount::cleanup_credentials.
|
// (davfs2 secrets, .cred-Datei) aufzuräumen, siehe crate::mount::cleanup_credentials.
|
||||||
let cfg = config::pairs::load()?;
|
let cfg = config::pairs::load()?;
|
||||||
let pair = config::pairs::find_pair(&cfg, id)?;
|
let pair = config::pairs::find_pair(&cfg, id)?;
|
||||||
|
|
||||||
@@ -154,7 +152,7 @@ async fn remove(id: &str) -> anyhow::Result<()> {
|
|||||||
// darf das Entfernen aus der Konfiguration nicht blockieren - sonst käme der Nutzer nicht
|
// darf das Entfernen aus der Konfiguration nicht blockieren - sonst käme der Nutzer nicht
|
||||||
// mehr an sein eigenes `drive remove` heran, ohne vorher erst als root/mit den richtigen
|
// mehr an sein eigenes `drive remove` heran, ohne vorher erst als root/mit den richtigen
|
||||||
// Rechten manuell auszuhängen.
|
// Rechten manuell auszuhängen.
|
||||||
if let Err(e) = smart_mount::reconcile::unmount_pair(&pair, &cfg.settings).await {
|
if let Err(e) = crate::reconcile::unmount_pair(&pair, &cfg.settings).await {
|
||||||
logger_ctdra::warn(
|
logger_ctdra::warn(
|
||||||
"drive",
|
"drive",
|
||||||
&format!("could not unmount drive pair '{id}' before removal: {e}"),
|
&format!("could not unmount drive pair '{id}' before removal: {e}"),
|
||||||
@@ -163,7 +161,7 @@ async fn remove(id: &str) -> anyhow::Result<()> {
|
|||||||
config::pairs::remove_pair(id)?;
|
config::pairs::remove_pair(id)?;
|
||||||
let creds = CredentialStore::open().await?;
|
let creds = CredentialStore::open().await?;
|
||||||
creds.delete(id, None).await?;
|
creds.delete(id, None).await?;
|
||||||
smart_mount::mount::cleanup_credentials(&pair, &cfg.settings);
|
crate::mount::cleanup_credentials(&pair, &cfg.settings);
|
||||||
|
|
||||||
logger_ctdra::info("drive", &format!("drive pair '{id}' removed"));
|
logger_ctdra::info("drive", &format!("drive pair '{id}' removed"));
|
||||||
println!("Drive pair '{id}' removed.");
|
println!("Drive pair '{id}' removed.");
|
||||||
@@ -356,7 +354,7 @@ async fn edit(id: &str, args: DriveArgs) -> anyhow::Result<()> {
|
|||||||
// würde ein aktiver Mount verwaisen. Nur eine explizite '--mount-point'-Angabe ändert ihn.
|
// würde ein aktiver Mount verwaisen. Nur eine explizite '--mount-point'-Angabe ändert ihn.
|
||||||
let mount_point = match args.mount_point {
|
let mount_point = match args.mount_point {
|
||||||
Some(p) => {
|
Some(p) => {
|
||||||
if smart_mount::mount::target::active_side(&existing).is_some() {
|
if crate::mount::target::active_side(&existing).is_some() {
|
||||||
println!(
|
println!(
|
||||||
"Warning: pair '{id}' appears to be actively mounted - the old backing \
|
"Warning: pair '{id}' appears to be actively mounted - the old backing \
|
||||||
directories will be orphaned. Run 'sudo smart-mount unmount --name {id}' \
|
directories will be orphaned. Run 'sudo smart-mount unmount --name {id}' \
|
||||||
@@ -515,7 +513,7 @@ fn invoking_user() -> Option<String> {
|
|||||||
|
|
||||||
/// Optional: falls gesetzt, bekommt dieser Nutzer bei CIFS/WebDAV vollen Zugriff
|
/// Optional: falls gesetzt, bekommt dieser Nutzer bei CIFS/WebDAV vollen Zugriff
|
||||||
/// (uid=/gid=/file_mode=0700/dir_mode=0700) statt der sonst üblichen root-Ownership - der
|
/// (uid=/gid=/file_mode=0700/dir_mode=0700) statt der sonst üblichen root-Ownership - der
|
||||||
/// Mount selbst läuft immer als root (siehe [`smart_mount::systemd`]). `default_owner` ist der
|
/// Mount selbst läuft immer als root (siehe [`crate::systemd`]). `default_owner` ist der
|
||||||
/// vorbelegte/vorgeschlagene Wert (bei `add`: der einrichtende Nutzer, siehe `invoking_user`;
|
/// vorbelegte/vorgeschlagene Wert (bei `add`: der einrichtende Nutzer, siehe `invoking_user`;
|
||||||
/// bei `edit`: der bisherige `owner_user`) - immer überschreibbar per Flag, im interaktiven
|
/// bei `edit`: der bisherige `owner_user`) - immer überschreibbar per Flag, im interaktiven
|
||||||
/// Prompt auch durch Ablehnen oder einen anderen Namen.
|
/// Prompt auch durch Ablehnen oder einen anderen Namen.
|
||||||
@@ -693,7 +691,7 @@ fn resolve_credentials(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use smart_mount::config::LocalAddress;
|
use crate::config::LocalAddress;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
fn sample_pair(mount_point: &str) -> DrivePair {
|
fn sample_pair(mount_point: &str) -> DrivePair {
|
||||||
|
|||||||
+2
-16
@@ -7,12 +7,11 @@ pub mod service;
|
|||||||
pub mod status;
|
pub mod status;
|
||||||
pub mod watch;
|
pub mod watch;
|
||||||
|
|
||||||
use clap::{CommandFactory, Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use clap_complete::Shell;
|
|
||||||
|
|
||||||
/// Startet den Prozess bei Bedarf transparent über `sudo` neu, falls nicht bereits als root
|
/// Startet den Prozess bei Bedarf transparent über `sudo` neu, falls nicht bereits als root
|
||||||
/// aufgerufen. Mounten läuft ausschließlich als root/System-Dienst (siehe
|
/// aufgerufen. Mounten läuft ausschließlich als root/System-Dienst (siehe
|
||||||
/// [`smart_mount::systemd`]) - es gibt seit dem Wegfall des Nutzerkontexts keine
|
/// [`crate::systemd`]) - es gibt seit dem Wegfall des Nutzerkontexts keine
|
||||||
/// unprivilegierte Mount-Variante mehr, für die ein Rechte-Check hier zu früh käme.
|
/// unprivilegierte Mount-Variante mehr, für die ein Rechte-Check hier zu früh käme.
|
||||||
///
|
///
|
||||||
/// `run_as_root()` ersetzt den aktuellen Prozess per `execve` und kehrt bei Erfolg nie zurück
|
/// `run_as_root()` ersetzt den aktuellen Prozess per `execve` und kehrt bei Erfolg nie zurück
|
||||||
@@ -88,9 +87,6 @@ pub enum Commands {
|
|||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
json: bool,
|
json: bool,
|
||||||
},
|
},
|
||||||
/// Prints a shell completion script, e.g.:
|
|
||||||
/// `smart-mount completions bash > /etc/bash_completion.d/smart-mount`.
|
|
||||||
Completions { shell: Shell },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Kurzname eines Subcommands fürs Logging (siehe [`dispatch`]) - kein `Debug`-Derive auf
|
/// Kurzname eines Subcommands fürs Logging (siehe [`dispatch`]) - kein `Debug`-Derive auf
|
||||||
@@ -104,7 +100,6 @@ fn command_label(cmd: &Commands) -> &'static str {
|
|||||||
Commands::Watch => "watch",
|
Commands::Watch => "watch",
|
||||||
Commands::Service { .. } => "service",
|
Commands::Service { .. } => "service",
|
||||||
Commands::Doctor { .. } => "doctor",
|
Commands::Doctor { .. } => "doctor",
|
||||||
Commands::Completions { .. } => "completions",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,14 +117,5 @@ pub async fn dispatch(cli: Cli) -> anyhow::Result<()> {
|
|||||||
Commands::Watch => watch::run().await,
|
Commands::Watch => watch::run().await,
|
||||||
Commands::Service { action } => service::run(action),
|
Commands::Service { action } => service::run(action),
|
||||||
Commands::Doctor { json } => doctor::run(json).await,
|
Commands::Doctor { json } => doctor::run(json).await,
|
||||||
Commands::Completions { shell } => {
|
|
||||||
clap_complete::generate(
|
|
||||||
shell,
|
|
||||||
&mut Cli::command(),
|
|
||||||
"smart-mount",
|
|
||||||
&mut std::io::stdout(),
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
//! `smart-mount mount` / `smart-mount unmount`.
|
//! `smart-mount mount` / `smart-mount unmount`.
|
||||||
|
|
||||||
use smart_mount::config::{self, DrivePair};
|
use crate::config::{self, DrivePair};
|
||||||
use smart_mount::db::credentials::CredentialStore;
|
use crate::db::credentials::CredentialStore;
|
||||||
use smart_mount::reconcile;
|
use crate::reconcile;
|
||||||
|
|
||||||
fn select_pairs(
|
fn select_pairs(
|
||||||
cfg: &smart_mount::config::AppConfig,
|
cfg: &crate::config::AppConfig,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
all: bool,
|
all: bool,
|
||||||
) -> anyhow::Result<Vec<DrivePair>> {
|
) -> anyhow::Result<Vec<DrivePair>> {
|
||||||
|
|||||||
+3
-2
@@ -1,8 +1,9 @@
|
|||||||
//! `smart-mount service crontab [--remove]`.
|
//! `smart-mount service crontab [--remove]`.
|
||||||
|
|
||||||
use clap::Subcommand;
|
use clap::Subcommand;
|
||||||
use smart_mount::config;
|
|
||||||
use smart_mount::systemd;
|
use crate::config;
|
||||||
|
use crate::systemd;
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub enum ServiceAction {
|
pub enum ServiceAction {
|
||||||
|
|||||||
+5
-5
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use smart_mount::config;
|
use crate::config;
|
||||||
use smart_mount::db::credentials::Side;
|
use crate::db::credentials::Side;
|
||||||
use smart_mount::mount::target;
|
use crate::mount::target;
|
||||||
use smart_mount::network;
|
use crate::network;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct PairStatus {
|
struct PairStatus {
|
||||||
@@ -48,7 +48,7 @@ pub async fn run(name: Option<String>, json: bool) -> anyhow::Result<()> {
|
|||||||
// wiederverwendet, statt sie für beide Zwecke unabhängig voneinander ein zweites
|
// wiederverwendet, statt sie für beide Zwecke unabhängig voneinander ein zweites
|
||||||
// Mal aufzulösen.
|
// Mal aufzulösen.
|
||||||
let resolved_local_ip =
|
let resolved_local_ip =
|
||||||
smart_mount::network::address::resolve_ip(&pair.local.address, &cfg.settings);
|
crate::network::address::resolve_ip(&pair.local.address, &cfg.settings);
|
||||||
let local_source = resolved_local_ip
|
let local_source = resolved_local_ip
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|ip| target::format_local_source(&pair.local, *ip))
|
.map(|ip| target::format_local_source(&pair.local, *ip))
|
||||||
|
|||||||
+3
-4
@@ -1,10 +1,9 @@
|
|||||||
//! `smart-mount watch` - ein einzelner Reconcile-Durchlauf, gedacht für systemd-Timer/Cron.
|
//! `smart-mount watch` - ein einzelner Reconcile-Durchlauf, gedacht für systemd-Timer/Cron.
|
||||||
|
|
||||||
use smart_mount::config;
|
|
||||||
use smart_mount::db::credentials::CredentialStore;
|
|
||||||
use smart_mount::reconcile::{self, Action};
|
|
||||||
|
|
||||||
use crate::cli::mount_cmd::print_outcome;
|
use crate::cli::mount_cmd::print_outcome;
|
||||||
|
use crate::config;
|
||||||
|
use crate::db::credentials::CredentialStore;
|
||||||
|
use crate::reconcile::{self, Action};
|
||||||
|
|
||||||
pub async fn run() -> anyhow::Result<()> {
|
pub async fn run() -> anyhow::Result<()> {
|
||||||
crate::cli::require_root("watch")?;
|
crate::cli::require_root("watch")?;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//! smart-mount: bindet lokale/Cloud-Laufwerkspaare (WebDAV/SMB/NFS) dynamisch ein und
|
//! smart-mount: bindet lokale/Cloud-Laufwerkspaare (WebDAV/SMB/NFS) dynamisch ein und
|
||||||
//! schaltet automatisch zwischen LAN und Cloud um.
|
//! schaltet automatisch zwischen LAN und Cloud um.
|
||||||
|
|
||||||
|
pub mod cli;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
|||||||
+1
-2
@@ -1,8 +1,7 @@
|
|||||||
mod cli;
|
|
||||||
|
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use smart_mount::cli;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> ExitCode {
|
async fn main() -> ExitCode {
|
||||||
|
|||||||
Reference in New Issue
Block a user