mirror of
https://github.com/s00500/ESPUI.git
synced 2024-11-21 17:40:54 +00:00
Add code comments in prepare_static_ui_sources.py
This commit is contained in:
parent
bec4eb1c0f
commit
b7b6b8a3cd
@ -1,11 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
### import always available modules
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
import argparse
|
import argparse
|
||||||
import re
|
import re
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
|
||||||
|
### import not always installed modules
|
||||||
missing = []
|
missing = []
|
||||||
try:
|
try:
|
||||||
from jsmin import jsmin as jsminify
|
from jsmin import jsmin as jsminify
|
||||||
@ -24,6 +26,7 @@ try:
|
|||||||
except ModuleNotFoundError as e:
|
except ModuleNotFoundError as e:
|
||||||
missing.append(e)
|
missing.append(e)
|
||||||
if len(missing) > 0:
|
if len(missing) > 0:
|
||||||
|
# ERROR: at least one module is missing
|
||||||
for m in missing:
|
for m in missing:
|
||||||
print("Cannot find module '%s'." % m.name)
|
print("Cannot find module '%s'." % m.name)
|
||||||
print("Can't find %s required python module%s. Please install %s. If you're not sure how, a web search" % (len(missing), "s" if len(missing) > 1 else "", "them" if len(missing) > 1 else "it"))
|
print("Can't find %s required python module%s. Please install %s. If you're not sure how, a web search" % (len(missing), "s" if len(missing) > 1 else "", "them" if len(missing) > 1 else "it"))
|
||||||
@ -32,6 +35,8 @@ if len(missing) > 0:
|
|||||||
print("Here's the long documentation: https://packaging.python.org/tutorials/installing-packages/")
|
print("Here's the long documentation: https://packaging.python.org/tutorials/installing-packages/")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
### String template for C header files
|
||||||
TARGET_TEMPLATE = '''const char {constant}[] PROGMEM = R"=====(
|
TARGET_TEMPLATE = '''const char {constant}[] PROGMEM = R"=====(
|
||||||
{minidata}
|
{minidata}
|
||||||
)=====";
|
)=====";
|
||||||
@ -39,7 +44,9 @@ TARGET_TEMPLATE = '''const char {constant}[] PROGMEM = R"=====(
|
|||||||
const uint8_t {constant}_GZIP[{gziplen}] PROGMEM = {{ {gzipdata} }};
|
const uint8_t {constant}_GZIP[{gziplen}] PROGMEM = {{ {gzipdata} }};
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments(args=None):
|
def parse_arguments(args=None):
|
||||||
|
""" Command line argument parser definitions """
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Prepares ESPUI header files by minifying and gzipping HTML, JS and CSS source files.")
|
description="Prepares ESPUI header files by minifying and gzipping HTML, JS and CSS source files.")
|
||||||
parser.add_argument("--auto", "--all", "-a", dest="auto", action="store_true",
|
parser.add_argument("--auto", "--all", "-a", dest="auto", action="store_true",
|
||||||
@ -58,6 +65,20 @@ def parse_arguments(args=None):
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
def get_context(infile, outfile):
|
def get_context(infile, outfile):
|
||||||
|
""" This function creates a 'context object': a dictionary containing all the data needed.
|
||||||
|
Dictionary members:
|
||||||
|
infile: Full path to the input file or directory as given or autodetected
|
||||||
|
indir: Full path to the infile parent.
|
||||||
|
dir: Full path to the input directory tree (indir or parent of indir).
|
||||||
|
name: Filename of infile excluding extension (i.e. filename up until the first dot)
|
||||||
|
type: Lowercase extension of infile; one of: html, js, css.
|
||||||
|
outfile: Full path to the output file or directory as given or autodetected.
|
||||||
|
outdir: Full path to output directory.
|
||||||
|
outfilename: Filename of outfile.
|
||||||
|
minifile: Full path and filename of the intermediary minified file.
|
||||||
|
constant: C header file constant name derived from infile.
|
||||||
|
If infile == minifile, the input file already is minified (contains ".min.")
|
||||||
|
"""
|
||||||
infile = os.path.realpath(infile)
|
infile = os.path.realpath(infile)
|
||||||
dir, name, type = (os.path.basename(os.path.dirname(infile)), os.path.basename(infile).split(os.path.extsep)[0], os.path.basename(infile).split(os.path.extsep)[-1] )
|
dir, name, type = (os.path.basename(os.path.dirname(infile)), os.path.basename(infile).split(os.path.extsep)[0], os.path.basename(infile).split(os.path.extsep)[-1] )
|
||||||
type = type.strip(".").lower()
|
type = type.strip(".").lower()
|
||||||
@ -80,6 +101,11 @@ def get_context(infile, outfile):
|
|||||||
return locals()
|
return locals()
|
||||||
|
|
||||||
def perform_gzip(c):
|
def perform_gzip(c):
|
||||||
|
""" Performs GZIP on c['minidata'].
|
||||||
|
The returned context object will contain additional fields:
|
||||||
|
gzipdata: Comma-separated string of decimal byte values representing gzipped data.
|
||||||
|
gziplen: Count of decimal byte values in gzipdata.
|
||||||
|
"""
|
||||||
compressed = gzip.compress(bytes(c['minidata'], 'utf-8'))
|
compressed = gzip.compress(bytes(c['minidata'], 'utf-8'))
|
||||||
c['gzipdata'] = ','.join([ str(b) for b in compressed ])
|
c['gzipdata'] = ','.join([ str(b) for b in compressed ])
|
||||||
c['gziplen'] = len(compressed)
|
c['gziplen'] = len(compressed)
|
||||||
@ -87,6 +113,9 @@ def perform_gzip(c):
|
|||||||
return c
|
return c
|
||||||
|
|
||||||
def perform_minify(c):
|
def perform_minify(c):
|
||||||
|
""" Performs minification on c['infile'].
|
||||||
|
The returned context object contains the additional field minidata: A string of minified file contents.
|
||||||
|
"""
|
||||||
with open(c['infile']) as infile:
|
with open(c['infile']) as infile:
|
||||||
minifier = {
|
minifier = {
|
||||||
'css': cssminify,
|
'css': cssminify,
|
||||||
@ -95,19 +124,27 @@ def perform_minify(c):
|
|||||||
}.get(c['type']) or htmlminify
|
}.get(c['type']) or htmlminify
|
||||||
print(" Using %s minifier" % c['type'])
|
print(" Using %s minifier" % c['type'])
|
||||||
c['minidata'] = minifier(infile.read())
|
c['minidata'] = minifier(infile.read())
|
||||||
return perform_gzip(c)
|
return c
|
||||||
|
|
||||||
def process_file(infile, outdir, storemini=True):
|
def process_file(infile, outdir, storemini=True):
|
||||||
|
""" Processes one file """
|
||||||
print("Processing file %s" % infile)
|
print("Processing file %s" % infile)
|
||||||
|
# Evaluate file and target context
|
||||||
c = get_context(infile, outdir)
|
c = get_context(infile, outdir)
|
||||||
|
# Minify file data
|
||||||
c = perform_minify(c)
|
c = perform_minify(c)
|
||||||
|
# Gzip minified data
|
||||||
|
c = perform_gzip(c)
|
||||||
|
|
||||||
if storemini:
|
if storemini:
|
||||||
|
# Write intermediary minified file
|
||||||
if c['infile'] == c['minifile']:
|
if c['infile'] == c['minifile']:
|
||||||
print(" Original file is already minified, refusing to overwrite it")
|
print(" Original file is already minified, refusing to overwrite it")
|
||||||
else:
|
else:
|
||||||
print(" Writing minified file %s" % c['minifile'])
|
print(" Writing minified file %s" % c['minifile'])
|
||||||
with open(c['minifile'], 'w+') as minifile:
|
with open(c['minifile'], 'w+') as minifile:
|
||||||
minifile.write(c['minidata'])
|
minifile.write(c['minidata'])
|
||||||
|
# Write minified and gzipped data to C header file
|
||||||
with open(c['outfile'], 'w+') as outfile:
|
with open(c['outfile'], 'w+') as outfile:
|
||||||
print(" Using C constant names %s and %s_GZIP" % (c['constant'], c['constant']))
|
print(" Using C constant names %s and %s_GZIP" % (c['constant'], c['constant']))
|
||||||
print(" Writing C header file %s" % c['outfile'])
|
print(" Writing C header file %s" % c['outfile'])
|
||||||
@ -117,6 +154,10 @@ def filenamefilter(pattern, strings):
|
|||||||
return filter(re.compile(pattern).search, strings)
|
return filter(re.compile(pattern).search, strings)
|
||||||
|
|
||||||
def process_dir(sourcedir, outdir, recursive=True, storemini=True):
|
def process_dir(sourcedir, outdir, recursive=True, storemini=True):
|
||||||
|
""" Processes a directory tree, recursively. Calls process_file on each HTML/CSS/JS file found.
|
||||||
|
Skips intermediary minified files. Standalone minified files (i.e. files containing ".min." that
|
||||||
|
do not have a full version) are processed without minifying again.
|
||||||
|
"""
|
||||||
pattern = r'/*\.(css|js|htm|html)$'
|
pattern = r'/*\.(css|js|htm|html)$'
|
||||||
files = glob(sourcedir + "/**/*", recursive=True)+glob(sourcedir + "/*") if recursive else glob(sourcedir + "/*")
|
files = glob(sourcedir + "/**/*", recursive=True)+glob(sourcedir + "/*") if recursive else glob(sourcedir + "/*")
|
||||||
files = filenamefilter(pattern, files)
|
files = filenamefilter(pattern, files)
|
||||||
@ -127,6 +168,7 @@ def process_dir(sourcedir, outdir, recursive=True, storemini=True):
|
|||||||
process_file(f, outdir, storemini)
|
process_file(f, outdir, storemini)
|
||||||
|
|
||||||
def check_args(args):
|
def check_args(args):
|
||||||
|
""" Checks argumental sanity and exits if the arguments are insane. """
|
||||||
abort = 0
|
abort = 0
|
||||||
if not os.path.exists(args.sources):
|
if not os.path.exists(args.sources):
|
||||||
print("ERROR: Source %s does not exist" % args.sources)
|
print("ERROR: Source %s does not exist" % args.sources)
|
||||||
@ -142,8 +184,12 @@ def check_args(args):
|
|||||||
sys.exit(abort)
|
sys.exit(abort)
|
||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
|
""" main entry point. """
|
||||||
|
# default source if not given: realpath(../examples/gui/data)
|
||||||
args.sources = os.path.realpath(args.sources or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "examples", "gui", "data")))
|
args.sources = os.path.realpath(args.sources or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "examples", "gui", "data")))
|
||||||
|
# default target if not given: realpath(../src)
|
||||||
args.target = os.path.realpath(args.target or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "src")))
|
args.target = os.path.realpath(args.target or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "src")))
|
||||||
|
# check arguments
|
||||||
check_args(args)
|
check_args(args)
|
||||||
if os.path.isfile(args.sources):
|
if os.path.isfile(args.sources):
|
||||||
print("Source %s is a file, will process one file only." % args.sources)
|
print("Source %s is a file, will process one file only." % args.sources)
|
||||||
|
Loading…
Reference in New Issue
Block a user