Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit 45ecaa5

Browse files
committed
Merge branch 'master' of github.com:RunestoneInteractive/RunestoneComponents into merging
2 parents 34e653f + b0e8ef2 commit 45ecaa5

File tree

33 files changed

+833
-714
lines changed

33 files changed

+833
-714
lines changed

runestone/__main__.py

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# *********
22
# |docname|
33
# *********
4+
5+
from runestone import cmap
46
import sys
57
import os
68
import shutil
@@ -9,6 +11,7 @@
911
import click
1012
import pathlib
1113
import re
14+
import subprocess
1215
from paver.easy import sh
1316
from pkg_resources import resource_string, resource_filename, require
1417
from .pretext.chapter_pop import manifest_data_to_db
@@ -191,10 +194,14 @@ def build(all, wd):
191194
paver_main(args=myargs)
192195

193196

194-
@cli.command()
197+
@cli.command(short_help="preview the book in a minimal server (NO API support)")
195198
@click.option("--port", default=8000, help="port for server to listen on")
196199
@click.option("--listen", default="", help="address for server to listen on")
197-
def serve(port, listen):
200+
def preview(port, listen):
201+
_preview(port, listen)
202+
203+
204+
def _preview(port, listen):
198205
click.echo("Note: this is a minimal static server without templates or a database.")
199206
click.echo("For many use cases this is fine.")
200207
click.echo(
@@ -246,6 +253,15 @@ def serve(port, listen):
246253
httpd.serve_forever()
247254

248255

256+
# configure preview as an alias for serve
257+
@cli.command(short_help="Deprecated - use preview")
258+
@click.option("--port", default=8000, help="port for server to listen on")
259+
@click.option("--listen", default="", help="address for server to listen on")
260+
def serve(port, listen):
261+
click.echo("The serve command is deprecated, use runestone preview")
262+
_preview(port, listen)
263+
264+
249265
@cli.command()
250266
@click.option("--dest", default="", help="destination for deploy")
251267
def deploy(dest):
@@ -286,7 +302,58 @@ def deploy(dest):
286302
sh("rsync -rav --delete {} {}".format(pavement.serving_dir, dest))
287303

288304

289-
from runestone import cmap
305+
@cli.command(short_help="Run sphinx build to convert RST to PreTeXt")
306+
@click.option("--course", default=None, help="Unique name of the book")
307+
@click.option("--sourcedir", default="_sources", help="Where is the source Luke?")
308+
@click.option("--outdir", default="build", help="Where is the source Luke?")
309+
def rs2ptx(course, sourcedir, outdir):
310+
"""
311+
Assemble and run a sphinx command similar to the following:
312+
313+
.. code-block:: bash
314+
315+
sphinx-build -b xml -d ./build/overview/doctrees -c . -Acourse_id=overview -Alogin_required=false -Aappname=runestone -Aloglevel=10 -Acourse_url=https://runestone.academy -Adynamic_pages=True -Ause_services=true -Abasecourse=overview -Apython3=true -Adownloads_enabled=true -Aallow_pairs=false -Aenable_chatcodes=false -Arunestone_version=5.7.1 -Abuild_info=unknown . ./build/xml
316+
317+
This command demonstrates a step toward independence from paver and the pavement.py file.
318+
This is kind of moot in a future where we rely on pretext to be the authoring language. But it **would**
319+
be easy to move the key variables and template_args from pavement.py to conf.py and update the build
320+
command to work like this...
321+
"""
322+
os.chdir(findProjectRoot())
323+
sys.path.insert(0, os.getcwd())
324+
del os.environ["DBURL"]
325+
try:
326+
import pavement
327+
except:
328+
click.echo("Could not read pavement.py file, aborting")
329+
sys.exit(1)
330+
331+
if not course:
332+
if pavement.project_name:
333+
course = pavement.project_name
334+
else:
335+
course = click.prompt("Name of Course ", default="rsbook")
336+
337+
if pavement.template_args:
338+
tdict = pavement.template_args
339+
else:
340+
tdict = {"course_id": course}
341+
342+
cmd_start = ["sphinx-build", "-E", "-b", "xml",
343+
"-d", f"./build/{course}/doctrees", "-c", "."]
344+
tplate_val = [f"-A{key}={val}" for key, val in tdict.items()]
345+
cmd_end = [f"{sourcedir}", f"./{outdir}/xml"]
346+
cmd = " ".join(cmd_start + tplate_val + cmd_end)
347+
click.echo(cmd)
348+
try:
349+
cp = subprocess.run(
350+
cmd , shell=True, check=True
351+
)
352+
except subprocess.CalledProcessError as e:
353+
click.echo(f"{e.stderr or ''}{e.stdout or ''}")
354+
raise
355+
356+
# TODO: Run the xsltproc command after a successful runestone convert
290357

291358

292359
@cli.command(short_help="type runestone doc directive to get help on directive")

runestone/activecode/activecode.py

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,25 @@ def setup(app):
5353
app.add_config_value("activecode_hide_load_history", False, "html")
5454
app.add_config_value("wasm_uri", "/_static", "html")
5555

56-
app.add_node(ActivcodeNode, html=(visit_ac_node, depart_ac_node))
56+
app.add_node(ActivecodeNode, html=(visit_ac_html, depart_ac_html),
57+
xml=(visit_ac_xml, depart_ac_xml))
5758

5859
app.connect("doctree-resolved", process_activcode_nodes)
5960
app.connect("env-purge-doc", purge_activecodes)
6061

6162

63+
XML_START = """
64+
<listing xml:id="{divid}">
65+
<caption>{caption}</caption>
66+
<program xml:id="{divid}_editor" interactive='yes' language="{language}">
67+
<input>
68+
{initialcode}
69+
</input>
70+
</program>
71+
</listing>
72+
73+
"""
74+
6275
TEMPLATE_START = """
6376
<div class="%(divclass)s">
6477
<div data-component="activecode" id=%(divid)s data-question_label="%(question_label)s">
@@ -79,51 +92,49 @@ def setup(app):
7992
"""
8093

8194

82-
class ActivcodeNode(nodes.General, nodes.Element, RunestoneIdNode):
83-
def __init__(self, content, **kwargs):
84-
"""
95+
class ActivecodeNode(nodes.General, nodes.Element, RunestoneIdNode):
96+
pass
97+
98+
99+
def visit_ac_xml(self, node):
100+
res = XML_START.format(**node["runestone_options"])
101+
self.output.append(res)
85102

86-
Arguments:
87-
- `self`:
88-
- `content`:
89-
"""
90-
super(ActivcodeNode, self).__init__(name=content["name"], **kwargs)
91-
self.runestone_options = content
92103

104+
def depart_ac_xml(self, node):
105+
pass
93106

94107
# self for these functions is an instance of the writer class. For example
95108
# in html, self is sphinx.writers.html.SmartyPantsHTMLTranslator
96109
# The node that is passed as a parameter is an instance of our node class.
97-
def visit_ac_node(self, node):
98-
# print self.settings.env.activecodecounter
99110

100-
# todo: handle above in node.runestone_options
101-
# todo handle 'hidecode' not in node.runestone_options:
102-
# todo: handle if 'gradebutton' in node.runestone_options: res += GRADES
103111

104-
node.delimiter = "_start__{}_".format(node.runestone_options["divid"])
112+
def visit_ac_html(self, node):
113+
# print self.settings.env.activecodecounter
114+
115+
node["delimiter"] = "_start__{}_".format(node["runestone_options"]["divid"])
105116

106-
self.body.append(node.delimiter)
117+
self.body.append(node["delimiter"])
107118

108-
res = TEMPLATE_START % node.runestone_options
119+
res = TEMPLATE_START % node["runestone_options"]
109120
self.body.append(res)
110121

111122

112-
def depart_ac_node(self, node):
123+
def depart_ac_html(self, node):
113124
"""This is called at the start of processing an activecode node. If activecode had recursive nodes
114-
etc and did not want to do all of the processing in visit_ac_node any finishing touches could be
125+
etc and did not want to do all of the processing in visit_ac_html any finishing touches could be
115126
added here.
116127
"""
117-
res = TEMPLATE_END % node.runestone_options
128+
res = TEMPLATE_END % node["runestone_options"]
118129
self.body.append(res)
119130

120131
addHTMLToDB(
121-
node.runestone_options["divid"],
122-
node.runestone_options["basecourse"],
123-
"".join(self.body[self.body.index(node.delimiter) + 1 :]),
132+
node["runestone_options"]["divid"],
133+
node["runestone_options"]["basecourse"],
134+
"".join(self.body[self.body.index(node["delimiter"]) + 1 :]),
124135
)
125136

126-
self.body.remove(node.delimiter)
137+
self.body.remove(node["delimiter"])
127138

128139

129140
def process_activcode_nodes(app, env, docname):
@@ -448,8 +459,10 @@ def run(self):
448459
"This should only affect the grading interface. Everything else should be fine."
449460
)
450461

