Skip to content

Commit 04d459d

Browse files
committed
new common.py
1 parent 00dc3a6 commit 04d459d

File tree

3 files changed

+109
-44
lines changed

3 files changed

+109
-44
lines changed

common.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/env python3
2+
3+
# This is free and unencumbered software released into the public
4+
# domain.
5+
6+
# Anyone is free to copy, modify, publish, use, compile, sell, or
7+
# distribute this software, either in source code form or as a
8+
# compiled binary, for any purpose, commercial or non-commercial, and
9+
# by any means.
10+
11+
# In jurisdictions that recognize copyright laws, the author or
12+
# authors of this software dedicate any and all copyright interest in
13+
# the software to the public domain. We make this dedication for the
14+
# benefit of the public at large and to the detriment of our heirs
15+
# and successors. We intend this dedication to be an overt act of
16+
# relinquishment in perpetuity of all present and future rights to
17+
# this software under copyright law.
18+
19+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
23+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
24+
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26+
27+
# For more information, please refer to <http://unlicense.org>
28+
29+
"""Things that other scripts import and use."""
30+
31+
import itertools
32+
import re
33+
import sys
34+
35+
36+
_LINK_REGEX = r'\[(.*?)\]\((.*?)\)'
37+
38+
39+
def find_links(file):
40+
"""Find all markdown links in a file object.
41+
42+
Yield (lineno, regexmatch) tuples.
43+
"""
44+
# don't yield same link twice
45+
seen = set()
46+
47+
# we need to loop over the file two lines at a time to support
48+
# multi-line (actually two-line) links, so this is kind of a mess
49+
firsts, seconds = itertools.tee(file)
50+
next(seconds) # first line is never second line
51+
52+
# we want 1-based indexing instead of 0-based and one-line links get
53+
# caught from linepair[1], so we need to start at two
54+
for lineno, linepair in enumerate(zip(firsts, seconds), start=2):
55+
lines = linepair[0] + linepair[1]
56+
for match in re.finditer(_LINK_REGEX, lines, flags=re.DOTALL):
57+
if match.group(0) not in seen:
58+
seen.add(match.group(0))
59+
yield match, lineno
60+
61+
62+
def get_markdown_files():
63+
"""Yield the names of all markdown files in this tutorial.
64+
65+
This assumes that the README contains links to everything.
66+
"""
67+
yield 'README.md'
68+
with open('README.md', 'r') as f:
69+
for match, lineno in find_links(f):
70+
target = match.group(2)
71+
# Currently the README doesn't link to itself, but I don't
72+
# want to break things if it will in the future.
73+
if target.endswith('.md') and target != 'README.md':
74+
yield target
75+
76+
77+
def askyesno(question, default=True):
78+
"""Ask a yes/no question and return True or False.
79+
80+
The default answer is yes if default is True and no if default is
81+
False.
82+
"""
83+
if default:
84+
# yes by default
85+
question += ' [Y/n] '
86+
else:
87+
# no by default
88+
question += ' [y/N] '
89+
while True:
90+
result = input(question).upper().strip()
91+
if result == 'Y':
92+
return True
93+
if result == 'N':
94+
return False
95+
if not result:
96+
return default

make-html.py

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@
2929
"""Create HTML files of the tutorial."""
3030

3131
import os
32-
import re
3332
import shutil
3433
import string
3534
import sys
3635
import webbrowser
3736

37+
import common
38+
3839
try:
3940
import mistune
4041
except ImportError:
@@ -52,8 +53,6 @@
5253
pygments = None
5354

5455

55-
LINK_REGEX = r'\[.*\]\((.*\.md)\)'
56-
5756
HTML_TEMPLATE = """\
5857
<!DOCTYPE html>
5958
<html>
@@ -68,30 +67,8 @@
6867
"""
6968

7069

