From 77787bd43b2b179cc119a6055e832d94a7ec6d60 Mon Sep 17 00:00:00 2001 From: Cody Scott Date: Mon, 15 Jan 2024 11:41:58 -0500 Subject: [PATCH] Add published if missing on build --- htmd/cli.py | 58 +++++++++++++++++++++++++++++++++++++++++--- htmd/site.py | 43 +++----------------------------- htmd/utils.py | 7 ------ tests/test_build.py | 42 +++++++++++++++++++------------- tests/test_verify.py | 23 +++++++----------- tests/utils.py | 13 ++++++++++ 6 files changed, 105 insertions(+), 81 deletions(-) create mode 100644 tests/utils.py diff --git a/htmd/cli.py b/htmd/cli.py index 59e04bc..c6870ec 100644 --- a/htmd/cli.py +++ b/htmd/cli.py @@ -1,4 +1,6 @@ +import datetime import importlib +import os import sys import click @@ -56,11 +58,12 @@ def verify(): importlib.reload(site) correct = True + required_fields = ('author', 'title') for post in site.posts: - for item in ['author', 'published', 'title']: - if item not in post.meta: + for field in required_fields: + if field not in post.meta: correct = False - msg = f'Post "{post.path}" does not have field {item}.' + msg = f'Post "{post.path}" does not have field {field}.' click.echo(click.style(msg, fg='red')) if 'published' in post.meta: try: @@ -89,6 +92,53 @@ def verify(): sys.exit(1) +def set_post_time(app, post, property, date_time): + file_path = os.path.join( + app.config['FLATPAGES_ROOT'], + post.path + app.config['FLATPAGES_EXTENSION'] + ) + with open(file_path, 'r') as file: + lines = file.readlines() + + found = False + with open(file_path, 'w') as file: + for line in lines: + if not found and property in line: + line = f'{property}: {date_time.isoformat()}\n' + found = True + elif not found and '...' in line: + file.write(f'{property}: {date_time.isoformat()}\n') + found = True + file.write(line) + + +def set_posts_datetime(app, posts): + # Ensure each post has a published date + # set time for correct date field + for post in posts: + if 'updated' not in post.meta: + published = post.meta.get('published') + if isinstance(published, datetime.datetime): + property = 'updated' + else: + property = 'published' + else: + property = 'updated' + + post_datetime = post.meta.get(property) + now = datetime.datetime.now() + current_time = now.time() + if isinstance(post_datetime, datetime.date): + post_datetime = datetime.datetime.combine( + post_datetime, current_time + ) + else: + post_datetime = now + post.meta[property] = post_datetime + set_post_time(app, post, property, post_datetime) + + + @cli.command('build', short_help='Create static version of the site.') @click.pass_context @click.option( @@ -119,6 +169,8 @@ def build(ctx, css_minify, js_minify): # setting them here doesn't work importlib.reload(site) + set_posts_datetime(site.app, site.posts) + freezer = site.freezer try: freezer.freeze() diff --git a/htmd/site.py b/htmd/site.py index d6392e5..1a9ac55 100644 --- a/htmd/site.py +++ b/htmd/site.py @@ -54,6 +54,7 @@ def get_project_dir(): # Flask configs are flat, config.toml is not # Define the configuration keys and their default values +# [section, key, default] config_keys = { 'SITE_NAME': ['site', 'name', ''], 'SITE_URL': ['site', 'url', ''], @@ -78,7 +79,6 @@ def get_project_dir(): # Update app.config using the configuration keys for flask_key, (table, key, default) in config_keys.items(): app.config[flask_key] = htmd_config.get(table, {}).get(key, default) - # To avoid full paths in config.toml @@ -174,26 +174,6 @@ def index(): return render_template('index.html', active='home', posts=latest[:4]) -def set_post_time(post, property, date_time): - file_path = os.path.join( - app.config['FLATPAGES_ROOT'], - post.path + app.config['FLATPAGES_EXTENSION'] - ) - with open(file_path, 'r') as file: - lines = file.readlines() - - found = False - with open(file_path, 'w') as file: - for line in lines: - if not found and property in line: - line = f'{property}: {date_time.isoformat()}\n' - found = True - elif not found and '...' in line: - file.write(f'{property}: {date_time.isoformat()}\n') - found = True - file.write(line) - - @app.route('/feed.atom') def feed(): name = app.config.get('SITE_NAME') @@ -205,7 +185,6 @@ def feed(): title=name, url=url ) - current_time = datetime.datetime.now().time() for post in posts: url = url_for( 'post', @@ -215,28 +194,12 @@ def feed(): path=post.path ) - if 'updated' not in post.meta: - published = post.meta.get('published') - if isinstance(published, datetime.datetime): - property = 'updated' - else: - property = 'published' - else: - property = 'updated' - - datetime_field = post.meta.get(property) - if isinstance(datetime_field, datetime.date): - datetime_field = datetime.datetime.combine( - datetime_field, current_time - ) - else: - datetime_field = datetime.datetime.now() - set_post_time(post, property, datetime_field) + post_datetime = post.meta.get('updated') or post.meta.get('published') atom.add( post.meta.get('title'), post.html, content_type='html', author=post.meta.get('author', app.config.get('DEFAULT_AUTHOR')), url=url, - updated=datetime_field, + updated=post_datetime, ) ret = atom.get_response() return ret diff --git a/htmd/utils.py b/htmd/utils.py index 3e37b7a..cf34ccb 100644 --- a/htmd/utils.py +++ b/htmd/utils.py @@ -79,13 +79,6 @@ def copy_file(source, destination): def copy_missing_templates(): template_dir = files('htmd.example_site') / 'templates' for template_file in sorted(template_dir.iterdir()): - skip_file = False - for skip_file_name in ('__pycache__',): - if skip_file_name in str(template_file): - skip_file = True - break - if skip_file: - continue file_name = os.path.basename(template_file) copy_file( template_file, diff --git a/tests/test_build.py b/tests/test_build.py index 552585c..772a32b 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -6,7 +6,7 @@ from click.testing import CliRunner from htmd.cli import build, start -from test_verify import remove_field_from_example_post +from utils import remove_fields_from_example_post SUCCESS_REGEX = ( @@ -31,7 +31,7 @@ def test_build_verify_fails(): runner = CliRunner() with runner.isolated_filesystem(): result = runner.invoke(start) - remove_field_from_example_post('title') + remove_fields_from_example_post(('title',)) result = runner.invoke(build) assert result.exit_code == 1 assert result.output == expected_output @@ -498,12 +498,9 @@ def test_build_published_time_is_added(): runner = CliRunner() with runner.isolated_filesystem(): runner.invoke(start) + remove_fields_from_example_post(('updated',)) with open(os.path.join('posts', 'example.md'), 'r') as post_file: b_lines = post_file.readlines() - with open(os.path.join('posts', 'example.md'), 'w') as post_file: - for line in b_lines: - if 'updated' not in line: - post_file.write(line) runner.invoke(build) with open(os.path.join('posts', 'example.md'), 'r') as post_file: a_lines = post_file.readlines() @@ -532,9 +529,7 @@ def test_build_published_time_is_added(): assert time_difference.total_seconds() < threshold_seconds # verify updated is not added - for a_line in a_lines: - if 'updated' in a_line: - assert False, 'updated found in example post' + assert 'updated' not in ''.join(a_lines) def test_build_updated_is_added(): @@ -545,15 +540,10 @@ def test_build_updated_is_added(): with runner.isolated_filesystem(): runner.invoke(start) # Remove updated from example post - with open(os.path.join('posts', 'example.md'), 'r') as post_file: - b_lines = post_file.readlines() - with open(os.path.join('posts', 'example.md'), 'w') as post_file: - for line in b_lines: - if 'updated' not in line: - post_file.write(line) - # First build adds published time + remove_fields_from_example_post(('updated',)) + # First build adds time to published runner.invoke(build) - # Second build adds updated + # Second build adds updated with time runner.invoke(build) with open(os.path.join('posts', 'example.md'), 'r') as post_file: a_lines = post_file.readlines() @@ -598,3 +588,21 @@ def test_build_updated_is_added_once(): count += 1 assert count == 1 + + +def test_build_without_published(): + runner = CliRunner() + with runner.isolated_filesystem(): + runner.invoke(start) + remove_fields_from_example_post(('published', 'updated',)) + + # First build adds published time + runner.invoke(build) + with open(os.path.join('posts', 'example.md'), 'r') as post_file: + a_lines = post_file.readlines() + count = 0 + for a_line in a_lines: + if 'published' in a_line: + count += 1 + + assert count == 1 diff --git a/tests/test_verify.py b/tests/test_verify.py index cdc4fa4..d4eb248 100644 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -3,6 +3,8 @@ from click.testing import CliRunner from htmd.cli import start, verify +from utils import remove_fields_from_example_post + def test_verify(): runner = CliRunner() @@ -14,22 +16,13 @@ def test_verify(): assert result.output == expected_output -def remove_field_from_example_post(field_name): - with open(os.path.join('posts', 'example.md'), 'r') as post: - lines = post.readlines() - with open(os.path.join('posts', 'example.md'), 'w') as post: - for line in lines: - if field_name not in line: - post.write(line) - - def test_verify_author_missing(): runner = CliRunner() with runner.isolated_filesystem(): runner.invoke(start) # Remove author from example post - remove_field_from_example_post('author') + remove_fields_from_example_post(('author',)) result = runner.invoke(verify) assert result.exit_code == 1 @@ -43,7 +36,7 @@ def test_verify_title_missing(): runner.invoke(start) # Remove title from example post - remove_field_from_example_post('title') + remove_fields_from_example_post(('title',)) result = runner.invoke(verify) assert result.exit_code == 1 @@ -57,12 +50,14 @@ def test_verify_published_missing(): runner.invoke(start) # Remove published from example post - remove_field_from_example_post('published') + remove_fields_from_example_post(('published',)) result = runner.invoke(verify) - assert result.exit_code == 1 - expected_output = 'Post "example" does not have field published.\n' + # verify doesn't check for published + # since it will be added on build. + expected_output = 'All posts are correctly formatted.\n' assert result.output == expected_output + assert result.exit_code == 0 def test_verify_published_invalid_year(): diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 0000000..2ea1cef --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,13 @@ +import os + + +def remove_fields_from_example_post(field_names): + with open(os.path.join('posts', 'example.md'), 'r') as post: + lines = post.readlines() + with open(os.path.join('posts', 'example.md'), 'w') as post: + for line in lines: + for field_name in field_names: + if field_name in line: + break + else: + post.write(line)