451-
acnode = ActivcodeNode(self.options, rawsource=self.block_text)
452-
acnode.source, acnode.line = self.state_machine.get_source_and_line(self.lineno)
462+
acnode = ActivecodeNode()
463+
acnode["runestone_options"] = self.options
464+
acnode["source"], acnode["line"] = self.state_machine.get_source_and_line(
465+
self.lineno)
453466
self.add_name(acnode) # make this divid available as a target for :ref:
454467

455468
maybeAddToAssignment(self)

runestone/assignment/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
def setup(app):
3838
app.add_directive("assignment", Assignment)
39-
app.add_node(AssignmentNode, html=(visit_a_node, depart_a_node))
39+
app.add_node(AssignmentNode, html=(visit_a_html, depart_a_html))
4040

4141
app.connect("doctree-resolved", process_nodes)
4242
app.connect("env-purge-doc", purge)
@@ -54,13 +54,13 @@ def __init__(self, content, **kwargs):
5454
self.a_components = content
5555

5656

57-
def visit_a_node(self, node):
57+
def visit_a_html(self, node):
5858
pass
5959

6060

61-
def depart_a_node(self, node):
62-
question_ids = node.a_components["question_ids"]
63-
basecourse = node.a_components["basecourse"]
61+
def depart_a_html(self, node):
62+
question_ids = node["a_components"]["question_ids"]
63+
basecourse = node["a_components"]["basecourse"]
6464
for q_id in question_ids:
6565
src = get_HTML_from_DB(q_id, basecourse)
6666
if src:

