1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
// Back - An extremely simple git issue tracking system. Inspired by tvix's
// panettone
//
// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This file is part of Back.
//
// 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 gix::ThreadSafeRepository;
use rocket::{launch, routes};
use url::Url;
use crate::issues::{closed, open, show_issue, styles};
mod issues;
static REPOSITORY: OnceLock<ThreadSafeRepository> = OnceLock::new();
static SOURCE_CODE_REPOSITORY: OnceLock<Url> = OnceLock::new();
#[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);
}
}
};
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])
}
|