|
1 | 1 | import json |
2 | | -import shutil |
| 2 | +import os |
3 | 3 | import subprocess |
4 | | -import sysconfig |
5 | 4 |
|
| 5 | +from deno import find_deno_bin |
| 6 | + |
| 7 | +BUNDLE_JS = "bids-validator.js" |
| 8 | +PERMISSIONS = [ |
| 9 | + "--allow-read", # read BIDS datasets |
| 10 | + "--allow-env", # read environment variables |
| 11 | + "--allow-net", # fetch remote schemas/datasets |
| 12 | + "--allow-write", # write validation results |
| 13 | + "--allow-run=git", # run git to read version info |
| 14 | +] |
| 15 | +WINDOWS_PERMISSIONS = [ |
| 16 | + "--allow-sys=osRelease", # Terminal capability detection |
| 17 | +] |
6 | 18 |
|
7 | | -def pdm_build_initialize(context): |
8 | | - context.ensure_build_dir() |
9 | 19 |
|
| 20 | +def pdm_build_initialize(context): |
| 21 | + # Version always comes from deno.json (sdist and wheel). |
10 | 22 | deno_json = context.root / "deno.json" |
11 | 23 | deno_config = json.loads(deno_json.read_text()) |
12 | 24 | context.config.metadata["version"] = deno_config["version"] |
13 | 25 |
|
14 | 26 | if context.target == "sdist": |
15 | 27 | return |
16 | 28 |
|
17 | | - # Inject compiled binary into scripts/, so it will be picked up to install |
18 | | - target = context.root / "scripts" / "bids-validator-deno" |
19 | | - |
20 | | - deno = shutil.which("deno") |
21 | | - if deno is None: |
22 | | - raise OSError("Deno is not installed or not in PATH") |
23 | | - |
24 | | - permissions = [ |
25 | | - # Access filesystem for reading BIDS datasets |
26 | | - "--allow-read", |
27 | | - # Accept environment variables |
28 | | - "--allow-env", |
29 | | - # Access network for fetching remote schemas |
30 | | - "--allow-net", |
31 | | - # Allow writing results to file |
32 | | - "--allow-write", |
33 | | - # Run git to get version info |
34 | | - "--allow-run=git", |
35 | | - ] |
36 | | - if sysconfig.get_platform().startswith("win"): |
37 | | - # Terminal detection code in supports-hyperlinks calls osRelease |
38 | | - permissions.append("--allow-sys=osRelease") |
| 29 | + build_dir = context.ensure_build_dir() |
| 30 | + package_dir = build_dir / "bids_validator_deno" |
| 31 | + package_dir.mkdir(parents=True, exist_ok=True) |
| 32 | + |
| 33 | + bundle = package_dir / BUNDLE_JS |
| 34 | + init = package_dir / "__init__.py" |
39 | 35 |
|
| 36 | + init.write_text(INIT_PY) |
| 37 | + |
| 38 | + deno = os.fsdecode(find_deno_bin()) |
| 39 | + |
| 40 | + # `deno bundle` resolves jsr/npm/wasm deps (network at build time) and |
| 41 | + # inlines them into a single platform-independent JS file plus a linked |
| 42 | + # source map (bundle.js.map). `--frozen` fails rather than silently |
| 43 | + # re-resolving if the committed deno.lock is out of date. |
40 | 44 | subprocess.run( |
41 | 45 | [ |
42 | 46 | deno, |
43 | | - "compile", |
44 | | - *permissions, |
45 | | - # Types are checked elsewhere. Type checking at wheel build |
46 | | - # is painful if some platforms have newer typescript than others. |
47 | | - "--no-check", |
| 47 | + "bundle", |
| 48 | + "--frozen", |
| 49 | + "--sourcemap", |
48 | 50 | "-o", |
49 | | - str(target), |
| 51 | + str(bundle), |
50 | 52 | "src/bids-validator.ts", |
51 | 53 | ], |
52 | 54 | check=True, |
| 55 | + cwd=context.root, |
53 | 56 | ) |
54 | 57 |
|
55 | | - # Add the current platform tag so the wheel is specific to the OS/architecture |
56 | | - platform_tag = sysconfig.get_platform().replace("-", "_").replace(".", "_") |
57 | | - context.config_settings["--plat-name"] = platform_tag |
| 58 | + |
| 59 | +INIT_PY = f'''\ |
| 60 | +# This module was generated at build time by pdm_build.py. |
| 61 | +# |
| 62 | +# This module was adapted from git-annex-wheel/src/git_annex/__init__.py @ commit 9a059be: |
| 63 | +# |
| 64 | +# https://github.com/psychoinformatics-de/git-annex-wheel/blob/9a059be12db8b90cb1ecf71e498d3a2135366b6f/src/git_annex/__init__.py |
| 65 | +# https://hub.datalad.org/git-annex/git-annex-wheel/src/commit/9a059be12db8b90cb1ecf71e498d3a2135366b6f/src/git_annex/__init__.py |
| 66 | +# |
| 67 | +# By agreement of the authors of that module, releasing this derivative work under MIT is |
| 68 | +# authorized. See https://github.com/bids-standard/bids-validator/pull/425. |
| 69 | +# |
| 70 | +# Changes: |
| 71 | +# * Adapted cli() to find Deno bundled in a separate package and exec the local bundle. |
| 72 | +# |
| 73 | +"""Find the deno runtime and exec the bundled BIDS validator.""" |
| 74 | +import os |
| 75 | +import sys |
| 76 | +
|
| 77 | +def cli(): |
| 78 | + from deno import find_deno_bin |
| 79 | +
|
| 80 | + deno = os.fsdecode(find_deno_bin()) |
| 81 | + windows = sys.platform.startswith('win') |
| 82 | + bundle = os.path.join(os.path.dirname(__file__), {BUNDLE_JS!r}) |
| 83 | +
|
| 84 | + permissions = {PERMISSIONS} |
| 85 | + if windows: |
| 86 | + permissions.extend({WINDOWS_PERMISSIONS}) |
| 87 | +
|
| 88 | + argv = [deno, *permissions, bundle, *sys.argv[1:]] |
| 89 | +
|
| 90 | + if windows: |
| 91 | + exec_subproc(deno, argv) |
| 92 | + else: |
| 93 | + os.execv(deno, argv) |
| 94 | +
|
| 95 | +
|
| 96 | +def exec_subproc(executable, argv): |
| 97 | + import subprocess |
| 98 | +
|
| 99 | + try: |
| 100 | + subprocess.run( |
| 101 | + argv, |
| 102 | + executable=executable, |
| 103 | + shell=False, |
| 104 | + check=True, |
| 105 | + ) |
| 106 | + # try flush here to trigger a BrokenPipeError within the try-except block |
| 107 | + # (happens if the calling process closed stdout already) |
| 108 | + sys.stdout.flush() |
| 109 | + except BrokenPipeError: |
| 110 | + # setting to None prevents Python from trying to flush again |
| 111 | + sys.stdout = None |
| 112 | + except subprocess.CalledProcessError as e: |
| 113 | + sys.exit(e.returncode) |
| 114 | +''' |
0 commit comments