diff --git a/ginger/build.py b/ginger/build.py index b98d0c3..fdc03ac 100644 --- a/ginger/build.py +++ b/ginger/build.py @@ -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( @@ -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: @@ -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: @@ -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): @@ -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)) @@ -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: @@ -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] @@ -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