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

Passing the link of empack_env_meta.json file #120

Merged
merged 12 commits into from
Oct 15, 2024
16 changes: 14 additions & 2 deletions jupyterlite_xeus/add_on.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""a JupyterLite addon for creating the env for xeus kernels"""

import json
import os
from pathlib import Path
Expand All @@ -18,7 +19,7 @@
SHARE_LABEXTENSIONS,
UTF8,
)
from traitlets import Bool, List, Unicode
from traitlets import Bool, Callable, List, Unicode

from .create_conda_env import (
create_conda_env_from_env_file,
Expand Down Expand Up @@ -102,6 +103,13 @@ class XeusAddon(FederatedExtensionAddon):
description="A comma-separated list of mount points, in the form <host_path>:<mount_path> to mount in the wasm prefix",
)

package_url_factory = Callable(
None,
allow_none=True,
config=True,
description="Factory to generate package download URL from package metadata. This is used to load python packages from external host",
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.xeus_output_dir = Path(self.manager.output_dir) / "xeus"
Expand Down Expand Up @@ -285,6 +293,9 @@ def pack_prefix(self, kernel_dir):
else:
pack_kwargs["file_filters"] = pkg_file_filter_from_yaml(DEFAULT_CONFIG_PATH)

if self.package_url_factory is not None:
pack_kwargs["package_url_factory"] = self.package_url_factory

pack_env(
env_prefix=self.prefix,
relocate_prefix="/",
Expand Down Expand Up @@ -342,7 +353,8 @@ def pack_prefix(self, kernel_dir):
# Pack JupyterLite content if enabled
# If we only build a voici output, mount jupyterlite content into the kernel by default
if self.mount_jupyterlite_content or (
list(self.manager.apps) == ["voici"] and self.mount_jupyterlite_content is None
list(self.manager.apps) == ["voici"]
and self.mount_jupyterlite_content is None
):
contents_dir = self.manager.output_dir / "files"

Expand Down
129 changes: 80 additions & 49 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IBroadcastChannelWrapper } from '@jupyterlite/contents';
import { IKernel, IKernelSpecs } from '@jupyterlite/kernel';

import { WebWorkerKernel } from './web_worker_kernel';
import { IEmpackEnvMetaFile } from './tokens';

function getJson(url: string) {
const json_url = URLExt.join(PageConfig.getBaseUrl(), url);
Expand All @@ -29,59 +30,89 @@ try {
throw err;
}

const plugins = kernel_list.map((kernel): JupyterLiteServerPlugin<void> => {
return {
id: `@jupyterlite/xeus-${kernel}:register`,
autoStart: true,
requires: [IKernelSpecs],
optional: [IServiceWorkerManager, IBroadcastChannelWrapper],
activate: (
app: JupyterLiteServer,
kernelspecs: IKernelSpecs,
serviceWorker?: IServiceWorkerManager,
broadcastChannel?: IBroadcastChannelWrapper
) => {
// Fetch kernel spec
const kernelspec = getJson('xeus/kernels/' + kernel + '/kernel.json');
kernelspec.name = kernel;
kernelspec.dir = kernel;
for (const [key, value] of Object.entries(kernelspec.resources)) {
kernelspec.resources[key] = URLExt.join(
PageConfig.getBaseUrl(),
value as string
);
}

const contentsManager = app.serviceManager.contents;

kernelspecs.register({
spec: kernelspec,
create: async (options: IKernel.IOptions): Promise<IKernel> => {
const mountDrive = !!(
(serviceWorker?.enabled && broadcastChannel?.enabled) ||
crossOriginIsolated
const plugins = kernel_list.map(
(kernel): JupyterLiteServerPlugin<void | IEmpackEnvMetaFile> => {
return {
id: `@jupyterlite/xeus-${kernel}:register`,
autoStart: true,
requires: [IKernelSpecs],
optional: [
IServiceWorkerManager,
IBroadcastChannelWrapper,
IEmpackEnvMetaFile
],
activate: (
app: JupyterLiteServer,
kernelspecs: IKernelSpecs,
serviceWorker?: IServiceWorkerManager,
broadcastChannel?: IBroadcastChannelWrapper,
empackEnvMetaFile?: IEmpackEnvMetaFile
) => {
// Fetch kernel spec
const kernelspec = getJson('xeus/kernels/' + kernel + '/kernel.json');
kernelspec.name = kernel;
kernelspec.dir = kernel;
for (const [key, value] of Object.entries(kernelspec.resources)) {
kernelspec.resources[key] = URLExt.join(
PageConfig.getBaseUrl(),
value as string
);
}

if (mountDrive) {
console.info(
`${kernelspec.name} contents will be synced with Jupyter Contents`
);
} else {
console.warn(
`${kernelspec.name} contents will NOT be synced with Jupyter Contents`
const contentsManager = app.serviceManager.contents;
kernelspecs.register({
spec: kernelspec,
create: async (options: IKernel.IOptions): Promise<IKernel> => {
const mountDrive = !!(
(serviceWorker?.enabled && broadcastChannel?.enabled) ||
crossOriginIsolated
);

if (mountDrive) {
console.info(
`${kernelspec.name} contents will be synced with Jupyter Contents`
);
} else {
console.warn(
`${kernelspec.name} contents will NOT be synced with Jupyter Contents`
);
}
const link = empackEnvMetaFile
? await empackEnvMetaFile.getLink(kernelspec)
: '';

return new WebWorkerKernel({
...options,
contentsManager,
mountDrive,
kernelSpec: kernelspec,
empackEnvMetaLink: link
});
}
});
}
};
}
);

return new WebWorkerKernel({
...options,
contentsManager,
mountDrive,
kernelSpec: kernelspec
});
}
});
}
};
});
const empackEnvMetaPlugin: JupyterLiteServerPlugin<IEmpackEnvMetaFile> = {
id: '@jupyterlite/xeus:empack-env-meta',
autoStart: true,
provides: IEmpackEnvMetaFile,
activate: (): IEmpackEnvMetaFile => {
return {
getLink: async (kernelspec: Record<string, any>) => {
const kernelName = kernelspec.name;
const kernel_root_url = URLExt.join(
PageConfig.getBaseUrl(),
`xeus/kernels/${kernelName}`
);
return `${kernel_root_url}`;
}
};
}
};

plugins.push(empackEnvMetaPlugin);

export default plugins;
13 changes: 13 additions & 0 deletions src/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '@jupyterlite/contents';

import { IWorkerKernel } from '@jupyterlite/kernel';
import { Token } from '@lumino/coreutils';

/**
* An interface for Xeus workers.
Expand Down Expand Up @@ -85,5 +86,17 @@ export namespace IXeusWorkerKernel {
baseUrl: string;
kernelSpec: any;
mountDrive: boolean;
empackEnvMetaLink?: string;
}
}

export interface IEmpackEnvMetaFile {
/**
* Get empack_env_meta link.
*/
getLink: (kernelspec: Record<string, any>) => Promise<string>;
}

export const IEmpackEnvMetaFile = new Token<IEmpackEnvMetaFile>(
'@jupyterlite/xeus:IEmpackEnvMetaFile'
);
19 changes: 15 additions & 4 deletions src/web_worker_kernel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,24 @@ export class WebWorkerKernel implements IKernel {
* @param options The instantiation options for a new WebWorkerKernel
*/
constructor(options: WebWorkerKernel.IOptions) {
const { id, name, sendMessage, location, kernelSpec, contentsManager } =
options;
const {
id,
name,
sendMessage,
location,
kernelSpec,
contentsManager,
empackEnvMetaLink
} = options;
this._id = id;
this._name = name;
this._location = location;
this._kernelSpec = kernelSpec;
this._contentsManager = contentsManager;
this._sendMessage = sendMessage;
this._empackEnvMetaLink = empackEnvMetaLink;
this._worker = this.initWorker(options);
this._remoteKernel = this.initRemote(options);

this.initFileSystem(options);
}

Expand Down Expand Up @@ -99,11 +106,13 @@ export class WebWorkerKernel implements IKernel {
};
remote = wrap(this._worker) as Remote<IXeusWorkerKernel>;
}

remote
.initialize({
kernelSpec: this._kernelSpec,
baseUrl: PageConfig.getBaseUrl(),
mountDrive: options.mountDrive
mountDrive: options.mountDrive,
empackEnvMetaLink: this._empackEnvMetaLink
})
.then(this._ready.resolve.bind(this._ready));

Expand Down Expand Up @@ -290,6 +299,7 @@ export class WebWorkerKernel implements IKernel {
| undefined = undefined;
private _parent: KernelMessage.IMessage | undefined = undefined;
private _ready = new PromiseDelegate<void>();
private _empackEnvMetaLink: string | undefined;
}

/**
Expand All @@ -303,5 +313,6 @@ export namespace WebWorkerKernel {
contentsManager: Contents.IManager;
mountDrive: boolean;
kernelSpec: any;
empackEnvMetaLink?: string | undefined;
}
}
9 changes: 4 additions & 5 deletions src/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export class XeusRemoteKernel {
}

async initialize(options: IXeusWorkerKernel.IOptions): Promise<void> {
const { baseUrl, kernelSpec } = options;
const { baseUrl, kernelSpec, empackEnvMetaLink } = options;
// location of the kernel binary on the server
const binary_js = URLExt.join(baseUrl, kernelSpec.argv[0]);
const binary_wasm = binary_js.replace('.js', '.wasm');
Expand All @@ -125,10 +125,9 @@ export class XeusRemoteKernel {
// This function is usually implemented in the pre/post.js
// in the emscripten build of that kernel
if (globalThis.Module['async_init'] !== undefined) {
const kernel_root_url = URLExt.join(
baseUrl,
`xeus/kernels/${kernelSpec.dir}`
);
const kernel_root_url = empackEnvMetaLink
? empackEnvMetaLink
: URLExt.join(baseUrl, `xeus/kernels/${kernelSpec.dir}`);
const pkg_root_url = URLExt.join(baseUrl, 'xeus/kernel_packages');
const verbose = true;
await globalThis.Module['async_init'](
Expand Down
Loading