Skip to content

Commit 97fdc90

Browse files
authored
Merge branch 'main' into patch-1
2 parents 5cf6f5b + f85aaf5 commit 97fdc90

File tree

9 files changed

+123
-109
lines changed

9 files changed

+123
-109
lines changed

.github/workflows/test-and-publish.yaml

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ on:
1515
required: false
1616
options:
1717
- ''
18-
- 'ubuntu-20.04'
18+
- 'ubuntu-22.04'
1919
- 'macos-13'
2020
- 'macos-14'
2121
- 'windows-2022'
@@ -49,6 +49,8 @@ env:
4949
# don't upgrade outdated brew packages because the process is too slow
5050
HOMEBREW_NO_INSTALL_UPGRADE: 1
5151
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
52+
# apt-get should run in noninteractive mode
53+
DEBIAN_FRONTEND: noninteractive
5254

5355
defaults:
5456
run:
@@ -64,16 +66,14 @@ jobs:
6466
strategy:
6567
fail-fast: false
6668
matrix:
67-
# Use Ubuntu 20.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey
68-
os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'ubuntu-22.04-arm' ] # macOS 14 runner exclusively runs on M1 hardwares
69+
# Use Ubuntu 22.04 / macOS 13 x86_64 / macOS 14 arm64 + Python 3.10 to build SpiderMonkey
70+
os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'ubuntu-22.04-arm' ] # macOS 14 runner exclusively runs on M1 hardwares
6971
# see https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available
7072
python_version: [ '3.10' ]
7173
runs-on: ${{ matrix.os }}
74+
container: ${{ (matrix.os == 'ubuntu-22.04' && 'ubuntu:20.04') || null }} # Use the Ubuntu 20.04 container inside Ubuntu 22.04 runner to build
7275
steps:
7376
- uses: actions/checkout@v4
74-
- uses: actions/setup-python@v5
75-
with:
76-
python-version: ${{ matrix.python_version }}
7777
- name: Read the mozilla-central commit hash to be used
7878
run: echo "MOZCENTRAL_VERSION=$(cat mozcentral.version)" >> $GITHUB_ENV
7979
- name: Cache spidermonkey build
@@ -84,6 +84,17 @@ jobs:
8484
./_spidermonkey_install/*
8585
key: spidermonkey-${{ env.MOZCENTRAL_VERSION }}-${{ runner.os }}-${{ runner.arch }}
8686
lookup-only: true # skip download
87+
- name: Setup container
88+
if: ${{ matrix.os == 'ubuntu-22.04' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }}
89+
run: |
90+
apt-get update -y
91+
apt-get install -y sudo libnss3-dev libssl-dev
92+
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata
93+
echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04
94+
- uses: actions/setup-python@v5
95+
if: ${{ steps.cache-spidermonkey.outputs.cache-hit != 'true' }}
96+
with:
97+
python-version: ${{ matrix.python_version }}
8798
- name: Setup XCode
8899
if: ${{ matrix.os == 'macos-13' && steps.cache-spidermonkey.outputs.cache-hit != 'true' }}
89100
# SpiderMonkey requires XCode SDK version at least 13.3
@@ -132,10 +143,28 @@ jobs:
132143
strategy:
133144
fail-fast: false
134145
matrix:
135-
os: [ 'ubuntu-20.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ]
146+
os: [ 'ubuntu-22.04', 'macos-13', 'macos-14', 'windows-2022', 'ubuntu-22.04-arm' ]
136147
python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ]
137148
runs-on: ${{ matrix.os }}
149+
container: ${{ (matrix.os == 'ubuntu-22.04' && 'ubuntu:20.04') || null }}
138150
steps:
151+
- name: Setup container
152+
if: ${{ matrix.os == 'ubuntu-22.04' }}
153+
run: |
154+
apt-get update -y
155+
apt-get install -y sudo libnss3-dev libssl-dev
156+
apt-get install -y git # required for `actions/checkout`
157+
apt-get install -y build-essential
158+
apt-get install -y strace # required to run JS tests
159+
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata # tzdata may ask for user interaction if not explicitly installed here
160+
echo "AGENT_TOOLSDIRECTORY=/" >> $GITHUB_ENV # do not use the Python installation cached for Ubuntu 22.04
161+
git config --global --add safe.directory '*' # silence "git failed because of dubious ownership"
162+
163+
# CMake 3.25 or higher is required
164+
apt-get install -y ca-certificates gpg wget
165+
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
166+
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null
167+
apt-get update -y && apt-get install -y cmake
139168
- uses: actions/checkout@v4
140169
with:
141170
submodules: recursive
@@ -166,7 +195,7 @@ jobs:
166195
env:
167196
PYTHON_VERSION: ${{ matrix.python_version }}
168197
- name: Build Docs # only build docs once
169-
if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }}
198+
if: ${{ matrix.os == 'ubuntu-22.04' && matrix.python_version == '3.11' }}
170199
run: |
171200
sudo apt-get install -y graphviz
172201
# the newest version in Ubuntu 20.04 repository is 1.8.17, but we need Doxygen 1.9 series
@@ -176,7 +205,7 @@ jobs:
176205
rm -rf doxygen-1.9.7 doxygen-1.9.7.linux.bin.tar.gz
177206
BUILD_DOCS=1 BUILD_TYPE=None poetry install
178207
- name: Upload Doxygen-generated docs as CI artifacts
179-
if: ${{ matrix.os == 'ubuntu-20.04' && matrix.python_version == '3.11' }}
208+
if: ${{ matrix.os == 'ubuntu-22.04' && matrix.python_version == '3.11' }}
180209
uses: actions/upload-artifact@v4
181210
with:
182211
name: docs-${{ github.run_id }}-${{ github.sha }}
@@ -219,49 +248,22 @@ jobs:
219248
with:
220249
name: wheel-${{ github.run_id }}-${{ github.sha }}-${{ runner.os }}_${{ runner.arch }}_Python${{ matrix.python_version }}
221250
path: ./dist/
222-
- name: Set cores to get stored in /cores
223-
if: ${{ matrix.os != 'windows-2022' }}
224-
# TODO (Caleb Aikens) figure out how to get Windows core dumps
225-
run: |
226-
sudo mkdir -p /cores
227-
sudo chmod 777 /cores
228-
# Core filenames will be of the form osname.pythonversion.executable.pid.timestamp:
229-
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
230-
sudo bash -c 'echo "/cores/${OSTYPE}.$(poetry run python --version).%e.%p.%t" > /proc/sys/kernel/core_pattern'
231-
else
232-
sudo sysctl kern.corefile="/cores/${OSTYPE}.$(poetry run python --version).%e.%p.%y"
233-
fi
234251
- name: Run Python tests (pytest)
235252
run: |
236-
if [[ "$OSTYPE" == "linux-gnu"* || "$OSTYPE" == "darwin"* ]]; then
237-
# TODO (Caleb Aikens) figure out how to get Windows core dumps
238-
ulimit -c unlimited
239-
fi
240253
WORKFLOW_BUILD_TYPE=${{ inputs.build_type }}
241254
BUILD_TYPE=${WORKFLOW_BUILD_TYPE:-"Debug"} poetry run python -m pip install --force-reinstall --verbose ./dist/*
242255
poetry run python -m pytest tests/python
243256
- name: Run JS tests (peter-jr)
244257
if: ${{ (success() || failure()) }}
245258
run: |
246-
if [[ "$OSTYPE" == "linux-gnu"* || "$OSTYPE" == "darwin"* ]]; then
247-
# TODO (Caleb Aikens) figure out how to get Windows core dumps
248-
ulimit -c unlimited
249-
fi
250259
poetry run bash ./peter-jr ./tests/js/
251260
- name: SSH debug session
252261
if: ${{ (success() || failure()) && github.event_name == 'workflow_dispatch' && inputs.debug_enabled_os == matrix.os && inputs.debug_enabled_python == matrix.python_version}}
253262
uses: fawazahmed0/action-debug@main
254263
with:
255264
credentials: "admin:admin"
256-
- name: Upload core dumps as CI artifacts
257-
uses: actions/upload-artifact@v4
258-
if: ${{ matrix.os != 'windows-2022' && failure() }}
259-
# TODO (Caleb Aikens) figure out how to get Windows core dumps
260-
with:
261-
name: cores-${{ matrix.os }}-${{ matrix.python_version }}
262-
path: /cores
263265
sdist:
264-
runs-on: ubuntu-20.04
266+
runs-on: ubuntu-22.04
265267
steps:
266268
- uses: actions/checkout@v4
267269
with:
@@ -283,22 +285,9 @@ jobs:
283285
with:
284286
name: wheel-${{ github.run_id }}-${{ github.sha }}-sdist
285287
path: ./dist/
286-
check-install-from-sdist:
287-
needs: sdist
288-
runs-on: ubuntu-24.04
289-
steps:
290-
- uses: actions/setup-python@v5
291-
with:
292-
python-version: '3.10'
293-
- name: Download wheels built
294-
uses: actions/download-artifact@v4
295-
with:
296-
name: wheel-${{ github.run_id }}-${{ github.sha }}-sdist
297-
path: ./dist/
298-
- run: pip install ./dist/pythonmonkey-*.tar.gz
299288
publish:
300289
needs: [build-and-test, sdist]
301-
runs-on: ubuntu-20.04
290+
runs-on: ubuntu-22.04
302291
if: ${{ success() && github.event_name == 'push' && github.ref_type == 'tag' }}
303292
steps:
304293
# no need to checkout
@@ -322,7 +311,7 @@ jobs:
322311
# Implement a very basic Python package repository (https://peps.python.org/pep-0503/)
323312
# and deploy the static files to GitHub Pages
324313
needs: [build-and-test, sdist]
325-
runs-on: ubuntu-20.04
314+
runs-on: ubuntu-22.04
326315
if: ${{ (success() || failure()) && (github.ref_name == 'main' || github.ref_type == 'tag') }} # publish nightly builds regardless of tests failure
327316
permissions: # grant GITHUB_TOKEN the permissions required to make a Pages deployment
328317
pages: write
@@ -382,7 +371,7 @@ jobs:
382371
publish-archive:
383372
# Publish to ⊇istributive's archive server (https://archive.distributed.computer/releases/pythonmonkey/)
384373
needs: [build-and-test, sdist]
385-
runs-on: ubuntu-20.04
374+
runs-on: ubuntu-22.04
386375
if: ${{ (success() || failure()) && (github.ref_name == 'main' || github.ref_type == 'tag') }}
387376
environment:
388377
name: archive

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ Read this if you want to build a local version.
7474
- rust
7575
- python3.8 or later with header files (python3-dev)
7676
- spidermonkey latest from mozilla-central
77-
- npm (nodejs)
7877
- [Poetry](https://python-poetry.org/docs/#installation)
7978
- [poetry-dynamic-versioning](https://github.com/mtkennerly/poetry-dynamic-versioning)
8079

mozcentral.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
cdfe9f2e144a04618cb6e9ffd9e6202d6d85ed56
1+
6bca861985ba51920c1cacc21986af01c51bd690

python/pminit/pmpm.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# @file pmpm.py
2+
# A minimum copy of npm written in pure Python.
3+
# Currently, this can only install dependencies specified by package-lock.json into node_modules.
4+
# @author Tom Tang <[email protected]>
5+
# @date July 2023
6+
7+
import json
8+
import io
9+
import os, shutil
10+
import tempfile
11+
import tarfile
12+
from dataclasses import dataclass
13+
import urllib.request
14+
from typing import List, Union
15+
16+
@dataclass
17+
class PackageItem:
18+
installation_path: str
19+
tarball_url: str
20+
has_install_script: bool
21+
22+
def parse_package_lock_json(json_data: Union[str, bytes]) -> List[PackageItem]:
23+
# See https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json#packages
24+
packages: dict = json.loads(json_data)["packages"]
25+
items: List[PackageItem] = []
26+
for key, entry in packages.items():
27+
if key == "":
28+
# Skip the root project (listed with a key of "")
29+
continue
30+
items.append(
31+
PackageItem(
32+
installation_path=key, # relative path from the root project folder
33+
# The path is flattened for nested node_modules, e.g., "node_modules/create-ecdh/node_modules/bn.js"
34+
tarball_url=entry["resolved"], # TODO: handle git dependencies
35+
has_install_script=entry.get("hasInstallScript", False) # the package has a preinstall, install, or postinstall script
36+
)
37+
)
38+
return items
39+
40+
def download_package(tarball_url: str) -> bytes:
41+
with urllib.request.urlopen(tarball_url) as response:
42+
tarball_data: bytes = response.read()
43+
return tarball_data
44+
45+
def unpack_package(work_dir:str, installation_path: str, tarball_data: bytes):
46+
installation_path = os.path.join(work_dir, installation_path)
47+
shutil.rmtree(installation_path, ignore_errors=True)
48+
49+
with tempfile.TemporaryDirectory(prefix="pmpm_cache-") as tmpdir:
50+
with io.BytesIO(tarball_data) as tar_file:
51+
with tarfile.open(fileobj=tar_file) as tar:
52+
tar.extractall(tmpdir)
53+
shutil.move(
54+
os.path.join(tmpdir, "package"), # Strip the root folder
55+
installation_path
56+
)
57+
58+
def main(work_dir: str):
59+
with open(os.path.join(work_dir, "package-lock.json"), encoding="utf-8") as f:
60+
items = parse_package_lock_json(f.read())
61+
for i in items:
62+
print("Installing " + i.installation_path)
63+
tarball_data = download_package(i.tarball_url)
64+
unpack_package(work_dir, i.installation_path, tarball_data)
65+
66+
if __name__ == "__main__":
67+
main(os.getcwd())

python/pminit/post-install-hook.py

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,13 @@
1-
import subprocess
2-
import sys
3-
import shutil
1+
import os
2+
import pmpm
43

5-
def execute(cmd: str):
6-
popen = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.STDOUT,
7-
shell = True, text = True )
8-
for stdout_line in iter(popen.stdout.readline, ""):
9-
sys.stdout.write(stdout_line)
10-
sys.stdout.flush()
11-
12-
popen.stdout.close()
13-
return_code = popen.wait()
14-
if return_code:
15-
raise subprocess.CalledProcessError(return_code, cmd)
4+
WORK_DIR = os.path.join(
5+
os.path.realpath(os.path.dirname(__file__)),
6+
"pythonmonkey"
7+
)
168

179
def main():
18-
node_package_manager = 'npm'
19-
# check if npm is installed on the system
20-
if (shutil.which(node_package_manager) is None):
21-
print("""
22-
23-
PythonMonkey Build Error:
24-
25-
26-
* It appears npm is not installed on this system.
27-
* npm is required for PythonMonkey to build.
28-
* Please install NPM and Node.js before installing PythonMonkey.
29-
* Refer to the documentation for installing NPM and Node.js here: https://nodejs.org/en/download
30-
31-
32-
""")
33-
raise Exception("PythonMonkey build error: Unable to find npm on the system.")
34-
else:
35-
execute(f"cd pythonmonkey && {node_package_manager} i --no-package-lock") # do not update package-lock.json
10+
pmpm.main(WORK_DIR) # cd pythonmonkey && npm i
3611

3712
if __name__ == "__main__":
38-
main()
39-
13+
main()

python/pminit/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ documentation = "https://docs.pythonmonkey.io/"
1111
repository = "https://github.com/Distributive-Network/PythonMonkey"
1212

1313
include = [
14+
"pmpm.py",
1415
# Install extra files into the pythonmonkey package
1516
"pythonmonkey/package*.json",
1617
{ path = "pythonmonkey/node_modules/**/*", format = "wheel" },

