Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WASMFS and WASI support #88

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"postCreateCommand": "/workspaces/wasm-git/.devcontainer/post-create.sh",
"customizations": {
"vscode": {
"extensions": ["dtsvet.vscode-wasm","ms-vscode.cpptools-extension-pack"]
}
}
}
29 changes: 29 additions & 0 deletions .devcontainer/post-create.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash
curl https://wasmtime.dev/install.sh -sSf | bash
npm install
sh setup.sh

git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
git pull
./emsdk install latest
./emsdk activate latest
cd ..

sudo apt update
sudo apt install -y clang-12
sudo apt install -y lld-12
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-12 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-12 100

sudo ln -s /usr/bin/wasm-ld-12 /usr/bin/wasm-ld

cd wasibuild

wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-linux.tar.gz
tar -xvzf wasi-sdk-20.0-linux.tar.gz
sudo cp -r wasi-sdk-20.0/lib/clang/16/lib/wasi /usr/lib/llvm-12/lib/clang/12.0.0/lib/

cd ..

curl https://wasmtime.dev/install.sh -sSf | bash
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ package
.idea
emsdk
nodefsclonetest
google-chrome-stable_current_amd64.deb
google-chrome-stable_current_amd64.deb
4 changes: 2 additions & 2 deletions emscriptenbuild/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ elif [ "$1" == "Debug-async" ]; then
POST_JS="--post-js $(pwd)/post-async.js"
fi

# Before building, remove any ../libgit2/src/transports/emscriptenhttp.c left from running setup.sh
# Before building, remove any ../libgit2/src/ transports/emscriptenhttp.c left from running setup.sh
[ -f "../libgit2/src/libgit2/transports/emscriptenhttp-async.c" ] && rm ../libgit2/src/libgit2/transports/emscriptenhttp-async.c

