Commit c4e9ee3f authored by Ludovic Courtès's avatar Ludovic Courtès
Browse files

Get rid of ";;guix kernel" and ";;guix run".

We now automatically spawn the kernel found in the environment instead
of running the "inner proxy".  That simplifies code (the inner proxy is
no longer used) and simplifies usage (no need to remember to do ";;guix
kernel" once you have set up the environment.)

* guix-jupyter-kernel.scm (reply-for-environment-kernel): New
procedure.
(create-environment): Build the profile from MANIFEST, and call
'available-kernel-specs-files' in there.  Return an error message if we
didn't find exactly one kernel spec.
(reply-execute-request): Support ";;guix environment NAME" magic.
Remove support for 'magic-run?' and 'magic-kernel?'.
(start-container): Take a profile rather than a manifest.
[spawn]: Use 'available-kernel-specs-files' and 'exec-kernel' rather
than 'run-inner-proxy'.
* guix/jupyter/magic.scm (magic-env?): Adjust accordingly.
* guix-kernel-demo.ipynb: Update.
parent e519e8d6
......@@ -32,6 +32,7 @@
(guix build utils)
(guix gexp)
(guix store)
(guix derivations)
(guix monads)
(guix modules)
(guix profiles)
......@@ -139,6 +140,23 @@ NAME with MANIFEST."
port)))
count))
(define* (reply-for-environment-kernel kernel message
#:key name specs (count 0))
"Send KERNEL a reply to MESSAGE saying that we found the kernel SPECS."
(send-message kernel
(reply message "execute_result"
(scm->json-string
`(("data" .
(("text/html"
. ,(sxml->html-string
`(div
"Running "
,(kernel-specs-display-name specs)
" kernel.")))))
("metadata" . ())
("execution_count" . ,count))))
#:kernel-socket kernel-iopub))
(define* (create-environment name specs state
#:key kernel message)
"Spawn a new execution environment called NAME and containing SPECS, a list
......@@ -147,23 +165,67 @@ to KERNEL as a reply to MESSAGE, and return STATE suitably adjusted."
(define manifest
(specifications->manifest (force %inferior) specs))
(define store
(proxy-state-store state))
(define counter
(proxy-state-execution-count state))
(format/log "creating new environment ~s~%" name)
;; Reply right away without waiting for the profile to be built.
(reply-for-environment kernel message
#:name name
#:manifest manifest
#:count (proxy-state-execution-count state))
(let* ((store (proxy-state-store state))
(container (run-with-store store
(start-container container-context
name manifest)))
(state (register-proxied name container state)))
(monitor-client container)
(send-message container message)
(set-proxy-state-default-environment (increment-execution-count state)
name)))
#:count counter)
(let ((profile (run-with-store store
(mlet %store-monad ((drv (profile-derivation manifest)))
(mbegin %store-monad
(built-derivations (list drv)) ;XXX: somewhat ugly
(return drv))))))
(match (available-kernel-specs-files
(list (string-append (derivation->output-path profile)
"/share/jupyter")))
((specs-file)
(let* ((container (run-with-store store
(start-container container-context
name profile)))
(specs (call-with-input-file specs-file
json->kernel-specs))
(state (register-proxied name container state)))
(monitor-client container)
(reply-for-environment-kernel kernel message
#:name name
#:specs specs
#:count counter)
(set-proxy-state-default-environment (increment-execution-count state)
name)))
(()
(reply-html kernel message
(sxml->html-string
`(bold "No kernel found in environment "
(code ,name) "!"))
counter)
;; TODO: Send "error".
state)
((lst ...)
(reply-html kernel message
(sxml->html-string
`(div
(bold "Found " ,(length lst)
" kernels in environment "
(code ,name) ":")
(ul ,@(map (lambda (file)
(let ((specs (call-with-input-file file
json->kernel-specs)))
`(li ,(kernel-specs-display-name specs))))
lst))
"Which one should we use? Please create an "
"environment containing exactly one kernel."))
counter)
;; TODO: Send "error".
state))))
(define (reply-execute-request kernel kind message state)
(let* ((content (message-content message))
......@@ -191,6 +253,21 @@ to KERNEL as a reply to MESSAGE, and return STATE suitably adjusted."
(unregister-proxied name state)
#:kernel kernel
#:message message))))
((_ "environment" name)
(match (lookup-proxied name state)
(#f
(reply-html kernel message
(sxml->html-string
`(bold "Unknown environment "
(code ,name) "."))
count)
(increment-execution-count state))
((? kernel? proxy)
(format/log "evaluating code in container ~s (PID ~s)~%"
name (kernel-pid proxy))
(send-message proxy message)
(let ((state (increment-execution-count state)))
(set-proxy-state-default-environment state name)))))
((lst ...)
(reply-html kernel message
(sxml->html-string
......@@ -198,15 +275,6 @@ to KERNEL as a reply to MESSAGE, and return STATE suitably adjusted."
" magic."))
count)
(increment-execution-count state))))
((or (magic-run? code)
(magic-kernel? code))
(let* ((list (string-split magic #\ ))
(env-name (list-ref list 2))
(proxy (lookup-proxied env-name state)))
(format/log "evaluating code in container ~s (PID ~s)~%"
env-name (kernel-pid proxy))
(send-message proxy message)
(increment-execution-count state)))
((magic-html? code)
(reply-html kernel message (delete-magic code) count)
(increment-execution-count state))
......@@ -228,9 +296,10 @@ yet. You can create one by entering a “magic command” in a cell as follows:
python-ipython python-ipykernel"))
"You can then select a kernel and hand it code
to execute:"
(p (code
(pre ";;guix kernel my-environment ipython\n"
"2 + 2")))))
(p (pre
(code
";;guix kernel my-environment ipython\n"
"2 + 2")))))
count)
state)))
(λ error
......@@ -274,9 +343,9 @@ imported."
(('jupyter _ ...) #t)
(_ #f)))
(define (start-container context name manifest)
"Start a container with the given NAME and with a profile built from
MANIFEST. Return, as a monadic value, a <kernel> connected to the process in
(define (start-container context name profile)
"Start a container with the given NAME, and run the kernel found in
PROFILE. Return, as a monadic value, a <kernel> connected to the process in
that container."
(define guile-gcrypt
(specification->package "guile-gcrypt"))
......@@ -290,20 +359,14 @@ that container."
(with-imported-modules (source-module-closure
'((guix profiles)
(guix search-paths)
(guix jupyter inner-proxy)
(jupyter kernels))
#:select? module-to-import?)
#~(begin
(use-modules (guix profiles)
(guix search-paths)
(guix jupyter inner-proxy)
(jupyter kernels) ;json->connection
(ice-9 match))
(format (current-error-port)
"starting inner proxy with profile '~a'...~%"
#$profile)
;; (set-network-interface-up "lo") ;up lo interface
;; Do like 'guix environment'.
......@@ -321,8 +384,14 @@ that container."
(profile-search-paths #$profile))
(let ((str #$(scm->json-string (connection->json connection))))
(run-inner-proxy #$(number->string session-id)
(json->connection str)))))))
(match (available-kernel-specs-files)
((specs-file)
(format (current-error-port)
"starting kernel from '~a'...~%"
specs-file)
(let ((specs (call-with-input-file specs-file
json->kernel-specs)))
(exec-kernel specs (json->connection str))))))))))
(define-values (connection kernel)
(allocate-connection context "tcp" "127.0.0.1"
......@@ -346,13 +415,12 @@ that container."
;; network namespace. TODO: Arrange to use Unix-domain sockets instead.
(delq 'net %namespaces))
(mlet* %store-monad ((_ ((lift1 mkdir-p %store-monad) root))
(profile (profile-derivation manifest))
(pid (eval/container* (spawn profile) root
#:mounts fs
#:namespaces namespaces
#:guest-uid 1000
#:guest-gid 1000)))
(mlet* %store-monad ((_ ((lift1 mkdir-p %store-monad) root))
(pid (eval/container* (spawn profile) root
#:mounts fs
#:namespaces namespaces
#:guest-uid 1000
#:guest-gid 1000)))
(return (set-kernel-pid kernel pid))))
......
......@@ -11,21 +11,9 @@
"![Guix-Jupyter](logo.png)\n",
"\n",
"---\n",
"## Features\n",
"## Getting Started\n",
"\n",
"### Magic command\n",
"\n",
"This kernel use magic cells for kernel command.\n",
"\n",
"```scheme\n",
";;guix <command> <args>\n",
"<code>\n",
"```\n",
"\n",
"Different commands are available:\n",
" - **environment** to create new environment with container\n",
" - **run** eval code in guix kernel container\n",
" - **kernel** eval code in specific kernel\n",
"The `;;guix environment` _magic command_ allows you to create an execution environment containing a Jupyter kernel, or to run code in a previously-created environment.\n",
"\n",
"---"
]
......@@ -34,39 +22,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Usage\n",
"### Evaluating Code in a Jupyter Kernel\n",
"\n",
"### Environment: Multi environment\n",
"\n",
"#### Default environment"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
";;guix environment env-guile <- guile@2.2 guile-commonmark\n",
"(version)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Run: Run code in existing environment\n",
"\n",
"Check current guile-version:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"(version)"
"Create an environment called `guile-kernel` containing the Guile kernel for Jupyter:"
]
},
{
......@@ -75,16 +33,14 @@
"metadata": {},
"outputs": [],
"source": [
";;guix run env-guile\n",
"(system* \"guile\" \"--version\")\n",
"(search-path (string-split (getenv \"PATH\") #\\;) \"guile\")"
";;guix environment guile-kernel-env <- jupyter-guile-kernel"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Define function:"
"Run code in guile kernel:"
]
},
{
......@@ -93,6 +49,7 @@
"metadata": {},
"outputs": [],
"source": [
";;guix environment guile-kernel-env\n",
"(define (list-environ env)\n",
" (for-each (lambda (variable)\n",
" (display variable)\n",
......@@ -100,55 +57,23 @@
" (environ)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Use function:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
";;guix run env-guile\n",
";; Here we don't repeat \"guix environment\", so we use the\n",
";; same environment as the previous cell.\n",
"(list-environ (environ))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Kernel: Eval code in other jupyter kernel\n",
"\n",
"Create environment 'guile-kernel' with guile kernel for jupyter:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
";;guix environment guile-kernel-env <- jupyter-guile-kernel"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Run code in guile kernel:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
";;guix kernel guile-kernel-env guile\n",
"(define (random-art num)\n",
" (define (new-char)\n",
" (if (eq? (random 10) 5)\n",
......@@ -164,7 +89,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Use previous function in guile kernel:"
"Call the previously-defined function in the Guile kernel:"
]
},
{
......@@ -173,7 +98,6 @@
"metadata": {},
"outputs": [],
"source": [
";;guix kernel guile-kernel-env guile\n",
"(random-art 3000)"
]
},
......@@ -190,20 +114,9 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><h3 style=\"color: green;\">Preparing environment <tt>my-ipython</tt> with these packages:</h3><ul><li><tt>python-ipython 7.5.0</tt></li><li><tt>python-ipykernel 5.1.1</tt></li></ul></div>"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
";;guix environment my-ipython <- python-ipython python-ipykernel"
]
......@@ -219,19 +132,10 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hello Jupyter !\n"
]
}
],
"outputs": [],
"source": [
";;guix kernel my-ipython ipython\n",
"# This is python lang !\n",
"def hello ():\n",
" print (\"Hello Jupyter !\")\n",
......@@ -241,44 +145,29 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'/'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
";;guix kernel my-ipython ipython\n",
"import os\n",
"os.getcwd()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"os.getuid()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['etc', 'var', 'tmp', 'gnu', 'dev', 'proc']"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
";;guix kernel my-ipython ipython\n",
"os.listdir('/')"
]
},
......@@ -304,7 +193,6 @@
"metadata": {},
"outputs": [],
"source": [
";;guix kernel matplotlib-env ipython\n",
"%matplotlib inline\n",
"from matplotlib import pyplot as plt\n",
"from matplotlib import style\n",
......@@ -321,63 +209,19 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div><h3 style=\"color: green;\">Preparing environment <tt>R</tt> with these packages:</h3><ul><li><tt>r-irkernel 1.0.2</tt></li><li><tt>r 3.6.1</tt></li></ul></div>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"<p>Done!</p>"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
";;guix environment R <- r-irkernel r"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(\".\" \"..\" \"R\" \"Rscript\")"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
";;guix run R\n",
"(use-modules (ice-9 ftw))\n",
"(scandir (getenv \"PATH\"))"
]
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
";;guix kernel R ir\n",
"2+2"
]
},
......
......@@ -58,15 +58,7 @@ return false"
#f))
(define (magic-env? code) ;;;guix environment ...
(if (magic-attr? code "environment")
(let* ((magic (get-magic-line code))
(list (string-split magic #\ )))
(unless (equal? (list-ref list 3) %magic-separator)
(display (string-append "WARNING: Separator '"
%magic-separator
"' not found !\n")))
#t)
#f))
(magic-attr? code "environment"))
(define (magic-run? code) ;;;guix run ...
(magic-attr? code "run"))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment