diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index 8455547..0000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,9 +0,0 @@ -[registry] -default = "gitea" - -[registries.gitea] -index = "sparse+https://gitea.creative-dragonslayer.de/api/packages/Rust-Crates/cargo/" # Sparse index -# index = "https://gitea.creative-dragonslayer.de/Rust-Crates/_cargo-index.git" # Git - -[net] -git-fetch-with-cli = true diff --git a/.idea/rust-crate-template.iml b/.idea/rust-crate-template.iml index cf84ae4..bbe0a70 100644 --- a/.idea/rust-crate-template.iml +++ b/.idea/rust-crate-template.iml @@ -3,6 +3,7 @@ + diff --git a/AGENTS.md b/AGENTS.md index 9976f22..5cdf713 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,12 +1,14 @@ # AGENTS.md -Dieses Dokument definiert Richtlinien, Konventionen und Arbeitsanweisungen für KI-Agenten und LLM-Tools, die an diesem Repository oder daraus erstellten Rust-Crates arbeiten. +Dieses Dokument definiert Richtlinien, Konventionen und Arbeitsanweisungen für KI-Agenten und LLM-Tools, die an der Rust-Bibliothek `program-ctdra` arbeiten. --- ## 1. Projektübersicht & Kontext -- **Typ:** Rust Library Crate Template +- **Name:** `program-ctdra` +- **Typ:** Rust Library Crate +- **Zweck:** Einfache und zuverlässige Ermittlung des Programmnamens (Dateistamm der aktuellen ausführbaren Datei) mit sicherem Fallback - **Rust Edition:** `2024` - **Einstiegspunkt:** `src/lib.rs` - **CI/CD Plattform:** Gitea Actions (`.gitea/workflows/`) @@ -20,11 +22,12 @@ Dieses Dokument definiert Richtlinien, Konventionen und Arbeitsanweisungen für ### 2.1 Sprache & Idiomatik - Verwende modernes, idiomatisches Rust (Edition 2024). - Bevorzuge explizite Typen und klare Signaturen in öffentlichen Schnittstellen (`pub`). -- Halte die API ergonomisch und benutzerfreundlich. +- Halte die API ergonomisch, minimalistisch und benutzerfreundlich. +- Vermeide unnötige externe Abhängigkeiten (Zero Dependencies). ### 2.2 Fehlerbehandlung - Nutze `Result` und `Option` für alle potenziell fehlschlagenden Operationen. -- Definiere aussagekräftige, domänenspezifische Fehlertypen (z. B. via `thiserror` oder standardmäßig `std::error::Error`). +- Definiere aussagekräftige, domänenspezifische Fehlertypen, falls zutreffend. - **Verboten im produktiven Bibliothekscode (`src/`):** - Unbegründete `unwrap()`, `expect()` oder `panic!()` Aufrufe. - Ignorieren von Fehlern via `let _ = ...`, es sei denn, es ist explizit begründet und dokumentiert. @@ -92,10 +95,9 @@ Die CI/CD-Pipelines werden über Gitea Actions gesteuert: --- -## 5. Arbeitsanweisungen für Agenten bei Projekt-Initialisierung +## 5. Richtlinien für Agenten bei Änderungen -Wenn dieser Template-Stand verwendet wird, um eine neue Crate zu erstellen: -1. Aktualisiere die `Cargo.toml`-Metadaten (`name`, `version`, `authors`, `repository`, `description`). -2. Passe die `README.md` an die konkrete Funktionalität der neuen Crate an. -3. Behalte die Gitea-Workflows bei oder passe sie an das Ziel-Repository an. +1. Halte die `Cargo.toml`-Metadaten (`name`, `version`, `authors`, `repository`, `description`) aktuell und konsistent. +2. Halte die `README.md` synchron mit allen Änderungen an der API oder Funktionalität der Crate. +3. Behalte die Gitea-Workflows bei und stelle sicher, dass alle Validierungsschritte bestehen. 4. Stelle sicher, dass keine Secrets, temporären Build-Dateien (`target/`) oder IDE-spezifischen Caches (außer `.idea` Konfigurationen) committed werden. diff --git a/Cargo.lock b/Cargo.lock index 1c5dbce..bf7446d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,5 +3,5 @@ version = 4 [[package]] -name = "rust-creat-template" +name = "program-ctdra" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index d875c83..0b3b570 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "rust-creat-template" # TODO Setzen -version = "1.0.0" # TODO Setzen +name = "program-ctdra" +version = "1.0.0" edition = "2024" -authors = ['DragonSlayer_14'] # TODO Setzen +authors = ['DragonSlayer_14'] readme = "README.md" license = "GPL-3.0-or-later" -repository = "https://gitea.creative-dragonslayer.de/Templates/rust-crate-template" # TODO Setzen -description = "Ein Template-Projekt, das fürs erstellen von Rust-Crates verwendet werden kann." # TODO Setzen +repository = "https://gitea.creative-dragonslayer.de/Rust-Crates/program" +description = "Eine schlanke Rust-Bibliothek zur einfachen und zuverlässigen Ermittlung des Namens der aktuellen ausführbaren Datei." [dependencies] diff --git a/README.md b/README.md index f532ff6..41bf07f 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,66 @@ -# Rust Crate Template +# program-ctdra -Ein vorkonfiguriertes Template-Projekt für die schnelle und standardisierte Entwicklung von Rust-Crates (Libraries) mit automatisierter CI/CD-Pipeline für Gitea. +Eine schlanke, abhängigkeitsfreie Rust-Bibliothek zur einfachen und zuverlässigen Ermittlung des Programmnamens (Dateistamm der aktuellen ausführbaren Datei). --- ## 🚀 Übersicht & Features -- **Rust Edition 2024**: Moderner Rust-Standard mit optimierten Profil-Einstellungen (`profile.release.debug = "none"`). +- **Einfache API**: + - `program_name()`: Ermittelt den Programmnamen mit sicherem Fallback (`"app"`). + - `program_name_or(fallback)`: Ermittelt den Programmnamen mit anpassbarem Fallback. + - `try_program_name()`: Gibt den Programmnamen als `Option` zurück. +- **Zero Dependencies**: Nutzt ausschließlich die Rust-Standardbibliothek (`std::env`, `std::path`). +- **Rust Edition 2024**: Moderner Rust-Standard mit optimierten Release-Profil-Einstellungen (`debug = "none"`). +- **Vollständig getestet & dokumentiert**: Mit Unit-Tests, Integrationstests und getesteten Rustdoc-Codebeispielen. - **Automatisierte CI/CD-Workflows (Gitea Actions)**: - - **Testing-Pipeline (`testing`-Branch)**: Führt Tests und Compiler-Checks aus und erstellt automatisch ein Gitea Pre-Release (`v-preview`) inklusive `.crate`-Paket als Release-Asset. - - **Main-Release-Pipeline (`main`-Branch)**: Führt Tests und Compiler-Checks aus, paketiert die Crate, veröffentlicht sie in der Gitea Cargo Package Registry und erstellt ein offizielles Gitea Release (`v`) mit Asset. -- **Integrierte Gitea Package Registry**: Vorkonfigurierte sparse index Registry-Anbindung. -- **GPL-3.0-or-later Lizenz**: Vorkonfiguriert mit Lizenzdatei und Metadaten. + - **Testing-Pipeline (`testing`-Branch)**: Baut, testet und erstellt automatisch ein Gitea Pre-Release (`v-preview`) inklusive `.crate`-Paket. + - **Main-Release-Pipeline (`main`-Branch)**: Baut, testet, paketiert, veröffentlicht in der Gitea Cargo Package Registry und erstellt ein Gitea Release (`v`). +- **GPL-3.0-or-later Lizenz**: Freie Software unter der GNU General Public License v3.0 oder neuer. + +--- + +## 📦 Installation & Einbindung + +Um `program-ctdra` aus der Gitea Package Registry in einem Cargo-Projekt zu verwenden: + +### 1. Registry konfigurieren +Füge die Gitea Package Registry zu deiner lokalen `~/.cargo/config.toml` oder projektweiten `.cargo/config.toml` hinzu: + +```toml +[registries.gitea] +index = "sparse+https://gitea.creative-dragonslayer.de/api/packages/Rust-Crates/cargo/" +``` + +### 2. Abhängigkeit in `Cargo.toml` deklarieren +```toml +[dependencies] +program-ctdra = { version = "1.0.0", registry = "gitea" } +``` + +--- + +## 💡 Anwendungsbeispiele + +```rust +use program_ctdra::{program_name, program_name_or, try_program_name}; + +fn main() { + // 1. Standard-Aufruf mit Fallback "app" + let name = program_name(); + println!("Aktuelles Programm: {name}"); + + // 2. Mit benutzerdefiniertem Fallback + let service_name = program_name_or("mein-dienst"); + println!("Dienst-Name: {service_name}"); + + // 3. Optionale Ermittlung ohne Fallback + match try_program_name() { + Some(name) => println!("Executable-Name ermittelt: {name}"), + None => eprintln!("Konnte Programmnamen nicht ermitteln!"), + } +} +``` --- @@ -25,7 +74,9 @@ Ein vorkonfiguriertes Template-Projekt für die schnelle und standardisierte Ent │ └── testing.yaml # CI/CD: Test, Check & Pre-Release für 'testing' ├── .idea/ # Vorkonfigurierte JetBrains IDE Einstellungen ├── src/ -│ └── lib.rs # Einstiegspunkt der Crate / Library +│ └── lib.rs # Bibliotheks-Implementierung & Unit-Tests +├── tests/ +│ └── integration_test.rs # Integrationstests für die öffentliche API ├── Cargo.lock ├── Cargo.toml # Crate-Manifest & Metadaten ├── LICENSE # GNU General Public License v3.0 @@ -35,39 +86,16 @@ Ein vorkonfiguriertes Template-Projekt für die schnelle und standardisierte Ent --- -## 🛠️ Verwendung als Template +## 💻 Lokale Entwicklung & Validierung -### 1. Template initialisieren & Metadaten anpassen -Passe nach dem Klonen bzw. Erstellen des neuen Repositories die Platzhalter in `Cargo.toml` an: - -```toml -[package] -name = "mein-crate-name" -version = "0.1.0" -edition = "2024" -authors = ['DeinName '] -readme = "README.md" -license = "GPL-3.0-or-later" -repository = "https://gitea.example.com/Organisation/mein-crate-name" -description = "Beschreibung der Crate." -``` - -### 2. Gitea Repository Secrets einrichten -Für die Veröffentlichung und Release-Erstellung in Gitea Actions muss mindestens ein Access-Token als Repository-Secret hinterlegt werden (z. B. unter `Einstellungen -> Secrets -> Actions`): -- `PACKAGE_TOKEN` (oder alternativ `RELEASE_TOKEN`, `GITEA_TOKEN`): Ein Personal Access Token mit Berechtigungen für Packages (`write:package`) und Repositories/Releases (`write:repository`). - ---- - -## 💻 Lokale Entwicklung & Befehle - -Die gängigen Cargo-Befehle zur Entwicklung: +Die gängigen Cargo-Befehle zur Entwicklung und Verifizierung: - **Kompilierung prüfen:** ```bash cargo check --all-targets ``` -- **Tests ausführen:** +- **Tests ausführen (Unit-, Integrations- und Doc-Tests):** ```bash cargo test ``` @@ -97,25 +125,7 @@ Die gängigen Cargo-Befehle zur Entwicklung: | `testing` | Push auf `testing` | • `cargo test`
• `cargo check --all-targets`
• `cargo package`
• Erstellt/Aktualisiert Pre-Release `v-preview` mit `.crate`-Asset | | `main` | Push auf `main` | • `cargo test`
• `cargo check --all-targets`
• `cargo package`
• Veröffentlicht Crate in Gitea Package Registry
• Erstellt/Aktualisiert Release `v` mit `.crate`-Asset | -> **Hinweis zur Versionierung:** Die Versionsnummer wird automatisch aus `Cargo.toml` (`version = "..."`) ausgelesen. Passe vor einem Merge auf `main` oder `testing` die Version in `Cargo.toml` entsprechend SemVer an. - ---- - -## 📦 Verwenden der Crate in anderen Projekten - -Um die in der Gitea Package Registry veröffentlichte Crate in einem anderen Cargo-Projekt zu verwenden: - -1. Trage die Registry in deiner lokalen `~/.cargo/config.toml` oder projektweiten `.cargo/config.toml` ein: - ```toml - [registries.gitea] - index = "sparse+https://gitea.creative-dragonslayer.de/api/packages/Rust-Crates/cargo/" - ``` - -2. Binde die Crate in deiner `Cargo.toml` ein: - ```toml - [dependencies] - mein-crate-name = { version = "1.0.0", registry = "gitea" } - ``` +> **Hinweis zur Versionierung:** Die Versionsnummer wird automatisch aus `Cargo.toml` (`version = "..."`) ausgelesen. Vor einem Merge auf `main` oder `testing` muss die Version in `Cargo.toml` entsprechend SemVer angepasst werden. --- diff --git a/src/lib.rs b/src/lib.rs index e69de29..4b0d1dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -0,0 +1,148 @@ +//! # program-ctdra +//! +//! Eine schlanke, abhängigkeitsfreie Rust-Bibliothek zur einfachen und zuverlässigen +//! Ermittlung des aktuellen Programmnamens (des Dateistamms der ausführbaren Datei). +//! +//! ## Übersicht +//! +//! - [`program_name`]: Gibt den Programmnamen zurück oder `"app"`, falls dieser nicht ermittelt werden kann. +//! - [`try_program_name`]: Gibt den Programmnamen als [`Option`] zurück. +//! - [`program_name_or`]: Gibt den Programmnamen oder einen benutzerdefinierten Fallback zurück. +//! +//! ## Beispiele +//! +//! ```rust +//! use program_ctdra::{program_name, program_name_or, try_program_name}; +//! +//! // Standard-Programmname mit Fallback "app" +//! let name = program_name(); +//! assert!(!name.is_empty()); +//! +//! // Programmname mit benutzerdefiniertem Fallback +//! let custom = program_name_or("mein-dienst"); +//! assert!(!custom.is_empty()); +//! +//! // Optionale Ermittlung ohne Fallback +//! if let Some(prog) = try_program_name() { +//! println!("Ausgeführt als: {prog}"); +//! } +//! ``` + +use std::env; +use std::path::Path; + +/// Ermittelt den Programmnamen (Dateistamm) aus einem übergebenen Pfad. +fn extract_stem_from_path(path: &Path) -> Option { + path.file_stem() + .map(|s| s.to_string_lossy().to_string()) + .filter(|s| !s.is_empty()) +} + +/// Versucht, den Programmnamen (Dateistamm der aktuellen ausführbaren Datei) zu ermitteln. +/// +/// Gibt `Some(String)` zurück, wenn der Pfad der aktuellen Executable ermittelt werden +/// konnte und ein nicht-leerer Dateistamm vorhanden ist, andernfalls `None`. +/// +/// # Beispiele +/// +/// ```rust +/// use program_ctdra::try_program_name; +/// +/// let maybe_name = try_program_name(); +/// // In einer regulären Test- oder Binärumgebung ist der Name in der Regel vorhanden: +/// assert!(maybe_name.is_some()); +/// ``` +#[must_use] +pub fn try_program_name() -> Option { + env::current_exe() + .ok() + .and_then(|p| extract_stem_from_path(&p)) +} + +/// Liefert den Programmnamen (Dateistamm der aktuellen ausführbaren Datei) oder einen Fallback-Wert. +/// +/// # Parameter +/// +/// - `fallback`: Ein Wert, der in ein [`String`] umgewandelt werden kann und verwendet wird, +/// wenn der Programmname nicht ermittelt werden kann. +/// +/// # Beispiele +/// +/// ```rust +/// use program_ctdra::program_name_or; +/// +/// let name = program_name_or("fallback_app"); +/// assert!(!name.is_empty()); +/// ``` +#[must_use] +pub fn program_name_or(fallback: impl Into) -> String { + try_program_name().unwrap_or_else(|| fallback.into()) +} + +/// Liefert den Programmnamen (Dateistamm der aktuellen ausführbaren Datei). +/// +/// # Rückgabewert +/// +/// - Dateistamm der aktuellen Executable als [`String`]. +/// - Fallback `"app"`, wenn der Name nicht ermittelt werden kann. +/// +/// # Beispiele +/// +/// ```rust +/// use program_ctdra::program_name; +/// +/// let name = program_name(); +/// assert!(!name.is_empty()); +/// ``` +#[must_use] +pub fn program_name() -> String { + program_name_or("app") +} + +#[cfg(test)] +mod tests { + use super::*; + use std::path::PathBuf; + + #[test] + fn test_extract_stem_from_path_valid() { + assert_eq!( + extract_stem_from_path(&PathBuf::from("/usr/bin/my-daemon")), + Some("my-daemon".to_string()) + ); + assert_eq!( + extract_stem_from_path(&PathBuf::from("/opt/apps/server.exe")), + Some("server".to_string()) + ); + assert_eq!( + extract_stem_from_path(&PathBuf::from("app.bin")), + Some("app".to_string()) + ); + } + + #[test] + fn test_extract_stem_from_path_empty_or_root() { + assert_eq!(extract_stem_from_path(&PathBuf::from("/")), None); + assert_eq!(extract_stem_from_path(&PathBuf::from("")), None); + } + + #[test] + fn test_program_name_returns_non_empty() { + let name = program_name(); + assert!(!name.is_empty()); + } + + #[test] + fn test_try_program_name_in_test_env() { + let name = try_program_name(); + assert!(name.is_some()); + let name_str = name.unwrap(); + assert!(!name_str.is_empty()); + } + + #[test] + fn test_program_name_or_with_custom_fallback() { + let name = program_name_or("custom_fallback"); + assert!(!name.is_empty()); + } +} diff --git a/tests/integration_test.rs b/tests/integration_test.rs new file mode 100644 index 0000000..7d7be5a --- /dev/null +++ b/tests/integration_test.rs @@ -0,0 +1,22 @@ +use program_ctdra::{program_name, program_name_or, try_program_name}; + +#[test] +fn test_public_api_program_name() { + let name = program_name(); + assert!(!name.is_empty()); +} + +#[test] +fn test_public_api_try_program_name() { + let name = try_program_name(); + assert!(name.is_some()); + if let Some(n) = name { + assert!(!n.is_empty()); + } +} + +#[test] +fn test_public_api_program_name_or() { + let name = program_name_or("fallback_integration_test"); + assert!(!name.is_empty()); +}