wayver's git archive


a simple self-hosted git server
git clone https://git.wayver.dev/bile

Commit: bd1a8f79badd439ab7a73e193be91ad175aafa67 (tree)
Parent: db2bc30f716095872b4ea33adafe072c0a8a7242 (tree)
Author: wayverd
Date: 2026 M02 17, Tue 22:18:00 -0500
3 files changed; 90 insertions 74 deletions
restructured bile library

it is now a struct to attempt to prevent multiple config sets

also renamed the commit variable in the git commit util to fix the variable shadowing lint

diff --git a/src/lib.rs b/src/lib.rs
index 748d757..d205dbd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -267,82 +267,96 @@ static STYLE_CSS: &str = include_str!("../assets/style.css");
 
 static META_PACKAGE_VERSION: &str = env!("CARGO_PKG_VERSION");
 
-pub fn config() -> &'static Config {
+pub(crate) fn config() -> &'static Config {
     CONFIG
         .get()
         .unwrap_or_else(|| unreachable!("failed to get global config, this should not happen"))
 }
 
-pub fn set_config(config: Config) {
-    CONFIG.set(config).expect("config already set");
-}
+#[allow(missing_copy_implementations, clippy::empty_structs_with_brackets)]
+pub struct Bile {}
+
+impl Bile {
+    /// Create a new Bile 'instance'
+    ///
+    /// # Panics
+    ///
+    /// This will panic if you create multiple Bile instances.
+    ///
+    /// Which you shouldn't BTW.
+    pub fn init(config: Config) -> Self {
+        CONFIG.set(config).expect("config already set");
+
+        Self {}
+    }
 
-#[rustfmt::skip]
-pub fn routes() -> Router {
-    // let backend = MokaBackend::builder().max_entries(10_000).build();
+    #[rustfmt::skip]
+    pub fn routes(&self) -> Router {
+        // let backend = MokaBackend::builder().max_entries(10_000).build();
 
-    // let config = hitbox::Config::builder()
-    //     .request_predicate(predicates::request::Method::new(http::Method::GET).unwrap())
-    //     .response_predicate(hitbox::Neutral::new().status_code_class(predicates::response::StatusClass::Success))
-    //     .extractor(extractors::Method::new())
-    //     .policy(
-    //         hitbox::policy::PolicyConfig::builder()
-    //             .ttl(Duration::from_secs(60))
-    //             .stale(Duration::from_secs(30))
-    //             .build(),
-    //     )
-    //     .build();
+        // let config = hitbox::Config::builder()
+        //     .request_predicate(predicates::request::Method::new(http::Method::GET).unwrap())
+        //     .response_predicate(hitbox::Neutral::new().status_code_class(predicates::response::StatusClass::Success))
+        //     .extractor(extractors::Method::new())
+        //     .policy(
+        //         hitbox::policy::PolicyConfig::builder()
+        //             .ttl(Duration::from_secs(60))
+        //             .stale(Duration::from_secs(30))
+        //             .build(),
+        //     )
+        //     .build();
 
-    // let cache = hitbox_tower::Cache::builder()
-    //     .backend(backend.clone())
-    //     .config(config)
-    //     .build();
+        // let cache = hitbox_tower::Cache::builder()
+        //     .backend(backend.clone())
+        //     .config(config)
+        //     .build();
 
-    Router::new()
-        .route("/", get(handlers::index::get))
-        // assets
-        .route("/apple-touch-icon.png", get(async || Png(APPLE_TOUCH_ICON_PNG)))
-        .route("/favicon.ico", get(async || Ico(FAVICON_ICO)))
-        .route("/icon-192-maskable.png", get(async || Png(ICON_192_MASKABLE)))
-        .route("/icon-192.png", get(async || Png(ICON_192)))
-        .route("/icon-512-maskable.png", get(async || Png(ICON_512_MASKABLE)))
-        .route("/icon-512.png", get(async || Png(ICON_512)))
-        .route("/manifest.json", get(async || Json(MANIFEST_JSON)))
-        .route("/robots.txt", get(async || Text(ROBOTS_TXT)))
-        .route("/style.css", get(async || Css(STYLE_CSS)))
-        //
-        .route("/{repo_name}", get(handlers::repo_home::get))
-        .route("/{repo_name}/", get(handlers::repo_home::get))
-        // git clone stuff
-        .route("/{repo_name}/info/refs", get(handlers::git::get_1))
-        .route("/{repo_name}/HEAD", get(handlers::git::get_1))
-        .route("/{repo_name}/objects/{*obj}", get(handlers::git::get_2))
-        // web pages
-        .route("/{repo_name}/commit/{commit}", get(handlers::repo_commit::get))
-        .route("/{repo_name}/refs", get(handlers::repo_refs::get))
-        .route("/{repo_name}/refs/", get(handlers::repo_refs::get))
-        .route("/{repo_name}/refs.xml", get(handlers::repo_refs_feed::get))
-        .route("/{repo_name}/refs/{tag}", get(handlers::repo_tag::get))
-        //
-        .route("/{repo_name}/log", get(handlers::repo_log::get_1))
-        .route("/{repo_name}/log/", get(handlers::repo_log::get_1))
-        .route("/{repo_name}/log.xml", get(handlers::repo_log_feed::get_1))
-        .route("/{repo_name}/log/{ref}", get(handlers::repo_log::get_2))
-        .route("/{repo_name}/log/{ref}/", get(handlers::repo_log::get_2))
-        .route("/{repo_name}/log/{ref}/feed.xml", get(handlers::repo_log_feed::get_2))
-        .route("/{repo_name}/log/{ref}/{*object_name}", get(handlers::repo_log::get_3))
-        //
-        .route("/{repo_name}/tree", get(handlers::repo_file::get_1))
-        .route("/{repo_name}/tree/", get(handlers::repo_file::get_1))
-        .route("/{repo_name}/tree/{ref}", get(handlers::repo_file::get_2))
-        .route("/{repo_name}/tree/{ref}/", get(handlers::repo_file::get_2))
-        .route("/{repo_name}/tree/{ref}/item/{*object_name}", get(handlers::repo_file::get_3))
-        .route("/{repo_name}/tree/{ref}/raw/{*object_name}", get(handlers::repo_file_raw::get))
-        //
-        .layer((
-            TraceLayer::new_for_http(),
-            TimeoutLayer::with_status_code(StatusCode::REQUEST_TIMEOUT, Duration::from_secs(10)),
-            CacheLayer::with_lifespan(Duration::from_secs(60)).use_stale_on_failure(),
-            HelmetLayer::with_defaults(),
-        ))
+        Router::new()
+            .route("/", get(handlers::index::get))
+            // assets
+            .route("/apple-touch-icon.png", get(async || Png(APPLE_TOUCH_ICON_PNG)))
+            .route("/favicon.ico", get(async || Ico(FAVICON_ICO)))
+            .route("/icon-192-maskable.png", get(async || Png(ICON_192_MASKABLE)))
+            .route("/icon-192.png", get(async || Png(ICON_192)))
+            .route("/icon-512-maskable.png", get(async || Png(ICON_512_MASKABLE)))
+            .route("/icon-512.png", get(async || Png(ICON_512)))
+            .route("/manifest.json", get(async || Json(MANIFEST_JSON)))
+            .route("/robots.txt", get(async || Text(ROBOTS_TXT)))
+            .route("/style.css", get(async || Css(STYLE_CSS)))
+            //
+            .route("/{repo_name}", get(handlers::repo_home::get))
+            .route("/{repo_name}/", get(handlers::repo_home::get))
+            // git clone stuff
+            .route("/{repo_name}/info/refs", get(handlers::git::get_1))
+            .route("/{repo_name}/HEAD", get(handlers::git::get_1))
+            .route("/{repo_name}/objects/{*obj}", get(handlers::git::get_2))
+            // web pages
+            .route("/{repo_name}/commit/{commit}", get(handlers::repo_commit::get))
+            .route("/{repo_name}/refs", get(handlers::repo_refs::get))
+            .route("/{repo_name}/refs/", get(handlers::repo_refs::get))
+            .route("/{repo_name}/refs.xml", get(handlers::repo_refs_feed::get))
+            .route("/{repo_name}/refs/{tag}", get(handlers::repo_tag::get))
+            //
+            .route("/{repo_name}/log", get(handlers::repo_log::get_1))
+            .route("/{repo_name}/log/", get(handlers::repo_log::get_1))
+            .route("/{repo_name}/log.xml", get(handlers::repo_log_feed::get_1))
+            .route("/{repo_name}/log/{ref}", get(handlers::repo_log::get_2))
+            .route("/{repo_name}/log/{ref}/", get(handlers::repo_log::get_2))
+            .route("/{repo_name}/log/{ref}/feed.xml", get(handlers::repo_log_feed::get_2))
+            .route("/{repo_name}/log/{ref}/{*object_name}", get(handlers::repo_log::get_3))
+            //
+            .route("/{repo_name}/tree", get(handlers::repo_file::get_1))
+            .route("/{repo_name}/tree/", get(handlers::repo_file::get_1))
+            .route("/{repo_name}/tree/{ref}", get(handlers::repo_file::get_2))
+            .route("/{repo_name}/tree/{ref}/", get(handlers::repo_file::get_2))
+            .route("/{repo_name}/tree/{ref}/item/{*object_name}", get(handlers::repo_file::get_3))
+            .route("/{repo_name}/tree/{ref}/raw/{*object_name}", get(handlers::repo_file_raw::get))
+            //
+            .layer((
+                TraceLayer::new_for_http(),
+                TimeoutLayer::with_status_code(StatusCode::REQUEST_TIMEOUT, Duration::from_secs(10)),
+                CacheLayer::with_lifespan(Duration::from_secs(60)).use_stale_on_failure(),
+                HelmetLayer::with_defaults(),
+            ))
+    }
 }
diff --git a/src/main.rs b/src/main.rs
index a5c051f..41b00eb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,6 @@
 #![deny(rust_2018_idioms, unsafe_code)]
 
-use bile::config::Config;
+use bile::{Bile, config::Config};
 use tracing_subscriber::{layer::SubscriberExt as _, util::SubscriberInitExt as _};
 
 #[tokio::main]
@@ -32,9 +32,9 @@ async fn main() -> bile::utils::error::Result<()> {
 
     let addr = format!("[::]:{}", config.port);
 
-    bile::set_config(config.finalize()?);
+    let bile = Bile::init(config.finalize()?);
 
-    let app = bile::routes();
+    let app = bile.routes();
 
     let listener = tokio::net::TcpListener::bind(addr).await?;
     tracing::info!("listening on {}", listener.local_addr()?);
diff --git a/src/utils/git/commit.rs b/src/utils/git/commit.rs
index 793715c..6d79c61 100644
--- a/src/utils/git/commit.rs
+++ b/src/utils/git/commit.rs
@@ -217,7 +217,7 @@ impl Repository {
         let mut options = DiffOptions::new();
         options.pathspec(path.into_c_string()?);
 
-        let commit = revwalk
+        let last_commit = revwalk
             .filter_map(|oid| oid.ok().and_then(|oid| self.inner.find_commit(oid).ok()))
             .find(|walked_commit| {
                 let commit_tree = match walked_commit.tree() {
@@ -270,6 +270,8 @@ impl Repository {
                 }
             });
 
-        Ok(Some(commit.context("file was not part of any commit")?))
+        Ok(Some(
+            last_commit.context("file was not part of any commit")?,
+        ))
     }
 }