vite/vite.py (view raw)
1#!/usr/bin/env python3
2
3"""
4Vite - A simple and minimal static site generator.
5"""
6
7import sys
8import pathlib
9import os
10import jinja2
11import time
12import http.server
13import socketserver
14import shutil
15
16from markdown2 import markdown_path
17from distutils.dir_util import copy_tree
18from huepy import *
19from vite import vite
20
21
22# constants
23PAGES_PATH = 'pages/'
24BUILD_PATH = 'build/'
25TEMPL_PATH = 'templates/'
26TEMPL_FILE = ''
27PORT = 1911
28
29
30def import_config():
31 try:
32 sys.path.append(os.getcwd())
33 globals()['config'] = __import__('config')
34 global TEMPL_FILE
35 TEMPL_FILE = os.path.join(TEMPL_PATH, config.template)
36 except ImportError:
37 print(bad('Error: config.py not found.'))
38 print(que('Are you sure you\'re in a project directory?'))
39 sys.exit(1)
40
41
42def create_project(path):
43 try:
44 abs_path = pathlib.Path(path).resolve()
45 cur_path = pathlib.Path('.').resolve()
46 os.makedirs(os.path.join(path, 'build'))
47 os.mkdir(os.path.join(path, 'pages'))
48 os.mkdir(os.path.join(path, 'templates'))
49 os.mkdir(os.path.join(path, 'static'))
50 create_config(path)
51 create_template(path)
52 print(good('Created project directory at %s.' % (abs_path)))
53 except FileExistsError:
54 print(bad('Error: specified path exists.'))
55
56
57def create_config(path):
58 with open(os.path.join(path, 'config.py'), 'w') as f:
59 f.write("""# config.py - Vite's configuration script
60
61title = ''
62author = ''
63header = ''
64footer = ''
65template = 'index.html' # default is index.html
66 """)
67
68
69def create_template(path):
70 with open(os.path.join(path, 'templates', 'index.html'), 'w') as f:
71 f.write("""<!DOCTYPE html>
72<html>
73<header>
74 {{ header }}
75 <title>
76 {{ title }}
77 </title>
78</header>
79
80<body>
81 {{ body }}
82</body>
83
84<footer>
85 {{ footer }}
86 <p> {{ author }} </p>
87<footer>
88
89 """)
90
91# jinja2
92def jinja_render(html_text, TEMPL_FILE):
93 template_loader = jinja2.FileSystemLoader('./')
94 env = jinja2.Environment(loader=template_loader)
95 template = env.get_template(TEMPL_FILE)
96 output = template.render(title=config.title,
97 author=config.author,
98 header=config.header,
99 footer=config.footer,
100 body=html_text)
101 return output
102
103
104def markdown_render(filename):
105 html_text = markdown_path(os.path.join(PAGES_PATH, filename))
106 return html_text
107
108
109def html_gen():
110 #TODO: refactor all of this!
111 for root, dirs, files in os.walk(PAGES_PATH):
112 for d in dirs:
113 os.mkdir(os.path.join(BUILD_PATH, d))
114 for f in os.listdir(os.path.join(PAGES_PATH, d)):
115 if os.path.splitext(f)[1] != '.md':
116 shutil.copyfile(os.path.join(PAGES_PATH, d, f),
117 os.path.join(BUILD_PATH, d, f))
118 print(run('Copied %s/%s' % (d, f)))
119 elif f == '_index.md':
120 index_html = markdown_render(os.path.join(d, f))
121 output = jinja_render(index_html, TEMPL_FILE)
122 with open(os.path.join(BUILD_PATH, d, 'index.html'), 'w') as f:
123 f.write(output)
124 print(run('Rendered %s/_index.md' % (d)))
125 else:
126 html_text = markdown_render(os.path.join(d, f))
127 html_file = os.path.splitext(os.path.join(BUILD_PATH, d, f))[0]
128 os.mkdir(html_file)
129 output = jinja_render(html_text, TEMPL_FILE)
130 with open(os.path.join(html_file, 'index.html'), 'w') as ff:
131 ff.write(output)
132 print(run('Rendered %s/%s' % (d, f)))
133
134 for f in os.listdir(PAGES_PATH):
135 if os.path.isfile(os.path.join(PAGES_PATH, f)):
136 if os.path.splitext(f)[1] != '.md':
137 shutil.copyfile(os.path.join(PAGES_PATH, f), os.path.join(BUILD_PATH, f))
138 print(run('Copied %s' % (f)))
139 elif f == '_index.md':
140 index_html = markdown_render(f)
141 output = jinja_render(index_html, TEMPL_FILE)
142 with open(os.path.join(BUILD_PATH, 'index.html'), 'w') as ff:
143 ff.write(output)
144 print(run('Rendered _index.md'))
145 else:
146 html_text = markdown_render(f)
147 html_file = os.path.splitext(os.path.join(BUILD_PATH, f))[0]
148 os.mkdir(html_file)
149 output = jinja_render(html_text, TEMPL_FILE)
150 with open(os.path.join(html_file, 'index.html'), 'w') as ff:
151 ff.write(output)
152 print(run('Rendered %s' % f))
153
154
155def server():
156 handler = http.server.SimpleHTTPRequestHandler
157 os.chdir(os.path.join(os.getcwd(), BUILD_PATH))
158 try:
159 with socketserver.TCPServer(('', PORT), handler) as httpd:
160 print(run(f'Serving the {italic("build")} directory at http://localhost:{PORT}'))
161 print(white('Ctrl+C') + ' to stop.')
162 httpd.serve_forever()
163 except KeyboardInterrupt:
164 print(info('Stopping server.'))
165 httpd.socket.close()
166 sys.exit(1)
167
168
169def clean():
170 shutil.rmtree(BUILD_PATH)
171 os.makedirs(BUILD_PATH)
172
173
174def builder():
175 path = os.getcwd()
176 start = time.process_time()
177 if not os.listdir(os.path.join(path, PAGES_PATH)):
178 print(info(italic('pages') + ' directory is empty. Nothing to build.'))
179 sys.exit(1)
180 else:
181 try:
182 clean()
183 html_gen()
184 if not os.path.exists(os.path.join(path, BUILD_PATH, 'static')):
185 os.mkdir(os.path.join(path, BUILD_PATH, 'static'))
186 copy_tree('static', os.path.join(path, BUILD_PATH, 'static'))
187 print(good('Done in %0.5fs.' % (time.process_time() - start)))
188 except jinja2.exceptions.TemplateNotFound:
189 print(bad('Error: specified template not found: %s' % TEMPL_FILE))
190