11"""Install RobotKernel wheels."""
22from importlib import resources
33from jupyterlite .addons .base import BaseAddon
4+ from jupyterlite .constants import JUPYTERLITE_JSON
5+ from jupyterlite .constants import LITE_PLUGIN_SETTINGS
6+ from jupyterlite .constants import JUPYTER_CONFIG_DATA
7+ from jupyterlite .constants import UTF8
8+ from jupyterlite .constants import ALL_JSON
9+ from jupyterlite .constants import JSON_FMT
10+ from jupyterlite .addons .piplite import PYPI_WHEELS
11+ from jupyterlite .addons .piplite import PIPLITE_URLS
412from pathlib import Path
13+ from hashlib import sha256
514
615import json
716import traitlets
817
918DEFAULT_WHEELS = json .loads (
1019 resources .read_text ("jupyterlite_robotkernel.addons" , "wheels.json" )
1120)
21+ ROBOLITE_PLUGIN_ID = "@jupyterlite/robolite-kernel-extension:kernel"
1222
1323
1424class RobotKernelAddon (BaseAddon ):
1525 """Ensures the unique dependencies of robotkernel are available."""
1626
17- __all__ = ["pre_build" ]
27+ __all__ = ["pre_build" , "post_build" ]
1828
1929 wheel_urls = traitlets .List (DEFAULT_WHEELS ).tag (config = True )
2030
@@ -27,5 +37,61 @@ def pre_build(self, manager):
2737 yield dict (
2838 name = f"""fetch:{ wheel .rsplit ("/" , 1 )[- 1 ]} """ ,
2939 actions = [(self .fetch_one , [wheel , dest ])],
30- targets = [dest ]
40+ targets = [dest ],
3141 )
42+
43+ def post_build (self , manager ):
44+ jupyterlite_json = manager .output_dir / JUPYTERLITE_JSON
45+ whl_index = manager .output_dir / PYPI_WHEELS / ALL_JSON
46+ yield dict (
47+ name = "patch" ,
48+ doc = f"ensure { JUPYTERLITE_JSON } includes any piplite wheels" ,
49+ file_dep = [jupyterlite_json , whl_index ],
50+ actions = [
51+ (
52+ self .patch_jupyterlite_json ,
53+ [jupyterlite_json , whl_index ],
54+ )
55+ ],
56+ targets = [f"{ whl_index } #" ], # TODO: target
57+ )
58+
59+ def patch_jupyterlite_json (self , jupyterlite_json , whl_index ):
60+ """add the piplite wheels to jupyter-lite.json"""
61+ config = json .loads (jupyterlite_json .read_text (** UTF8 ))
62+ old_urls = (
63+ config .setdefault (JUPYTER_CONFIG_DATA , {})
64+ .setdefault (LITE_PLUGIN_SETTINGS , {})
65+ .setdefault (ROBOLITE_PLUGIN_ID , {})
66+ .get (PIPLITE_URLS , [])
67+ )
68+
69+ new_urls = []
70+ whl_index_url , whl_index_url_with_sha = self .get_index_urls (whl_index )
71+ added_build = False
72+ for url in old_urls :
73+ if url .split ("#" )[0 ].split ("?" )[0 ] == whl_index_url :
74+ new_urls += [whl_index_url_with_sha ]
75+ added_build = True
76+ else :
77+ new_urls += [url ]
78+ if not added_build :
79+ new_urls = [whl_index_url_with_sha , * new_urls ]
80+
81+ # ... and only update if actually changed
82+ if len (new_urls ) > len (old_urls ) or added_build :
83+
84+ config [JUPYTER_CONFIG_DATA ][LITE_PLUGIN_SETTINGS ][ROBOLITE_PLUGIN_ID ][
85+ PIPLITE_URLS
86+ ] = new_urls
87+
88+ jupyterlite_json .write_text (json .dumps (config , ** JSON_FMT ), ** UTF8 )
89+
90+ self .maybe_timestamp (jupyterlite_json )
91+
92+ def get_index_urls (self , whl_index ):
93+ """get output dir relative URLs for all.json files"""
94+ whl_index_sha256 = sha256 (whl_index .read_bytes ()).hexdigest ()
95+ whl_index_url = f"./{ whl_index .relative_to (self .manager .output_dir ).as_posix ()} "
96+ whl_index_url_with_sha = f"{ whl_index_url } ?sha256={ whl_index_sha256 } "
97+ return whl_index_url , whl_index_url_with_sha
0 commit comments