Now with docs.

master
Manager Bot 3 years ago
parent c154d006e6
commit 5999701be1
  1. 286
      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 ) = @_;

Loading…
Cancel
Save