Skip to content

Commit 7866d5a

Browse files
committed
Added Dockerfile for Docker build:
* Dockerfile and docker_cleanup_and_build.sh. * Added documentation for Docker build. Updated libgit2 from version 1.7.1 to 1.8.1: * Removed git_error_clear() call in examples/checkout.c cause method had been removed. Added new commands: * examples/branch.c: List local and remote branches. Delete local branches. * examples/log-last-commit-of-branch.c: Log info about latest commit of a branch. * examples/rebase.c: Interactive rebase functionality. Changed commands: * examples/push.c: Does have an optional parameter --force for force pushing. (Needed after a rebase.) * examples/fetch.c: Does now --prune by default. * examples/init.c: Change default branch to main. Others * Added HTTP basic auth for authentication with password or pat. * Added method writeArrayToMemory manually to post.js cause it was not found.
1 parent 7236b20 commit 7866d5a

File tree

16 files changed

+1096
-11
lines changed

16 files changed

+1096
-11
lines changed

Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
FROM ubuntu:latest
2+
3+
RUN apt-get update && apt-get install -y \
4+
build-essential \
5+
curl \
6+
wget \
7+
cmake \
8+
dos2unix \
9+
git \
10+
nodejs \
11+
npm \
12+
nano \
13+
sudo \
14+
apt-transport-https \
15+
ca-certificates \
16+
software-properties-common
17+
18+
WORKDIR /src
19+
20+
RUN git clone https://github.com/emscripten-core/emsdk.git && \
21+
/src/emsdk/emsdk install latest && \
22+
/src/emsdk/emsdk activate latest

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,28 @@ for using with `NODEFS` you'll also need https://github.com/emscripten-core/emsc
5656

5757
All of these pull requests are merged to emscripten master as of 2020-03-29.
5858

59+
See [.github/workflows/main.yml](./.github/workflows/main.yml) for a full build and test pipeline including installing emscripten.
60+
61+
Run [setup.sh](setup.sh) first to download libgit2 and apply patches.
62+
63+
Given you have installed and activated emscripten, you can use the script in [emscriptenbuild/build.sh](emscriptenbuild/build.sh) to configure and build, and you'll find the resulting `lg2.js` / `lg2.wasm` under the generated `emscriptenbuild/examples` folder.
64+
65+
An example of interacting with libgit2 from nodejs can be found in [examples/example_node.js](examples/example_node.js).
66+
67+
An example for the browser (using webworkers) can be found in [examples/example_webworker.js](examples/example_webworker.js). You can start a webserver for this by running the [examples/webserverwithgithubproxy.js](examples/webserverwithgithubproxy.js) script, which will launch a http server at http://localhost:5000 with a proxy to github. Proxy instead of direct calls is needed because of CORS restrictions in a browser environment.
68+
69+
## Docker build
70+
71+
Build image in repository directory:
72+
73+
```bash
74+
docker build -t wasm-git-image .
75+
```
76+
77+
Example Release build and SINGLE_FILE parameter:
78+
79+
```bash
80+
docker run -v .:/src/wasm-git --rm wasm-git-image /bin/bash -c "cd /src/wasm-git && git ls-files | xargs dos2unix && /src/wasm-git/docker_cleanup_and_build.sh Release SINGLE_FILE"
81+
```
82+
83+
After build outputs can be found in emscriptenbuild/libgit2/examples/lg2.js and and in case no SINGLE_FILE parameter was provided also emscriptenbuild/libgit2/examples/lg2.wasm.

docker_cleanup_and_build.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
cd /src/wasm-git
2+
rm -rf libgit2
3+
rm -rf emscriptenbuild/libgit2
4+
rm -rf emscriptenbuild/CMakeFiles
5+
rm -f emscriptenbuild/lg2.wasm
6+
rm -f emscriptenbuild/lg2.js
7+
rm -f emscriptenbuild/cmake_install.cmake
8+
rm -f emscriptenbuild/CMakeCache.txt
9+
rm -f emscriptenbuild/Makefile
10+
npm install
11+
sh setup.sh
12+
source /src/emsdk/emsdk_env.sh
13+
cd /src/wasm-git/emscriptenbuild
14+
./build.sh "$@"

emscriptenbuild/build.sh

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,17 @@ elif [ "$1" == "Debug-async" ]; then
3232
export LG2_OUTPUT_NAME=lg2_async
3333
fi
3434