71-
def askyesno(question, default=True):
72-
"""Ask a yes/no question and return True or False.
73-
74-
The default answer is yes if default is True and no if default is
75-
False.
76-
"""
77-
if default:
78-
# yes by default
79-
question += ' [Y/n] '
80-
else:
81-
# no by default
82-
question += ' [y/N] '
83-
while True:
84-
result = input(question).upper().strip()
85-
if result == 'Y':
86-
return True
87-
if result == 'N':
88-
return False
89-
if not result:
90-
return default
91-
92-
9370
def mkdir_open(filename, mode):
94-
"""Like built-in open(), but make a directory as needed."""
71+
"""Like open(), but make directories as needed."""
9572
directory = os.path.dirname(filename)
9673
os.makedirs(directory, exist_ok=True)
9774
return open(filename, mode)
@@ -204,25 +181,21 @@ def main():
204181
print()
205182
print("You can also continue without Pygments, but the code examples")
206183
print("will not be in color.")
207-
if not askyesno("Continue without pygments?"):
184+
if not common.askyesno("Continue without pygments?"):
208185
print("Interrupt.")
209186
return
210187

211188
if os.path.exists('html'):
212-
if not askyesno("html exists. Do you want to remove it?"):
189+
if not common.askyesno("html exists. Do you want to remove it?"):
213190
print("Interrupt.")
214191
return
215192
if os.path.isdir('html'):
216193
shutil.rmtree('html')
217194
else:
218195
os.remove('html')
219196

220-
print("Getting a list of files to generate...")
221-
with open('README.md', 'r') as f:
222-
filelist = re.findall(LINK_REGEX, f.read()) + ['README.md']
223-
224197
print("Generating HTML files...")
225-
for markdownfile in filelist:
198+
for markdownfile in common.get_markdown_files():
226199
htmlfile = os.path.join('html', fix_filename(markdownfile))
227200
print(' ', markdownfile, '->', htmlfile)
228201
with open(markdownfile.replace('/', os.sep), 'r') as f:
@@ -241,7 +214,7 @@ def main():
241214
print("Ready! The files are in the html directory.")
242215
print("Go to html and double-click index.html to read the tutorial.")
243216
print()
244-
if askyesno("Do you want to view the tutorial now?", default=False):
217+
if common.askyesno("Do you want to view the tutorial now?", default=False):
245218
print("Opening the tutorial...")
246219
webbrowser.open(os.path.join('html', 'index.html'))
247220

update-ends.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@
2828

2929
"""Update ends of markdown files."""
3030

31-
import os
3231
import re
3332

33+
import common
34+
3435

3536
# Markdown and HTML links use / as a path separator so there's no need
36-
# for os.path, but we do need to replace it with os.sep when opening the
37+
# for os.path, but we do need to replace / with os.sep when opening the
3738
# files.
3839
BASIC_END = """\
3940
You may use this tutorial freely at your own risk. See
@@ -51,8 +52,7 @@
5152
"""
5253

5354

54-
LINK_REGEX = r'\[.*\]\((.*\.md)\)'
55-
CHAPTER_LINK_REGEX = r'^\d+\. ' + LINK_REGEX + r'$'
55+
CHAPTER_LINK_REGEX = r'^\d+\. \[.*\]\((.*\.md)\)$'
5656

5757

5858
def get_filenames():
@@ -80,11 +80,7 @@ def get_filenames():
8080
# it's a link to a chapter
8181
chapters.append(match.group(1))
8282

83-
# now let's find other links to markdown files
84-
with open('README.md', 'r') as f:
85-
all_files = re.findall(LINK_REGEX, f.read())
86-
others = set(all_files) - set(chapters)
87-
83+
others = set(common.get_markdown_files()) - set(chapters)
8884
return chapters, others
8985

9086

@@ -156,7 +152,7 @@ def main():
156152

157153
print("Other files:")
158154
for filename in other_files:
159-
end = BASIC_END.format(toplevel='../' * filename.count('/'))
155+
end = BASIC_END.format(toplevel='../'*filename.count('/'))
160156
update_end(filename, end)
161157

162158

0 commit comments

Comments
 (0)