setup.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ echo "Done installing dependencies"
4444
echo "Downloading spidermonkey source code"
4545
# Read the commit hash for mozilla-central from the `mozcentral.version` file
4646
MOZCENTRAL_VERSION=$(cat mozcentral.version)
47-
wget -c -q -O firefox-source-${MOZCENTRAL_VERSION}.zip https://github.com/mozilla/gecko-dev/archive/${MOZCENTRAL_VERSION}.zip
48-
unzip -q firefox-source-${MOZCENTRAL_VERSION}.zip && mv gecko-dev-${MOZCENTRAL_VERSION} firefox-source
47+
wget -c -q -O firefox-source-${MOZCENTRAL_VERSION}.zip https://github.com/mozilla-firefox/firefox/archive/${MOZCENTRAL_VERSION}.zip
48+
unzip -q firefox-source-${MOZCENTRAL_VERSION}.zip && mv firefox-${MOZCENTRAL_VERSION} firefox-source
4949
echo "Done downloading spidermonkey source code"
5050

5151
echo "Building spidermonkey"

tests/python/test_dicts.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -367,14 +367,6 @@ def test_toLocaleString():
367367
pm.eval("(result, obj) => {result[0] = obj.toLocaleString()}")(result, items)
368368
assert result[0] == '[object Object]'
369369