35+
# Check if output should be bundled in a single js file
36+
for param in "$@"; do
37+
# Check if the parameter is 'abc'
38+
if [ "$param" == "SINGLE_FILE" ]; then
39+
EXTRA_CMAKE_C_FLAGS="${EXTRA_CMAKE_C_FLAGS} -s SINGLE_FILE"
40+
break
41+
fi
42+
done
43+
3544
# Before building, remove any ../libgit2/src/ transports/emscriptenhttp.c left from running setup.sh
3645
[ -f "../libgit2/src/libgit2/transports/emscriptenhttp-async.c" ] && rm ../libgit2/src/libgit2/transports/emscriptenhttp-async.c
3746

38-
emcmake cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_C_FLAGS="$EXTRA_CMAKE_C_FLAGS --pre-js $(pwd)/pre.js $POST_JS -s \"EXPORTED_RUNTIME_METHODS=['FS','MEMFS','IDBFS','NODEFS','callMain']\" -sFORCE_FILESYSTEM -sEXPORT_ES6 -s INVOKE_RUN=0 -s ALLOW_MEMORY_GROWTH=1 -s STACK_SIZE=131072 -lidbfs.js -lnodefs.js" -DREGEX_BACKEND=regcomp -DSONAME=OFF -DUSE_HTTPS=OFF -DBUILD_SHARED_LIBS=OFF -DTHREADSAFE=OFF -DUSE_SSH=OFF -DBUILD_CLAR=OFF -DBUILD_EXAMPLES=ON ..
47+
emcmake cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_C_FLAGS="$EXTRA_CMAKE_C_FLAGS --pre-js $(pwd)/pre.js $POST_JS -s \"EXPORTED_RUNTIME_METHODS=['FS','MEMFS','IDBFS','NODEFS','callMain']\" -sFORCE_FILESYSTEM -sEXPORT_ES6 -s INVOKE_RUN=0 -s ALLOW_MEMORY_GROWTH=1 -s STACK_SIZE=131072 -lidbfs.js -lnodefs.js -flto" -DREGEX_BACKEND=regcomp -DSONAME=OFF -DUSE_HTTPS=OFF -DBUILD_SHARED_LIBS=OFF -DTHREADSAFE=OFF -DUSE_SSH=OFF -DBUILD_CLAR=OFF -DBUILD_EXAMPLES=ON ..
3948
emmake make lg2

emscriptenbuild/post.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
const emscriptenhttpconnections = {};
1313
let httpConnectionNo = 0;
1414

