squeeze

A static site generator that can put the toothpaste back in the tube.
git clone https://git.stjo.hn/squeeze
Log | Files | Refs | README | LICENSE

commit ac94e0010ade402002aeda5eccdb90690a537ae8
parent eed5cbb2d819ddab54df63fd8a1ef17a6331ae08
Author: St John Karp <contact@stjo.hn>
Date:   Sun, 29 Aug 2021 12:20:09 -0400

Remove non-ISO Prolog predicates

Removed the dialect-specific non-ISO Prolog predicates. I'm using
the shell to generate the build date for the RSS feed, but there
is no provision in the POSIX `date` spec for formatting dates other
than now, so I've had to write some custom Prolog predicates to
take the dates of the articles and format them as RFC 822 dates,
which is what's required by the RSS spec.

Both the shell script and the Prolog predicates are expecting articles
to have a date in the format YYYY-MM-DD. I may extend this in the future
to include a time and timezone, but I'm not anticipating having to
support any crazy date format.

Diffstat:
Ddialects/gnu-prolog.pl | 29-----------------------------
Ddialects/swi-prolog.pl | 21---------------------
Mgenerate_rss.pl | 15+++------------
Mhelpers.pl | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mparse_entry.pl | 6------
Msqueeze.sh | 2+-
6 files changed, 72 insertions(+), 69 deletions(-)

