Compare commits
10 Commits
125a790efb
...
029a99216d
Author | SHA1 | Date | |
---|---|---|---|
029a99216d | |||
5234e54a81 | |||
13c9615330 | |||
88ec76dcee | |||
191c3a78e5 | |||
9257373163 | |||
1f4009c2d4 | |||
d024465573 | |||
29d0344081 | |||
3ffd5c19b2 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -4,5 +4,4 @@ css
|
|||||||
bash
|
bash
|
||||||
posts
|
posts
|
||||||
*.conf
|
*.conf
|
||||||
index.html
|
./index.html
|
||||||
README.html
|
|
9
Makefile
9
Makefile
@ -1,7 +1,16 @@
|
|||||||
install:
|
install:
|
||||||
@echo "Installing bob"
|
@echo "Installing bob"
|
||||||
cp bob /usr/local/bin
|
cp bob /usr/local/bin
|
||||||
|
mkdir -p /usr/local/lib/bob/template
|
||||||
|
cp lib/template/* /usr/local/lib/bob/template
|
||||||
|
cp lib/*.awk /usr/local/lib/bob
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
@echo "Uninstalling bob"
|
@echo "Uninstalling bob"
|
||||||
rm /usr/local/bin/bob
|
rm /usr/local/bin/bob
|
||||||
|
rm -rf /usr/local/lib/bob
|
||||||
|
|
||||||
|
.PHONY: test # Declare 'test' as a phony target
|
||||||
|
|
||||||
|
test:
|
||||||
|
bash ./test/test.sh
|
@ -62,3 +62,6 @@ bob help
|
|||||||
* Consider adding configuration files for some/all posts (if they
|
* Consider adding configuration files for some/all posts (if they
|
||||||
need special javascript included e.g. MathJax, AJAX, sockets ...).
|
need special javascript included e.g. MathJax, AJAX, sockets ...).
|
||||||
* Add a preview function for TRUE drafts being written
|
* Add a preview function for TRUE drafts being written
|
||||||
|
* Take into account the headers possibilities of multimarkdown, which could
|
||||||
|
replace the self header writing process and include other features such as
|
||||||
|
Mathjax
|
||||||
|
591
bob
591
bob
@ -1,493 +1,15 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
_get_blog_name()
|
if [ -z "${BOB_LIB}" ]; then
|
||||||
{
|
BOB_LIB=/usr/local/lib/bob
|
||||||
# Extract the configuration file
|
else
|
||||||
conf=`cat .blog.conf`
|
BOB_LIB=./lib
|
||||||
name_regex="blog\:([a-zA-Z ]+)"
|
|
||||||
|
|
||||||
# Echo the name of the blog, if any was given
|
|
||||||
if [[ $conf =~ $name_regex ]]; then
|
|
||||||
echo ${BASH_REMATCH[1]}
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_dark_param()
|
|
||||||
{
|
|
||||||
# Extract the configuration file
|
|
||||||
conf=`cat .blog.conf`
|
|
||||||
dark_regex="dark:(y|n|N)"
|
|
||||||
|
|
||||||
if [[ $conf =~ $dark_regex ]]; then
|
|
||||||
echo ${BASH_REMATCH[1]}
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_blog_lang()
|
|
||||||
{
|
|
||||||
# Extract the configuration file
|
|
||||||
conf=`cat .blog.conf`
|
|
||||||
lang_regex="lang:([a-z]+)"
|
|
||||||
|
|
||||||
if [[ $conf =~ $lang_regex ]]; then
|
|
||||||
echo ${BASH_REMATCH[1]}
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_add_header()
|
|
||||||
{
|
|
||||||
post_name=$1
|
|
||||||
blog_name=$2
|
|
||||||
lang=$3
|
|
||||||
dark=$4
|
|
||||||
|
|
||||||
css="../css/poststyle.css"
|
|
||||||
if [[ $dark =~ "y" ]]; then
|
|
||||||
css="../css/poststyle.dark.css"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > ./posts/$post_name.html << EOF
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="$lang" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>$post_name</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Cutive+Mono|IBM+Plex+Mono&display=swap" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" type="text/css" href="$css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<article class='post'>
|
|
||||||
<header>
|
|
||||||
<h2><a href="../index.html">$blog_name</a></h2>
|
|
||||||
</header>
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
_add_footer()
|
|
||||||
{
|
|
||||||
post_name=$1
|
|
||||||
cat >> ./posts/$post_name.html << EOF
|
|
||||||
</article>
|
|
||||||
<footer>
|
|
||||||
<span>generated by <a href="https://www.github.com/SiwonP/bob">bob</a></span>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
EOF
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_get_last_modif_date()
|
|
||||||
{
|
|
||||||
# Extract the date of the last modification of the file $1
|
|
||||||
# and echo it with format dd/mm/yyyy
|
|
||||||
date=`stat -f "%Sm" -t "%d/%m/%Y" $1`
|
|
||||||
echo $date
|
|
||||||
}
|
|
||||||
|
|
||||||
publish()
|
|
||||||
{
|
|
||||||
delete_posts
|
|
||||||
|
|
||||||
# Collect all configuration parameters so that the regex are only evaluted
|
|
||||||
# once per publication. Done to improve the speed of the publication
|
|
||||||
dark=$(_get_dark_param)
|
|
||||||
lang=$(_get_blog_lang)
|
|
||||||
blog_name=$(_get_blog_name)
|
|
||||||
|
|
||||||
# list all the drafts stored as most recently modified to
|
|
||||||
# least recently modified, as it should appear on a blog
|
|
||||||
drafts=`ls -t ./bases/`
|
|
||||||
# echo $drafts
|
|
||||||
|
|
||||||
# Tranform the string into an array
|
|
||||||
list=($(echo "$drafts" | tr ' ' '\n'))
|
|
||||||
|
|
||||||
# date=$(_get_last_modif_date "./drafts/${list[0]}")
|
|
||||||
|
|
||||||
# Regex to extract the name without the extension
|
|
||||||
name_regex="([a-zA-Z]+)\.(md|markdown)"
|
|
||||||
|
|
||||||
# Array to story only the names of the posts
|
|
||||||
posts_names=()
|
|
||||||
|
|
||||||
for (( i=0; i<${#list[@]}; i++ ));
|
|
||||||
do
|
|
||||||
if [[ ${list[i]} =~ $name_regex ]]; then
|
|
||||||
# Append the names to the array
|
|
||||||
posts_names+=(${BASH_REMATCH[1]})
|
|
||||||
fi
|
|
||||||
_create_posts "./bases/${list[i]}" "$blog_name" "$lang" "$dark"
|
|
||||||
done
|
|
||||||
|
|
||||||
# function to update the index.html
|
|
||||||
# Passing the drafts as argument since it's sorted
|
|
||||||
_update_index "$drafts" "$blog_name" "$lang" "$dark"
|
|
||||||
}
|
|
||||||
|
|
||||||
_create_posts()
|
|
||||||
{
|
|
||||||
draft=$1
|
|
||||||
blog_name=$2
|
|
||||||
lang=$3
|
|
||||||
dark=$4
|
|
||||||
|
|
||||||
# Convert the markdown file $draft into html
|
|
||||||
# and store the result in $content
|
|
||||||
content=`multimarkdown --nolabels $draft`
|
|
||||||
|
|
||||||
# Regex to extract the simple post name
|
|
||||||
md_regex="([a-zA-Z\-]+)\.(md|markdown)"
|
|
||||||
|
|
||||||
if [[ $draft =~ $md_regex ]]; then
|
|
||||||
# If the file have md or markdown extension, cut it
|
|
||||||
post_name=${BASH_REMATCH[1]}
|
|
||||||
else
|
|
||||||
# if not and it has no extension, keep it this way
|
|
||||||
post_name=$draft
|
|
||||||
fi
|
|
||||||
# Integrate the html converted content into a proper html file
|
|
||||||
_build_post "$post_name" "$blog_name" "$content" "$lang" "$dark"
|
|
||||||
}
|
|
||||||
|
|
||||||
_build_post()
|
|
||||||
{
|
|
||||||
# Create the html file of the post $post_name with the
|
|
||||||
# previsouly converted markdown to html $content
|
|
||||||
post_name=$1
|
|
||||||
blog_name=$2
|
|
||||||
content=$3
|
|
||||||
lang=$4
|
|
||||||
dark=$5
|
|
||||||
|
|
||||||
_add_header "$post_name" "$blog_name" "$lang" "$dark"
|
|
||||||
echo $content >> ./posts/$post_name.html
|
|
||||||
_add_footer "$post_name"
|
|
||||||
}
|
|
||||||
|
|
||||||
_update_index()
|
|
||||||
{
|
|
||||||
title=$2
|
|
||||||
lang=$3
|
|
||||||
dark=$4
|
|
||||||
|
|
||||||
css="./css/indexstyle.css"
|
|
||||||
if [[ $dark =~ "y" ]]; then
|
|
||||||
css="./css/indexstyle.dark.css"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > index.html << EOF
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="$lang" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>$title</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Cutive+Mono|IBM+Plex+Mono&display=swap" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" type="text/css" href="$css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1 class='title'>$title</h1>
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Retrieve the string containing all drafts names and splitting it
|
|
||||||
# into an array
|
|
||||||
drafts=$1
|
|
||||||
drafts_list=($(echo "$drafts" | tr ' ' '\n'))
|
|
||||||
|
|
||||||
# Number of posts in the draft list, needed for the for loop
|
|
||||||
nbposts=${#drafts_list[@]}
|
|
||||||
|
|
||||||
# If there are posts to post, begin the list
|
|
||||||
if [ $nbposts -gt 0 ]
|
|
||||||
then
|
|
||||||
echo "<ul class='posts_list'>" >> index.html
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Regex to extract just the name of the post
|
|
||||||
post_regex="([a-zA-Z\-]+)\.(md|markdown)"
|
|
||||||
|
|
||||||
for (( i=0; i<${#drafts_list[@]}; i++ ));
|
|
||||||
do
|
|
||||||
# Retrieve the date of the last modification of the draft
|
|
||||||
date=$(_get_last_modif_date "./bases/${drafts_list[i]}")
|
|
||||||
|
|
||||||
# In case the next regex doesn't work, even though it's supposed to
|
|
||||||
# work everytime
|
|
||||||
post_name="unknown"
|
|
||||||
|
|
||||||
# Extract the strict name of the post in the same
|
|
||||||
# order of the drafts because they are sorted according
|
|
||||||
# to the last modification date
|
|
||||||
if [[ ${drafts_list[i]} =~ $post_regex ]]; then
|
|
||||||
post_name=${BASH_REMATCH[1]}
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Function to add items to the posts list
|
|
||||||
_add_post_link "./posts/$post_name.html" "$post_name" "$date"
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
# If there are posts posted, close the list
|
|
||||||
if [ $nbposts -gt 0 ]; then
|
|
||||||
echo "</ul>" >> index.html
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat >> index.html << EOF
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
_add_post_link()
|
|
||||||
{
|
|
||||||
url=$1
|
|
||||||
post_name=$2
|
|
||||||
date=$3
|
|
||||||
post_name=${post_name//\-/ }
|
|
||||||
echo "<li class='post'>" >> index.html
|
|
||||||
echo "<a href="$url">$post_name</a>" >> index.html
|
|
||||||
echo "<span class='date'>$date</span>" >> index.html
|
|
||||||
echo "</li>" >> index.html
|
|
||||||
}
|
|
||||||
|
|
||||||
init()
|
|
||||||
{
|
|
||||||
echo Name of the author of the blog :
|
|
||||||
read author
|
|
||||||
echo "author:$author" > .blog.conf
|
|
||||||
echo Name of the blog :
|
|
||||||
read blog
|
|
||||||
echo "blog:$blog" >> .blog.conf
|
|
||||||
echo "Language of the blog : (en)"
|
|
||||||
read lang
|
|
||||||
if [ -z $lang ]; then
|
|
||||||
lang=en
|
|
||||||
fi
|
|
||||||
echo "lang:$lang" >> .blog.conf
|
|
||||||
echo "Activate dark mode : (y/N)"
|
|
||||||
read dark
|
|
||||||
if [ -z $lang ]; then
|
|
||||||
dark=n
|
|
||||||
fi
|
|
||||||
echo "dark:$dark" >> .blog.conf
|
|
||||||
mkdir drafts
|
|
||||||
mkdir bases
|
|
||||||
mkdir posts
|
|
||||||
mkdir css
|
|
||||||
_init_css
|
|
||||||
_index "$blog" "$lang" "$dark"
|
|
||||||
}
|
|
||||||
|
|
||||||
_init_css()
|
|
||||||
{
|
|
||||||
# Initiate css files for both the index and the posts,
|
|
||||||
# both dark and light themes
|
|
||||||
cat > ./css/indexstyle.css << EOF
|
|
||||||
.wrap {
|
|
||||||
width: 40vw;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
.title {
|
|
||||||
margin-top: 5vh;
|
|
||||||
margin-bottom: 7vh;
|
|
||||||
text-align: center;
|
|
||||||
font-family: 'IBM Plex Mono', monospace;
|
|
||||||
}
|
|
||||||
.posts_list {
|
|
||||||
text-align: center;
|
|
||||||
padding-left: 0px;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
.post {
|
|
||||||
margin-bottom: 3vh;
|
|
||||||
font-family: 'IBM Plex Mono', monospace;
|
|
||||||
}
|
|
||||||
.post a:link {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.post a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: #AAA;
|
|
||||||
}
|
|
||||||
.post a {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
.date {
|
|
||||||
color: #777;
|
|
||||||
font-family: 'Cutive Mono', monospace;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat > ./css/indexstyle.dark.css << EOF
|
|
||||||
body {
|
|
||||||
background: #222;
|
|
||||||
}
|
|
||||||
.wrap {
|
|
||||||
width: 40vw;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
.title {
|
|
||||||
margin-top: 5vh;
|
|
||||||
margin-bottom: 7vh;
|
|
||||||
color: #e1e1e1;
|
|
||||||
text-align: center;
|
|
||||||
font-family: 'IBM Plex Mono', monospace;
|
|
||||||
}
|
|
||||||
.posts_list {
|
|
||||||
text-align: center;
|
|
||||||
padding-left: 0px;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
.post {
|
|
||||||
margin-bottom: 3vh;
|
|
||||||
color: #e1e1e1;
|
|
||||||
font-family: 'IBM Plex Mono', monospace;
|
|
||||||
}
|
|
||||||
.post a:link {
|
|
||||||
color: #e1e1e1;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.post a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: #AAA;
|
|
||||||
}
|
|
||||||
.post a {
|
|
||||||
color: #e1e1e1;
|
|
||||||
}
|
|
||||||
.date {
|
|
||||||
color: #777;
|
|
||||||
font-family: 'Cutive Mono', monospace;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat > ./css/poststyle.css << EOF
|
|
||||||
body {
|
|
||||||
font-family: 'IBM Plex Mono', monospace;
|
|
||||||
}
|
|
||||||
header a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
header a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
header {
|
|
||||||
margin-bottom: 6vh;
|
|
||||||
}
|
|
||||||
.post {
|
|
||||||
width: 70vw;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
footer {
|
|
||||||
width: 70vw;
|
|
||||||
margin-top: 6vh;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 1.3vh;
|
|
||||||
}
|
|
||||||
footer span a {
|
|
||||||
color: #FF8608;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat > ./css/poststyle.dark.css << EOF
|
|
||||||
body {
|
|
||||||
font-family: 'IBM Plex Mono', monospace;
|
|
||||||
background: #222;
|
|
||||||
color: #e1e1e1;
|
|
||||||
}
|
|
||||||
header a {
|
|
||||||
color: #777;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
header a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: #e1e1e1;
|
|
||||||
}
|
|
||||||
header {
|
|
||||||
margin-bottom: 6vh;
|
|
||||||
}
|
|
||||||
.post {
|
|
||||||
width: 70vw;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
footer {
|
|
||||||
width: 70vw;
|
|
||||||
margin-top: 6vh;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 1.3vh;
|
|
||||||
}
|
|
||||||
footer span a {
|
|
||||||
color: #FF8608;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
_index()
|
|
||||||
{
|
|
||||||
title=$1
|
|
||||||
lang=$2
|
|
||||||
dark=$3
|
|
||||||
css="./css/indexstyle.css"
|
|
||||||
|
|
||||||
if [ $3 -eq "y" ]; then
|
|
||||||
css="./css/indexstyle.dark.css"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create the first index file, empty of any posts
|
|
||||||
cat > index.html << EOF
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="$lang" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>$title</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Cutive+Mono|IBM+Plex+Mono&display=swap" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" type="text/css" href="./css/indexstyle.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1 class='title'>$title</h1>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
change_mode()
|
|
||||||
{
|
|
||||||
# READ FILE LINE BY LINE SO THAT THE NEW CONF FILE IS NOT ON ONE LINE
|
|
||||||
echo "Activate dark mode : (y/N)"
|
|
||||||
read dark
|
|
||||||
if [ -z $lang ]; then
|
|
||||||
dark=N
|
|
||||||
fi
|
|
||||||
conf=`cat .blog.conf`
|
|
||||||
echo ${conf//dark:(y|n|N)/dark:$dark} > .blog.conf
|
|
||||||
}
|
|
||||||
|
|
||||||
delete_posts()
|
|
||||||
{
|
|
||||||
# posts=`ls ./posts/`
|
|
||||||
# echo $posts/
|
|
||||||
# if [ "$posts" == "/" ]; then
|
|
||||||
# echo empty
|
|
||||||
# fi
|
|
||||||
|
|
||||||
rm ./posts/*.html
|
|
||||||
}
|
|
||||||
|
|
||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
echo
|
echo
|
||||||
echo "This script is made for those who want to blog and are also addicted
|
echo "This script is made for those who want to blog and are also addicted to the command line"
|
||||||
to the command line"
|
|
||||||
echo
|
echo
|
||||||
echo "Run the initiation for a start. After that, place all your future blog
|
echo "Run the initiation for a start. After that, place all your future blog
|
||||||
posts, written in markdown (.md or .markdown), in the draft folder."
|
posts, written in markdown (.md or .markdown), in the draft folder."
|
||||||
@ -499,18 +21,113 @@ usage()
|
|||||||
your blog"
|
your blog"
|
||||||
echo
|
echo
|
||||||
echo "bob commands :"
|
echo "bob commands :"
|
||||||
echo " help display this help"
|
echo " help display this help"
|
||||||
echo " init initiate the blog"
|
echo " init initiate a blog"
|
||||||
echo " publish publish the blog"
|
echo " publish <post> publish the post"
|
||||||
|
echo " unpublish <post> unpublish the post"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init()
|
||||||
|
{
|
||||||
|
echo Name of the author of the blog :
|
||||||
|
read author
|
||||||
|
echo "author=$author" > .blog.conf
|
||||||
|
echo Name of the blog :
|
||||||
|
read blog
|
||||||
|
echo "blog=$blog" >> .blog.conf
|
||||||
|
echo "Language of the blog : [en]"
|
||||||
|
read lang
|
||||||
|
if [ -z $lang ]; then
|
||||||
|
lang=en
|
||||||
|
fi
|
||||||
|
echo "lang=$lang" >> .blog.conf
|
||||||
|
echo "Activate dark mode : (y/N)"
|
||||||
|
read dark
|
||||||
|
if [ -z $dark ]; then
|
||||||
|
dark=n
|
||||||
|
fi
|
||||||
|
echo "dark=$dark" >> .blog.conf
|
||||||
|
mkdir drafts
|
||||||
|
# mkdir templates
|
||||||
|
mkdir posts
|
||||||
|
# mkdir css
|
||||||
|
# _init_css
|
||||||
|
# _index "$blog" "$lang" "$dark"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_index()
|
||||||
|
{
|
||||||
|
posts=$(ls -t ./posts | awk '
|
||||||
|
BEGIN {
|
||||||
|
print "<ul>"
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ref=$0
|
||||||
|
gsub(".html","",ref)
|
||||||
|
gsub(/[_-]/, " ", ref)
|
||||||
|
print "<li><a href=\"./posts/" $0 "\">" ref "</a></li>"
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
print "</ul>"
|
||||||
|
}')
|
||||||
|
|
||||||
|
template="${BOB_LIB}/template/index.html"
|
||||||
|
awk -v content="$posts" '{gsub(/{{articles}}/, content); print}' "$template" > "./index.html"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
publish()
|
||||||
|
{
|
||||||
|
post=$(awk -f ${BOB_LIB}/markdown.awk ./drafts/$1.md)
|
||||||
|
template="${BOB_LIB}/template/post.html"
|
||||||
|
awk -v content="$post" '{gsub(/{{article}}/, content); print}' "$template" > "./posts/$1.html"
|
||||||
|
mv ./drafts/$1.md ./drafts/published/$1.md
|
||||||
|
|
||||||
|
update_index
|
||||||
|
}
|
||||||
|
|
||||||
|
unpublish()
|
||||||
|
{
|
||||||
|
rm ./posts/$1.html
|
||||||
|
mv ./drafts/published/$1.md ./drafts/$1.md
|
||||||
|
|
||||||
|
update_index
|
||||||
|
}
|
||||||
|
|
||||||
|
unpublish_all()
|
||||||
|
{
|
||||||
|
rm ./posts/*
|
||||||
|
mv ./drafts/published/* ./drafts/
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy()
|
||||||
|
{
|
||||||
|
echo "TODO"
|
||||||
|
}
|
||||||
|
|
||||||
if [[ $# -eq 0 ]]; then
|
if [[ $# -eq 0 ]]; then
|
||||||
usage
|
usage
|
||||||
|
elif [[ "$1" == "help" ]]; then
|
||||||
|
usage
|
||||||
|
elif [[ "$1" == "usage" ]]; then
|
||||||
|
usage
|
||||||
elif [[ "$1" == "init" ]]; then
|
elif [[ "$1" == "init" ]]; then
|
||||||
init
|
init
|
||||||
elif [[ "$1" == "publish" ]]; then
|
elif [[ "$1" == "publish" ]]; then
|
||||||
publish
|
if [[ $# -eq 1 ]]; then
|
||||||
|
echo "Usage : bob publish <draft_name>"
|
||||||
|
else
|
||||||
|
publish $2
|
||||||
|
fi
|
||||||
|
elif [[ "$1" == "unpublish" ]]; then
|
||||||
|
if [[ $# -eq 1 ]]; then
|
||||||
|
echo "Usage : bob unpublish <post_name>"
|
||||||
|
else
|
||||||
|
unpublish $2
|
||||||
|
fi
|
||||||
|
elif [[ "$1" == "deploy" ]]; then
|
||||||
|
deploy
|
||||||
elif [[ "$1" == "help" ]]; then
|
elif [[ "$1" == "help" ]]; then
|
||||||
usage
|
usage
|
||||||
fi
|
fi
|
||||||
|
150
lib/markdown.awk
Executable file
150
lib/markdown.awk
Executable file
@ -0,0 +1,150 @@
|
|||||||
|
#!/usr/bin/awk
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
env = "none"
|
||||||
|
stack_pointer = 0
|
||||||
|
push(env)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to push a value onto the stack
|
||||||
|
function push(value) {
|
||||||
|
stack_pointer++
|
||||||
|
stack[stack_pointer] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to pop a value from the stack (LIFO)
|
||||||
|
function pop() {
|
||||||
|
if (stack_pointer > 0) {
|
||||||
|
value = stack[stack_pointer]
|
||||||
|
delete stack[stack_pointer]
|
||||||
|
stack_pointer--
|
||||||
|
return value
|
||||||
|
} else {
|
||||||
|
return "empty"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get last value in LIFO
|
||||||
|
function last() {
|
||||||
|
return stack[stack_pointer]
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceEmAndStrong(line, result, start, end) {
|
||||||
|
# Replace occurrences of **...** with <strong>...</strong>
|
||||||
|
while (match(line, /\*\*([^*]+)\*\*/)) {
|
||||||
|
start = RSTART
|
||||||
|
end = RSTART + RLENGTH - 1
|
||||||
|
# Build the result: before match, <strong>, content, </strong>, after match
|
||||||
|
line = substr(line, 1, start-1) "<strong>" substr(line, start+2, RLENGTH-4) "</strong>" substr(line, end+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Replace occurrences of *...* with <em>...</em>
|
||||||
|
while (match(line, /\*([^*]+)\*/)) {
|
||||||
|
start = RSTART
|
||||||
|
end = RSTART + RLENGTH - 1
|
||||||
|
# Build the result: before match, <em>, content, </em>, after match
|
||||||
|
line = substr(line, 1, start-1) "<em>" substr(line, start+1, RLENGTH-2) "</em>" substr(line, end+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function closeOne() {
|
||||||
|
env = pop()
|
||||||
|
print "</" env ">"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Matching headers
|
||||||
|
/^#+ / {
|
||||||
|
match($0, /#+ /);
|
||||||
|
n = RLENGTH;
|
||||||
|
print "<h" n-1 ">" substr($0, n + 1) "</h" n-1 ">"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Matching blockquotes
|
||||||
|
/^> / {
|
||||||
|
env = last()
|
||||||
|
if (env == "blockquote")
|
||||||
|
{
|
||||||
|
# In a blockquote block only print the text
|
||||||
|
print substr($0, 3);
|
||||||
|
} else {
|
||||||
|
# Otherwise, init the blockquote block
|
||||||
|
push("blockquote")
|
||||||
|
print "<blockquote>\n" substr($0, 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Matching unordered lists
|
||||||
|
/^[-+*] / {
|
||||||
|
env = last()
|
||||||
|
if (env == "ul" ) {
|
||||||
|
# In a unordered list block, print a new item
|
||||||
|
print "<li>" substr($0, 3) "</li>"
|
||||||
|
} else {
|
||||||
|
# Otherwise, init the unordered list block
|
||||||
|
push("ul")
|
||||||
|
print "<ul>\n<li>" substr($0, 3) "</li>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Matching ordered lists
|
||||||
|
/^[0-9]+\./ {
|
||||||
|
env = last()
|
||||||
|
if (env == "ol") {
|
||||||
|
# In a ordered list block, print a new item
|
||||||
|
print "<li>" substr($0, 4) "</li>"
|
||||||
|
} else {
|
||||||
|
# Otherwise, init the ordered list block
|
||||||
|
push("ol")
|
||||||
|
print "<ol>\n<li>" substr($0, 4) "</li>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Matching code block
|
||||||
|
/^( |\t)/ {
|
||||||
|
env = last()
|
||||||
|
match($0, /( |\t)/);
|
||||||
|
n = RLENGTH;
|
||||||
|
if (env == "code") {
|
||||||
|
# In a code block, print a new item
|
||||||
|
print substr($0, n+1)
|
||||||
|
} else {
|
||||||
|
# Otherwise, init the code block
|
||||||
|
push("pre")
|
||||||
|
push("code")
|
||||||
|
print "<pre><code>" substr($0, n+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Matching a simple paragraph
|
||||||
|
!/^(#|\*|-|\+|>|`|$|\t| )/ {
|
||||||
|
env = last()
|
||||||
|
if (env == "none") {
|
||||||
|
# If no block, print a paragraph
|
||||||
|
print "<p>" replaceEmAndStrong($0) "</p>"
|
||||||
|
} else if (env == "blockquote") {
|
||||||
|
print $0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$0 == "" {
|
||||||
|
env = last()
|
||||||
|
while (env != "none") {
|
||||||
|
env = pop()
|
||||||
|
print "</" env ">"
|
||||||
|
env = last()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
END {
|
||||||
|
env = last()
|
||||||
|
while (env != "none") {
|
||||||
|
env = pop()
|
||||||
|
print "</" env ">"
|
||||||
|
env = last()
|
||||||
|
}
|
||||||
|
}
|
17
lib/template/index.html
Normal file
17
lib/template/index.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr" dir="ltr">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>simpet</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Cutive+Mono|IBM+Plex+Mono&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" type="text/css" href="./css/indexstyle.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1 class='title'>simpet</h1>
|
||||||
|
{{articles}}
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
19
lib/template/post.html
Normal file
19
lib/template/post.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr" dir="ltr">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>simpet</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Cutive+Mono|IBM+Plex+Mono&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../css/poststyle.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1 class='title'><a href="../index.html">simpet</a></h1>
|
||||||
|
<article>
|
||||||
|
{{article}}
|
||||||
|
</article>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
0
test/bob/test_init.sh
Normal file
0
test/bob/test_init.sh
Normal file
12
test/parser/test01.md
Normal file
12
test/parser/test01.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Major title
|
||||||
|
|
||||||
|
## Minor title
|
||||||
|
|
||||||
|
### Subtitle
|
||||||
|
|
||||||
|
- ici
|
||||||
|
- on
|
||||||
|
- est
|
||||||
|
- là
|
||||||
|
|
||||||
|
ok
|
18
test/parser/test02.md
Normal file
18
test/parser/test02.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# test
|
||||||
|
|
||||||
|
salut à tous
|
||||||
|
|
||||||
|
- item 1
|
||||||
|
- item 2
|
||||||
|
|
||||||
|
## test1
|
||||||
|
|
||||||
|
okkk
|
||||||
|
|
||||||
|
> blockquote
|
||||||
|
> again
|
||||||
|
> again and again
|
||||||
|
|
||||||
|
code
|
||||||
|
|
||||||
|
paragraph *em* and **strong**
|
157
test/parser/test_md_parser.sh
Executable file
157
test/parser/test_md_parser.sh
Executable file
@ -0,0 +1,157 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Text color variables
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
NC='\033[0m' # No Color (reset)
|
||||||
|
|
||||||
|
# Ensure a script is provided
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Usage: $0 <markdown_parser_script>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
PARSER="$1"
|
||||||
|
|
||||||
|
# Check if the parser script exists
|
||||||
|
if [ ! -f "$PARSER" ]; then
|
||||||
|
echo "Error: $PARSER not found!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine if it's AWK or Shell (optional second argument)
|
||||||
|
PARSER_TYPE="bash" # Default to bash script
|
||||||
|
if [ -n "$2" ]; then
|
||||||
|
PARSER_TYPE="$2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Define test cases as an array of markdown inputs and expected outputs
|
||||||
|
declare -a tests=(
|
||||||
|
"Header 1"
|
||||||
|
"# Header 1"
|
||||||
|
"<h1>Header 1</h1>"
|
||||||
|
|
||||||
|
"Header 2"
|
||||||
|
"## Header 2"
|
||||||
|
"<h2>Header 2</h2>"
|
||||||
|
|
||||||
|
"Header 3"
|
||||||
|
"### Header 3"
|
||||||
|
"<h3>Header 3</h3>"
|
||||||
|
|
||||||
|
"Header 4"
|
||||||
|
"#### Header 4"
|
||||||
|
"<h4>Header 4</h4>"
|
||||||
|
|
||||||
|
"Header 5"
|
||||||
|
"##### Header 5"
|
||||||
|
"<h5>Header 5</h5>"
|
||||||
|
|
||||||
|
"Header 6"
|
||||||
|
"###### Header 6"
|
||||||
|
"<h6>Header 6</h6>"
|
||||||
|
|
||||||
|
"Multiple headers 1"
|
||||||
|
$'# Header 1\n## Header 2'
|
||||||
|
"<h1>Header 1</h1><h2>Header 2</h2>"
|
||||||
|
|
||||||
|
# "Multiple headers 2"
|
||||||
|
# $'### Header 3\n\n## Header 2\n\n# Header 1'
|
||||||
|
# "<h3>Header 3</h3><h2>Header 2</h2><h1>Header 1</h1>"
|
||||||
|
|
||||||
|
"Unordered List"
|
||||||
|
$'- item\n* item'
|
||||||
|
"<ul><li>item</li><li>item</li></ul>"
|
||||||
|
|
||||||
|
"Ordered List"
|
||||||
|
$'1. item1\n1. item1\n3. item3'
|
||||||
|
"<ol><li>item1</li><li>item1</li><li>item3</li></ol>"
|
||||||
|
|
||||||
|
"Blockquote 1"
|
||||||
|
"> test of blockquote"
|
||||||
|
"<blockquote>test of blockquote</blockquote>"
|
||||||
|
|
||||||
|
"Blockquote 2"
|
||||||
|
$'> line1\n> line2'
|
||||||
|
"<blockquote>line1line2</blockquote>"
|
||||||
|
|
||||||
|
"Blockquote 2"
|
||||||
|
$'> line1\nline2'
|
||||||
|
"<blockquote>line1line2</blockquote>"
|
||||||
|
|
||||||
|
"Code Block 1"
|
||||||
|
$' code1'
|
||||||
|
"<pre><code>code1</code></pre>"
|
||||||
|
|
||||||
|
"Code Block 2"
|
||||||
|
$'\tcode1'
|
||||||
|
"<pre><code>code1</code></pre>"
|
||||||
|
|
||||||
|
"Paragraph 1"
|
||||||
|
"paragraph 1"
|
||||||
|
"<p>paragraph 1</p>"
|
||||||
|
|
||||||
|
"Paragraph 2"
|
||||||
|
"paragraph *emphasis* and **strong**"
|
||||||
|
"<p>paragraph <em>emphasis</em> and <strong>strong</strong></p>"
|
||||||
|
|
||||||
|
"Mix Code blocks and paragraphs 1"
|
||||||
|
$'First paragraph\n\n code block'
|
||||||
|
"<p>First paragraph</p><pre><code>code block</code></pre>"
|
||||||
|
|
||||||
|
"Mix Code blocks and paragraphs 2"
|
||||||
|
$'First paragraph\n\n code1\n code2\n\nSecond paragraph'
|
||||||
|
"<p>First paragraph</p><pre><code>code1code2</code></pre><p>Second paragraph</p>"
|
||||||
|
|
||||||
|
# You can add more test cases following the same format...
|
||||||
|
)
|
||||||
|
|
||||||
|
input="# test"
|
||||||
|
expected="<h1>test</h1>"
|
||||||
|
|
||||||
|
# Function to run a single test case
|
||||||
|
run_test() {
|
||||||
|
local input="$1"
|
||||||
|
local expected="$2"
|
||||||
|
local actual=""
|
||||||
|
|
||||||
|
# Get the actual output from the parser
|
||||||
|
if [ "$PARSER_TYPE" == "awk" ]; then
|
||||||
|
# Run AWK script with the input
|
||||||
|
actual=$(echo "$input" | awk -f "$PARSER" | tr -d '\n')
|
||||||
|
else
|
||||||
|
# Assume it's a shell script, run it
|
||||||
|
actual=$(echo "$input" | bash "$PARSER" | tr -d '\n')
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compare the actual output with the expected output
|
||||||
|
if [ "$actual" == "$expected" ]; then
|
||||||
|
echo -e "${GREEN}Test Passed!${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Test Failed!${NC}"
|
||||||
|
echo "Input:"
|
||||||
|
echo "$input"
|
||||||
|
echo "Expected:"
|
||||||
|
echo "$expected"
|
||||||
|
echo "Got:"
|
||||||
|
echo "$actual"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
STATUS=0
|
||||||
|
|
||||||
|
# Main loop to run all test cases
|
||||||
|
num_tests=$((${#tests[@]} / 3)) # Divide by 2 because each test has input/output pair
|
||||||
|
for ((i = 0; i < num_tests; i++)); do
|
||||||
|
input="${tests[i * 3 + 1]}"
|
||||||
|
expected="${tests[i * 3 + 2]}"
|
||||||
|
echo "Test $((i + 1)):" ${tests[i * 3]}
|
||||||
|
run_test "$input" "$expected"
|
||||||
|
STATUS_i=$?
|
||||||
|
STATUS=$((STATUS+STATUS_i))
|
||||||
|
done
|
||||||
|
|
||||||
|
exit $STATUS
|
33
test/test.sh
Executable file
33
test/test.sh
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Text color variables
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[0;33m'
|
||||||
|
NC='\033[0m' # No Color (reset)
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Testing markown parser :${NC}\n"
|
||||||
|
|
||||||
|
./test/parser/test_md_parser.sh ./lib/markdown.awk awk
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Testing bob init :${NC}\n"
|
||||||
|
|
||||||
|
author="author"
|
||||||
|
blog="blog"
|
||||||
|
lang="fr"
|
||||||
|
dark="y"
|
||||||
|
|
||||||
|
./bob2 init << EOF
|
||||||
|
$author
|
||||||
|
$blog
|
||||||
|
$lang
|
||||||
|
$dark
|
||||||
|
EOF
|
||||||
|
|
||||||
|
conf_author=$(grep "^author=" .blog.conf | cut -d '=' -f 2)
|
||||||
|
conf_blog=$(grep "^blog=" .blog.conf | cut -d '=' -f 2)
|
||||||
|
conf_lang=$(grep "^lang=" .blog.conf | cut -d '=' -f 2)
|
||||||
|
conf_dark=$(grep "^dark=" .blog.conf | cut -d '=' -f 2)
|
||||||
|
|
||||||
|
rm -r posts
|
||||||
|
rm -r drafts
|
Loading…
Reference in New Issue
Block a user