petersalomonsen / wasm-git

GIT for nodejs and the browser using https://libgit2.org compiled to WebAssembly with https://emscripten.org
Other
632 stars 36 forks source link

Running libgit2 commands #62

Closed iliakan closed 1 year ago

iliakan commented 1 year ago

Supercool! It actually works!

How can I run commands like:

opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED |
        GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
        GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR;

git_status_list_new(&statuslist, g_repo, &opts);

(sorry for writing it C-style)?

P.S. This is the signature: https://libgit2.org/libgit2/#v1.5.1/group/status/git_status_list_new

P.P.S. Here's an example in this repo: https://github.com/petersalomonsen/wasm-git/blob/master/libgit2patchedfiles/examples/status.c

Also, is it possible to access repository tree, e.g. I want to test the repository structure, tree of commits, in my code.

iliakan commented 1 year ago

It seems that this whole compilation project only allows to call the main function of lg2.c, and there's no way to call any other methods.

Please correct me if I'm mistaken.

petersalomonsen commented 1 year ago

Yeah the current approach to it is that you can run all the libgit2 examples which are a "mixture of basic emulation of core Git command line functions and simple snippets demonstrating libgit2 API usage".

However I've actually added a few more than the ones included with libgit2, which you can find here: https://github.com/petersalomonsen/wasm-git/tree/master/libgit2patchedfiles/examples

I would suggest that you build on / add more on these to extend with the functionality that you need.

In recent versions of libgit2 there's also a CLI. My plan is at some point to switch to this ( or add it ).

iliakan commented 1 year ago

So if I want to call other libgit2 functions, then I need to build upon wasm-git?

For instance, what should be my steps if I need to call git_status_list_new ?

P.S. I tried libgit2 CLI yesterday, it's more like a POC. There are literally few commands.

petersalomonsen commented 1 year ago

Yes you should add more to the libgit2patchedfiles/examples folder.

Regarding git_status_list_new you can already see that it's called in https://github.com/petersalomonsen/wasm-git/blob/master/libgit2patchedfiles/examples/status.c#L102

Thanks for the info on CLI status, I haven't really tested it yet, but it's probably better then to wait until it's a bit more mature.

iliakan commented 1 year ago

Are these examples somehow linked into lg2.js?

petersalomonsen commented 1 year ago

yes they are! if you add into there, it should be automatically linked. You can also add more commands here: https://github.com/petersalomonsen/wasm-git/blob/master/libgit2patchedfiles/examples/lg2.c#L12

iliakan commented 1 year ago

Are many of them in fact your own?

E.g. this one: https://github.com/petersalomonsen/wasm-git/blob/master/libgit2patchedfiles/examples/reset.c I couldn't find the same in libgit2 ;)

petersalomonsen commented 1 year ago

Yeah all of these in this repository are mine.

iliakan commented 1 year ago

I came across a fairly old comment https://github.com/isomorphic-git/isomorphic-git/issues/268#issuecomment-395610965

Yep. Compilation with emscripten works. But there are lots of edgecases that don't. Anything that touches mmap syscall fails. The emscripten fs is a spaghetti and too deeply embedded (and a requirement for me to be able to interop with other js code that uses fs).

How valid is it nowadays?

I'm especially concerned with "edgecases" that don't work (anything that touches mmap?). Is there something in libgit2 that won't work?

petersalomonsen commented 1 year ago

I did fix the mmap issues in emscripten as you can see here: https://github.com/petersalomonsen/wasm-git#building

As you can see I did 3 Pull Requests to the emscripten repository to fix the mmap issues.

iliakan commented 1 year ago

Cool! So you don't foresee any problems? ;)

Asking that just in case, to know what to expect.

petersalomonsen commented 1 year ago

No, at this point I don't know of anything specific in libgit2 that shouldn't work. There may be of course limitation on very large repositories, both that it would be slower, and also because of limitations of the size of http payloads, but I don't know about any functional issues.

iliakan commented 1 year ago

Let's say I want to improve examples, add new functions.

Is there an easy way to compile and test those directly, not involving wasm recompilation?

P.S. My C skills are coming from 20 years ago student experience. But this was a good experience, so I remember how to code ;)

petersalomonsen commented 1 year ago

you need to recompile the wasm, but there is a setup already for gitpod so that you should have all the tools needed to recompile.

iliakan commented 1 year ago

These are C files... maybe I can test in libgit2 environment?

petersalomonsen commented 1 year ago

you can of course test in libgit2, but you will get the full experience ( in the browser or node ) if you compile with emscripten. Also I would add some testcode for testing your additions like this for nodejs ( there are also tests for the browser ):

https://github.com/petersalomonsen/wasm-git/blob/master/test/checkout.spec.js

iliakan commented 1 year ago

Let's say I want status as JS object.

How can I achieve that? Should I implement a new command and use JSON-encoder in C, or there's an easier way?

petersalomonsen commented 1 year ago

you can also just in JS encode the result received from C, but it depends on how/what you want to extract from the output

iliakan commented 1 year ago

E.g. this line from status.c:

    check_lg2(git_status_list_new(&status, repo, &o.statusopt),
              "Could not get status", NULL);

I'd like to get the resulting status structure in JS. Can I pass it directly?

petersalomonsen commented 1 year ago

If you want to be aligned with future updates of wasm-git I would recommend that you write separate command files for your own extensions ( and not modify status.c unless actually improving it to be closer to real git cli ).

But if you want to add your own command and output a javascript object, you should look into emscripten features for calling JS from C which is described here: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#calling-javascript-from-c-c

iliakan commented 1 year ago

I see ccall and cwrap examples at https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-ccall-cwrap

Maybe it's possible to call libgit2 functions directly using them, without lg2.callMain and without making a new example?

petersalomonsen commented 1 year ago

yeah if you annotate a function with EMSCRIPTEN_KEEPALIVE ( https://emscripten.org/docs/api_reference/emscripten.h.html?highlight=emscripten_keepalive#c.EMSCRIPTEN_KEEPALIVE ) you can call it without implementing a new example.

iliakan commented 1 year ago

annotate? that is, by modifying libgit2? ;)

petersalomonsen commented 1 year ago

no, rather add a new c file in wasm-git that contains a function that calls libgit2. You need to expose them somehow. ccall / cwrap expects the functions to be exported in the webassembly file.

iliakan commented 1 year ago

so I could, like, create an export.c file with all the functions I want to export from libgit2 and call them directly? ;)

petersalomonsen commented 1 year ago

yes that should work. just remember to include it in the compilation.

iliakan commented 1 year ago

A simple function, such as int_sqrt seems to work (with added compilation flags).

Although doing git init doesn't work.

Please take a look here: https://github.com/petersalomonsen/wasm-git/pull/64.

P.S. I hope I'm calling the function correctly. P.P.S. Please, help ;)

petersalomonsen commented 1 year ago

I think you need to look in here on how to initialize a repo: https://github.com/libgit2/libgit2/blob/main/examples/init.c#L45 And here: https://github.com/libgit2/libgit2/blob/main/examples/lg2.c#L70

There's a lot more involved into using libgit2, you cannot just call one of the library methods alone, you also have to init and shutdown libgit2. Some good documentation is also here: https://libgit2.org/docs/guides/101-samples/

If building on the examples codebase you get a lot of the initialization code out of the box.

iliakan commented 1 year ago

Oh, indeed I overlooked that call. Now the initialization works as it should.

Thank you for the help!