WIP: lohr: add default and additional remotes

Test
This commit is contained in:
Bruno BELANYI 2021-03-29 19:18:00 +02:00
parent ae3ab8c893
commit 274d1cedb6
5 changed files with 100 additions and 29 deletions

34
Cargo.lock generated
View file

@ -231,6 +231,12 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "dtoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
[[package]] [[package]]
name = "filetime" name = "filetime"
version = "0.2.14" version = "0.2.14"
@ -459,6 +465,12 @@ version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]] [[package]]
name = "log" name = "log"
version = "0.3.9" version = "0.3.9"
@ -486,6 +498,7 @@ dependencies = [
"rocket", "rocket",
"rocket_contrib", "rocket_contrib",
"serde", "serde",
"serde_yaml",
] ]
[[package]] [[package]]
@ -851,6 +864,18 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_yaml"
version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
dependencies = [
"dtoa",
"linked-hash-map",
"serde",
"yaml-rust",
]
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.9.3" version = "0.9.3"
@ -1104,6 +1129,15 @@ dependencies = [
"winapi-build", "winapi-build",
] ]
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]] [[package]]
name = "yansi" name = "yansi"
version = "0.5.0" version = "0.5.0"

View file

@ -14,3 +14,4 @@ log = "0.4.14"
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_yaml = "0.8.17"

View file

@ -8,6 +8,7 @@ use anyhow::bail;
use log::info; use log::info;
use crate::gitea::Repository; use crate::gitea::Repository;
use crate::settings::{GlobalSettings, RepoUrl};
pub(crate) struct Job { pub(crate) struct Job {
repo: Repository, repo: Repository,
@ -91,34 +92,37 @@ impl Job {
Ok(()) Ok(())
} }
fn get_remotes(&self) -> anyhow::Result<String> { fn get_remotes(&self, config: &GlobalSettings) -> anyhow::Result<Vec<RepoUrl>> {
let output = Command::new("git") let local_path = self.local_path.as_ref().unwrap();
.arg("-C")
.arg(format!("{}", self.local_path.as_ref().unwrap().display()))
.arg("show")
.arg("HEAD:.lohr")
.output()?;
if !output.status.success() { let stem_to_repo = |stem: &RepoUrl| -> RepoUrl {
let error = str::from_utf8(&output.stderr)?; let mut res = stem.clone();
let code = output if !res.ends_with('/') {
.status res.push('/');
.code() };
.unwrap_or_else(|| output.status.signal().unwrap()); res.push_str(local_path.file_name().unwrap().to_str().unwrap());
res
};
bail!( let mut remotes: Vec<_> = {
"couldn't read .lohr file from repo {}: exit code {}, stderr:\n{}", let mut path_to_dot_lohr = local_path.clone();
self.repo.full_name, path_to_dot_lohr.push(".lohr");
code,
error
);
}
Ok(String::from_utf8(output.stdout)?) if let Ok(contents) = std::fs::read(path_to_dot_lohr.as_path()) {
let contents = String::from_utf8(contents)?;
contents.lines().map(String::from).collect()
} else {
config.default_remotes.iter().map(stem_to_repo).collect()
}
};
remotes.append(&mut config.additional_remotes.iter().map(stem_to_repo).collect());
Ok(remotes)
} }
fn update_mirrors(&self) -> anyhow::Result<()> { fn update_mirrors(&self, config: &GlobalSettings) -> anyhow::Result<()> {
for remote in self.get_remotes()?.lines() { for remote in &self.get_remotes(config)? {
info!("Updating mirror {}:{}...", remote, self.repo.full_name); info!("Updating mirror {}:{}...", remote, self.repo.full_name);
let output = Command::new("git") let output = Command::new("git")
@ -148,7 +152,7 @@ impl Job {
Ok(()) Ok(())
} }
pub(crate) fn run(&mut self, homedir: &Path) -> anyhow::Result<()> { pub(crate) fn run(&mut self, homedir: &Path, config: &GlobalSettings) -> anyhow::Result<()> {
let local_path = homedir.join(&self.repo.full_name); let local_path = homedir.join(&self.repo.full_name);
assert!(local_path.is_absolute()); assert!(local_path.is_absolute());
self.local_path = Some(local_path); self.local_path = Some(local_path);
@ -159,6 +163,6 @@ impl Job {
self.update_repo()?; self.update_repo()?;
} }
self.update_mirrors() self.update_mirrors(config)
} }
} }

View file

@ -1,6 +1,7 @@
#![feature(proc_macro_hygiene, decl_macro)] #![feature(proc_macro_hygiene, decl_macro)]
use std::env; use std::env;
use std::fs::File;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{ use std::sync::{
mpsc::{channel, Receiver, Sender}, mpsc::{channel, Receiver, Sender},
@ -19,6 +20,9 @@ use gitea::GiteaWebHook;
mod job; mod job;
use job::Job; use job::Job;
mod settings;
use settings::GlobalSettings;
struct JobSender(Mutex<Sender<Job>>); struct JobSender(Mutex<Sender<Job>>);
#[post("/", data = "<payload>")] #[post("/", data = "<payload>")]
@ -32,29 +36,44 @@ fn gitea_webhook(payload: Json<GiteaWebHook>, sender: State<JobSender>) -> Statu
Status::Ok Status::Ok
} }
fn repo_updater(rx: Receiver<Job>, homedir: PathBuf) { fn repo_updater(rx: Receiver<Job>, homedir: PathBuf, config: GlobalSettings) {
loop { loop {
let mut job = rx.recv().unwrap(); let mut job = rx.recv().unwrap();
if let Err(err) = job.run(&homedir) { if let Err(err) = job.run(&homedir, &config) {
error!("couldn't process job: {}", err); error!("couldn't process job: {}", err);
} }
} }
} }
fn main() { fn parse_config(mut path: PathBuf) -> anyhow::Result<GlobalSettings> {
path.push("lohr-config");
path.set_extension("yaml");
let config = if let Ok(file) = File::open(path.as_path()) {
serde_yaml::from_reader(file)?
} else {
Default::default()
};
Ok(config)
}
fn main() -> anyhow::Result<()> {
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());
let homedir: PathBuf = homedir.into(); let homedir: PathBuf = homedir.into();
let homedir = homedir.canonicalize().expect("LOHR_HOME isn't valid!"); let homedir = homedir.canonicalize().expect("LOHR_HOME isn't valid!");
let config = parse_config(homedir.clone())?;
thread::spawn(move || { thread::spawn(move || {
repo_updater(receiver, homedir); repo_updater(receiver, homedir, config);
}); });
rocket::ignite() rocket::ignite()
.mount("/", routes![gitea_webhook]) .mount("/", routes![gitea_webhook])
.manage(JobSender(Mutex::new(sender))) .manage(JobSender(Mutex::new(sender)))
.launch(); .launch();
Ok(())
} }

13
src/settings.rs Normal file
View file

@ -0,0 +1,13 @@
use serde::Deserialize;
pub(crate) type RepoUrl = String; // FIXME: probably needs a better type than this
#[derive(Default, Deserialize)]
pub(crate) struct GlobalSettings {
/// List of remote stems to use when no `.lohr` file is found
#[serde(default)]
pub default_remotes: Vec<RepoUrl>,
/// List of remote stems to use for every repository
#[serde(default)]
pub additional_remotes: Vec<RepoUrl>,
}