diff options
Diffstat (limited to 'pkgs/by-name/ba')
-rw-r--r-- | pkgs/by-name/ba/back/Cargo.lock | 122 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/Cargo.toml | 4 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/contrib/config.json | 4 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/src/cli.rs | 13 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/src/config/mod.rs | 58 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/src/error/mod.rs | 56 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/src/main.rs | 73 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/src/web/format/mod.rs (renamed from pkgs/by-name/ba/back/src/issues/format/mod.rs) | 0 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/src/web/issue/mod.rs (renamed from pkgs/by-name/ba/back/src/issues/issue/mod.rs) | 15 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/src/web/issue/raw.rs (renamed from pkgs/by-name/ba/back/src/issues/issue/raw.rs) | 2 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/src/web/issue_show.rs (renamed from pkgs/by-name/ba/back/src/issues/issue_show.rs) | 0 | ||||
-rw-r--r-- | pkgs/by-name/ba/back/src/web/mod.rs (renamed from pkgs/by-name/ba/back/src/issues/mod.rs) | 35 |
12 files changed, 305 insertions, 77 deletions
diff --git a/pkgs/by-name/ba/back/Cargo.lock b/pkgs/by-name/ba/back/Cargo.lock index ed7f120..b72f23c 100644 --- a/pkgs/by-name/ba/back/Cargo.lock +++ b/pkgs/by-name/ba/back/Cargo.lock @@ -71,6 +71,55 @@ dependencies = [ ] [[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] name = "arc-swap" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -141,11 +190,13 @@ name = "back" version = "0.1.0" dependencies = [ "chrono", + "clap", "gix", "markdown", "rocket", "serde", "serde_json", + "thiserror", "url", ] @@ -247,12 +298,58 @@ dependencies = [ ] [[package]] +name = "clap" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] name = "clru" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbd0f76e066e64fdc5631e3bb46381254deab9ef1158292f27c8c57e3bf3fe59" [[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] name = "cookie" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1470,6 +1567,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1776,6 +1879,12 @@ dependencies = [ ] [[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] name = "itoa" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2549,6 +2658,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] name = "syn" version = "2.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2898,6 +3013,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -2913,6 +3029,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/pkgs/by-name/ba/back/Cargo.toml b/pkgs/by-name/ba/back/Cargo.toml index f697511..2fc0600 100644 --- a/pkgs/by-name/ba/back/Cargo.toml +++ b/pkgs/by-name/ba/back/Cargo.toml @@ -23,12 +23,14 @@ license = "AGPL-3.0-or-later" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] chrono = "0.4.39" +clap = { version = "4.5.23", features = ["derive"] } gix = "0.69.1" markdown = "1.0.0-alpha.21" rocket = "0.5.1" serde = "1.0.216" serde_json = "1.0.134" -url = "2.5.4" +thiserror = "2.0.9" +url = { version = "2.5.4", features = ["serde"] } [profile.release] lto = true diff --git a/pkgs/by-name/ba/back/contrib/config.json b/pkgs/by-name/ba/back/contrib/config.json new file mode 100644 index 0000000..10173fb --- /dev/null +++ b/pkgs/by-name/ba/back/contrib/config.json @@ -0,0 +1,4 @@ +{ + "source_code_repository_url": "https://git.foss-syndicate.org/vhack.eu/nixos-server/tree/pkgs/by-name/ba/back", + "repository_path": "/path/to/your/repository" +} diff --git a/pkgs/by-name/ba/back/src/cli.rs b/pkgs/by-name/ba/back/src/cli.rs new file mode 100644 index 0000000..1820bf3 --- /dev/null +++ b/pkgs/by-name/ba/back/src/cli.rs @@ -0,0 +1,13 @@ +use std::path::PathBuf; + +use clap::Parser; + +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +#[allow(clippy::module_name_repetitions)] +/// An extremely simple git issue tracking system. +/// Inspired by tvix's panettone +pub struct Cli { + /// The path to the configuration file. The file should be written in JSON. + pub config_file: PathBuf, +} diff --git a/pkgs/by-name/ba/back/src/config/mod.rs b/pkgs/by-name/ba/back/src/config/mod.rs new file mode 100644 index 0000000..4986a41 --- /dev/null +++ b/pkgs/by-name/ba/back/src/config/mod.rs @@ -0,0 +1,58 @@ +use std::{ + fs, + path::{Path, PathBuf}, +}; + +use gix::ThreadSafeRepository; +use serde::Deserialize; +use url::Url; + +use crate::error::{self, Error}; + +pub struct BackConfig { + // NOTE(@bpeetz): We do not need to html escape this, as the value must be a valid url. As such + // `<tags>` of all kinds _should_ be invalid. <2024-12-26> + pub source_code_repository_url: Url, + pub repository: ThreadSafeRepository, +} + +#[derive(Deserialize)] +struct RawBackConfig { + source_code_repository_url: Url, + repository_path: PathBuf, +} + +impl BackConfig { + pub fn from_config_file(path: &Path) -> error::Result<Self> { + let value = fs::read_to_string(path).map_err(|err| Error::ConfigRead { + file: path.to_owned(), + error: err, + })?; + + let raw: RawBackConfig = + serde_json::from_str(&value).map_err(|err| Error::ConfigParse { + file: path.to_owned(), + error: err, + })?; + + Self::try_from(raw) + } +} + +impl TryFrom<RawBackConfig> for BackConfig { + type Error = error::Error; + + fn try_from(value: RawBackConfig) -> Result<Self, Self::Error> { + let repository = { + ThreadSafeRepository::open(&value.repository_path).map_err(|err| Error::RepoOpen { + repository_path: value.repository_path, + error: Box::new(err), + }) + }?; + + Ok(Self { + repository, + source_code_repository_url: value.source_code_repository_url, + }) + } +} diff --git a/pkgs/by-name/ba/back/src/error/mod.rs b/pkgs/by-name/ba/back/src/error/mod.rs new file mode 100644 index 0000000..7e1c9cf --- /dev/null +++ b/pkgs/by-name/ba/back/src/error/mod.rs @@ -0,0 +1,56 @@ +use std::{fmt::Display, io, path::PathBuf}; + +use thiserror::Error; + +pub type Result<T> = std::result::Result<T, Error>; + +#[derive(Error, Debug)] +pub enum Error { + ConfigParse { + file: PathBuf, + error: serde_json::Error, + }, + ConfigRead { + file: PathBuf, + error: io::Error, + }, + RepoOpen { + repository_path: PathBuf, + error: Box<gix::open::Error>, + }, + RocketLaunch(#[from] rocket::Error), +} + +impl Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Error::ConfigParse { file, error } => { + write!( + f, + "while trying to parse the config file ({}): {error}", + file.display() + ) + } + Error::ConfigRead { file, error } => { + write!( + f, + "while trying to read the config file ({}): {error}", + file.display() + ) + } + Error::RepoOpen { + repository_path, + error, + } => { + write!( + f, + "while trying to open the repository ({}): {error}", + repository_path.display() + ) + } + Error::RocketLaunch(error) => { + write!(f, "while trying to start back: {error}") + } + } + } +} diff --git a/pkgs/by-name/ba/back/src/main.rs b/pkgs/by-name/ba/back/src/main.rs index 86fe196..e8f36d2 100644 --- a/pkgs/by-name/ba/back/src/main.rs +++ b/pkgs/by-name/ba/back/src/main.rs @@ -9,62 +9,31 @@ // You should have received a copy of the License along with this program. // If not, see <https://www.gnu.org/licenses/agpl.txt>. -use std::{env::args, path::PathBuf, process, sync::OnceLock}; +use clap::Parser; +use config::BackConfig; +use rocket::routes; -use gix::ThreadSafeRepository; -use rocket::{launch, routes}; -use url::Url; +use crate::web::{closed, open, show_issue, styles}; -use crate::issues::{closed, open, show_issue, styles}; +mod cli; +pub mod config; +mod error; +mod web; -mod issues; +#[rocket::main] +async fn main() -> Result<(), error::Error> { + let args = cli::Cli::parse(); -static REPOSITORY: OnceLock<ThreadSafeRepository> = OnceLock::new(); -static SOURCE_CODE_REPOSITORY: OnceLock<Url> = OnceLock::new(); + let config = BackConfig::from_config_file(&args.config_file)?; -#[launch] -fn rocket() -> _ { - let repository_path = { - let maybe_path = args().skip(1).rev().last(); - if let Some(path) = maybe_path { - PathBuf::from(path) - } else { - eprintln!("Usage: back <issue repoitory>"); - process::exit(1); - } - }; - let source_code_url = { - match std::env::var("BACK_SOURCE_CODE_REPOSITORY_URL") { - Ok(value) => match Url::parse(&value) { - Ok(url) => url, - Err(err) => { - eprintln!("Can't parse `BACK_SOURCE_CODE_REPOSITORY_URL` value as url: {err}"); - process::exit(1); - } - }, - Err(err) => { - eprintln!("back needs you to specify a source code repositiory as `BACK_SOURCE_CODE_REPOSITORY_URL`: {err}"); - process::exit(1); - } - } - }; + rocket::build() + .mount("/", routes![open, closed, show_issue, styles]) + .manage(config) + .ignite() + .await + .expect("This error should only happen on a miss-configuration.") + .launch() + .await?; - SOURCE_CODE_REPOSITORY - .set(source_code_url) - .expect("This should be unset by this stage"); - - REPOSITORY - .set( - ThreadSafeRepository::open(&repository_path).unwrap_or_else(|err| { - eprintln!( - "Error while opening repository ('{}'): {} ", - repository_path.display(), - err - ); - process::exit(1); - }), - ) - .expect("There should be only one thread accessing this right now"); - - rocket::build().mount("/", routes![open, closed, show_issue, styles]) + Ok(()) } diff --git a/pkgs/by-name/ba/back/src/issues/format/mod.rs b/pkgs/by-name/ba/back/src/web/format/mod.rs index f78d3b3..f78d3b3 100644 --- a/pkgs/by-name/ba/back/src/issues/format/mod.rs +++ b/pkgs/by-name/ba/back/src/web/format/mod.rs diff --git a/pkgs/by-name/ba/back/src/issues/issue/mod.rs b/pkgs/by-name/ba/back/src/web/issue/mod.rs index b78f473..79ef70f 100644 --- a/pkgs/by-name/ba/back/src/issues/issue/mod.rs +++ b/pkgs/by-name/ba/back/src/web/issue/mod.rs @@ -16,7 +16,7 @@ use gix::{bstr::ByteSlice, Commit, Id, ObjectId, Repository}; use raw::{Operation, RawIssue}; use rocket::response::content::RawHtml; -use crate::SOURCE_CODE_REPOSITORY; +use crate::config::BackConfig; use super::format::{BackString, Markdown}; @@ -114,12 +114,17 @@ impl<'a> Issue<'a> { pub fn from_commit_id(repo: &'a Repository, commit_id: ObjectId) -> Self { fn unwrap_id<'b>(repo: &Repository, id: &Commit<'b>) -> (RawIssue, Id<'b>) { let tree_obj = repo - .find_object(id.tree_id().unwrap()) + .find_object( + id.tree_id() + .expect("All of git-bug's commits should have trees attached to them'"), + ) .expect("The object with this id should exist.") .try_into_tree() .expect("The git-bug's data model enforces this."); - let ops_ref = tree_obj.find_entry("ops").unwrap(); + let ops_ref = tree_obj + .find_entry("ops") + .expect("All of git-bug's trees should contain a 'ops' json file"); let issue_data = repo .find_object(ops_ref.object_id()) @@ -237,7 +242,7 @@ impl<'a> Issue<'a> { )) } - pub fn to_html(&self) -> RawHtml<String> { + pub fn to_html(&self, config: &BackConfig) -> RawHtml<String> { let fmt_comments: String = self .comments .iter() @@ -325,7 +330,7 @@ impl<'a> Issue<'a> { </body> </html> "#, - SOURCE_CODE_REPOSITORY.get().expect("This should be set") + config.source_code_repository_url )) } } diff --git a/pkgs/by-name/ba/back/src/issues/issue/raw.rs b/pkgs/by-name/ba/back/src/web/issue/raw.rs index 48d2a9f..bb447ec 100644 --- a/pkgs/by-name/ba/back/src/issues/issue/raw.rs +++ b/pkgs/by-name/ba/back/src/web/issue/raw.rs @@ -13,7 +13,7 @@ use gix::{bstr::ByteSlice, Repository}; use serde::Deserialize; use serde_json::Value; -use crate::issues::format::BackString; +use crate::web::format::BackString; use super::{Author, Status}; diff --git a/pkgs/by-name/ba/back/src/issues/issue_show.rs b/pkgs/by-name/ba/back/src/web/issue_show.rs index 638840e..638840e 100644 --- a/pkgs/by-name/ba/back/src/issues/issue_show.rs +++ b/pkgs/by-name/ba/back/src/web/issue_show.rs diff --git a/pkgs/by-name/ba/back/src/issues/mod.rs b/pkgs/by-name/ba/back/src/web/mod.rs index 744d5ba..ed91e7e 100644 --- a/pkgs/by-name/ba/back/src/issues/mod.rs +++ b/pkgs/by-name/ba/back/src/web/mod.rs @@ -12,19 +12,17 @@ use std::path::Path; use crate::{ - issues::issue::{Issue, Status}, - SOURCE_CODE_REPOSITORY, + config::BackConfig, + web::issue::{Issue, Status}, }; -use format::BackString; use gix::{refs::Target, Repository}; use issue_show::BackPrefix; use rocket::{ get, response::content::{RawCss, RawHtml}, + State, }; -use crate::REPOSITORY; - mod format; mod issue; mod issue_show; @@ -51,8 +49,12 @@ fn list_all_issues(repo: &'_ Repository) -> Vec<Issue<'_>> { .collect() } -pub fn issue_list_boilerplate(wanted_status: Status, counter_status: Status) -> RawHtml<String> { - let repository = REPOSITORY.get().expect("This should have been set"); +pub fn issue_list_boilerplate( + config: &State<BackConfig>, + wanted_status: Status, + counter_status: Status, +) -> RawHtml<String> { + let repository = &config.repository; let issue_list = list_all_issues(&repository.to_thread_local()) .iter() @@ -94,25 +96,22 @@ pub fn issue_list_boilerplate(wanted_status: Status, counter_status: Status) -> </body> </html> "#, - SOURCE_CODE_REPOSITORY.get().expect("This should be set") + config.source_code_repository_url )) } #[get("/issues/open")] -pub fn open() -> RawHtml<String> { - issue_list_boilerplate(Status::Open, Status::Closed) +pub fn open(config: &State<BackConfig>) -> RawHtml<String> { + issue_list_boilerplate(config, Status::Open, Status::Closed) } #[get("/issues/closed")] -pub fn closed() -> RawHtml<String> { - issue_list_boilerplate(Status::Closed, Status::Open) +pub fn closed(config: &State<BackConfig>) -> RawHtml<String> { + issue_list_boilerplate(config, Status::Closed, Status::Open) } #[get("/issue/<prefix>")] -pub fn show_issue(prefix: BackPrefix) -> RawHtml<String> { - let repository = REPOSITORY - .get() - .expect("This should have been set") - .to_thread_local(); +pub fn show_issue(config: &State<BackConfig>, prefix: BackPrefix) -> RawHtml<String> { + let repository = config.repository.to_thread_local(); let all_issues = list_all_issues(&repository); let maybe_issue = all_issues @@ -120,7 +119,7 @@ pub fn show_issue(prefix: BackPrefix) -> RawHtml<String> { .find(|issue| issue.id.to_string().starts_with(&prefix.to_string())); match maybe_issue { - Some(issue) => issue.to_html(), + Some(issue) => issue.to_html(config), None => RawHtml(format!("Issue with id '{prefix}' not found!")), } } |