+
+|}]
+
+let format_feed ~title ~subtitle ~author ~feed_url ~site_url ~last_updated ~(entries: Post.t list) =
+ let opener =
+ String.concat "" [
+{|
+
+ |}; title; {|
+ |}; feed_url; {|
+ |}; subtitle; {|
+ |}; ISO8601.Permissive.string_of_datetime last_updated; {|
+
+
+|}] in
+ opener ^
+ (String.concat "\n" @@ List.map
+ (fun (md,contents) ->
+ format_entry
+ ~title:md.title
+ ~date:md.date
+ ~url:(site_url ^ md.filename)
+ ~author
+ ~contents)
+ entries) ^
+ ""
diff --git a/src/dune b/src/dune
index 7183ddf..48df5e0 100644
--- a/src/dune
+++ b/src/dune
@@ -1,3 +1,4 @@
(executable
(name webcc)
- (libraries omd ISO8601 str))
+ (libraries omd ISO8601 str)
+ (modules_without_implementation post))
diff --git a/src/post.mli b/src/post.mli
new file mode 100644
index 0000000..6417dd3
--- /dev/null
+++ b/src/post.mli
@@ -0,0 +1,5 @@
+type date = float (* repr for the ISO8601 library *)
+type metadata = { title : string ; date : date ; tags : string list ;
+ filename : string ;
+ other : (string * string) list }
+type t = metadata * string
diff --git a/src/webcc.ml b/src/webcc.ml
index f148575..8156847 100644
--- a/src/webcc.ml
+++ b/src/webcc.ml
@@ -1,21 +1,27 @@
+open Post
+
+let author = "Daniel"
+let site_url = "https://groupoid.moe"
+let feed_url = "https://groupoid.moe/feed.xml"
+let site_title = "groupoid.moe"
+let feed_title = "Recent posts"
let input = ref []
let output = ref ""
let gen_index = ref false
+let gen_atom = ref false
let spec =
[
("-o", Arg.Set_string output,
" file.html Specify the output file (default is stdout).");
("-i", Arg.Set gen_index,
- " generate a post index instead of compiling individual posts.");
+ " generate the post index instead of compiling individual posts.");
+ ("-a", Arg.Set gen_atom,
+ " generate the atom feed.");
("--", Rest(fun s -> input := s :: !input),
" Consider all remaining arguments as input file names.")
]
-type post_metadata = { title : string ; date : float ; tags : string list ;
- filename : string ;
- other : (string * string) list }
-
(** Utitilies *)
let with_open_in fn f =
let ic = open_in fn in
@@ -29,7 +35,7 @@ let with_open_out fn f =
| r -> close_out oc; r
| exception e -> close_out_noerr oc; raise e
-let read_metadata filename ic : post_metadata =
+let read_metadata filename ic : Post.metadata =
let rec go lst =
let line =
try input_line ic
@@ -46,12 +52,23 @@ let read_metadata filename ic : post_metadata =
| None -> "-"
in
let date = ISO8601.Permissive.date (lookup "date") in
+ (* TODO! Fix the paths here!!!!!! *)
+ let target_fname =
+ let open Str in
+ if string_match (regexp {|content/\(.*\)\.md|}) filename 0
+ then "/posts/" ^ matched_group 1 filename ^ ".html"
+ else filename
+ in
{ title = lookup "title";
date = date;
tags = String.split_on_char ',' (lookup "tags");
- filename = filename;
+ filename = target_fname;
other = md }
-
+
+let read_post filename ic : Post.t =
+ let metadata = read_metadata filename ic in
+ let md = Omd.of_channel ic in
+ (metadata, Omd.to_html md)
(** Functions for processing an individual post *)
@@ -77,7 +94,7 @@ let format_page ~title ~contents =
atom feed
-
|}; title; {|
|};
+
|}; title; {|
|};
contents;
{|
@@ -97,41 +114,32 @@ let format_post ~title ~tags ~date ~contents =
(* convert contents from [ic] to a post webpage, output to [oc] *)
let process filename ic oc =
- let metadata = read_metadata filename ic in
- let md = Omd.of_channel ic in
+ let (metadata, contents) = read_post filename ic in
let html = format_post
~title:(metadata.title)
~tags:(String.concat ", " metadata.tags)
~date:(ISO8601.Permissive.string_of_date metadata.date)
- ~contents:(Omd.to_html md)
+ ~contents
in
output_string oc html
+(** Compile the posts to HTML *)
let compile_posts oc =
if !input = [] then process "" stdin oc
else begin
let f filename = with_open_in filename @@ fun ic -> process filename ic oc in
List.iter f !input
end
-
-(** Generating index of posts *)
+
+(** Generate the index of posts *)
let generate_index oc =
let f filename = with_open_in filename (read_metadata filename) in
let mds = List.map f !input in
let mds = List.sort (fun md1 md2 -> compare md2.date md1.date) mds in
- (* TODO! Fix the paths here!!!!!! *)
let format_item md =
- (* path to the html file *)
- let fname = md.filename in
- let target_fname =
- let open Str in
- if string_match (regexp {|content/\(.*\)\.md|}) fname 0
- then matched_group 1 fname ^ ".html"
- else fname
- in
String.concat "" [
- {|
|}]
in
@@ -139,6 +147,28 @@ let generate_index oc =
let html = format_page ~title:"Recent posts" ~contents in
output_string oc html
+(** Generate the atom feed *)
+let generate_atom oc =
+ let f filename = with_open_in filename (read_post filename) in
+ let posts = List.map f !input in
+ let posts = List.sort (fun (md1,_) (md2,_) -> compare md2.date md1.date) posts in
+ let last_updated =
+ match posts with
+ | [] -> 0.
+ | (md,_)::_ -> md.date
+ in
+ let xml = Atom.format_feed
+ ~title:site_title
+ ~subtitle:feed_title
+ ~author
+ ~feed_url
+ ~site_url
+ ~last_updated
+ ~entries:posts
+ in
+ output_string oc xml
+
+
(** main *)
let main () =
Arg.parse (Arg.align spec)
@@ -150,10 +180,14 @@ let main () =
else
with_open_out !output f
in
- with_output @@
+ begin
+ with_output @@
if !gen_index
then generate_index
else compile_posts
+ end;
+ if !gen_atom then with_output generate_atom
+
let () =
try