runestone/blockly/blockly.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
def setup(app):
3434
app.add_directive("blockly", Blockly)
3535

36-
app.add_node(BlocklyNode, html=(visit_block_node, depart_block_node))
36+
app.add_node(BlocklyNode, html=(visit_block_html, depart_block_html))
3737

3838
app.connect("doctree-resolved", process_activcode_nodes)
3939
app.connect("env-purge-doc", purge_activecodes)
@@ -154,10 +154,12 @@ def __init__(self, content, **kwargs):
154154
# self for these functions is an instance of the writer class. For example
155155
# in html, self is sphinx.writers.html.SmartyPantsHTMLTranslator
156156
# The node that is passed as a parameter is an instance of our node class.
157-
def visit_block_node(self, node):
158-
res = START % (node.runestone_options)
157+
158+
159+
def visit_block_html(self, node):
160+
res = START % (node["runestone_options"])
159161
res += CTRL_START
160-
for ctrl in node.runestone_options["controls"]:
162+
for ctrl in node["runestone_options"]["controls"]:
161163
if ctrl == "variables":
162164
res += '<category name="Variables" custom="VARIABLE"></category>'
163165
elif ctrl == "":
@@ -169,11 +171,11 @@ def visit_block_node(self, node):
169171
else:
170172
res += '<block type="%s"></block>\n' % (ctrl)
171173
res += CTRL_END
172-
res += END % (node.runestone_options)
174+
res += END % (node["runestone_options"])
173175
path = os.path.join(
174-
node.runestone_options["blocklyHomePrefix"],
176+
node["runestone_options"]["blocklyHomePrefix"],
175177
"_static",
176-
node.runestone_options["divid"] + ".html",
178+
node["runestone_options"]["divid"] + ".html",
177179
)
178180
final = (
179181
'<iframe class="blk-iframe" seamless src="%s" width="600" '
@@ -185,9 +187,9 @@ def visit_block_node(self, node):
185187
self.body.append(final)
186188

187189

188-
def depart_block_node(self, node):
190+
def depart_block_html(self, node):
189191
""" This is called at the start of processing an activecode node. If activecode had recursive nodes
190-
etc and did not want to do all of the processing in visit_ac_node any finishing touches could be
192+
etc and did not want to do all of the processing in visit_ac_html any finishing touches could be
191193
added here.
192194
"""
193195
pass

runestone/cellbotics/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class BlePairNode(nodes.General, nodes.Element):
3131
pass
3232

3333

34-
def visit_ble_pair_node(self, node):
34+
def visit_ble_pair_html(self, node):
3535
self.body.append(
3636
'<div data-component="ble">\n'
3737
' <script>runestone_import("ble");</script>\n'
@@ -41,7 +41,7 @@ def visit_ble_pair_node(self, node):
4141
)
4242

4343

44-
def depart_ble_pair_node(self, node):
44+
def depart_ble_pair_html(self, node):
4545
pass
4646

4747

@@ -57,5 +57,5 @@ def run(self):
5757

5858
def setup(app):
5959
# Add the Pair button directive.
60-
app.add_node(BlePairNode, html=(visit_ble_pair_node, depart_ble_pair_node))
60+
app.add_node(BlePairNode, html=(visit_ble_pair_html, depart_ble_pair_html))
6161
app.add_directive('ble-pair-button', BlePairDirective)

0 commit comments

Comments
 (0)