emcmake cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_C_FLAGS="$EXTRA_CMAKE_C_FLAGS --pre-js $(pwd)/pre.js $POST_JS -s \"EXTRA_EXPORTED_RUNTIME_METHODS=['FS','callMain']\" -lnodefs.js -lidbfs.js -s INVOKE_RUN=0 -s ALLOW_MEMORY_GROWTH=1 -s STACK_SIZE=131072" -DREGEX_BACKEND=regcomp -DSONAME=OFF -DUSE_HTTPS=OFF -DBUILD_SHARED_LIBS=OFF -DTHREADSAFE=OFF -DUSE_SSH=OFF -DBUILD_CLAR=OFF -DBUILD_EXAMPLES=ON ../libgit2
emcmake cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_C_FLAGS="$EXTRA_CMAKE_C_FLAGS --pre-js $(pwd)/pre.js $POST_JS -s \"EXTRA_EXPORTED_RUNTIME_METHODS=['FS','callMain']\" -sFORCE_FILESYSTEM -sEXPORT_ES6 -sWASMFS -s INVOKE_RUN=0 -s ALLOW_MEMORY_GROWTH=1 -s STACK_SIZE=131072" -DREGEX_BACKEND=regcomp -DSONAME=OFF -DUSE_HTTPS=OFF -DBUILD_SHARED_LIBS=OFF -DTHREADSAFE=OFF -DUSE_SSH=OFF -DBUILD_CLAR=OFF -DBUILD_EXAMPLES=ON ../libgit2
emmake make lg2
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "wasm-git",
"version": "0.0.11",
"type": "module",
"author": {
"name": "Peter Salomonsen",
"url": "https://petersalomonsen.com"
Expand Down
2 changes: 2 additions & 0 deletions setup.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/bin/bash

curl -L https://github.com/libgit2/libgit2/archive/refs/tags/v1.7.1.tar.gz --output libgit2.tar.gz
tar -xzf libgit2.tar.gz
mv libgit2-1.7.1 libgit2
Expand Down
10 changes: 10 additions & 0 deletions setup_wasi.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

curl -L https://github.com/libgit2/libgit2/archive/refs/tags/v1.7.1.tar.gz --output libgit2.tar.gz
tar -xzf libgit2.tar.gz
mv libgit2-1.7.1 libgit2
rm libgit2.tar.gz
rm libgit2/src/libgit2/transports/http.c
rm libgit2/src/libgit2/streams/socket.c

cp -r libgit2patchedfiles/examples/* libgit2/examples/
4 changes: 2 additions & 2 deletions test/checkout.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const lgPromise = require('./common.js').lgPromise;
const assert = require('assert');
import { lgPromise } from './common.js';
import assert from 'assert';

describe('git checkout', () => {
beforeEach(async () => {
Expand Down
19 changes: 1 addition & 18 deletions test/common.js
Original file line number Diff line number Diff line change
@@ -1,18 +1 @@
module.exports = {
lgPromise: new Promise(resolve => {
const lg = require('./lg2.js');
lg.onRuntimeInitialized = () => {
const FS = lg.FS;
const MEMFS = FS.filesystems.MEMFS;

FS.mkdir('/working');
FS.mount(MEMFS, { }, '/working');
FS.chdir('/working');

FS.writeFile('/home/web_user/.gitconfig', '[user]\n' +
'name = Test User\n' +
'email = [email protected]');
resolve(lg);
};
})
}
export const lgPromise = await import('./lg2.js').then(r => r.default());
4 changes: 2 additions & 2 deletions test/conflict.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const lgPromise = require('./common.js').lgPromise;
const assert = require('assert');
import { lgPromise } from './common.js';
import assert from 'assert';

describe('conflicts', function() {
beforeEach(async () => {
Expand Down
4 changes: 2 additions & 2 deletions test/fetch.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const assert = require('assert');
const lgPromise = require('./common.js').lgPromise;
import { lgPromise } from './common.js';
import assert from 'assert';

describe('git fetch', () => {
beforeEach(async () => {
Expand Down
18 changes: 18 additions & 0 deletions test/hellowasmfs.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { lgPromise } from './common.js';

describe.only('hello wasmfs', () => {
it.only('hello wasmfs', async () => {
const lg = await lgPromise;
const FS = lg.FS;

FS.mkdir('/test');
FS.chdir('/test');
lg.callMain(['init', '.']);
lg.callMain(['config', 'user.name', 'test']);
lg.callMain(['config', 'user.email', '[email protected]']);
FS.writeFile('test.txt', 'abcdef');
lg.callMain(['add', 'test.txt']);
lg.callMain(['commit', '-m', 'test commit']);
lg.callMain(['log']);
});
});
6 changes: 3 additions & 3 deletions test/nodefs.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const lgPromise = require('./common.js').lgPromise;
const assert = require('assert');
const { rmSync } = require('fs');
import { lgPromise } from './common.js';
import assert from 'assert';
import {rmSync} from 'fs';

describe('nodefs', function () {
this.timeout(20000);
Expand Down
4 changes: 2 additions & 2 deletions test/revert.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const lgPromise = require('./common.js').lgPromise;
const assert = require('assert');
import { lgPromise } from './common.js';
import assert from 'assert';

describe('git revert', () => {
beforeEach(async () => {
Expand Down
13 changes: 13 additions & 0 deletions wasibuild/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CMake*
src
deps
examples
libgit2*
include
Makefile
*.cmake
*.a
tests
wasi-sdk*
!wasi_toolchain.cmake
CopyOfCMakeCache.txt
14 changes: 14 additions & 0 deletions wasibuild/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
BUILD_TYPE=Debug

# Set build type to Release for release
if [ "$1" == "Release" ]; then
BUILD_TYPE=Release
EXTRA_CMAKE_C_FLAGS="-Oz"
fi

clang --target=wasm32-wasi --sysroot=wasi-sdk-20.0/share/wasi-sysroot -D_WASI_EMULATED_MMAN -Iwasi_mocks -c wasi_mocks/pwd.c -o wasi_mocks/pwd.o
clang --target=wasm32-wasi --sysroot=wasi-sdk-20.0/share/wasi-sysroot -D_WASI_EMULATED_MMAN -Iwasi_mocks -c wasi_mocks/posix_mocks.c -o wasi_mocks/posix_mocks.o
cmake -DCMAKE_TOOLCHAIN_FILE=`pwd`/wasi_toolchain.cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_C_FLAGS="$EXTRA_CMAKE_C_FLAGS" -DREGEX_BACKEND=regcomp -DSONAME=OFF -DUSE_HTTPS=OFF -DBUILD_SHARED_LIBS=OFF -DUSE_THREADS=OFF -DUSE_SSH=OFF -DBUILD_CLAR=OFF -DBUILD_EXAMPLES=ON ../libgit2
make lg2 VERBOSE=1
mv examples/lg2 lg2.wasm
1 change: 1 addition & 0 deletions wasibuild/wasi_mocks/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.o
86 changes: 86 additions & 0 deletions wasibuild/wasi_mocks/posix_mocks.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include "posix_mocks.h"
#include <errno.h>

char *realpath(const char *path, char *resolved_path) {
if (resolved_path) {
// Mock implementation - return an empty string or some mock path
resolved_path[0] = '\0';
}
return resolved_path;
}

pid_t getpid(void) {
return 1; // Mock PID
}

pid_t getppid(void) {
return 1; // Mock Parent PID
}

pid_t getpgid(pid_t pid) {
return 1; // Mock PGID
}

pid_t getsid(pid_t pid) {
return 1; // Mock SID
}

uid_t getuid(void) {
return 0; // Mock UID
}

gid_t getgid(void) {
return 1000; // Mock GID
}

int chmod(const char *pathname, mode_t mode) {
return 0; // Mock success
}

uid_t geteuid(void) {
return 0; // Mock effective UID
}

struct passwd *getpwuid(uid_t uid) {
static struct passwd dummy_passwd;
// Populate dummy_passwd with mock data
return &dummy_passwd;
}

int git_socket_stream_global_init(void) {
return 0; // Mock success
}

void *git_socket_stream_new(int a, int b, int c) {
return NULL; // Mock return
}

void *git_smart_subtransport_http(void) {
return NULL; // Mock return
}

int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result) {
if (!pwd || !buf || buflen < sizeof(struct passwd)) {
errno = ERANGE;
return ERANGE;
}

// You can fill in the `pwd` structure with mock data as needed
pwd->pw_name = "codespace";
pwd->pw_passwd = "mockpassword";
pwd->pw_uid = uid;
pwd->pw_gid = 0; // Mock GID
pwd->pw_gecos = "Mock User";
pwd->pw_dir = "/home/codespace";
pwd->pw_shell = "/bin/sh";

// Copy the structure to the provided buffer
memcpy(buf, pwd, sizeof(struct passwd));

// Set the result
*result = (struct passwd *)buf;

return 0; // Return success
}

// ... Add more function implementations as needed ...
24 changes: 24 additions & 0 deletions wasibuild/wasi_mocks/posix_mocks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef POSIX_MOCKS_H
#define POSIX_MOCKS_H

#include <sys/types.h>
#include <unistd.h>
#include "pwd.h"

// Mock function declarations
char *realpath(const char *path, char *resolved_path);
pid_t getpid(void);
pid_t getppid(void);
pid_t getpgid(pid_t pid);
pid_t getsid(pid_t pid);
uid_t getuid(void);
gid_t getgid(void);
int chmod(const char *pathname, mode_t mode);
uid_t geteuid(void);
struct passwd *getpwuid(uid_t uid);
int git_socket_stream_global_init(void);
void *git_socket_stream_new(int a, int b, int c);
void *git_smart_subtransport_http(void);
int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result);

#endif // POSIX_MOCKS_H
31 changes: 31 additions & 0 deletions wasibuild/wasi_mocks/pwd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <sys/types.h>
#include <stddef.h>

// Mock structure similar to 'struct passwd' in pwd.h
struct passwd {
char *pw_name; // user's name
char *pw_passwd; // user's password
uid_t pw_uid; // user's user ID
gid_t pw_gid; // user's group ID
char *pw_gecos; // user's real name
char *pw_dir; // user's home directory
char *pw_shell; // user's shell program
};

// Mock function similar to 'getpwnam' in pwd.h
struct passwd *getpwnam(const char *name) {
static struct passwd mock_user;

// Hardcoded user information
mock_user.pw_name = "codespace";
mock_user.pw_passwd = "mockpassword";
mock_user.pw_uid = 0;
mock_user.pw_gid = 0;
mock_user.pw_gecos = "Mock User";
mock_user.pw_dir = "/home/codespace";
mock_user.pw_shell = "/bin/sh";

return &mock_user;
}

// ... other mock functions as needed ...
20 changes: 20 additions & 0 deletions wasibuild/wasi_mocks/pwd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef MOCK_PWD_H
#define MOCK_PWD_H

#include <sys/types.h>

// Mock structure similar to 'struct passwd' in pwd.h
struct passwd {
char *pw_name; // user's name
char *pw_passwd; // user's password
uid_t pw_uid; // user's user ID
gid_t pw_gid; // user's group ID
char *pw_gecos; // user's real name
char *pw_dir; // user's home directory
char *pw_shell; // user's shell program
};

// Mock function declaration
struct passwd *getpwnam(const char *name);

#endif // MOCK_PWD_H
16 changes: 16 additions & 0 deletions wasibuild/wasi_toolchain.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
SET(CMAKE_C_COMPILER clang)
SET(CMAKE_FIND_ROOT_PATH ${CMAKE_CURRENT_LIST_DIR}/wasi-sdk-20.0/share/wasi-sysroot/)
SET(CMAKE_SYSROOT ${CMAKE_CURRENT_LIST_DIR}/wasi-sdk-20.0/share/wasi-sysroot/)
set(CMAKE_C_FLAGS "--target=wasm32-wasi -Wl,--initial-memory=268435456 -I${CMAKE_CURRENT_LIST_DIR}/wasi_mocks -D_WASI_EMULATED_MMAN ${CMAKE_C_FLAGS}")

set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES "${CMAKE_SYSROOT}/include")

set(CMAKE_C_FLAGS_DEBUG "")

SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_AR "llvm-ar" CACHE FILEPATH "llvm-ar")
set(CMAKE_RANLIB "llvm-ranlib" CACHE FILEPATH "llvm-ranlib")

set(CMAKE_EXE_LINKER_FLAGS "-lwasi-emulated-mman ${CMAKE_CURRENT_LIST_DIR}/wasi_mocks/pwd.o ${CMAKE_CURRENT_LIST_DIR}/wasi_mocks/posix_mocks.o ${CMAKE_EXE_LINKER_FLAGS}")
Loading