Skip to content
This repository was archived by the owner on Mar 20, 2021. It is now read-only.
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 112 additions & 44 deletions ginger/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,8 @@
env = Environment(loader=loader)


def make_path(parts):
"""
If parts is an array join them with os.path.sep
else return untouched
"""

file_name = parts
if isinstance(parts, list):
file_name = os.path.sep.join(parts)

return file_name


def save_to_output(content, file_name):
"""
Save content to the given file.
If file_name is an array, join it with os.path.sep
"""

file_name = make_path(file_name)
"""Save content to a file called file_name in output_dir"""

os.makedirs(
os.path.dirname(
Expand All @@ -57,13 +39,24 @@ def save_to_output(content, file_name):


def save_compiled_css():
"""Compile and optionally minify source sass files

Compile the file found at settings.css_input_file

If we are not in dev mode also minify the file prior to saving.

The output of the compilation is hashed prior to the file
being saved with a name based on settings.css_output_file_mask

Return the path of the saved file
"""

# Compile our SASS
css_in_fn = make_path([settings.input_dir,
settings.templates_dir,
settings.css_dir,
settings.css_input_file
])
css_in_fn = os.path.join(settings.input_dir,
settings.templates_dir,
settings.css_dir,
settings.css_input_file
)
sass_output = sass.compile(filename=css_in_fn)

if not args.dev:
Expand All @@ -75,19 +68,53 @@ def save_compiled_css():
# save the css file
css_out_name = settings.css_output_file_mask.format(
hash=css_hash[:settings.filename_hash_length])
css_file_name = save_to_output(sass_output, [settings.css_dir, css_out_name])
css_file_name = save_to_output(sass_output, os.path.join(settings.css_dir,
css_out_name))

return '/' + css_file_name


def save_merged_js():
"""Concatenate and optionally minify source javascript files

# we'll maintain the original folder name as well as the file name
js_files = {}
For each directory in the settings.js_dir create a file
named after the directory containing all js files
concatenated together.

If we are not in dev mode also minify the files.

Each file is hashed, before saving and the hash can
form part of the filename based on the settings.

Each files is then saved to the output directory.

js_dir = make_path([settings.input_dir,
settings.templates_dir,
settings.js_dir])
return a dictionary keyed by the folder name holding the
path to the js file.js_output_file_mask format mask

Example:
Given the following directory structure:
- input/templates/js_dir/vendor/a.js
- input/templates/js_dir/vendor/b.js
- input/templates/js_dir/vendor/c.js
- input/templates/js_dir/main/d.js

(with js_output_file_mask={name}.{hash}.js)

This will create:
- output/js_dir/vendor.filehash.js (containing a.js, b.js and c.js)
- output/js_dir/main.filehash.js (containing d.js)

Returning:
{
'vendor': '/js_dir/vendor.filehash.js',
'main': '/js_dir/main.filehash.js'
}
"""

js_files = {}
js_dir = os.path.join(settings.input_dir,
settings.templates_dir,
settings.js_dir)

for folder, sub_dirs, files in os.walk(js_dir):
if files:
Expand All @@ -106,16 +133,22 @@ def save_merged_js():
# generate name and save the file
js_file_name = settings.js_output_file_mask.format(
name=js_folder_name, hash=js_hash[:settings.filename_hash_length])
js_files[js_folder_name] = save_to_output(js, [settings.js_dir, js_file_name])
js_files[js_folder_name] = '/' + save_to_output(
js, os.path.join(settings.js_dir, js_file_name))

return js_files


def get_input_pages():
"""Get a list of input pages defined by yml files

Gather pages from settings.input_dir/settings.content_dir
return the page variables defined in the source yml
"""

pages = []

content_dir = make_path([settings.input_dir, settings.content_dir])
content_dir = os.path.join(settings.input_dir, settings.content_dir)
for folder, sub_dirs, files in os.walk(content_dir):
for yaml_file in files:
if os.path.isfile(folder + os.path.sep + yaml_file):
Expand All @@ -127,6 +160,7 @@ def get_input_pages():


def delete_output_contents():
"""Delete all files and directories in settings.output_dir"""
for root, dirs, files in os.walk(settings.output_dir):
for f in files:
os.unlink(os.path.join(root, f))
Expand All @@ -135,8 +169,14 @@ def delete_output_contents():


def copy_files():
"""Copy files from input to output.

Copy any files that match settings.copy_unmodified
Copy from settings.input_dir/settings.template_dir
to settings.output_dir retaining the reletive path
"""

template_dir = make_path([settings.input_dir, settings.templates_dir])
template_dir = os.path.join(settings.input_dir, settings.templates_dir)
for root, dirs, files in os.walk(template_dir):
for file in files:
for copy_re in settings.copy_unmodified:
Expand All @@ -151,18 +191,18 @@ def copy_files():
shutil.copy(input_filename, output_filename)


def build():

start_time = time.time()
print("Rebuilding... ", end="")
sys.stdout.flush()

if not settings.preserve_output_on_rebuild:
delete_output_contents()
def generate_html(css_file_name, js_file_names):
"""Generate html files from the input yml

css_file_name = save_compiled_css()

js_file_names = save_merged_js()
Save a html file in the output folder for every input page.
Each template is given:
any variable defined in context from its source yml
`css_file_name` - the path to the generated css
`js_file_names` - a dictory holding
source_folder_name: path to generated js
`pages` - a list holding the meta info of all pages
`meta` - the meta information of the current page
"""

pages = get_input_pages()
pages_meta = [p.get('meta', {}) for p in pages]
Expand All @@ -185,6 +225,34 @@ def build():
filename = meta.get('save_as', 'missing_save_as.html')
save_to_output(output, filename)


def build():
"""Rebuild all html.

build is called every time `ginger` is called from the command line.
build is called when `ginger` is watch the input directory and
sees a modification.

build will:
Optionally delete the output folder
Compile and optionally minify the css file
Concatenate and optionally minify any js files
Rebuild all html from the templates / yml input
"""

start_time = time.time()
print("Rebuilding... ", end="")
sys.stdout.flush()

if not settings.preserve_output_on_rebuild:
delete_output_contents()

css_file_name = save_compiled_css()

js_file_names = save_merged_js()

generate_html(css_file_name, js_file_names)

copy_files()

time_taken = (time.time() - start_time) * 1000
Expand Down