@elixir-playground/git 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +15 -0
- package/fs/bundles/0.tar +0 -0
- package/fs/manifest.json +1 -0
- package/git.wasm +0 -0
- package/index.d.ts +4 -0
- package/index.js +34 -0
- package/licenses/git-2.56.0/COPYING +360 -0
- package/licenses/git-2.56.0/LGPL-2.1 +511 -0
- package/licenses/index.json +51 -0
- package/licenses/wasi-compat-playground/LICENSE +18 -0
- package/licenses/wasi-libc-2e6fb9d8ee0c/LICENSE +17 -0
- package/licenses/wasi-libc-2e6fb9d8ee0c/LICENSE-APACHE +201 -0
- package/licenses/wasi-libc-2e6fb9d8ee0c/LICENSE-APACHE-LLVM +220 -0
- package/licenses/wasi-libc-2e6fb9d8ee0c/LICENSE-MIT +23 -0
- package/licenses/wasi-libc-2e6fb9d8ee0c/cloudlibc-LICENSE +22 -0
- package/licenses/wasi-libc-2e6fb9d8ee0c/musl-COPYRIGHT +193 -0
- package/licenses/wasi-libc-2e6fb9d8ee0c/musl-fts-COPYING +26 -0
- package/licenses/zlib-1.3.2/LICENSE +22 -0
- package/package.json +48 -4
- package/source/git/README.md +17 -0
- package/source/git/git-2.56.0.tar.xz +0 -0
- package/source/git/tools/git/build.py +168 -0
- package/source/git/tools/git/config.mak +42 -0
- package/source/git/tools/git/patches/0001-wasi-spawn.patch +76 -0
- package/source/git/tools/git/patches/0002-wasi-async.patch +124 -0
- package/source/git/tools/wasi-compat/LICENSE +18 -0
- package/source/git/tools/wasi-compat/autoconf.py +158 -0
- package/source/git/tools/wasi-compat/config.site +31 -0
- package/source/git/tools/wasi-compat/include/grp.h +6 -0
- package/source/git/tools/wasi-compat/include/mntent.h +10 -0
- package/source/git/tools/wasi-compat/include/netdb.h +7 -0
- package/source/git/tools/wasi-compat/include/paths.h +2 -0
- package/source/git/tools/wasi-compat/include/pwd.h +5 -0
- package/source/git/tools/wasi-compat/include/setjmp.h +17 -0
- package/source/git/tools/wasi-compat/include/sys/wait.h +8 -0
- package/source/git/tools/wasi-compat/include/syslog.h +7 -0
- package/source/git/tools/wasi-compat/include/termios.h +10 -0
- package/source/git/tools/wasi-compat/include/wasi-compat.h +38 -0
- package/source/git/tools/wasi-compat/include/wasi-posix.h +79 -0
- package/source/git/tools/wasi-compat/stubs.c +326 -0
- package/source/git/tools/wasi-compat/wrap.c +54 -0
- package/source/git/zlib-1.3.2.tar.gz +0 -0
- package/README.md +0 -3
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Copyright (c) 1989, 1993
|
|
2
|
+
The Regents of the University of California. All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions
|
|
6
|
+
are met:
|
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
10
|
+
notice, this list of conditions and the following disclaimer in the
|
|
11
|
+
documentation and/or other materials provided with the distribution.
|
|
12
|
+
3. Neither the name of the University nor the names of its contributors
|
|
13
|
+
may be used to endorse or promote products derived from this software
|
|
14
|
+
without specific prior written permission.
|
|
15
|
+
|
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
17
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
18
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
19
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
20
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
21
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
22
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
23
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
24
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
25
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
26
|
+
SUCH DAMAGE.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright notice:
|
|
2
|
+
|
|
3
|
+
(C) 1995-2026 Jean-loup Gailly and Mark Adler
|
|
4
|
+
|
|
5
|
+
This software is provided 'as-is', without any express or implied
|
|
6
|
+
warranty. In no event will the authors be held liable for any damages
|
|
7
|
+
arising from the use of this software.
|
|
8
|
+
|
|
9
|
+
Permission is granted to anyone to use this software for any purpose,
|
|
10
|
+
including commercial applications, and to alter it and redistribute it
|
|
11
|
+
freely, subject to the following restrictions:
|
|
12
|
+
|
|
13
|
+
1. The origin of this software must not be misrepresented; you must not
|
|
14
|
+
claim that you wrote the original software. If you use this software
|
|
15
|
+
in a product, an acknowledgment in the product documentation would be
|
|
16
|
+
appreciated but is not required.
|
|
17
|
+
2. Altered source versions must be plainly marked as such, and must not be
|
|
18
|
+
misrepresented as being the original software.
|
|
19
|
+
3. This notice may not be removed or altered from any source distribution.
|
|
20
|
+
|
|
21
|
+
Jean-loup Gailly Mark Adler
|
|
22
|
+
jloup@gzip.org madler@alumni.caltech.edu
|
package/package.json
CHANGED
|
@@ -1,6 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elixir-playground/git",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"license": "(Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT) AND BSD-2-Clause AND BSD-3-Clause AND GPL-2.0-only AND MIT AND Zlib",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/SteffenDE/run-elixir.dev.git"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"NOTICE.md",
|
|
11
|
+
"fs",
|
|
12
|
+
"git.wasm",
|
|
13
|
+
"index.d.ts",
|
|
14
|
+
"index.js",
|
|
15
|
+
"licenses",
|
|
16
|
+
"source"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"types": "./index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./index.d.ts",
|
|
23
|
+
"default": "./index.js"
|
|
24
|
+
},
|
|
25
|
+
"./package.json": "./package.json"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@elixir-playground/runtime": "^1.0.0"
|
|
29
|
+
},
|
|
30
|
+
"playground": {
|
|
31
|
+
"abi": {
|
|
32
|
+
"wasi": 1,
|
|
33
|
+
"processes": 1
|
|
34
|
+
},
|
|
35
|
+
"programs": {
|
|
36
|
+
"git": {
|
|
37
|
+
"module": "git.wasm"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"fs": {
|
|
41
|
+
"format": 3,
|
|
42
|
+
"root": "/usr/libexec/git-core",
|
|
43
|
+
"manifest": "fs/manifest.json",
|
|
44
|
+
"bundles": "fs/bundles/",
|
|
45
|
+
"count": 1,
|
|
46
|
+
"version": "14ca27ec67928487"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"playgroundDigest": "ca33357805ab"
|
|
50
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# git 2.56.0: corresponding source
|
|
2
|
+
|
|
3
|
+
The source of the WebAssembly build of git 2.56.0 in this package,
|
|
4
|
+
under GPL-2.0-only (its COPYING): what the build is made from, as the
|
|
5
|
+
playground's repository has it.
|
|
6
|
+
|
|
7
|
+
- `git-2.56.0.tar.xz`
|
|
8
|
+
- `tools/git/build.py`
|
|
9
|
+
- `tools/git/config.mak`
|
|
10
|
+
- `tools/git/patches`
|
|
11
|
+
- `tools/wasi-compat`
|
|
12
|
+
- `zlib-1.3.2.tar.gz`
|
|
13
|
+
|
|
14
|
+
The build applies `patches/` to the release, links `wasi-compat/` (MIT)
|
|
15
|
+
and wasi-libc, and compiles with the wasi-sdk Docker image its script
|
|
16
|
+
names by digest. From a checkout of the playground's repository, with
|
|
17
|
+
these files in their places there, `python3 -I tools/git/build.py` builds it.
|
|
Binary file
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""git built to WebAssembly (wasm32-wasip1): the git CLI itself, for the
|
|
2
|
+
shell and the nodes (docs/git.md).
|
|
3
|
+
|
|
4
|
+
python3 -I tools/git/build.py # → target/git/git.wasm
|
|
5
|
+
|
|
6
|
+
git's release with patches/ applied, and zlib, built with wasi-sdk in
|
|
7
|
+
Docker (backend/Dockerfile's wasi-sdk). WASI preview 1 lacks processes, users,
|
|
8
|
+
modes, terminals and sockets: tools/wasi-compat/ (every C tool's) declares what
|
|
9
|
+
git asks of them and stubs it (stubs.c), its processes the playground's
|
|
10
|
+
host's (the `processes` imports, packages/runtime/src/processes.ts:
|
|
11
|
+
run-command.c spawns instead of forking), and config.mak turns off the
|
|
12
|
+
rest.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import hashlib
|
|
16
|
+
import importlib.util
|
|
17
|
+
import os
|
|
18
|
+
import shutil
|
|
19
|
+
import subprocess
|
|
20
|
+
import tarfile
|
|
21
|
+
import urllib.request
|
|
22
|
+
|
|
23
|
+
# The repository (this file is tools/NAME/build.py).
|
|
24
|
+
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
25
|
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
26
|
+
# What WASI lacks, for every C tool (wasi-compat.h, stubs.c).
|
|
27
|
+
COMPAT = os.path.join(ROOT, "tools", "wasi-compat")
|
|
28
|
+
OUT = os.path.join(ROOT, "target", "git")
|
|
29
|
+
DOCKER = os.environ.get("DOCKER", "sudo -n docker").split()
|
|
30
|
+
# wasi-sdk 33 (clang 23), as the backend's NIF toolchain (backend/Dockerfile).
|
|
31
|
+
IMAGE = "ghcr.io/webassembly/wasi-sdk@sha256:52595085a0ffbaf574d8d678a9aa81305f0b3af81c639291f15bc7713e42848e"
|
|
32
|
+
GIT = ("2.56.0", "https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.56.0.tar.xz",
|
|
33
|
+
"26c56c296b38c0695b26fa95f475f1d01704d2d38e73465ca30b0b2f5dc789d3")
|
|
34
|
+
ZLIB = ("1.3.2", "https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz",
|
|
35
|
+
"bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16")
|
|
36
|
+
# git's Makefile reads `uname` before config.mak: on the command line, so
|
|
37
|
+
# that the host's (Linux) settings stay out.
|
|
38
|
+
UNAME = "uname_S=WASI uname_M=wasm32 uname_O=WASI uname_R=1 uname_V=1"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def fetch(source, sha256, path):
|
|
42
|
+
if not os.path.exists(path):
|
|
43
|
+
urllib.request.urlretrieve(source, path + ".part")
|
|
44
|
+
with open(path + ".part", "rb") as f:
|
|
45
|
+
got = hashlib.sha256(f.read()).hexdigest()
|
|
46
|
+
if got != sha256:
|
|
47
|
+
raise SystemExit(f"{source}: sha256 {got}, not {sha256}")
|
|
48
|
+
os.rename(path + ".part", path)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def stamp():
|
|
52
|
+
"""What the build is made from: the image, the sources, our files."""
|
|
53
|
+
hashed = hashlib.sha256(f"{IMAGE}\0{GIT[2]}\0{ZLIB[2]}\0".encode())
|
|
54
|
+
for top in (HERE, COMPAT):
|
|
55
|
+
for directory, _, names in sorted(os.walk(top)):
|
|
56
|
+
for name in sorted(names):
|
|
57
|
+
if name.endswith(".py"):
|
|
58
|
+
continue
|
|
59
|
+
path = os.path.join(directory, name)
|
|
60
|
+
with open(path, "rb") as f:
|
|
61
|
+
hashed.update(os.path.relpath(path, ROOT).encode() + b"\0" + f.read())
|
|
62
|
+
return hashed.hexdigest()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def licensed(git_archive, zlib_archive):
|
|
66
|
+
"""target/git/licenses (tools/licenses.py) and target/git/source: git is
|
|
67
|
+
GPL-2.0, so its source goes with it: the releases, the patches and the
|
|
68
|
+
build's files, zlib's too (git links it)."""
|
|
69
|
+
spec = importlib.util.spec_from_file_location("licenses", os.path.join(ROOT, "tools", "licenses.py"))
|
|
70
|
+
licenses = importlib.util.module_from_spec(spec)
|
|
71
|
+
spec.loader.exec_module(licenses)
|
|
72
|
+
if licenses.current(OUT, stamp()):
|
|
73
|
+
return
|
|
74
|
+
fetch(GIT[1], GIT[2], git_archive)
|
|
75
|
+
fetch(ZLIB[1], ZLIB[2], zlib_archive)
|
|
76
|
+
zlib = licenses.Inventory().add("zlib", ZLIB[0], "Zlib", "https://zlib.net",
|
|
77
|
+
licenses.archive_texts(zlib_archive, f"zlib-{ZLIB[0]}", ["LICENSE"]))
|
|
78
|
+
sources = {os.path.basename(git_archive): git_archive, os.path.basename(zlib_archive): zlib_archive,
|
|
79
|
+
"tools/git/build.py": os.path.join(HERE, "build.py"),
|
|
80
|
+
"tools/git/config.mak": os.path.join(HERE, "config.mak"),
|
|
81
|
+
"tools/git/patches": os.path.join(HERE, "patches"), "tools/wasi-compat": COMPAT}
|
|
82
|
+
inventory = licenses.c_tool(OUT, "git", GIT[0], "GPL-2.0-only", "https://git-scm.com", git_archive,
|
|
83
|
+
["COPYING", "LGPL-2.1"], sources, "tools/git/build.py", [zlib])
|
|
84
|
+
licenses.finish(inventory, OUT, stamp())
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def unpack(archive, name, into):
|
|
88
|
+
shutil.rmtree(into, ignore_errors=True)
|
|
89
|
+
with tarfile.open(archive) as tar:
|
|
90
|
+
tar.extractall(OUT, filter="data")
|
|
91
|
+
os.rename(os.path.join(OUT, name), into)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# git's commands that are shell scripts (its SCRIPT_SH and SCRIPT_LIB), which
|
|
95
|
+
# the playground's sh runs from git's exec path.
|
|
96
|
+
SCRIPTS = [
|
|
97
|
+
"git-difftool--helper", "git-filter-branch", "git-merge-octopus", "git-merge-one-file",
|
|
98
|
+
"git-merge-resolve", "git-mergetool", "git-quiltimport", "git-request-pull", "git-submodule",
|
|
99
|
+
"git-web--browse", "git-mergetool--lib", "git-sh-i18n", "git-sh-setup",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def main():
|
|
104
|
+
os.makedirs(OUT, exist_ok=True)
|
|
105
|
+
built = os.path.join(OUT, "stamp")
|
|
106
|
+
git_archive = os.path.join(OUT, f"git-{GIT[0]}.tar.xz")
|
|
107
|
+
zlib_archive = os.path.join(OUT, f"zlib-{ZLIB[0]}.tar.gz")
|
|
108
|
+
if os.path.exists(os.path.join(OUT, "git.wasm")) and os.path.exists(built):
|
|
109
|
+
with open(built) as f:
|
|
110
|
+
if f.read() == stamp():
|
|
111
|
+
return licensed(git_archive, zlib_archive)
|
|
112
|
+
fetch(GIT[1], GIT[2], git_archive)
|
|
113
|
+
fetch(ZLIB[1], ZLIB[2], zlib_archive)
|
|
114
|
+
src = os.path.join(OUT, "src")
|
|
115
|
+
zlib = os.path.join(OUT, "zlib-src")
|
|
116
|
+
unpack(git_archive, f"git-{GIT[0]}", src)
|
|
117
|
+
for name in sorted(os.listdir(os.path.join(HERE, "patches"))):
|
|
118
|
+
subprocess.run(["patch", "-p1", "-s", "-d", src, "-i", os.path.join(HERE, "patches", name)],
|
|
119
|
+
check=True)
|
|
120
|
+
unpack(zlib_archive, f"zlib-{ZLIB[0]}", zlib)
|
|
121
|
+
shutil.copy(os.path.join(HERE, "config.mak"), os.path.join(src, "config.mak"))
|
|
122
|
+
wasi = os.path.join(OUT, "wasi")
|
|
123
|
+
shutil.rmtree(wasi, ignore_errors=True)
|
|
124
|
+
shutil.copytree(COMPAT, wasi)
|
|
125
|
+
cc = "/opt/wasi-sdk/bin/clang --target=wasm32-wasip1 --sysroot=/opt/wasi-sdk/share/wasi-sysroot"
|
|
126
|
+
script = (
|
|
127
|
+
# zlib's configure runs what it builds: its files by hand instead.
|
|
128
|
+
"cd /zlib-src\n"
|
|
129
|
+
"mkdir -p /zlib/include /zlib/lib\n"
|
|
130
|
+
f"for c in adler32 compress crc32 deflate gzclose gzlib gzread gzwrite infback inffast "
|
|
131
|
+
f"inflate inftrees trees uncompr zutil; do {cc} -Oz -DHAVE_UNISTD_H -DHAVE_STDARG_H -c $c.c -o $c.o; done\n"
|
|
132
|
+
"/opt/wasi-sdk/bin/llvm-ar rcs /zlib/lib/libz.a *.o\n"
|
|
133
|
+
"cp zlib.h zconf.h /zlib/include/\n"
|
|
134
|
+
"cd /src\n"
|
|
135
|
+
# test-tool, GIT-BUILD-OPTIONS and templates/blt: for git's own tests
|
|
136
|
+
# (packages/runtime/test/git).
|
|
137
|
+
f"make -s -j$(nproc) {UNAME} git {' '.join(SCRIPTS)} t/helper/test-tool GIT-BUILD-OPTIONS >/dev/null\n"
|
|
138
|
+
"make -s -C templates >/dev/null\n"
|
|
139
|
+
f"chown -R {os.getuid()}:{os.getgid()} /src /zlib-src /zlib /wasi\n"
|
|
140
|
+
)
|
|
141
|
+
zlib_out = os.path.join(OUT, "zlib")
|
|
142
|
+
os.makedirs(zlib_out, exist_ok=True)
|
|
143
|
+
subprocess.run(DOCKER + [
|
|
144
|
+
"run", "--rm", "-v", f"{src}:/src", "-v", f"{zlib}:/zlib-src", "-v", f"{zlib_out}:/zlib",
|
|
145
|
+
"-v", f"{wasi}:/wasi", IMAGE, "sh", "-ec", script,
|
|
146
|
+
], check=True)
|
|
147
|
+
shutil.copy(os.path.join(src, "git"), os.path.join(OUT, "git.wasm"))
|
|
148
|
+
shutil.copy(os.path.join(src, "t", "helper", "test-tool"), os.path.join(OUT, "test-tool.wasm"))
|
|
149
|
+
# The scripts, for the site's /usr/libexec/git-core (runtime/build.py).
|
|
150
|
+
libexec = os.path.join(OUT, "libexec")
|
|
151
|
+
shutil.rmtree(libexec, ignore_errors=True)
|
|
152
|
+
os.makedirs(libexec)
|
|
153
|
+
for name in SCRIPTS:
|
|
154
|
+
shutil.copy(os.path.join(src, name), os.path.join(libexec, name))
|
|
155
|
+
# The build's paths, as the tests on the host see them (not Docker's /src).
|
|
156
|
+
options = os.path.join(src, "GIT-BUILD-OPTIONS")
|
|
157
|
+
with open(options) as f:
|
|
158
|
+
text = f.read().replace("='/src", f"='{src}")
|
|
159
|
+
with open(options, "w") as f:
|
|
160
|
+
f.write(text)
|
|
161
|
+
with open(built, "w") as f:
|
|
162
|
+
f.write(stamp())
|
|
163
|
+
licensed(git_archive, zlib_archive)
|
|
164
|
+
print(f"{OUT}/git.wasm: {os.path.getsize(os.path.join(OUT, 'git.wasm')) / 1e6:.1f} MB")
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
if __name__ == "__main__":
|
|
168
|
+
main()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# git's build for wasm32-wasip1 (tools/git/build.py copies this into the source
|
|
2
|
+
# as config.mak). WASI preview 1 has no processes, threads, users, modes,
|
|
3
|
+
# terminals or sockets: what git would ask of them, tools/wasi-compat/ declares and
|
|
4
|
+
# stubs; what has a compat fallback in git (regex, mmap, poll) uses it.
|
|
5
|
+
CC = /opt/wasi-sdk/bin/clang --target=wasm32-wasip1 --sysroot=/opt/wasi-sdk/share/wasi-sysroot
|
|
6
|
+
AR = /opt/wasi-sdk/bin/llvm-ar
|
|
7
|
+
CFLAGS = -Oz -Wno-macro-redefined -I/zlib/include -I/wasi/include -include /wasi/include/wasi-compat.h \
|
|
8
|
+
-Dchmod=wasi_chmod -Dfchmod=wasi_fchmod \
|
|
9
|
+
-D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_PROCESS_CLOCKS -D_WASI_EMULATED_GETPID -D_WASI_EMULATED_MMAN
|
|
10
|
+
# A stack of 1 MiB (wasm-ld's default is 64 KiB): history walks recurse.
|
|
11
|
+
# The stack pointer exported: the host switches it between git and an
|
|
12
|
+
# async's coroutine (stubs.c wasi_async_start).
|
|
13
|
+
LDFLAGS = -L/zlib/lib -Wl,-z,stack-size=1048576 -Wl,--export=__stack_pointer \
|
|
14
|
+
-lwasi-emulated-signal -lwasi-emulated-process-clocks -lwasi-emulated-getpid -lwasi-emulated-mman
|
|
15
|
+
LIB_OBJS += /wasi/stubs.o
|
|
16
|
+
|
|
17
|
+
prefix = /usr
|
|
18
|
+
NO_RUST = YesPlease
|
|
19
|
+
NO_PTHREADS = YesPlease
|
|
20
|
+
NO_CURL = YesPlease
|
|
21
|
+
NO_EXPAT = YesPlease
|
|
22
|
+
NO_GETTEXT = YesPlease
|
|
23
|
+
NO_ICONV = YesPlease
|
|
24
|
+
NO_OPENSSL = YesPlease
|
|
25
|
+
NO_PERL = YesPlease
|
|
26
|
+
NO_PYTHON = YesPlease
|
|
27
|
+
NO_TCLTK = YesPlease
|
|
28
|
+
NO_REGEX = YesPlease
|
|
29
|
+
NO_MMAP = YesPlease
|
|
30
|
+
NO_UNIX_SOCKETS = YesPlease
|
|
31
|
+
NO_IPV6 = YesPlease
|
|
32
|
+
NO_SETITIMER = YesPlease
|
|
33
|
+
NO_STRUCT_ITIMERVAL = YesPlease
|
|
34
|
+
NO_INITGROUPS = YesPlease
|
|
35
|
+
NO_GECOS_IN_PWENT = YesPlease
|
|
36
|
+
NO_TRUSTABLE_FILEMODE = YesPlease
|
|
37
|
+
NO_SYMLINK_HEAD = YesPlease
|
|
38
|
+
NO_INSTALL_HARDLINKS = YesPlease
|
|
39
|
+
NO_POSIX_GOODIES = UnfortunatelyYes
|
|
40
|
+
SKIP_DASHED_BUILT_INS = YesPlease
|
|
41
|
+
CSPRNG_METHOD = getentropy
|
|
42
|
+
HAVE_DEV_TTY =
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
--- a/run-command.c
|
|
2
|
+
+++ b/run-command.c
|
|
3
|
+
@@ -745,7 +745,7 @@
|
|
4
|
+
if (cmd->odb_to_close)
|
|
5
|
+
odb_close(cmd->odb_to_close);
|
|
6
|
+
|
|
7
|
+
-#ifndef GIT_WINDOWS_NATIVE
|
|
8
|
+
+#if !defined(GIT_WINDOWS_NATIVE) && !defined(__wasi__)
|
|
9
|
+
{
|
|
10
|
+
int notify_pipe[2];
|
|
11
|
+
int null_fd = -1;
|
|
12
|
+
@@ -908,6 +908,64 @@
|
|
13
|
+
}
|
|
14
|
+
end_of_spawn:
|
|
15
|
+
|
|
16
|
+
+#elif defined(__wasi__)
|
|
17
|
+
+/*
|
|
18
|
+
+ * WASI has no fork: the host starts the child with three of our
|
|
19
|
+
+ * descriptors as its standard streams (wasi_spawn), as Windows does.
|
|
20
|
+
+ */
|
|
21
|
+
+{
|
|
22
|
+
+ int fhin = 0, fhout = 1, fherr = 2;
|
|
23
|
+
+ const char **sargv = cmd->args.v;
|
|
24
|
+
+ struct strvec nargv = STRVEC_INIT;
|
|
25
|
+
+ char **childenv;
|
|
26
|
+
+
|
|
27
|
+
+ if (cmd->no_stdin)
|
|
28
|
+
+ fhin = open("/dev/null", O_RDWR);
|
|
29
|
+
+ else if (need_in)
|
|
30
|
+
+ fhin = dup(fdin[0]);
|
|
31
|
+
+ else if (cmd->in)
|
|
32
|
+
+ fhin = dup(cmd->in);
|
|
33
|
+
+
|
|
34
|
+
+ if (cmd->no_stderr)
|
|
35
|
+
+ fherr = open("/dev/null", O_RDWR);
|
|
36
|
+
+ else if (need_err)
|
|
37
|
+
+ fherr = dup(fderr[1]);
|
|
38
|
+
+ else if (cmd->err > 2)
|
|
39
|
+
+ fherr = dup(cmd->err);
|
|
40
|
+
+
|
|
41
|
+
+ if (cmd->no_stdout)
|
|
42
|
+
+ fhout = open("/dev/null", O_RDWR);
|
|
43
|
+
+ else if (cmd->stdout_to_stderr)
|
|
44
|
+
+ fhout = dup(fherr);
|
|
45
|
+
+ else if (need_out)
|
|
46
|
+
+ fhout = dup(fdout[1]);
|
|
47
|
+
+ else if (cmd->out > 1)
|
|
48
|
+
+ fhout = dup(cmd->out);
|
|
49
|
+
+
|
|
50
|
+
+ if (cmd->git_cmd)
|
|
51
|
+
+ cmd->args.v = prepare_git_cmd(&nargv, sargv);
|
|
52
|
+
+ else if (cmd->use_shell)
|
|
53
|
+
+ cmd->args.v = prepare_shell_cmd(&nargv, sargv);
|
|
54
|
+
+
|
|
55
|
+
+ trace_argv_printf(cmd->args.v, "trace: start_command:");
|
|
56
|
+
+ childenv = prep_childenv(cmd->env.v);
|
|
57
|
+
+ cmd->pid = wasi_spawn(cmd->args.v, childenv, cmd->dir, fhin, fhout, fherr);
|
|
58
|
+
+ failed_errno = errno;
|
|
59
|
+
+ if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
|
|
60
|
+
+ error_errno("cannot run %s", cmd->args.v[0]);
|
|
61
|
+
+ if (cmd->clean_on_exit && cmd->pid >= 0)
|
|
62
|
+
+ mark_child_for_cleanup(cmd->pid, cmd);
|
|
63
|
+
+
|
|
64
|
+
+ free(childenv);
|
|
65
|
+
+ strvec_clear(&nargv);
|
|
66
|
+
+ cmd->args.v = sargv;
|
|
67
|
+
+ if (fhin != 0)
|
|
68
|
+
+ close(fhin);
|
|
69
|
+
+ if (fhout != 1)
|
|
70
|
+
+ close(fhout);
|
|
71
|
+
+ if (fherr != 2)
|
|
72
|
+
+ close(fherr);
|
|
73
|
+
+}
|
|
74
|
+
#else
|
|
75
|
+
{
|
|
76
|
+
int fhin = 0, fhout = 1, fherr = 2;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
diff --git a/run-command.c b/run-command.c
|
|
2
|
+
index 99e18d2..37d909b 100644
|
|
3
|
+
--- a/run-command.c
|
|
4
|
+
+++ b/run-command.c
|
|
5
|
+
@@ -1192,6 +1192,48 @@ int git_atexit(void (*handler)(void))
|
|
6
|
+
}
|
|
7
|
+
#define atexit git_atexit
|
|
8
|
+
|
|
9
|
+
+#ifdef __wasi__
|
|
10
|
+
+/*
|
|
11
|
+
+ * WASI: an async function runs beside git as a coroutine of the host's,
|
|
12
|
+
+ * on a stack of its own (wasi_async_start, tools/wasi-compat/stubs.c). It shares
|
|
13
|
+
+ * git's descriptors and memory as a thread would; the host says which
|
|
14
|
+
+ * runs, and ends one that dies.
|
|
15
|
+
+ */
|
|
16
|
+
+int in_async(void)
|
|
17
|
+
+{
|
|
18
|
+
+ return wasi_async_current() != NULL;
|
|
19
|
+
+}
|
|
20
|
+
+
|
|
21
|
+
+static void NORETURN async_exit(int code)
|
|
22
|
+
+{
|
|
23
|
+
+ wasi_async_exit(code);
|
|
24
|
+
+}
|
|
25
|
+
+
|
|
26
|
+
+static NORETURN void die_async(const char *err, va_list params)
|
|
27
|
+
+{
|
|
28
|
+
+ report_fn die_message_fn = get_die_message_routine();
|
|
29
|
+
+
|
|
30
|
+
+ die_message_fn(err, params);
|
|
31
|
+
+
|
|
32
|
+
+ if (in_async()) {
|
|
33
|
+
+ struct async *async = wasi_async_current();
|
|
34
|
+
+ if (async->proc_in >= 0)
|
|
35
|
+
+ close(async->proc_in);
|
|
36
|
+
+ if (async->proc_out >= 0)
|
|
37
|
+
+ close(async->proc_out);
|
|
38
|
+
+ async_exit(128);
|
|
39
|
+
+ }
|
|
40
|
+
+
|
|
41
|
+
+ exit(128);
|
|
42
|
+
+}
|
|
43
|
+
+
|
|
44
|
+
+/* What the host's coroutine runs: the exit status, as a forked one's. */
|
|
45
|
+
+__attribute__((export_name("wasi_run_async")))
|
|
46
|
+
+int wasi_run_async(struct async *async)
|
|
47
|
+
+{
|
|
48
|
+
+ return !!async->proc(async->proc_in, async->proc_out, async->data);
|
|
49
|
+
+}
|
|
50
|
+
+#else
|
|
51
|
+
static int process_is_async;
|
|
52
|
+
int in_async(void)
|
|
53
|
+
{
|
|
54
|
+
@@ -1202,6 +1244,7 @@ static void NORETURN async_exit(int code)
|
|
55
|
+
{
|
|
56
|
+
exit(code);
|
|
57
|
+
}
|
|
58
|
+
+#endif
|
|
59
|
+
|
|
60
|
+
#endif
|
|
61
|
+
|
|
62
|
+
@@ -1260,7 +1303,22 @@ int start_async(struct async *async)
|
|
63
|
+
else
|
|
64
|
+
proc_out = -1;
|
|
65
|
+
|
|
66
|
+
-#ifdef NO_PTHREADS
|
|
67
|
+
+#if defined(__wasi__)
|
|
68
|
+
+ {
|
|
69
|
+
+ static int started;
|
|
70
|
+
+ if (!started) {
|
|
71
|
+
+ started = 1;
|
|
72
|
+
+ set_die_routine(die_async);
|
|
73
|
+
+ }
|
|
74
|
+
+ }
|
|
75
|
+
+ async->proc_in = proc_in;
|
|
76
|
+
+ async->proc_out = proc_out;
|
|
77
|
+
+ async->pid = wasi_async_start(async, &async->stack);
|
|
78
|
+
+ if (async->pid < 0) {
|
|
79
|
+
+ error_errno("cannot start async");
|
|
80
|
+
+ goto error;
|
|
81
|
+
+ }
|
|
82
|
+
+#elif defined(NO_PTHREADS)
|
|
83
|
+
/* Flush stdio before fork() to avoid cloning buffers */
|
|
84
|
+
fflush(NULL);
|
|
85
|
+
|
|
86
|
+
@@ -1339,6 +1397,10 @@ int finish_async(struct async *async)
|
|
87
|
+
int ret = wait_or_whine(async->pid, "child process", 0);
|
|
88
|
+
|
|
89
|
+
invalidate_lstat_cache();
|
|
90
|
+
+#ifdef __wasi__
|
|
91
|
+
+ free(async->stack);
|
|
92
|
+
+ async->stack = NULL;
|
|
93
|
+
+#endif
|
|
94
|
+
|
|
95
|
+
return ret;
|
|
96
|
+
#else
|
|
97
|
+
@@ -1354,7 +1416,7 @@ int finish_async(struct async *async)
|
|
98
|
+
|
|
99
|
+
int async_with_fork(void)
|
|
100
|
+
{
|
|
101
|
+
-#ifdef NO_PTHREADS
|
|
102
|
+
+#if defined(NO_PTHREADS) && !defined(__wasi__)
|
|
103
|
+
return 1;
|
|
104
|
+
#else
|
|
105
|
+
return 0;
|
|
106
|
+
diff --git a/run-command.h b/run-command.h
|
|
107
|
+
index c2fad4f..754109c 100644
|
|
108
|
+
--- a/run-command.h
|
|
109
|
+
+++ b/run-command.h
|
|
110
|
+
@@ -363,7 +363,13 @@ struct async {
|
|
111
|
+
*/
|
|
112
|
+
int in; /* caller writes here and closes it */
|
|
113
|
+
int out; /* caller reads from here and closes it */
|
|
114
|
+
-#ifdef NO_PTHREADS
|
|
115
|
+
+#if defined(__wasi__)
|
|
116
|
+
+ /* A coroutine of the host's beside git's (wasi_async_start). */
|
|
117
|
+
+ pid_t pid;
|
|
118
|
+
+ int proc_in;
|
|
119
|
+
+ int proc_out;
|
|
120
|
+
+ void *stack;
|
|
121
|
+
+#elif defined(NO_PTHREADS)
|
|
122
|
+
pid_t pid;
|
|
123
|
+
#else
|
|
124
|
+
pthread_t tid;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 The Elixir Playground Authors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
16
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|