[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [MirageOS-devel] Irmin API newbie questions

On 9 February 2015 at 14:41, Thomas Gazagnaire <thomas@xxxxxxxxxxxxxx> wrote:
> Hi Thomas,
>> (BTW, I think it might be useful to add the equivalent git command
>> next to functions in the documentation, since most people will
>> understand that already)
> ack, I'll do this.
>> The BASIC docs are missing
>> (https://mirage.github.io/irmin/Irmin.BASIC.html), but the code shows:
>>  type ('a, 'b) basic = (module BASIC with type key = 'a and type value = 'b)
>> It seems that using Irmin.Contents.String gets me "key = string list",
>> but "step" remains abstract. How do I use cons, decons, etc?
> Why do you need to use cons and decons? Normally you should just need to use 
> the usual list operators (ie. (::) for cons and pattern-matching for decons). 
> If you have a use-case where this is not enough, please share it! It's 
> possible that I forgot to export a type constraint somewhere.

When walking the tree it's useful to get the last component with
rdecons, since there's no built-in function for this. Easy enough to
work around, of course. It's actually a bit strange that "list"
returns a "key list" rather than a "step list" (i.e. it returns full
paths). The docs say "list t k list the sub-paths of the path k in t",
but it looks like it's just the immediate children. Returning a step
would make that clear, if so.

>> If I have a RW store, I can watch a key:
>>  val watch : t -> key -> value option Lwt_stream.t
>> Presumably, I also need to take care to stop watching it when I'm
>> done, otherwise the stream will grow without limit, right? I guess
>> there should be an unwatch, or maybe this should be a React signal or
>> something.
> Yes the watch API still needs some work. It's working-ish enough to demo 
> small examples (for instance you can run some of the examples and connect to 
> to see a nice animated graph of the store), but 
> as you noticed there is no GC of ressources, maybe some leaks and the 
> behaviour under load is not satisfactory (see issue 
> https://github.com/mirage/irmin/issues/124).
>> I got a bit confused when I reached the BC page:
>>  https://mirage.github.io/irmin/Irmin.BC.html
>> It uses 'tag' to mean a pointer to a commit that is updates on each
>> operation (i.e. what Git would call a 'branch'). I realise that tags
>> and branches are the same thing internally, but 'branch' seems to
>> capture better what Irmin is using them for ("The tag value is updated
>> every time the store is updated, so every handle connected or which
>> will be connected to the same tag will see the changes."). [ BTW,
>> what's a "handle"? ]
> The documentation is not totally clear here, you're right. You have two ways 
> to identify a branch: either by name or by hash. In Irmin terminology, a 
> branch name is a "tag". A commit hash is a "head".
>> val update_tag : t -> tag -> unit Lwt.t
>> update_tag t tag updates t's current branch with the contents of the
>> branch named tag.
>> What does "update" mean here? Is this "git reset --hard tag"? A merge?
>> A "--ff-only" merge?
> `update_tag` is similar to `git reset --hard <tag>`. merge_tag is similar to 
> `git merge <tag>`. I've tried to keep the update/merge duality in most of the 
> places (you can update/merge a head, a view, an other branch).

Might be worth mentioning that this may cause data-loss then (I don't
think that's clear from "update").

>> My mental model of Git is that the store is a DAG and I can append to
>> any branch. e.g. we have:
>>   git commit-tree <tree> [(-p <parent>)...] < changelog
>> If I'm understanding the Irmin API correctly, each "store"
>> (repository? branch?) has a current "tag" (branch) and I need to set
>> the tag I want to work on, e.g.
>>  val switch : Store.t -> tag -> unit Lwt.t
> The simplest way to initialise a branch using a tag is to use `Irmin.of_tag 
> ... <tag>`. If you want to create a branch in a "detached" mode, use 
> `Irmin.of_head ... <head>`. But yes, you can use switch to switch to another 
> named branch.
>> If I want to work on another branch without changing the current
>> branch for other users, I should "clone" the store:
>>  val clone_force : ('a -> Irmin.task) -> t -> tag -> ('a -> t) Lwt.t
>> But, this is not a "git clone", it's like "git branch tag" - a new
>> branch I can work on without affecting the repository's default
>> branch. It seems strange that Irmin has a mutable "current branch" at
>> all - this seems like a UI concept that's only needed for command-line
>> use (to save typing).
> Irmin has a concept of default branch (ie. "master") which is used when you 
> use "Irmin.create".  I choose that because the simplest use-case is to use 
> Irmin as a normal k/v store, without having to worry about branches and such.

OK, I think my confusion here is because (in my mind) there are two
separate concepts here: a repository is a collection of branches and a
branch head is a k/v store. But these are both combined into a single
"store" type.

>> A "head" is defined as "a given store revision" (i.e. what Git would
>> call a commit). It wasn't clear to me at first whether a head was a
>> commit or an anonymous branch. e.g.
> A head is a commit hash. You can use a head with Irmin.of_head to create an 
> anonymous branch. I agree that the documentation is not very clear on that.
>> val rename_tag : t -> tag -> [ `Duplicated_tag | `Ok ] Lwt.t
>> Change the current tag name. Fail if a tag with the same name already
>> exists. The head is unchanged.
>> "The head is unchanged" suggests that heads might change in other
>> cases. Looking at the code, I see a "type head = Commit.key" in one
>> place, so I guess they're (usually?) commits. Does "head" here mean
>> "the default branch"?
> I'll make another pass on that part of the documentation to try to make all 
> of these concepts clearer. I'll try to relate the API functions to Git 
> command-line arguments, although I'm not sure the Git command-line is a model 
> of clarity as well: `git reset --hard` is very different from `git reset 
> --soft` for instance, and there are no direct notion on index file in Irmin 
> (although the views can be seen as a kind of staging area).
>> Finally, how do I get history? e.g. if I want to show users the recent
>> changes to a document. I see a "slice" type, but it's not clear what I
>> can do with it.
> Anil asked me the question recently, and I promise him to add the missing 
> function in the "simple" API. For now on, the functions are well-hidden 
> inside the private API: The History[1] functor gives you a "closure" 
> function, which gives you a slice of the history graph. The functor needs a 
> contents store (if S is of type Irmin.S, then S,Private.Contents) and a node 
> store (S.Private.Node). But that's far too hard to use, I'll add an helper 
> function in the API to get you a OCamlgraph graph of commits (and optionally 
> tree and blobs) instead.
> Thanks for that very helpful report! I hope it makes things a little bit 
> clearer.

Yes, much clearer, thanks!

> Thomas
> [1] http://mirage.github.io/irmin/Irmin.Private.Commit.History.html
>> Thanks!
>> --
>> Dr Thomas Leonard        http://0install.net/
>> GPG: 9242 9807 C985 3C07 44A6  8B9A AE07 8280 59A5 3CC1
>> GPG: DA98 25AE CAD0 8975 7CDA  BD8E 0713 3F96 CA74 D8BA
>> _______________________________________________
>> MirageOS-devel mailing list
>> MirageOS-devel@xxxxxxxxxxxxxxxxxxxx
>> http://lists.xenproject.org/cgi-bin/mailman/listinfo/mirageos-devel

Dr Thomas Leonard        http://0install.net/
GPG: 9242 9807 C985 3C07 44A6  8B9A AE07 8280 59A5 3CC1
GPG: DA98 25AE CAD0 8975 7CDA  BD8E 0713 3F96 CA74 D8BA

MirageOS-devel mailing list



Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.