124 lines
4.1 KiB
Org Mode
124 lines
4.1 KiB
Org Mode
#+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.
|
|
|
|
** 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
|
|
=lohr= looks for a =lohr-config.yaml= file in its =LOHR_HOME= directory. The
|
|
=LOHR_CONFIG= variable takes precedence over looking into the state directory.
|
|
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.
|