#!/usr/bin/env raku use v6.e.PREVIEW; use DB; use DB::BlogMeta; use DB::Series; use DB::MarkdownPost; use DB::IdrisPost; use Pretty::Table; my %*SUB-MAIN-OPTS = :named-anywhere, :bundling, ; #| The directory this script is located in my IO::Path:D $default-blog-dir = $*PROGRAM.parent; #| Default database directory my IO::Path:D $default-db-dir = do if %*ENV { $default-blog-dir.add('test-db/') } else { $default-blog-dir.add('db/') }; #| The default output directory my IO::Path:D $default-site-dir = $default-blog-dir.add('site/'); #| The default idris ipkg my IO::Path:D $default-ipkg = $default-blog-dir.add('projects/Idris/Idris.ipkg'); #| Initalize the database multi MAIN( "db", "init", #| The path of the database file IO::Path(Str) :$db-dir = $default-db-dir, #| Overwrite an already existing database file Bool :$force ) { die "Database folder already exists, use --force to overwrite: {$db-dir.Str}" if $db-dir.e && !$force; print "Blog Title: "; my $title = get; print "Tagline: "; my $tagline = get; print "Base URL: "; my $base-url = get; my $meta = BlogMeta.new: title => $title, tagline => $tagline, base-url => $base-url; my $db = DB::PostDB.init: $meta; $db.write: $db-dir; } #| Ensure that the database loads, erroring otherwise multi MAIN( "db", "verify", #| The path of the database file IO::Path(Str) :$db-dir = $default-db-dir, ) { my $db = read-db $db-dir; $db.write: $db-dir; say "Database OK"; } #| Create a new markdown post multi MAIN( "post", "new", "markdown", #| The path to the markdown file IO::Path(Str) $source, #| The path of the database file IO::Path(Str) :$db-dir = $default-db-dir, #| The date/time the post should be recorded as posted at DateTime(Str) :$posted-at = DateTime.now, #| Should the post be hidden from the archive? Bool :$hidden = False, ) { my $db = read-db $db-dir; my $id = $db.insert-post: MarkdownPost.new( source => $source.absolute.IO, posted-at => $posted-at, hidden => $hidden, ); $db.write: $db-dir; say 'Post inserted with id ', $id; say 'Post has slugs: ', $db.posts{$id}.all-slugs; } #| Create a new idris post multi MAIN( "post", "new", "idris", #| The path to the idris file IO::Path(Str) $source, #| The path to the ipkg file IO::Path(Str) :$ipkg = $default-ipkg, #| The path of the database file IO::Path(Str) :$db-dir = $default-db-dir, #| The date/time the post should be recorded as posted at DateTime(Str) :$posted-at = DateTime.now, #| Should the post be hidden from the archive? Bool :$hidden = False, ) { my $db = read-db $db-dir; my $id = $db.insert-post: IdrisPost.new( source => $source.absolute.IO, posted-at => $posted-at, hidden => $hidden, ipkg => $ipkg.absolute.IO, ); $db.write: $db-dir; say 'Post inserted with id ', $id; say 'Post has slugs: ', $db.posts{$id}.all-slugs; } #| Update the last editied time on a post multi MAIN( "post", "edit", #| The post id to touch Int:D $id, #| The path of the database file IO::Path(Str) :$db-dir = $default-db-dir, #| The date/time the post should be recorded as laste edited at DateTime(Str) :$edited-at = DateTime.now, ) { my $db = read-db $db-dir; my $post = $db.posts{$id.Int}; $post.edited-at.push: $edited-at; $db.write: $db-dir; } #| Render the blog to html multi MAIN( "render", #| The path of the database directory IO::Path(Str) :$db-dir = $default-db-dir, #| The path of the output directory IO::Path(Str) :$site-dir = $default-site-dir, ) { my $db = read-db $db-dir; $db.render: $site-dir; } #| Provide a table of posts, in newest to oldest order multi MAIN( "post", "list", #| The path of the database directory IO::Path(Str) :$db-dir = $default-db-dir, #| The number of posts to show on a single page Int :$per-page = 10; #| The page number to show Int :$page = 1; ) { my $db = read-db $db-dir; my @pages = $db.sorted-posts.rotor($per-page, :partial); my @page = @pages[$page - 1].flat; my $table = Pretty::Table.new: title => "Posts (page $page/{@pages.elems})", field-names => ["ID", "Title", "Type"]; for @page -> $pair { my $id = $pair.key; my $post = $pair.value; # TODO: Terminal aware truncation my $title = do if $post.title.chars > 50 { "{$post.title.substr(0, 50)}..." } else { $post.title }; my $type = do given $post { when MarkdownPost { "md" } when IdrisPost { "idr" } default { "" } } $table.add-row: [$id, $title, $type]; } say $table; } #| Display information about a post multi MAIN( "post", "info", #| The id of the post to display information for Int $id, #| The path of the database directory IO::Path(Str) :$db-dir = $default-db-dir, #| Display all of the information and not just the primaries Bool :$full, ) { my $db = read-db $db-dir; my $post = $db.posts{$id.Int}; given $post { say 'Title: ', .title; say 'Type: ', .WHAT.^name; say 'Source: ', .source.relative; if .hidden { say "Hidden"; } if .all-slugs { if $full { say 'Slugs: '; for .all-slugs -> $slug { say ' * ', $slug; } } else { say 'Primary Slug: ', .all-slugs[*-1]; } } else { say 'Slugs: []'; } if .tags { say 'Tags:'; for .tags -> $tag { say ' * ', $tag; } } given .posted-at { say 'Posted At: ', .Date.Str, ' ', .hh-mm-ss; } if .edited-at { if $full { say 'Edits: '; for .edited-at.sort.reverse { say ' * ', .Date.Str, ' ', .hh-mm-ss; } } else { given .edited-at.sort[*-1] { say 'Last Edited At: ', .Date.Str, ' ', .hh-mm-ss; } } } } } #| Add or remove a tag to a post multi MAIN( "post", "tag", #| The id of the post to display information for Int $id, #| The tag to add/remove Str $tag, #| remove the tag instead of adding it Bool :$remove, #| The path of the database directory IO::Path(Str) :$db-dir = $default-db-dir, ) { my $db = read-db $db-dir; my $post = $db.posts{$id.Int}; if $remove { die "Post did not have requested tag" unless $tag ~~ any($post.tags); my $index = $post.tags.first: $tag; $post.tags.=grep(* ne $tag); } else { die "Post already had requested tag" if $tag ~~ any($post.tags); $post.tags.push: $tag; } $db.write: $db-dir; } #| Update the posted-at time on a post to the current time multi MAIN( "post", "now", #| The id of the post to update the posted-at time Int $id, #| The path of the database directory IO::Path(Str) :$db-dir = $default-db-dir, ){ my $db = read-db $db-dir; my $post = $db.posts{$id.Int}; $post.posted-at = DateTime.now; $db.write: $db-dir; } #| Create a new series multi MAIN( "series", "new", #| The path of the database file IO::Path(Str) :$db-dir = $default-db-dir, ) { my $db = read-db $db-dir; say 'Series Title: '; my $title = get; say 'Series Description: '; my $desc = get; my $series = Series.new: title => $title, desc => $desc; my $id = $db.insert-series: $series; say 'Series inserted with id ', $id; $db.write: $db-dir; } #| Provide a table of series multi MAIN( "series", "list", #| The path of the database directory IO::Path(Str) :$db-dir = $default-db-dir, #| The number of items to show on a single page Int :$per-page = 10; #| The page number to show Int :$page = 1; ) { my $db = read-db $db-dir; my @pages = $db.series.sort(*.key).rotor($per-page, :partial); my @page = @pages[$page - 1].flat; my $table = Pretty::Table.new: title => "Series (page $page/{@pages.elems})", field-names => ["ID", "Title", "Desc"]; for @page -> $pair { my $id = $pair.key; my $series = $pair.value; # TODO: Terminal aware truncation my $title = do if $series.title.chars > 40 { "{$series.title.substr(0, 50)}..." } else { $series.title }; my $desc = do if $series.desc.chars > 40 { "{$series.desc.substr(0, 50)}..." } else { $series.desc }; $table.add-row: [$id, $title, $desc]; } say $table; } #| Display the contents of a series multi MAIN( "series", "info", #| The id of the series to display Int $id, #| The path of the database directory IO::Path(Str) :$db-dir = $default-db-dir, ) { my $db = read-db $db-dir; my $series = $db.series{$id.Int}; say 'Title: ', $series.title; say 'Description:'; for $series.desc.lines -> $line { say ' ', $line; } say 'Posts:'; for $series.post-ids -> $post-id { my $post = $db.posts{$post-id}; say ' * ', $post-id, ': ', $post.title; } } #| Add a post to a series multi MAIN( "series", "add", #| The id of the series to add to Int $series-id, #| The id of the post to add Int $post-id, #| The path of the database directory IO::Path(Str) :$db-dir = $default-db-dir, ) { my $db = read-db $db-dir; my $series = $db.series{$series-id.Int}; $series.post-ids.push: $post-id.Int; $db.write: $db-dir; }