370-
# repr
371-
372-
373-
def test_repr_max_recursion_depth():
374-
subprocess.check_call('npm install crypto-js', shell=True)
375-
CryptoJS = pm.require('crypto-js')
376-
assert str(CryptoJS).__contains__("{'lib': {'Base': {'extend':")
377-
378370

379371
# __class__
380372
def test___class__attribute():

tests/python/test_functions_this.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,6 @@ class Class:
126126
# require
127127

128128

129-
def test_require_correct_this():
130-
subprocess.check_call('npm install crypto-js', shell=True)
131-
CryptoJS = pm.require('crypto-js')
132-
cipher = CryptoJS.SHA256("Hello, World!").toString()
133-
assert cipher == "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f"
134-
subprocess.check_call('npm uninstall crypto-js', shell=True)
135-
136-
137129
def test_require_correct_this_old_style_class():
138130
example = pm.eval("""
139131
() => {
@@ -207,12 +199,12 @@ def pyFunc():
207199
def test_method_no_self():
208200
class What:
209201
def some_method():
210-
return 3
202+
return 3
211203

212204
obj = What()
213205

214206
try:
215207
pm.eval('x => x.some_method()')(obj)
216208
assert (False)
217209
except pm.SpiderMonkeyError as e:
218-
assert 'takes 0 positional arguments but 1 was given' in str(e)
210+
assert 'takes 0 positional arguments but 1 was given' in str(e)

0 commit comments

Comments
 (0)