The easy response
I’m not sure if you want to use irmin-unix
/git-unix
or if you want to make a MirageOS application but for the first case (and the second as well), you need to craft a Mimic.ctx
which permits Irmin (and Git) to allocate a resource which correspond to an active connection (TCP, SSH, or HTTP(S)). Such value can be provided by Git_unix.ctx
which requires an happy-eyeballs instance (to be able to resolve domain-name).
This ctx
is filled with several protocols given by the git_mirage_*
series (tcp
, ssh
with awa-ssh
and http(s)
with paf
). All of them requires few more values. For instance, if you want to start a SSH connection, you must give an SSH key. Git_mirage_ssh.git_mirage_ssh_key
is your witness to fill a Mimic.ctx
with an SSH key. From that and a Smart_git.Endpoint.t
, you can pull
/push
.
Something like:
let addr = Result.get_ok (Smart_git.Endpoint.of_string "git@github.com:foo/bar.git")
let run git_repo : unit Lwt.t =
let+ key = Awa.Keys.of_string ... in
Git_unix.ctx (Happy_eyeballs_lwt.create ()) >>= fun ctx ->
let ctx = Mimic.add Git_mirage_ssh.git_mirage_ssh_key key ctx in
Irmin_git_unix.KV.Backend.Remote.v git_repo >>= fun remote ->
Irmin_git_unix.KV.Backend.Remove.pull remote (ctx, addr) main >>= fun _ ->
Lwt.return_unit
Should work but I’m not an Irmin expert (and I easily get lost between the functors and the signatures)
The complete response
You should take a look at the Mimic tutorial that explains the purpose of this library. The choice was made a long time ago to use Conduit as the library that can distribute the flow implementation needed to communicate with a peer. However, Conduit was created a long time ago and before extensible variants were available.
The goal of Conduit is to be able to allocate/connect
a resource that can communicate with a peer, regardless of its implementation. This last point is particularly important for the MirageOS goal where the implementation must be completely abstract - and we mainly use functors for this. The crucial part here is: how to allocate such a resource? In our experience, the connect function is strongly implementation-dependent and difficult to abstract. This is the case between lwt_ssl
and ocaml-tls
for example, they can do the same job but they expect different values (an Ssl.context
or a Tls.Config.client
).
Of course, we can then imagine a supra-interface for TLS and hide the implementation details in a nice API. But such a job can be difficult (even if we consider that lwt_ssl
and ocaml-tls
do the same thing, there are noticeable differences especially in the details) and arbitrary (the API can be made to take advantage of one implementation rather than another).
That being said, Conduit provides an implementation-independent function to allocate such a resource: Conduit_lwt_unix.connect
. This function also depends on a “ctx” that contains a description of what the user expects (a TCP connection? a TLS connection? etc.).
However, as I said, internally, Conduit does not use the latest OCaml features including extensible variants. The latter is necessary for us to extend the possible “communication” implementations. In the specific case of Git, we needed to extend Conduit with an SSH implementation.
Other minor points are to be regretted by Conduit but we won’t dwell on them. However, a lot of work has been done in Conduit (including CoHTTP) to fix this situation with version 3.0. However, due to internal differences in the Mirage core team (and, among other things, because I didn’t have the courage to continue), the project was aborted.
However, being a user of ocaml-git
and MirageOS, I still considered this solution to be viable and the core users were quite happy with the change. So I integrated my work under the name Mimic! I especially facilitated the integration into MirageOS which I think is the most important. But I have examples of uses of Mimic where I use for example a FIFO to implement tests between a real Git server and my implementation. Or an integration of OpenSSH instead of awa-ssh
.
More simply, Mimic offers the ability to have an implementation of a protocol that will be decided at runtime: a bit like the virtual method in C++ but with the module sauce . Thus, Git only waits for a protocol implementation that will be concretized in the famous “ctx”. Then, on top of it, we have our Git protocol implementation: the Smart protocol. The advantage is to be able to switch between SSH or HTTPS without really changing our code (as we could do with a functor).