diff --git a/dialects/gnu-prolog.pl b/dialects/gnu-prolog.pl @@ -1,29 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Predicate implementations for GNU-Prolog dialects. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% Detect GNU-Prolog -gnu_prolog:- - catch(current_prolog_flag(dialect, gprolog), _, fail). - -gnu_prolog:- - catch(current_prolog_flag(prolog_name, 'GNU Prolog'), _, fail). - - -% GNU-Prolog-specific handling of dates. -today(FormattedDateCodes):- - gnu_prolog, - date_time(dt(Year, Month, Day, Hour, Minute, Second)), - join([Year, '-', Month, '-', Day, ' ', Hour, ':', Minute, ':', Second], '', DateAtom), - atom_codes(DateAtom, DateCodes), - format_date(FormattedDateCodes, DateCodes). - -% Format a date as RFC 822 (with a four-digit year). -format_date(FormattedDateCodes, DateCodes):- - gnu_prolog, - atom_codes(DateAtom, DateCodes), - join(['--date="', DateAtom, '"'], '', Arg), - join(['date', Arg, '--rfc-email'], ' ', Command), - exec(Command, _, StreamOut, _), - read_file(StreamOut, FormattedDateCodes), - close(StreamOut). diff --git a/dialects/swi-prolog.pl b/dialects/swi-prolog.pl @@ -1,21 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Predicate implementations for SWI-Prolog dialects. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% Detect SWI-Prolog -swi_prolog:- - catch(current_prolog_flag(dialect, swi), _, fail). - - -% SWI-Prolog-specific predicates for date handling. -today(FormattedDateCodes):- - swi_prolog, - get_time(DateStamp), - format_time(codes(FormattedDateCodes), '%a, %d %b %Y %T %z', DateStamp). - -% Format a date as RFC 822 (with a four-digit year). -format_date(FormattedDateCodes, DateCodes):- - swi_prolog, - atom_codes(DateAtom, DateCodes), - parse_time(DateAtom, DateStamp), - format_time(codes(FormattedDateCodes), '%a, %d %b %Y %T %z', DateStamp). diff --git a/generate_rss.pl b/generate_rss.pl @@ -6,22 +6,13 @@ :- include('helpers.pl'). :- include('rss.pl'). -% Include files for dialect-dependent predicates. -:- discontiguous(markdown_to_html/2). -:- discontiguous(format_date/2). -:- discontiguous(today/1). -:- include('dialects/gnu-prolog.pl'). -:- include('dialects/swi-prolog.pl'). - % generate_rss(+Filenames). % Filenames is a list of atoms containing paths to all Markdown files with a date. % These files will be read and used to generate an RSS of the most % recent posts. -generate_rss(Filenames):- +generate_rss(Filenames, BuildDate):- % Read in all the files so we have their dates and contents. files_to_articles(Filenames, Articles), - % Get the build date. - today(BuildDate), % Convert to RSS and write to stdout. rss(BuildDate, Articles, RSSCodes, []), write_codes(user_output, RSSCodes), @@ -31,10 +22,10 @@ generate_rss(Filenames):- % Alternative interface to generate_rss(+Filenames) that reads % the list of files from stdin. This allows the filenames to be piped % from the output of another command like grep. -generate_rss:- +generate_rss(BuildDate):- read_file(user_input, FileListCodes), file_list(FileList, FileListCodes, []), - generate_rss(FileList). + generate_rss(FileList, BuildDate). file_list([]) --> []. diff --git a/helpers.pl b/helpers.pl @@ -56,6 +56,74 @@ join([First|Rest], Separator, Result):- atom_concat(FirstPlusSeparator, End, Result). +% format_date(-RFCDate, +Date). +% Parse and format a date according to RFC 822. +format_date(RFCDate, Date):- + date_stamp(YearCodes, MonthCodes, DayCodes, Date, []), + number_codes(Year, YearCodes), + number_codes(Month, MonthCodes), + number_codes(Day, DayCodes), + day_of_week(date(Year, Month, Day), DayOfWeek), + day(DayOfWeek, DayOfWeekNameCodes), + month(Month, MonthNameCodes, _), + rfc_822(YearCodes, MonthNameCodes, DayCodes, DayOfWeekNameCodes, RFCDate, []). + +% TODO: Implement support for other date formats. +% Currently we support YYYY-MM-DD. +date_stamp(YearCodes, MonthCodes, DayCodes) --> + anything(YearCodes), + "-", + anything(MonthCodes), + "-", + anything(DayCodes). + +rfc_822(YearCodes, MonthNameCodes, DayCodes, DayOfWeekNameCodes) --> + anything(DayOfWeekNameCodes), + ", ", + anything(DayCodes), + " ", + anything(MonthNameCodes), + " ", + anything(YearCodes), + " 00:00:00 GMT". + +day_of_week(date(Year, Month, Day), DayOfWeek):- + magic_year(Year, Month, MagicYear), + month(Month, _, MagicMonth), + DayOfWeek is (MagicYear + MagicYear // 4 - MagicYear // 100 + MagicYear // 400 + MagicMonth + Day) mod 7. + +magic_year(Year, Month, MagicYear):- + Month < 3, + MagicYear is Year - 1. + +magic_year(Year, _, Year). + +% month(?MonthNumber, ?ShortName, -MagicNumber). +% Magic numbers, used for calculating the day of the week, +% are as defined in Sakamoto's methods: +% https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week#Sakamoto's_methods +month(1, "Jan", 0). +month(2, "Feb", 3). +month(3, "Mar", 2). +month(4, "Apr", 5). +month(5, "May", 0). +month(6, "Jun", 3). +month(7, "Jul", 5). +month(8, "Aug", 1). +month(9, "Sep", 4). +month(10, "Oct", 6). +month(11, "Nov", 2). +month(12, "Dec", 4). + +day(0, "Sun"). +day(1, "Mon"). +day(2, "Tue"). +day(3, "Wed"). +day(4, "Thu"). +day(5, "Fri"). +day(6, "Sat"). + + anything([]) --> []. anything([X|Rest]) --> [X], anything(Rest). diff --git a/parse_entry.pl b/parse_entry.pl @@ -6,12 +6,6 @@ :- include('helpers.pl'). :- include('markdown.pl'). -% Include files for dialect-dependent predicates. -:- discontiguous(format_date/2). -:- discontiguous(today/1). -:- include('dialects/gnu-prolog.pl'). -:- include('dialects/swi-prolog.pl'). - % parse_entry. % Read in an HTML file from stdin. parse_entry:- diff --git a/squeeze.sh b/squeeze.sh @@ -62,5 +62,5 @@ find "$OUTPUT_PATH" -type f -name "*.html" \ # Reformat to just the file names. cut -f 1 -d : | # Parse the articles and generate the RSS. - swipl --traditional --quiet -l generate_rss.pl -g "consult('$SITE_PATH/site.pl'), generate_rss." \ + swipl --traditional --quiet -l generate_rss.pl -g "consult('$SITE_PATH/site.pl'), generate_rss(\"$(date '+%a, %d %b %Y %T %Z')\")." \ > "$OUTPUT_PATH/feeds/rss.xml"