diff options
Diffstat (limited to 'generators')
-rw-r--r-- | generators/generators.py | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/generators/generators.py b/generators/generators.py index adfe819a..3122f9c8 100644 --- a/generators/generators.py +++ b/generators/generators.py @@ -18,6 +18,8 @@ import copy import email.utils import time +import shutil + from rss import * from config.config import * @@ -689,3 +691,141 @@ def generate_index_and_feed(): sys.stderr.write("wrote rss.xml\n") generate_sitemap(feed) + + +# exclude_list is only inialized once to avoid constant disk IO +@utils.static_vars(exclude_list=None) +def generate_blog(fresh=False, report_total_errors=True): + """Generate the blog in BUILDDIR. + + Parameters + ---------- + fresh : bool + If True, remove all existing build artifects and start afresh; + otherwise, only copy or build new or modified files. Default is + False. + report_total_errors : bool + If True, a line will be printed to stderr at the end of build + (assuming the function doesn't raise early) reporting the total + number of errors, e.g., "build finished with 0 errors". This is + turned on by default, but pass False to turn it off, which will + result in a completely silent session if nothing changed. This + is useful for auto-regen, for instance. + + Returns + ------- + failed_builds : int + Number of build failures. + + """ + + # pylint: disable=too-many-branches,too-many-locals,too-many-statements + + if not os.path.isdir(SOURCEDIR): + raise OSError("source directory %s does not exist" % SOURCEDIR) + if not os.path.exists(HTMLTEMPLATE): + raise OSError("HTML template %s not found" % HTMLTEMPLATE) + + if not os.path.isdir(BUILDDIR): + if os.path.exists(BUILDDIR): + os.remove(BUILDDIR) + os.mkdir(BUILDDIR, mode=0o755) + if fresh: + for name in os.listdir(BUILDDIR): + if name == ".git": + continue + obj = os.path.join(BUILDDIR, name) + if os.path.isdir(obj): + shutil.rmtree(obj) + else: + os.remove(obj) + + # nojekyll: https://help.github.com/articles/files-that-start-with-an-underscore-are-missing/ + if not os.path.exists(os.path.join(BUILDDIR, ".nojekyll")): + with open(os.path.join(BUILDDIR, ".nojekyll"), "w") as fileobj: + pass + + if CUSTOM_DOMAIN and not os.path.exists(os.path.join(BUILDDIR, "CNAME")): + with open(os.path.join(BUILDDIR, "CNAME"), "w") as fileobj: + fileobj.write(CUSTOM_DOMAIN) + + failed_builds = 0 + generator_mtime = os.path.getmtime(GENERATORSOURCE) + template_mtime = os.path.getmtime(HTMLTEMPLATE) + fundamental_mtime = max(generator_mtime, template_mtime) + anything_modified = False + + exclude_list = generate_blog.exclude_list # get value of static variable + if exclude_list is None: + try: + with open(EXCLUDELIST) as fp: + exclude_list = [os.path.abspath(os.path.join(SOURCEDIR, line.rstrip())) + for line in list(fp) + if line.strip() != "" and not line.startswith('#')] + except OSError: + exclude_list = [] + generate_blog.exclude_list = exclude_list # assign to static variable for the future + + for root, dirs, files in os.walk(SOURCEDIR): + # If root is in exclude list, skip all files and remove all subdirs from traversal list. + if root in exclude_list: + dirs[:] = [] + continue + + relroot = os.path.relpath(root, start=SOURCEDIR) + dstroot = os.path.join(BUILDDIR, relroot) + if not os.path.isdir(dstroot): + if os.path.exists(dstroot): + os.remove(dstroot) + os.mkdir(dstroot, mode=0o755) + + for name in files: + if name.startswith('.') or os.path.join(root, name) in exclude_list: + continue + + extension = name.split(".")[-1] + if extension not in ["css", "js", "asc", "html", "jpg", "md", "png", "svg", "ico", "txt", + "eot", "ttf", "woff", "woff2"]: + continue + + relpath = os.path.join(relroot, name) + srcpath = os.path.join(root, name) + if extension == "md": + dstpath = os.path.join(dstroot, re.sub(r'\.md$', '.html', name)) + else: + dstpath = os.path.join(dstroot, name) + if ((not os.path.exists(dstpath) or + os.path.getmtime(dstpath) <= + max(fundamental_mtime, os.path.getmtime(srcpath)))): + # new post or modified post + anything_modified = True + if srcpath == INDEXMD: + continue # index will be processed separately + if extension in ["css", "js", "asc", "html", "jpg", "png", "svg", "ico", "txt", + "eot", "ttf", "woff", "woff2"]: + sys.stderr.write("copying %s\n" % relpath) + shutil.copy(srcpath, dstpath) + elif extension == "md": + sys.stderr.write("compiling %s\n" % relpath) + pandoc_args = [ + "pandoc", srcpath, + "--template", HTMLTEMPLATE, + "--highlight-style=pygments", + "-o", dstpath, + ] + try: + subprocess.check_call(pandoc_args) + except subprocess.CalledProcessError: + failed_builds += 1 + sys.stderr.write("error: failed to generate %s" % + relpath) + # postprocess generated HTML file + utils.postprocess_html_file(dstpath) + + if anything_modified: + generate_index_and_feed() + sys.stderr.write("done\n") + + if report_total_errors: + sys.stderr.write("build finished with %d errors\n" % failed_builds) + return failed_builds |