Compare commits
9 commits
209e1e58c7
...
78194b69ad
Author | SHA1 | Date | |
---|---|---|---|
Antoine Martin | 78194b69ad | ||
Antoine Martin | 54fafc6a46 | ||
Antoine Martin | aba153726b | ||
Antoine Martin | 422024d919 | ||
Antoine Martin | ff90b5fb2d | ||
8e7e0e9a84 | |||
6f63b4c95c | |||
d38e4556e1 | |||
9de7c783ae |
100
Cargo.lock
generated
100
Cargo.lock
generated
|
@ -56,6 +56,24 @@ dependencies = [
|
||||||
"opaque-debug",
|
"opaque-debug",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.7.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.40"
|
version = "1.0.40"
|
||||||
|
@ -143,6 +161,21 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "2.33.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
|
"atty",
|
||||||
|
"bitflags",
|
||||||
|
"strsim",
|
||||||
|
"textwrap",
|
||||||
|
"unicode-width",
|
||||||
|
"vec_map",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cookie"
|
name = "cookie"
|
||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
|
@ -467,9 +500,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.91"
|
version = "0.2.92"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
|
checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
|
@ -500,13 +533,16 @@ name = "lohr"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"clap",
|
||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
"log 0.4.14",
|
"log 0.4.14",
|
||||||
|
"regex",
|
||||||
"rocket",
|
"rocket",
|
||||||
"rocket_contrib",
|
"rocket_contrib",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serde_regex",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"sha2",
|
"sha2",
|
||||||
]
|
]
|
||||||
|
@ -756,6 +792,23 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rocket"
|
name = "rocket"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
|
@ -860,7 +913,7 @@ checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.65",
|
"syn 1.0.67",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -874,6 +927,16 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_regex"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf"
|
||||||
|
dependencies = [
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_yaml"
|
name = "serde_yaml"
|
||||||
version = "0.8.17"
|
version = "0.8.17"
|
||||||
|
@ -917,6 +980,12 @@ version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483"
|
checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.4.0"
|
version = "2.4.0"
|
||||||
|
@ -936,15 +1005,24 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.65"
|
version = "1.0.67"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
|
checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"unicode-xid 0.2.1",
|
"unicode-xid 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.1.43"
|
version = "0.1.43"
|
||||||
|
@ -1024,6 +1102,12 @@ dependencies = [
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -1057,6 +1141,12 @@ dependencies = [
|
||||||
"percent-encoding 1.0.1",
|
"percent-encoding 1.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
|
|
@ -12,12 +12,15 @@ repository = "https://github.com/alarsyo/lohr"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.40"
|
anyhow = "1.0.40"
|
||||||
|
clap = "2.33.3"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
hmac = "0.10.1"
|
hmac = "0.10.1"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
|
regex = "1"
|
||||||
rocket = "0.4.7"
|
rocket = "0.4.7"
|
||||||
rocket_contrib = { version = "0.4.7", features = [ "json" ] }
|
rocket_contrib = { version = "0.4.7", features = [ "json" ] }
|
||||||
serde = { version = "1.0.125", features = [ "derive" ] }
|
serde = { version = "1.0.125", features = [ "derive" ] }
|
||||||
serde_json = "1.0.64"
|
serde_json = "1.0.64"
|
||||||
|
serde_regex = "1.1.0"
|
||||||
serde_yaml = "0.8.17"
|
serde_yaml = "0.8.17"
|
||||||
sha2 = "0.9.3"
|
sha2 = "0.9.3"
|
||||||
|
|
15
README.org
15
README.org
|
@ -73,8 +73,13 @@ variable.
|
||||||
|
|
||||||
**** Extra remote configuration
|
**** Extra remote configuration
|
||||||
|
|
||||||
=lohr= looks for a =lohr-config.yaml= file in its =LOHR_HOME= directory. This
|
You can provide =lohr= with a YAML file containing additional configuration. You
|
||||||
file takes the following format:
|
can pass its path to the =--config= flag when launching =lohr=. If no
|
||||||
|
configuration is provided via a CLI flag, =lohr= will check the =LOHR_CONFIG=
|
||||||
|
environment variable. If the environment variable isn't set either, it will
|
||||||
|
check in =LOHR_HOME= is a =lohr-config.yaml= file exists, and try to load it.
|
||||||
|
|
||||||
|
This file takes the following format:
|
||||||
|
|
||||||
#+begin_src yaml
|
#+begin_src yaml
|
||||||
default_remotes:
|
default_remotes:
|
||||||
|
@ -83,12 +88,18 @@ default_remotes:
|
||||||
|
|
||||||
additional_remotes:
|
additional_remotes:
|
||||||
- "git@git.sr.ht:~user"
|
- "git@git.sr.ht:~user"
|
||||||
|
|
||||||
|
blacklist:
|
||||||
|
- "private-.*"
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
- ~default_remotes~ is a list of remotes to use if no ~.lohr~ file is found in a
|
- ~default_remotes~ is a list of remotes to use if no ~.lohr~ file is found in a
|
||||||
repository.
|
repository.
|
||||||
- ~additional_remotes~ is a list of remotes to add in any case, whether the
|
- ~additional_remotes~ is a list of remotes to add in any case, whether the
|
||||||
original set of remotes is set via ~default_remotes~ or via a =.lohr= file.
|
original set of remotes is set via ~default_remotes~ or via a =.lohr= file.
|
||||||
|
- ~blacklist~ is a list of regular expressions to match against the full
|
||||||
|
repository names. Any that matches will not be mirrored, even if it contains a
|
||||||
|
`.lohr` file.
|
||||||
|
|
||||||
Both settings take as input a list of "stems", i.e. incomplete remote addresses,
|
Both settings take as input a list of "stems", i.e. incomplete remote addresses,
|
||||||
to which the repo's name will be appended (so for example, if my
|
to which the repo's name will be appended (so for example, if my
|
||||||
|
|
|
@ -37,6 +37,13 @@
|
||||||
defaultPackage = naersk-lib.buildPackage {
|
defaultPackage = naersk-lib.buildPackage {
|
||||||
src = ./.;
|
src = ./.;
|
||||||
pname = "lohr";
|
pname = "lohr";
|
||||||
|
|
||||||
|
meta = with pkgs.lib; {
|
||||||
|
description = "A Git mirroring tool";
|
||||||
|
homepage = "https://github.com/alarsyo/lohr";
|
||||||
|
license = with licenses; [ mit asl20 ];
|
||||||
|
platforms = platforms.unix;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
defaultApp = flake-utils.lib.mkApp {
|
defaultApp = flake-utils.lib.mkApp {
|
||||||
|
|
73
src/main.rs
73
src/main.rs
|
@ -2,17 +2,18 @@
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
mpsc::{channel, Receiver, Sender},
|
mpsc::{channel, Receiver, Sender},
|
||||||
Mutex,
|
Mutex,
|
||||||
};
|
};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use clap::{App, Arg};
|
||||||
|
use log::{error, info};
|
||||||
use rocket::{http::Status, post, routes, State};
|
use rocket::{http::Status, post, routes, State};
|
||||||
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
mod gitea;
|
mod gitea;
|
||||||
use gitea::GiteaWebHook;
|
use gitea::GiteaWebHook;
|
||||||
|
|
||||||
|
@ -29,7 +30,23 @@ struct JobSender(Mutex<Sender<Job>>);
|
||||||
struct Secret(String);
|
struct Secret(String);
|
||||||
|
|
||||||
#[post("/", data = "<payload>")]
|
#[post("/", data = "<payload>")]
|
||||||
fn gitea_webhook(payload: SignedJson<GiteaWebHook>, sender: State<JobSender>) -> Status {
|
fn gitea_webhook(
|
||||||
|
payload: SignedJson<GiteaWebHook>,
|
||||||
|
sender: State<JobSender>,
|
||||||
|
config: State<GlobalSettings>,
|
||||||
|
) -> Status {
|
||||||
|
if config
|
||||||
|
.blacklist
|
||||||
|
.iter()
|
||||||
|
.any(|re| re.is_match(&payload.repository.full_name))
|
||||||
|
{
|
||||||
|
info!(
|
||||||
|
"Ignoring webhook for repo {} which is blacklisted",
|
||||||
|
payload.repository.full_name
|
||||||
|
);
|
||||||
|
return Status::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let sender = sender.0.lock().unwrap();
|
let sender = sender.0.lock().unwrap();
|
||||||
let repo = &payload.repository;
|
let repo = &payload.repository;
|
||||||
|
@ -49,18 +66,46 @@ fn repo_updater(rx: Receiver<Job>, homedir: PathBuf, config: GlobalSettings) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_config(mut path: PathBuf) -> anyhow::Result<GlobalSettings> {
|
fn parse_config(home: &Path, flags: &clap::ArgMatches) -> anyhow::Result<GlobalSettings> {
|
||||||
path.push("lohr-config");
|
// prioritize CLI flag, then env var
|
||||||
path.set_extension("yaml");
|
let config_path = flags.value_of("config").map(PathBuf::from);
|
||||||
let config = if let Ok(file) = File::open(path.as_path()) {
|
let config_path = config_path.or_else(|| env::var("LOHR_CONFIG").map(PathBuf::from).ok());
|
||||||
serde_yaml::from_reader(file)?
|
|
||||||
} else {
|
let file = match config_path {
|
||||||
Default::default()
|
Some(config_path) => File::open(&config_path).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"could not open provided configuration file at {}",
|
||||||
|
config_path.display()
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
None => {
|
||||||
|
// check if file exists in lohr home
|
||||||
|
let config_path = home.join("lohr-config.yaml");
|
||||||
|
if !config_path.is_file() {
|
||||||
|
return Ok(Default::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
File::open(config_path).context("failed to open configuration file in LOHR_HOME")?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(config)
|
|
||||||
|
serde_yaml::from_reader(file).context("could not parse configuration file")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
|
let matches = App::new("lohr")
|
||||||
|
.version("0.3.0")
|
||||||
|
.about("Git mirroring daemon")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("config")
|
||||||
|
.short("c")
|
||||||
|
.long("config")
|
||||||
|
.value_name("FILE")
|
||||||
|
.help("Use a custom config file")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
let (sender, receiver) = channel();
|
let (sender, receiver) = channel();
|
||||||
|
|
||||||
let homedir = env::var("LOHR_HOME").unwrap_or_else(|_| "./".to_string());
|
let homedir = env::var("LOHR_HOME").unwrap_or_else(|_| "./".to_string());
|
||||||
|
@ -70,7 +115,8 @@ fn main() -> anyhow::Result<()> {
|
||||||
let secret = env::var("LOHR_SECRET")
|
let secret = env::var("LOHR_SECRET")
|
||||||
.expect("please provide a secret, otherwise anyone can send you a malicious webhook");
|
.expect("please provide a secret, otherwise anyone can send you a malicious webhook");
|
||||||
|
|
||||||
let config = parse_config(homedir.clone())?;
|
let config = parse_config(&homedir, &matches)?;
|
||||||
|
let config_state = config.clone();
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
repo_updater(receiver, homedir, config);
|
repo_updater(receiver, homedir, config);
|
||||||
|
@ -80,6 +126,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
.mount("/", routes![gitea_webhook])
|
.mount("/", routes![gitea_webhook])
|
||||||
.manage(JobSender(Mutex::new(sender)))
|
.manage(JobSender(Mutex::new(sender)))
|
||||||
.manage(Secret(secret))
|
.manage(Secret(secret))
|
||||||
|
.manage(config_state)
|
||||||
.launch();
|
.launch();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -2,7 +2,7 @@ use serde::Deserialize;
|
||||||
|
|
||||||
pub(crate) type RepoUrl = String; // FIXME: probably needs a better type than this
|
pub(crate) type RepoUrl = String; // FIXME: probably needs a better type than this
|
||||||
|
|
||||||
#[derive(Default, Deserialize)]
|
#[derive(Clone, Default, Deserialize)]
|
||||||
pub(crate) struct GlobalSettings {
|
pub(crate) struct GlobalSettings {
|
||||||
/// List of remote stems to use when no `.lohr` file is found
|
/// List of remote stems to use when no `.lohr` file is found
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
@ -10,4 +10,8 @@ pub(crate) struct GlobalSettings {
|
||||||
/// List of remote stems to use for every repository
|
/// List of remote stems to use for every repository
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub additional_remotes: Vec<RepoUrl>,
|
pub additional_remotes: Vec<RepoUrl>,
|
||||||
|
/// List of regexes, if a repository's name matches any of the, it is not mirrored by `lohr`
|
||||||
|
/// even if it contains a `.lorh` file.
|
||||||
|
#[serde(with = "serde_regex")]
|
||||||
|
pub blacklist: Vec<regex::Regex>,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue