From 5999701be1c75867c8af7851bb1dd2e27fdc92ab Mon Sep 17 00:00:00 2001 From: Manager Bot Date: Thu, 17 Nov 2022 18:49:15 +0000 Subject: [PATCH] Now with docs. --- .../lib/MJB/Backend/Jekyll.pm | 286 ++++++++++++------ 1 file changed, 189 insertions(+), 97 deletions(-) diff --git a/libs/MJB-Backend-Jekyll/lib/MJB/Backend/Jekyll.pm b/libs/MJB-Backend-Jekyll/lib/MJB/Backend/Jekyll.pm index 5c57493..bd7625b 100644 --- a/libs/MJB-Backend-Jekyll/lib/MJB/Backend/Jekyll.pm +++ b/libs/MJB-Backend-Jekyll/lib/MJB/Backend/Jekyll.pm @@ -9,7 +9,9 @@ use Mojo::File; use MJB::Backend::Jekyll::MarkdownFile; use MJB::Backend::Jekyll::ConfigFile; -# The root path for the repositories +#== +# The path to the directory that will be used to hold the git repositories for each blog blogs. +#== has root => ( is => 'ro', required => 1, @@ -19,30 +21,25 @@ has root => ( }, ); -# The domain name for this jekyll blog +#== +# The domain name for this specific blog. +#== has domain => ( is => 'ro', required => 1, ); -# The full path to the git repo this is backed by. +#== +# The full remote path ( i.e. git@foo.com:mjb/domain.com.git) to the git repository that we will push to. +#== has repo => ( is => 'ro', required => 1, ); -has config => ( - is => 'lazy', -); - -sub _build_config { - my ( $self ) = @_; - - return MJB::Backend::Jekyll::ConfigFile->new( - path => $self->repo_path . "/_config.yml", - )->read; -} - +#== +# The full local path (i.e. /var/repos/domain.com ) to the git repository that we will execute git commands in. +#== has repo_path => ( is => 'lazy', ); @@ -53,13 +50,39 @@ sub _build_repo_path { return $self->root . "/" . $self->domain; } -# The full path to the git repo to clone when using -# init on a new repository. +#== +# The full git path (i.e. git@foo.com:mjb/default-site.git) of the repository to use as an initial +# template when using the init() method to create a new blog. +#== has init_from => ( is => 'ro', required => 1, ); +#== +# The configuration file for the Jekyll blog itself. +#== +has config => ( + is => 'lazy', +); + +sub _build_config { + my ( $self ) = @_; + + return MJB::Backend::Jekyll::ConfigFile->new( + path => $self->repo_path . "/_config.yml", + )->read; +} + +#== +# This method will initialize a new blog. +# +# It will clone the git repo from $self->init_from and set a new remote, then +# push the repository (and expect the git server to create the repo on push). +# +# It returns $self +#== + sub init { my ( $self ) = @_; @@ -92,6 +115,16 @@ sub init { return $self; } +#== +# This method will list the media files that are in the blog's /assets/media directory, +# where images, pdfs, etc may be stored. +# +# It returns a list of hashrefs containing +# path | The full path to the file +# filename | The basename of the file. +# url | The http url that the image should exist at +# markdown | The markdown code to embedd the asset as an image +#== sub list_media { my ( $self ) = @_; @@ -114,6 +147,15 @@ sub list_media { return [ @return ]; } +#== +# This method will list posts for the blog that are in the /_posts +# collection.. +# +# It returns a list of MJB::Backend::Jekyll::MarkdownFile objects. +# +# For speed read() is NOT called on these objects, so the file will +# not be loaded until you call read() on the object. +#== sub list_posts { my ( $self ) = @_; @@ -134,6 +176,13 @@ sub list_posts { return [ @files ]; } +#== +# This method removes a markdown file from the git repository for this blog. +# +# It accepts a Mojo::File object to remove. +# +# It returns self. +#== sub remove_markdown_file { my ( $self, $file ) = @_; @@ -155,6 +204,16 @@ sub remove_markdown_file { return $self; } +#== +# This method lists all of the pages that exist in this blog. +# +# It will search for .md and .markdown files and returns an arrayref +# of MJB::Backend::Jekyll::MarkdownFile objects. +# +# For speed read() is NOT called on these objects, so the file will +# not be loaded until you call read() on the object. +#== + sub list_pages { my ( $self ) = @_; @@ -175,6 +234,13 @@ sub list_pages { return [ @files ]; } +#== +# This method will load a post by its filename. +# +# It returns an MJB::Backend::Jekyll::MarkdownFile object +# if the file exists. Otherwise, it returns undef. +# +#== sub get_post { my ( $self, $filename ) = @_; @@ -190,7 +256,26 @@ sub get_post { )->read; } - +#== +# This method will create a new post on the blog. +# +# It expects the filename for the collection in YYYY-MM-DD-some-title.markdown format. +# (i.e. 2020-12-25-it-is-christmas.markdown) +# +# It returns an MJB::Backend::Jekyll::MarkdownFile object that is expected to be +# populated by the caller. +# +# Once populated, this object should be given to write_post() to commit it. +# +# TODO: get_post and new_post are the very nearly the same, and should be refactored into +# one function. +# 1. Write a new function load_or_create_post() that will function as get_post, but +# if the post doesn't exist, it will function as new_post and return an object +# anyway. +# 2. Run ack in the controllers and update any use of get_post or new_post to use the +# new function. Confirm it works at each step of the way. +# 3. Remove get_post and new_post from this file. +#== sub new_post { my ( $self, $filename ) = @_; @@ -203,6 +288,20 @@ sub new_post { ); } +#== +# This method will create a new page. +# +# It expects a filepath in the form of my/file/path/and/name.markdown, and will +# return a MJB::Backend::Jekyll::MarkdownFile object. +# +# That object should be given to write_post. +# +# TODO: The difference between this and the post is that this can go off the root +# of the repo, where the posts go off the /_post/. +# +# Think about how this would work with being refactored the same as the new_post bit... +# it could be all three should be one function. +#== sub new_page { my ( $self, $filename ) = @_; @@ -215,37 +314,14 @@ sub new_page { ); } -sub get_title_of_post { - my ( $self, $file ) = @_; - - open my $lf, "<", $file - or die "Failed to open $file for reading: $!"; - while ( defined( my $line = <$lf> ) ) { - if ( $line =~ /^title: (.+)$/ ) { - close $lf; - return $1; - } - } - close $lf; - return undef; -} - -# Think about this.... -# probably want 'slug: ' as an override for the file path -sub _post_path { - my ( $self, $headers ) = @_; - - my $title = $headers->{title}; - - $title = lc($title); - $title =~ s/[^a-zA-Z0-9-_]+/_/g; - $title =~ s/[_]+/_/g; - $title =~ s/_$//g; - $title =~ s/^_//g; - - return $self->repo_path . "/_posts/" . $title . ".markdown"; -} +#== +# This method writes the jekyll blog configuration file. +# You can pass an MJB::Backend::Jekyll::ConfigFile object to write, +# otherwise the one in $self is written. +# +# The config file is written, commited, and pushed to the git origin server. +#== sub write_config { my ( $self, $config ) = @_; @@ -271,6 +347,12 @@ sub write_config { return 1; } +#== +# This method accepts an MJB::Backend::Jekyll::MarkdownFile object +# and writes it to the blog, then commits and pushes it to the origin. +# +# It is used by the post and page editing/creating functions. +#== sub write_post { my ( $self, $md_file ) = @_; @@ -298,6 +380,12 @@ sub write_post { return 1; } +#== +# This method accepts a file path and a comment and will commit the file, +# and push the repo. +# +# This is used to commit media and non-post files. +#== sub commit_file { my ( $self, $file, $comment ) = @_; @@ -323,6 +411,12 @@ sub commit_file { } +#== +# This method accepts a file path and a comment and will remove the file, +# and push the repo. +# +# This is used to delete media and other files. +#== sub remove_file { my ( $self, $file, $comment ) = @_; @@ -348,26 +442,9 @@ sub remove_file { } -sub revert_commit { - my ( $self, $commit ) = @_; - - # Check that the repo exists and is latest. - $self->_ensure_repository_is_latest; - - # Add the file to git - $self->system_command( [ qw( git revert --no-edit ), $commit ], { - chdir => $self->repo_path, - }); - - # Push the repo to the store server - $self->system_command( [ qw( git push origin master ) ], { - chdir => $self->repo_path, - }); - - return 1; - -} - +#== +# Given a commit, restore the repo to that state. +#== sub restore_commit { my ( $self, $commit ) = @_; @@ -393,33 +470,14 @@ sub restore_commit { } -sub delete_post { - my ( $self, $title, $file ) = @_; - - # Check if the repo exists and update the repo if needed - $self->_ensure_repository_is_latest; - - # Ensure the post exists - irony - die "Error: Cannot delete post that doesn't exists at " . $file - if ! -f $file; - - # git rm the file - $self->system_command( [ qw( git rm ), $file ], { - chdir => $self->repo_path, - }); - - # git commit the file - $self->system_command( [ qw( git commit -m ), "Deleted post $title" ], { - chdir => $self->repo_path, - }); - - # Push the repo to the store server - $self->system_command( [ qw( git push origin master ) ], { - chdir => $self->repo_path, - }); - -} - +#== +# This method lists the history of the git repo. +# +# It returns an arrayref of hashrefs with the following keys: +# commit | The commit hash +# dateref | The date, expressed relative (i.e. 3 days ago) +# message | The commit message +#== sub history { my ( $self ) = @_; @@ -449,8 +507,11 @@ sub history { return [ @return ]; } -# Helper function to ensure the repo exists and has the latest -# changes. +#== +# This method will checkout the repo if it doesn't exist on the filesystem. +# +# It will update the repo with a git pull. +#== sub _ensure_repository_is_latest { my ( $self ) = @_; @@ -468,6 +529,37 @@ sub _ensure_repository_is_latest { return 1; } +#== +# Run a system command. +# $self->system_command( +# [qw( the command here )], +# { options => 'here' }, +# ); +# +# This method accepts an arrayref with a command, and a hashref with +# options. +# +# The command will be executed. +# +# The following options may be passed: +# chdir | Directory to chdir to before executing the command +# mask | A hash like { My$ecretP@ssword => '--PASSWORD--' } to censor in +# logging STDOUT/STDERR, and logging the command itself. +# fail_on_stderr | An arrayref like [ +# qr/pattern/ => 'die reason', +# qr/other pattern/ => 'another die reason' +# ] where system_command will emmit a die if the pattern matches on stderr. +# +# A hashref will be returned that contains the following keys: +# { +# stdout => 'standard output content', +# stderr => 'standard error content', +# exitno => 1, # the exit status of the command +# } +# +# If the environment variable MJB_DEBUG is set true, these return values +# will also be printed to STDOUT. +#== sub system_command { my ( $self, $cmd, $settings ) = @_;