diff --git a/.github/workflows/cachix.yaml b/.github/workflows/cachix.yaml deleted file mode 100644 index 3edb139..0000000 --- a/.github/workflows/cachix.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: "Cachix build" -on: [push] -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2.3.4 - - uses: cachix/install-nix-action@v13 - with: - install_url: https://nixos-nix-install-tests.cachix.org/serve/lb41az54kzk6j12p81br4bczary7m145/install - install_options: '--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve' - extra_nix_config: | - experimental-features = nix-command flakes - - uses: cachix/cachix-action@v8 - with: - name: alarsyo - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - - run: | - nix build --verbose diff --git a/Cargo.lock b/Cargo.lock index 365f914..2d4247d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -241,9 +241,9 @@ dependencies = [ [[package]] name = "figment" -version = "0.10.5" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca029e813a72b7526d28273d25f3e4a2f365d1b7a1018a6f93ec9053a119763" +checksum = "708a94ecb9ca72e347442fef4563e459035b950c78091a355ed8a40180b33367" dependencies = [ "atomic", "pear", @@ -443,9 +443,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.4" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" +checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" dependencies = [ "bytes", "fnv", @@ -465,9 +465,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.3.6" +version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc35c995b9d93ec174cf9a27d425c7892722101e14993cd227fdb51d70cf9589" +checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691" [[package]] name = "httpdate" @@ -539,9 +539,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.93" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "linked-hash-map" @@ -551,9 +551,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" dependencies = [ "scopeguard", ] @@ -569,7 +569,7 @@ dependencies = [ [[package]] name = "lohr" -version = "0.4.0" +version = "0.3.1" dependencies = [ "anyhow", "clap", @@ -788,9 +788,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] @@ -915,7 +915,7 @@ dependencies = [ [[package]] name = "rocket" version = "0.5.0-dev" -source = "git+https://github.com/SergioBenitez/Rocket?rev=8d4d01106e2e10b08100805d40bfa19a7357e900#8d4d01106e2e10b08100805d40bfa19a7357e900" +source = "git+https://github.com/SergioBenitez/Rocket?rev=2893ce754d6535e0a752586e60d7e292343016c0#2893ce754d6535e0a752586e60d7e292343016c0" dependencies = [ "async-trait", "atomic", @@ -948,7 +948,7 @@ dependencies = [ [[package]] name = "rocket_codegen" version = "0.5.0-dev" -source = "git+https://github.com/SergioBenitez/Rocket?rev=8d4d01106e2e10b08100805d40bfa19a7357e900#8d4d01106e2e10b08100805d40bfa19a7357e900" +source = "git+https://github.com/SergioBenitez/Rocket?rev=2893ce754d6535e0a752586e60d7e292343016c0#2893ce754d6535e0a752586e60d7e292343016c0" dependencies = [ "devise", "glob", @@ -961,7 +961,7 @@ dependencies = [ [[package]] name = "rocket_http" version = "0.5.0-dev" -source = "git+https://github.com/SergioBenitez/Rocket?rev=8d4d01106e2e10b08100805d40bfa19a7357e900#8d4d01106e2e10b08100805d40bfa19a7357e900" +source = "git+https://github.com/SergioBenitez/Rocket?rev=2893ce754d6535e0a752586e60d7e292343016c0#2893ce754d6535e0a752586e60d7e292343016c0" dependencies = [ "cookie", "either", @@ -1219,9 +1219,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.68" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" dependencies = [ "proc-macro2", "quote", @@ -1401,9 +1401,9 @@ dependencies = [ [[package]] name = "uncased" -version = "0.9.6" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baeed7327e25054889b9bd4f975f32e5f4c5d434042d59ab6cd4142c0a76ed0" +checksum = "300932469d646d39929ffe84ad5c1837beecf602519ef5695e485b472de4082b" dependencies = [ "serde", "version_check", diff --git a/Cargo.toml b/Cargo.toml index 83eefef..9ee6f4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lohr" -version = "0.4.0" +version = "0.3.1" authors = ["Antoine Martin "] edition = "2018" license = "Apache-2.0 OR MIT" @@ -33,4 +33,4 @@ version = "2.33.3" default-features = false [patch.crates-io] -rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "8d4d01106e2e10b08100805d40bfa19a7357e900" } +rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "2893ce754d6535e0a752586e60d7e292343016c0" } diff --git a/README.md b/README.md deleted file mode 100644 index 9abfe4a..0000000 --- a/README.md +++ /dev/null @@ -1,138 +0,0 @@ -# lohr - -`lohr` is a Git mirroring tool. - -I created it to solve a simple problem I had: I host my own git server at -, but want to mirror my public projects to GitHub / -GitLab, for backup and visibility purposes. - -GitLab has a mirroring setting, but it doesn't allow for multiple mirrors, as -far as I know. I also wanted my instance to be the single source of truth. - -## How it works - -Gitea is setup to send webhooks to my `lohr` server on every push update. When -`lohr` receives a push, it clones the concerned repository, or updates it if -already cloned. Then it pushes the update to **all remotes listed** in the -[.lohr](.lohr) file at the repo root. - -### Destructive - -This is a very destructive process: anything removed from the single source of -truth is effectively removed from any mirror as well. - -## Installing - -`lohr` is [published on crates.io](https://crates.io/crates/lohr), so you can -install it with `cargo install`: - - $ cargo install lohr - -Note: currently this method won't get you the latest version of `lohr`, as it -depends on Rocket v0.5.0, which isn't released yet. Updated versions of `lohr` -will be published on crates.io as soon as Rocket v0.5.0 releases. - -## Setup - -### Quickstart - -Setting up `lohr` should be quite simple: - -1. Create a `Rocket.toml` file and [add your - configuration](https://rocket.rs/v0.4/guide/configuration/). - -2. Export a secret variable: - - $ export LOHR_SECRET=42 # please don't use this secret - -3. Run `lohr`: - - $ cargo run # or `cargo run --release` for production usage - -4. Configure your favorite git server to send a webhook to `lohr`'s address on - every push event. - - I used [Gitea's webhooks format](https://docs.gitea.io/en-us/webhooks/), but - I **think** they're similar to GitHub and GitLab's webhooks, so these should - work too! (If they don't, **please** file an issue!) - - Don't forget to set the webhook secret to the one you chose above. - -5. Add a `.lohr` file containing the remotes you want to mirror this repo to: - - git@github.com:you/your_repo - - and push it. That's it! `lohr` is mirroring your repo now. - - -### Configuration - -#### Home directory - -`lohr` needs a place to clone repos and store its data. By default, it's the -current directory, but you can set the `LOHR_HOME` environment variable to -customize it. - -#### Shared secret - -As shown in the quickstart guide, you **must** set the `LOHR_SECRET` environment -variable. - -#### Extra remote configuration - -You can provide `lohr` with a YAML file containing additional configuration. You -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: - -``` yaml -default_remotes: - - "git@github:user" - - "git@gitlab:user" - -additional_remotes: - - "git@git.sr.ht:~user" - -filters: - - FIXME: -``` - -- `default_remotes` is a list of remotes to use if no `.lohr` file is found in a - repository. -- `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. -- `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, -to which the repo's name will be appended (so for example, if my -`default_remotes` contains `git@github.com:alarsyo`, and a push event webhook is -received for repository `git@gitlab.com:some/long/path/repo_name`, then the -mirror destination will be `git@github.com:alarsyo/repo_name`. - -## Contributing - -I accept patches anywhere! Feel free to [open a GitHub Pull -Request](https://github.com/alarsyo/lohr/pulls), [a GitLab Merge -Request](https://gitlab.com/alarsyo/lohr/-/merge_requests), or [send me a patch -by email](https://lists.sr.ht/~alarsyo/lohr-dev)! - -## Why lohr? - -I was looking for a cool name, and thought about the Magic Mirror in Snow White. -Some **[furious wikipedia -searching](https://en.wikipedia.org/wiki/Magic_Mirror_(Snow_White))** later, I -found that the Magic Mirror was probably inspired by [the Talking Mirror in Lohr -am Main](http://spessartmuseum.de/seiten/schneewittchen_engl.html). That's it, -that's the story. - -## License - -`lohr` is distributed under the terms of both the MIT license and the Apache -License (Version 2.0). - -See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details. diff --git a/README.org b/README.org new file mode 100644 index 0000000..07c5c01 --- /dev/null +++ b/README.org @@ -0,0 +1,135 @@ +#+title: lohr + +=lohr= is a Git mirroring tool. + +I created it to solve a simple problem I had: I host my own git server at +[[https://git.alarsyo.net]], but want to mirror my public projects to GitHub / +GitLab, for backup and visibility purposes. + +GitLab has a mirroring setting, but it doesn't allow for multiple mirrors, as +far as I know. I also wanted my instance to be the single source of truth. + +** How it works + +Gitea is setup to send webhooks to my =lohr= server on every push update. When +=lohr= receives a push, it clones the concerned repository, or updates it if +already cloned. Then it pushes the update to *all remotes listed* in the [[file:.lohr][.lohr]] +file at the repo root. + +*** Destructive + +This is a very destructive process: anything removed from the single source of +truth is effectively removed from any mirror as well. + +** Installing + +=lohr= is [[https://crates.io/crates/lohr][published on crates.io]], so you can install it with ~cargo install~: + +#+begin_src sh +$ cargo install lohr +#+end_src + +** Setup + +*** Quickstart + +Setting up =lohr= should be quite simple: + +1. Create a =Rocket.toml= file and [[https://rocket.rs/v0.4/guide/configuration/][add your configuration]]. + +2. Export a secret variable: + + #+begin_src sh + $ export LOHR_SECRET=42 # please don't use this secret + #+end_src + +3. Run =lohr=: + + #+begin_src sh + $ cargo run # or `cargo run --release` for production usage + #+end_src + +4. Configure your favorite git server to send a webhook to =lohr='s address on + every push event. + + I used [[https://docs.gitea.io/en-us/webhooks/][Gitea's webhooks format]], but I *think* they're similar to GitHub and + GitLab's webhooks, so these should work too! (If they don't, *please* file an + issue!) + + Don't forget to set the webhook secret to the one you chose above. + +5. Add a =.lohr= file containing the remotes you want to mirror this repo to: + + #+begin_example + git@github.com:you/your_repo + #+end_example + + and push it. That's it! =lohr= is mirroring your repo now. + +*** Configuration + +**** Home directory + +=lohr= needs a place to clone repos and store its data. By default, it's the +current directory, but you can set the =LOHR_HOME= environment variable to +customize it. + +**** Shared secret + +As shown in the quickstart guide, you *must* set the =LOHR_SECRET= environment +variable. + +**** Extra remote configuration + +You can provide =lohr= with a YAML file containing additional configuration. You +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 +default_remotes: + - "git@github:user" + - "git@gitlab:user" + +additional_remotes: + - "git@git.sr.ht:~user" + +blacklist: + - "private-.*" +#+end_src + +- ~default_remotes~ is a list of remotes to use if no ~.lohr~ file is found in a + repository. +- ~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. +- ~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, +to which the repo's name will be appended (so for example, if my +~default_remotes~ contains ~git@github.com:alarsyo~, and a push event webhook +is received for repository =git@gitlab.com:some/long/path/repo_name=, then the +mirror destination will be =git@github.com:alarsyo/repo_name=. + +** Contributing + +I accept patches anywhere! Feel free to [[https://github.com/alarsyo/lohr/pulls][open a GitHub Pull Request]], [[https://gitlab.com/alarsyo/lohr/-/merge_requests][a GitLab +Merge Request]], or [[https://lists.sr.ht/~alarsyo/lohr-dev][send me a patch by email]]! + +** Why lohr? + +I was looking for a cool name, and thought about the Magic Mirror in Snow White. +Some *[[https://en.wikipedia.org/wiki/Magic_Mirror_(Snow_White)][furious wikipedia searching]]* later, I found that the Magic Mirror was +probably inspired by [[http://spessartmuseum.de/seiten/schneewittchen_engl.html][the Talking Mirror in Lohr am Main]]. That's it, that's the +story. + +** License + +=lohr= is distributed under the terms of both the MIT license and the Apache +License (Version 2.0). + +See [[file:LICENSE-APACHE][LICENSE-APACHE]] and [[file:LICENSE-MIT][LICENSE-MIT]] for details. diff --git a/flake.nix b/flake.nix index cc866ad..b87c588 100644 --- a/flake.nix +++ b/flake.nix @@ -16,11 +16,11 @@ { defaultPackage = pkgs.rustPlatform.buildRustPackage { pname = "lohr"; - version = "0.4.0"; + version = "0.3.1"; src = ./.; - cargoSha256 = "sha256-5a2mK+E6LlR5RHDAhHDvnfPNG+0JdvpnL4kuTiz7vVg="; + cargoSha256 = "sha256-XnBvb13Pv7bNTLCL3WV+bxRK0/uMEKA1/Bk0Tfua3Rs="; meta = with pkgs.lib; { description = "A Git mirroring tool"; diff --git a/src/gitea.rs b/src/gitea.rs index eae1528..e4826e5 100644 --- a/src/gitea.rs +++ b/src/gitea.rs @@ -4,7 +4,7 @@ use serde::Deserialize; pub(crate) struct Repository { pub(crate) name: String, pub(crate) full_name: String, - pub(crate) ssh_url: String, + pub(crate) clone_url: String, } #[derive(Deserialize)] diff --git a/src/job.rs b/src/job.rs index 0e386c4..2e91cf1 100644 --- a/src/job.rs +++ b/src/job.rs @@ -38,7 +38,7 @@ impl Job { let output = Command::new("git") .arg("clone") .arg("--mirror") - .arg(&self.repo.ssh_url) + .arg(&self.repo.clone_url) .arg(format!("{}", self.local_path.as_ref().unwrap().display())) .output()?; diff --git a/src/main.rs b/src/main.rs index 6bf0d1d..2eccf61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ use std::sync::{ use std::thread; use anyhow::Context; -use clap::{crate_version, App, Arg}; +use clap::{App, Arg}; use log::{error, info}; use rocket::{http::Status, post, routes, State}; @@ -34,15 +34,12 @@ fn gitea_webhook( config: State, ) -> Status { if config - .filters + .blacklist .iter() - // Find first filter that matches the given destination - .find(|filter| filter.destination.as_ref().map_or(false, |re| re.is_match(&payload.repository.full_name))) - // Default to mirroring, unless told not to - .map_or(true, |filter| filter.mirror) + .any(|re| re.is_match(&payload.repository.full_name)) { info!( - "Ignoring webhook for repo {} which is marked as not mirrored", + "Ignoring webhook for repo {} which is blacklisted", payload.repository.full_name ); return Status::Ok; @@ -96,7 +93,7 @@ fn parse_config(home: &Path, flags: &clap::ArgMatches) -> anyhow::Result anyhow::Result<()> { let matches = App::new("lohr") - .version(crate_version!()) + .version("0.3.1") .about("Git mirroring daemon") .arg( Arg::with_name("config") diff --git a/src/settings.rs b/src/settings.rs index 8b91376..8dc71f9 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -10,29 +10,8 @@ pub(crate) struct GlobalSettings { /// List of remote stems to use for every repository #[serde(default)] pub additional_remotes: Vec, - /// List of filters to blacklist repositories, or modify push options on specific remotes. - /// Only the first matching filter is applied, so order is important. - #[serde(default)] - pub filters: Vec, -} - -#[derive(Clone, Default, Deserialize)] -pub(crate) struct FilterSettings { - /// Match on the source remote - #[serde(with = "serde_regex", default)] - pub source: Option, - /// Match on the destination remote - #[serde(with = "serde_regex", default)] - pub destination: Option, - /// Whether to mirror the repository or not - #[serde(default = "default_true")] - pub mirror: bool, - /// Push options to be used for the matched remote - #[serde(default)] - pub push_options: Vec, -} - -// Workaround for https://github.com/serde-rs/serde/issues/368 -fn default_true() -> bool { - true + /// 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, }