-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpsg.py
executable file
·167 lines (137 loc) · 5.11 KB
/
psg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/bin/env python3
import http.server
import os
import shutil
import socketserver
import subprocess
import sys
import textwrap
import time
help = """
usage: psg [command]
commands:
build - converts the site source stored in the `src` directory, and places it in the `docs` directory.
serve - builds the docs directory and launches Python's builtin server to serve the docs directory.
clean - deletes the docs directory.
help - display this message.
psg depends on the existence of the following:
- `pandoc` in your $PATH
- header.html, which is prepended to all generated html fragments
- footer.html, which is appended to all generated html fragments.
- a "src" directory containing the website to be generated.
""" # noqa
valid_commands = ["build", "serve", "clean", "help"]
# Check if there is at least one argument,
# setting it to `command` for future reference.
if (len(sys.argv) < 2 or
sys.argv[1] == "help" or
sys.argv[1] not in valid_commands):
print(help)
sys.exit(1)
command = sys.argv[1]
# checking for required files/directories.
if not os.path.isfile("header.html"):
print("header.html does not exist. Exiting now.")
sys.exit(1)
else:
with open("header.html", "r") as file:
header_html = file.read()
if not os.path.isfile("footer.html"):
print("footer.html does not exist. Exiting now.")
sys.exit(1)
else:
with open("footer.html", "r") as file:
footer_html = file.read()
if not os.path.isdir("src"):
print("src directory does not exist. Exiting now.")
sys.exit(1)
def convert_to_markdown(src, dest):
pandoc_execution = subprocess.run([
"pandoc",
"--from",
"markdown",
"--to",
"html",
src],
capture_output=True,
text=True)
if pandoc_execution.stderr != "":
print("psg: pandoc error found. Printing pandoc stderr below:\n")
print(textwrap.indent(pandoc_execution.stderr, '\t'))
print("psg: exiting now, built site may be incomplete")
sys.exit(1)
out_html = (header_html + "\n" +
pandoc_execution.stdout + "\n" +
footer_html)
with open(dest, "w") as file:
file.write(out_html)
def needs_updating(source_path, dest_path):
# Check if the built file doesn't exist
if not os.path.exists(dest_path):
return True
# Compare the modification times of the source and built files, as
# well as the header.html and footer.html. The check for the header/footer_html
# is guarded by a check that the file is markdown, because if not it doesn't matter.
return (os.path.getmtime(source_path) > os.path.getmtime(dest_path)
or
(source_path.endswith(".md") and
os.path.getmtime("header.html") > os.path.getmtime(dest_path))
or
(source_path.endswith(".md") and
os.path.getmtime("footer.html") > os.path.getmtime(dest_path)))
def build():
"""
- find the `src` dir
- iterate through every file in it.
- run the case statement on the file extension:
if md, pandoc and copy. Also add header and footer to it.
if not md, just copy
"""
source_directory = "src"
destination_directory = "docs"
os.makedirs(destination_directory, exist_ok=True)
for root, dirs, files in os.walk(source_directory):
for directory in dirs:
dir_to_copy = os.path.join(root, directory)
dest_dir = os.path.join(
destination_directory,
os.path.relpath(dir_to_copy, source_directory))
os.makedirs(dest_dir, exist_ok=True)
for file in files:
source_path = os.path.join(root, file)
dest_path = os.path.join(
destination_directory,
os.path.relpath(source_path, source_directory))
dest_path = dest_path.replace('.md', '.html')
# checks if the file at dest_path needs updating or creation
if needs_updating(source_path, dest_path):
if file.endswith(".md"):
# Handle Markdown files differently
print(f"converting {source_path}")
convert_to_markdown(source_path, dest_path)
else:
# Copy non-Markdown files
print(f"copying {source_path} to destination")
shutil.copy(source_path, dest_path)
# update the timestamp on copied files so that they
# aren't always getting rebuilt.
current_time = time.time()
os.utime(dest_path, (current_time, current_time))
def serve():
"""
calls `build`,
and calls the python http server to serve the `docs` dir.
"""
build()
os.chdir('./docs/')
handler = http.server.SimpleHTTPRequestHandler
port = 8080
with socketserver.TCPServer(("", port), handler) as httpd:
print(f"Serving directory at http://localhost:{port}")
httpd.serve_forever()
def clean():
"""
simply deletes the docs directory.
"""
shutil.rmtree("./docs/")
eval(f"{command}()")