diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-04-10 19:26:23 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-04-10 19:26:23 +0000 |
| commit | 8aef478c6b1e9e3f6ebbad6d57f59f1a84a261ea (patch) | |
| tree | 2aa56188b13fc4b8e6a2fdf302dea19afb65a5a7 /src/main.rs | |
| parent | 2161e3c0a8169a85111cd6dc01ffe2b0fed1493f (diff) | |
feat: add cleanup-empty-repos subcommand to remove stale events for empty git repos
Adds a maintenance subcommand that scans the LMDB database for kind 30617
(repository announcement) events whose bare git repo on disk is empty or
missing, then removes both the 30617 and any matching 30618 (state) events.
A relay should not serve announcement or state events for a repository with
no git data. This was needed to clean up repos leaked by the bug fixed in
2161e3c, and is useful as an ongoing maintenance tool.
Usage (dry-run by default, stop relay before --execute):
ngit-grasp cleanup-empty-repos [--relay-data-path <path>] [--git-data-path <path>] [--execute]
The relay itself is now invoked as an implicit 'serve' subcommand, preserving
full backward compatibility with existing deployments and env-var configuration.
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 57 |
1 files changed, 55 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs index 12a875c..bc77fcb 100644 --- a/src/main.rs +++ b/src/main.rs | |||
| @@ -2,12 +2,14 @@ use std::time::Duration; | |||
| 2 | use std::{path::PathBuf, sync::Arc}; | 2 | use std::{path::PathBuf, sync::Arc}; |
| 3 | 3 | ||
| 4 | use anyhow::Result; | 4 | use anyhow::Result; |
| 5 | use clap::Parser; | ||
| 5 | use tokio::signal; | 6 | use tokio::signal; |
| 6 | use tracing::{error, info, warn}; | 7 | use tracing::{error, info, warn}; |
| 7 | use tracing_subscriber::{EnvFilter, FmtSubscriber}; | 8 | use tracing_subscriber::{EnvFilter, FmtSubscriber}; |
| 8 | 9 | ||
| 9 | use ngit_grasp::{ | 10 | use ngit_grasp::{ |
| 10 | audit_cleanup, | 11 | audit_cleanup, |
| 12 | cleanup_empty_repos, | ||
| 11 | config::{Config, DatabaseBackend}, | 13 | config::{Config, DatabaseBackend}, |
| 12 | git, http, | 14 | git, http, |
| 13 | metrics::Metrics, | 15 | metrics::Metrics, |
| @@ -16,10 +18,61 @@ use ngit_grasp::{ | |||
| 16 | sync::{naughty_list::NaughtyListTracker, SyncManager}, | 18 | sync::{naughty_list::NaughtyListTracker, SyncManager}, |
| 17 | }; | 19 | }; |
| 18 | 20 | ||
| 21 | /// Top-level CLI dispatcher. | ||
| 22 | /// | ||
| 23 | /// With no subcommand the binary runs the relay (all relay flags apply). | ||
| 24 | /// With a subcommand it runs the requested maintenance tool instead. | ||
| 25 | #[derive(Debug, Parser)] | ||
| 26 | #[command(author, version, about = "ngit-grasp GRASP relay", long_about = None)] | ||
| 27 | #[command(propagate_version = true)] | ||
| 28 | enum Cli { | ||
| 29 | /// Run the GRASP relay server (default when no subcommand is given). | ||
| 30 | #[command(name = "serve")] | ||
| 31 | Serve(Config), | ||
| 32 | |||
| 33 | /// Remove kind 30617/30618 events whose bare git repository is empty or missing. | ||
| 34 | /// | ||
| 35 | /// Runs in dry-run mode by default. Pass --execute to make changes. | ||
| 36 | /// Stop the relay service before running with --execute. | ||
| 37 | CleanupEmptyRepos(cleanup_empty_repos::CleanupArgs), | ||
| 38 | } | ||
| 39 | |||
| 19 | #[tokio::main] | 40 | #[tokio::main] |
| 20 | async fn main() -> Result<()> { | 41 | async fn main() -> Result<()> { |
| 21 | // Load configuration first (priority: CLI flags > env vars > .env file > defaults) | 42 | // Load .env file before clap parses, so env vars are available. |
| 22 | let config = Config::load()?; | 43 | dotenvy::dotenv().ok(); |
| 44 | |||
| 45 | // Peek at argv[1] to decide whether a subcommand was explicitly provided. | ||
| 46 | // If not, prepend the implicit "serve" subcommand so that clap routes to Cli::Serve | ||
| 47 | // and all relay flags are parsed normally (preserving backward compatibility). | ||
| 48 | let mut args: Vec<String> = std::env::args().collect(); | ||
| 49 | let known_subcommands = ["serve", "cleanup-empty-repos", "help"]; | ||
| 50 | let has_subcommand = args.get(1).map_or(false, |a| { | ||
| 51 | known_subcommands.contains(&a.as_str()) | ||
| 52 | || matches!(a.as_str(), "-h" | "--help" | "-V" | "--version") | ||
| 53 | }); | ||
| 54 | if !has_subcommand { | ||
| 55 | args.insert(1, "serve".to_string()); | ||
| 56 | } | ||
| 57 | |||
| 58 | match Cli::parse_from(args) { | ||
| 59 | Cli::CleanupEmptyRepos(cleanup_args) => { | ||
| 60 | cleanup_empty_repos::run(&cleanup_args).await | ||
| 61 | } | ||
| 62 | Cli::Serve(mut config) => { | ||
| 63 | // Finish initialising the Config (load relay owner key if not provided). | ||
| 64 | if config.relay_owner_nsec.is_none() { | ||
| 65 | config.relay_owner_nsec = Some(Config::load_or_generate_relay_owner_key()?); | ||
| 66 | } else { | ||
| 67 | config.relay_owner_nsec = | ||
| 68 | config.relay_owner_nsec.take().map(|s| s.trim().to_string()); | ||
| 69 | } | ||
| 70 | run_relay(config).await | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | async fn run_relay(config: Config) -> Result<()> { | ||
| 23 | 76 | ||
| 24 | // Initialize tracing with configured log level | 77 | // Initialize tracing with configured log level |
| 25 | let subscriber = FmtSubscriber::builder() | 78 | let subscriber = FmtSubscriber::builder() |