15+
var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};
16+
1517
if(ENVIRONMENT_IS_WORKER) {
1618
Object.assign(Module, {
1719
emscriptenhttpconnect: function(url, buffersize, method, headers) {

emscriptenbuild/pre.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
Object.assign(Module, globalThis.wasmGitModuleOverrides);
22

3+
// Add HTTP Basic auth headers
4+
if (Module.username || Module.accessToken) {
5+
XMLHttpRequest.prototype._open = XMLHttpRequest.prototype.open;
6+
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
7+
this._open(method, url, async, user, password);
8+
if (Module.accessToken) {
9+
const username = Module.username || '';
10+
this.setRequestHeader('Authorization', `Basic ${btoa(username + ':' + Module.accessToken)}`);
11+
}
12+
};
13+
}
14+
315
if (!Module.print && !Module.printErr) {
416
let capturedOutput = null;
517
let capturedError = null;
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* libgit2 "branch" example - Get local / remote branch list and delete a local branch.
3+
*
4+
* Written by the libgit2 contributors
5+
*
6+
* To the extent possible under law, the author(s) have dedicated all copyright
7+
* and related and neighboring rights to this software to the public domain
8+
* worldwide. This software is distributed without any warranty.
9+
*
10+
* You should have received a copy of the CC0 Public Domain Dedication along
11+
* with this software. If not, see
12+
* <http://creativecommons.org/publicdomain/zero/1.0/>.
13+
*/
14+
15+
#include "common.h"
16+
17+
/**
18+
* The following example demonstrates how to list and delete branches with libgit2.
19+
*
20+
* It will use the repository in the current working directory and list local branches by default, but also allows deleting local branches and list remote branches with options.
21+
*
22+
* Recognized options are:
23+
* -r: list remote branches.
24+
* -d <branch_name>: delete local branch.
25+
*/
26+
27+
typedef struct {
28+
int list : 1;
29+
int remote : 1;
30+
int delete : 1;
31+
char* branch_name;
32+
} branch_options;
33+
34+
static void print_usage(void)
35+
{
36+
fprintf(stderr, "usage: branch [options]\n"
37+
"Options are :\n"
38+
" : list local branches."
39+
" -r: list remote branches.\n"
40+
" -d <branch_name>: delete local branch.\n");
41+
exit(1);
42+
}
43+
44+
static void parse_options(const char **repo_path, branch_options *opts, struct args_info *args)
45+
{
46+
memset(opts, 0, sizeof(*opts));
47+
48+
/* Default values */
49+
opts->list = 1;
50+
opts->remote = 0;
51+
opts->delete = 0;
52+
opts->branch_name = NULL;
53+
54+
for (args->pos = 1; args->pos < args->argc; ++args->pos) {
55+
const char *curr = args->argv[args->pos];
56+
57+
if (match_arg_separator(args)) {
58+
break;
59+
} else if (!strcmp(curr, "-r")) {
60+
opts->remote = 1;
61+
if (args->pos != args->argc -1) {
62+
print_usage();
63+
}
64+
} else if (!strcmp(curr, "-d")) {
65+
opts->list = 0;
66+
opts->delete = 1;
67+
68+
if (args->pos == args->argc -1) {
69+
print_usage();
70+
} else {
71+
opts->branch_name = strdup(args->argv[args->pos + 1]);
72+
}
73+
}
74+
}
75+
}
76+
77+
int lg2_branch(git_repository *repo, int argc, char **argv)
78+
{
79+
struct args_info args = ARGS_INFO_INIT;
80+
branch_options opts;
81+
const char *path = ".";
82+
83+
git_branch_iterator *iter = NULL;
84+
git_branch_t git_branch_type = GIT_BRANCH_LOCAL;
85+
git_reference *ref = NULL;
86+
git_reference *upstream_ref = NULL;
87+
88+
/** Parse our command line options */
89+
parse_options(&path, &opts, &args);
90+
91+
if (opts.list) {
92+
if (opts.remote) {
93+
git_branch_type = GIT_BRANCH_REMOTE;
94+
}
95+
96+
// Create the branch iterator for branches
97+
if (git_branch_iterator_new(&iter, repo, git_branch_type) != 0) {
98+
fprintf(stderr, "Could not create branch iterator\n");
99+
goto cleanup;
100+
}
101+
102+
// Iterate through the branches
103+
while (git_branch_next(&ref, &git_branch_type, iter) != GIT_ITEROVER) {
104+
const char *branch_name;
105+
if (git_branch_name(&branch_name, ref) == 0) {
106+
if (!opts.remote) {
107+
if (git_branch_upstream(&upstream_ref, ref) == 0) {
108+
printf("%s:%s\n", branch_name, branch_name);
109+
} else {
110+
printf("%s\n", branch_name);
111+
}
112+
} else {
113+
printf("%s\n", branch_name);
114+
}
115+
116+
}
117+
git_reference_free(ref);
118+
}
119+
} else if (opts.delete) {
120+
// Lookup the reference for the branch
121+
if (git_branch_lookup(&ref, repo, opts.branch_name, GIT_BRANCH_LOCAL) != 0) {
122+
fprintf(stderr, "Error looking up branch: %s\n", opts.branch_name);
123+
goto cleanup;
124+
}
125+
126+
// Delete the reference
127+
if (git_branch_delete(ref) != 0) {
128+
fprintf(stderr, "Error deleting branch: %s\n", opts.branch_name);
129+
goto cleanup;
130+
}
131+
}
132+
133+
cleanup:
134+
if (iter) git_branch_iterator_free(iter);
135+
136+
return 0;
137+
}

libgit2patchedfiles/examples/checkout.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,6 @@ int lg2_checkout(git_repository *repo, int argc, char **argv)
341341

342342
err = git_branch_set_upstream(branch_ref,upstreamname);
343343
if (err == GIT_ENOTFOUND) {
344-
// no upstream exists
345-
git_error_clear();
346344
err = 0;
347345
}
348346
if (err != 0) {

libgit2patchedfiles/examples/common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656

5757
extern int lg2_add(git_repository *repo, int argc, char **argv);
5858
extern int lg2_blame(git_repository *repo, int argc, char **argv);
59+
extern int lg2_branch(git_repository *repo, int argc, char **argv);
5960
extern int lg2_cat_file(git_repository *repo, int argc, char **argv);
6061
extern int lg2_checkout(git_repository *repo, int argc, char **argv);
6162
extern int lg2_clone(git_repository *repo, int argc, char **argv);
@@ -69,10 +70,12 @@ extern int lg2_general(git_repository *repo, int argc, char **argv);
6970
extern int lg2_index_pack(git_repository *repo, int argc, char **argv);
7071
extern int lg2_init(git_repository *repo, int argc, char **argv);
7172
extern int lg2_log(git_repository *repo, int argc, char **argv);
73+
extern int lg2_log_last_commit_of_branch(git_repository *repo, int argc, char **argv);
7274
extern int lg2_ls_files(git_repository *repo, int argc, char **argv);
7375
extern int lg2_ls_remote(git_repository *repo, int argc, char **argv);
7476
extern int lg2_merge(git_repository *repo, int argc, char **argv);
7577
extern int lg2_push(git_repository *repo, int argc, char **argv);
78+
extern int lg2_rebase(git_repository *repo, int argc, char **argv);
7679
extern int lg2_remote(git_repository *repo, int argc, char **argv);
7780
extern int lg2_reset(git_repository *repo, int argc, char **argv);
7881
extern int lg2_revert(git_repository *repo, int argc, char **argv);
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#include "common.h"
2+
3+
static int progress_cb(const char *str, int len, void *data)
4+
{
5+
(void)data;
6+
printf("remote: %.*s", len, str);
7+
fflush(stdout); /* We don't have the \n to force the flush */
8+
return 0;
9+
}
10+
11+
/**
12+
* This function gets called for each remote-tracking branch that gets
13+
* updated. The message we output depends on whether it's a new one or
14+
* an update.
15+
*/
16+
static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data)
17+
{
18+
char a_str[GIT_OID_SHA1_HEXSIZE+1], b_str[GIT_OID_SHA1_HEXSIZE+1];
19+
(void)data;
20+
21+
git_oid_fmt(b_str, b);
22+
b_str[GIT_OID_SHA1_HEXSIZE] = '\0';
23+
24+
if (git_oid_is_zero(a)) {
25+
printf("[new] %.20s %s\n", b_str, refname);
26+
} else {
27+
git_oid_fmt(a_str, a);
28+
a_str[GIT_OID_SHA1_HEXSIZE] = '\0';
29+
printf("[updated] %.10s..%.10s %s\n", a_str, b_str, refname);
30+
}
31+
32+
return 0;
33+
}
34+
35+
/**
36+
* This gets called during the download and indexing. Here we show
37+
* processed and total objects in the pack and the amount of received
38+
* data. Most frontends will probably want to show a percentage and
39+
* the download rate.
40+
*/
41+
static int transfer_progress_cb(const git_indexer_progress *stats, void *payload)
42+
{
43+
(void)payload;
44+
45+
if (stats->received_objects == stats->total_objects) {
46+
printf("Resolving deltas %u/%u\r",
47+
stats->indexed_deltas, stats->total_deltas);
48+
} else if (stats->total_objects > 0) {
49+
printf("Received %u/%u objects (%u) in %" PRIuZ " bytes\r",
50+
stats->received_objects, stats->total_objects,
51+
stats->indexed_objects, stats->received_bytes);
52+
}
53+
return 0;
54+
}
55+
56+
/** Entry point for this command */
57+
int lg2_fetch(git_repository *repo, int argc, char **argv)
58+
{
59+
git_remote *remote = NULL;
60+
const git_indexer_progress *stats;
61+
git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
62+
63+
if (argc < 2) {
64+
fprintf(stderr, "usage: %s fetch <repo>\n", argv[-1]);
65+
return EXIT_FAILURE;
66+
}
67+
68+
fetch_opts.prune = GIT_FETCH_PRUNE;
69+
70+
/* Figure out whether it's a named remote or a URL */
71+
printf("Fetching %s for repo %p\n", argv[1], repo);
72+
if (git_remote_lookup(&remote, repo, argv[1]) < 0)
73+
if (git_remote_create_anonymous(&remote, repo, argv[1]) < 0)
74+
goto on_error;
75+
76+
/* Set up the callbacks (only update_tips for now) */
77+
fetch_opts.callbacks.update_tips = &update_cb;
78+
fetch_opts.callbacks.sideband_progress = &progress_cb;
79+
fetch_opts.callbacks.transfer_progress = transfer_progress_cb;
80+
fetch_opts.callbacks.credentials = cred_acquire_cb;
81+
82+
/**
83+
* Perform the fetch with the configured refspecs from the
84+
* config. Update the reflog for the updated references with
85+
* "fetch".
86+
*/
87+
if (git_remote_fetch(remote, NULL, &fetch_opts, "fetch") < 0)
88+
goto on_error;
89+
90+
/**
91+
* If there are local objects (we got a thin pack), then tell
92+
* the user how many objects we saved from having to cross the
93+
* network.
94+
*/
95+
stats = git_remote_stats(remote);
96+
if (stats->local_objects > 0) {
97+
printf("\rReceived %u/%u objects in %" PRIuZ " bytes (used %u local objects)\n",
98+
stats->indexed_objects, stats->total_objects, stats->received_bytes, stats->local_objects);
99+
} else{
100+
printf("\rReceived %u/%u objects in %" PRIuZ "bytes\n",
101+
stats->indexed_objects, stats->total_objects, stats->received_bytes);
102+
}
103+
104+
git_remote_free(remote);
105+
106+
return 0;
107+
108+
on_error:
109+
git_remote_free(remote);
110+
return -1;
111+
}

0 commit comments

Comments
 (0)