Obsidian上的内容自动化构建为Hugo博客

说明

篇幅长且啰嗦,内容只是我的 Hugo 博客文章是如何实现“自动化”构建的一份记录。

首先,以下内容仅且只是我个人按自己的需求一步步实现的所谓“自动化”,其中很多步骤用处不大,只是我个人有自己的小需求才特意加上去,所以以下内容仅供参考,实现方法其实挺笨的,但胜在能满足我个人需求了。

再次,本篇内容默认运行在一般的开发环境已经搭建完成的电脑上,环境搭建可参考:

https://laomai.org/archives/macos-env-setup-record-sharing/

Hugo

一款基于 Go 语言的静态网站生成工具,我是从 20 年 8 月中旬开始接触 Hugo 的,一直以来都有在使用,哪怕是期间换成了 Wordpress,我依然觉得静态的个人博客才是我所需要的且是我博客的最终形态。所以在我云服务器将要过期的时候,我又一次将博客的程序换回了 Hugo,并且直接托管在 Github Pages 上,虽然国内访问的速度会很慢,但架不住它不用钱啊,免费还是很香的。

官网地址:

https://gohugo.io

安装 extended 这个版本,在 Github 上直接下载并解压,将解压后的 hugo 目录移动到/usr/local/目录下,然后配置一下变量即可。

# 编辑配置文件
vim ~/.zshrc

# 在适当的位置添加
export PATH="/usr/local/hugo:$PATH"

# 保存退出后重新加载配置文件
source ~/.zshrc

Hugo 的版本更新迭代速度挺快的,当时为了使用带扩展的版本,就用了上面的方法去安装,在 Hugo 的频繁更新下,这种安装方法更新起来还是很麻烦的。前段时间在大峰那看到他用 Homebrew 来安装,我就去 Homebrew 的官网那里搜了下文档,这时才发现原来 Homebrew 安装的 Hugo 默认就是带扩展的版本,特意在虚拟机上验证了一下,的确是带扩展的版本,因此建议直接使用 Homebrew 安装 Hugo

laomai@debian:~$ brew install hugo
Running `brew update --auto-update`...
==> Fetching dependencies for hugo: linux-headers@5.15, glibc, gmp, isl, mpfr, libmpc, lz4, xz, zlib, zstd, binutils and gcc
==> Fetching linux-headers@5.15
==> Downloading https://mirrors.ustc.edu.cn/homebrew-bottles/linux-headers%405.15-5.15.92.x86_64_linux.bottle.tar.gz
Already downloaded: /home/laomai/.cache/Homebrew/downloads/51f6a08c797a657e5131eadef86eb085539a51dd111daf28744c8743cdd4251a--linux-headers@5.15-5.15.92.x86_64_linux.bottle.tar.gz
……
🍺  /home/linuxbrew/.linuxbrew/Homebrew/Cellar/hugo/0.110.0: 48 files, 53.4MB
==> Running `brew cleanup hugo`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
==> Caveats
==> hugo
Bash completion has been installed to:
  /home/linuxbrew/.linuxbrew/Homebrew/etc/bash_completion.d
laomai@debian:~$ hugo version
hugo v0.110.0+extended linux/amd64 BuildDate=unknown

https://github.com/Homebrew/homebrew-core/blob/master/Formula/hugo.rb#L22

Obsidian

我关注这个软件是在博客圈讨论笔记软件那会,我在对比试用过 Obsidian 和 Logseq 后选择了前者,Logseq 也十分的优秀,但是后者更适合我。其实我个人是更喜欢 Typora 的,但无奈它收费了。喜欢 Typora 是因为它简单易用,Obsidian 的强大是要花时间去学习、摸索后才能使之发挥起来,对于我来说,这不够直接,扣分。

Obsidian 新建仓库时建议直接在 iCloud 上新建,这样就可以简单地实现远程备份与同步的功能了。如果你也是用 Obsidian 来管理更新 Hugo 上的文章内容,那么装以下两个插件可以更加便捷的帮助我们整理内容。

Templater

第三方插件,用来管理模板。功能很强大,但我只用了一个功能,就是在特定的文件夹里新建文件时自动套用指定的模板。

一、先在 Obsidian 仓库根目录新建一个目录用来存放模板文件——文章模板.md

截屏2023-02-11 10.47.46

我使用了 Templater 上的时间函数,这样新建文档时就会在 date 这一栏自动添加当前时间。同理,在 title 这一栏里可以使用91. 「毛毛」生日快乐这个函数实现自动将文档的文件名输入进来。我的文章是以文件夹的形式保存的(文件夹名字就是文章的 title),因此 title 这一栏我并不适用,折中的办法是改用post这个函数,但是这并不完美,会将 post 也输入进来。

二、开启插件的文件夹模板功能;

截屏2023-02-11 10.43.01

Image auto upload Plugin

第三方插件,配合 PicGo 来食用。以前我是将文档里的图片存放在文档所在目录里的,这样子的确很好整理与迁移。但一旦时间久了,图片多了,整个 post 文件夹就会变得十分臃肿,再三思考,决定还是用回图床的模式。

Obsidian 上强大的插件还有很多,但是与此内容不符,因此就不再深入探究了。

自动化构建

自动化流程

上图是我根据自己的实际情况做的一个过程图,所谓的“自动化”其实就是利用 Crontab 与 Git 来实现每隔一段时间就自动进行提交内容到 Github 上。其中我先将文章内容与代码都先提交到 Gitee 后又重新拉取文档文件回 Nas 里是因为方便区分与多重备份,可根据自己的实际情况将这些步骤去掉,直接从 iCloud 里复制文档内容到 Temp 里进行构建。

我的自动化构建过程大概就是:

一、在$HOME目录下创建.crontab-sh目录,同时在目录里新建一个脚本文件;

# 在$HOME目录下创建隐藏文件夹.crontab-sh
mkdir ~/.crontab-sh
# 创建脚本文件
touch ~/.crontab-sh/autoPush.sh

二、安装好 Obsidian 后创建仓库时文档保存的路径选择保存在 iCloud 里,Windows 直接保存在本地即可;

三、将 Hugo 上保存文章的文件夹复制到上面新建的仓库里,比如我的是 post 和 diary 这两个文件夹;

四、在 Obsidian 仓库里创建 Git 并添加远程仓库 Gitee;

Obsidian 仓库详细路径可以在菜单栏 File ☞ Open Vault… 上查看,值得注意的是,因为 iCloud 目录默认保存在/Users/laomai/Library/Mobile Documents/目录下,Mobile 后面有个空格,所以使用 cd 命令时需在空格前加一个反斜杠\

# 进入Obsidian仓库目录
cd /Users/laomai/Library/Mobile\ Documents/com~apple~CloudDocs/laomai.org
# 创建Git
git init
# 添加远程仓库
git remote add gitee git@gitee.com:laomai/laomai.org.git

五、编辑步骤一创建的脚本文件;

# 编辑脚本文件
vim ~/.crontab-sh/autoPush.sh

将以下内容复制到脚本文件里:

#!/bin/bash

echo -e "\033[0;32mDeploying updates to laomai...\033[0m"
msg="Push at `TZ=UTC-8 date +%Y-%m-%d" "%H:%M:%S`"
if [ $# -eq 1 ]
then msg="$1"
fi

# 该目录为Obsidian仓库目录
cd /Users/laomai/Library/Mobile\ Documents/com~apple~CloudDocs/laomai.org
git add .
git commit -m "$msg"
git push -u gitee main

六、从 Gitee 里拉取 Obsidian 的文档文件备份到 Nas 上;

因为我担心在终端上折腾群晖系统会影响到它的稳定性,所以我在群晖上跑了个虚拟机专门用来折腾,这时就会涉及到文件共享。就我个人而言,我家里一直有两个虚拟机长期运行着的,一个跑在 Nas 上,一个跑在软路由上,跑在软路由上的虚拟机我平时很少动,它主要负责跑一些线上的小程序,只求稳定。跑在 Nas 上的虚拟机则是用来测试的,符合我要求的线上程序我就会搬到软路由上的虚拟机上跑。按理说 Nas 上的虚拟机完全可以跑在电脑上的,但是因为架构的原因,无奈之下在 Nas 上也跑了个虚拟机。加上电脑上有时也会跑两个 ARM 架构的虚拟机,所以这么多虚拟机之间的文件共享就成了问题。我现在使用的方案是,资料集中存储到群晖上,然后虚拟机上安装 NFS 进行调用。至于 MacOS 直接使用 AFP 服务,体验更佳。

群晖上开启相应的服务:控制面板 ☞ 文件服务 ☞AFP/NFS☞ 勾选启用;

NFS 客户端安装:

以 Debian11 为例,root 用户。

# 安装nfs-common 系统一般自带
apt install nfs-common
# 测试挂载远程目录到/home/nas
# IP为群晖的内网IP
# volume1为群晖的存储池 存储池可以是多个 volume2,volume3,……
# laomai为存储池1上的共享文件夹
mount -t nfs 192.168.1.100:/volume1/laomai /home/nas
#查看
df
# 取消挂载
umount -l /home/nas
# 安装autofs
apt install autofs
# 配置autofs主体文件
vim /etc/auto.master
#/misc	/etc/auto.misc
/home/nas  /etc/auto.nas
# 配置auto.nas
vim /etc/auto.nas
# 这里有点难懂,我的理解是当我们在/home/nas这个目录时,只要我们cd laomai
# 进入/home/nas/laomai这个目录时就会触发autofs,从而自动挂载到远程目录上
laomai	-rw	192.168.1.100:/volume1/laomai
# 重启autofs服务
systemctl restart autofs.service

为了可以快速进入这个挂载的远程目录,可以添加一条 alias,这样子在终端里一敲 nas 就会自动进入远程目录了。在配置文件适当的位置添加以下命令:

alias nas='cd /home/nas/laomai/'

哈哈哈,好像扯很远了,回到将 Push 到 Gitee 里文档文件备份到 Nas 上这个问题里,既然有虚拟机 24 小时在跑,那么以下所有自动化都会跑在上面那个 Debian11 的虚拟机上。

# 进入挂载好的远程目录
cd /home/nas/laomai
# 创建并进入obsidian目录
mkdir obsidian && cd obsidian
# 创建Git
git init
# 添加远程仓库
git remote add gitee git@gitee.com:laomai/laomai.org.git
# 拉取
git pull gitee main

七、创建 Temp 目录并创建相对应的 Crontab 脚本;

这个目录的作用是组合 Hugo 程序与文章,然后推送到 Github,再让 Github Actions 完成真正的自动化构建。上面的流程图可以看到,我在个性配置或者修改主题时,也是用 Git 去管理代码。平时开发就用 Dev 分支,完成一个功能或者版本时就合并到 Main 这个主分支上,Temp 拉取 Hugo 程序时只会拉取 Main 这个主分支,两个分支很好的避免了开发到一半时就被 Crontab 脚本自动拉取并推送到线上。

# 进入挂载好的远程目录
cd /home/nas/laomai
# 创建并进入Temp目录
mkdir Temp && cd Temp
# 创建Git
git init
# 添加远程仓库
# 这里添加两个远程仓库 从Gitee上拉取 推送到Github
# Gitee这个仓库与上面的仓库不是同一个 这个是用来托管我对Hugo的个性配置和主题的
git remote add gitee git@gitee.com:laomai/newHugo.git
git remote add github git@github.com:laomai/newHugo.git

接下来编辑虚拟机上的脚本,同样在$HOME目录创建一个.crontab-sh的隐藏目录。

# 在$HOME目录下创建隐藏文件夹.crontab-sh
mkdir ~/.crontab-sh
# 分别创建并编辑脚本文件
# 脚本内容为下方对应的代码块
vim ~/.crontab-sh/autoPull.sh
vim ~/.crontab-sh/buildHugo.sh

autoPull.sh用作自动拉取文章内容:

#!/bin/bash

cd /home/nas/laomai/obsidian
git pull gitee main

buildHugo.sh用作自动推送到 Github 上自动化构建:

#!/bin/bash

echo -e "\033[0;32mDeploying updates to laomai...\033[0m"
msg="rebuilding site `TZ=UTC-8 date +%Y-%m-%d" "%H:%M:%S`"
if [ $# -eq 1 ]
then msg="$1"
fi

cd /home/nas/laomai/Temp
# 拉取Gitee上的Main分支
git pull gitee main --rebase

# 将Obsidian上的文章内容复制过来
/bin/cp -rf /home/nas/laomai/obsidian/老麦笔记/diary /home/nas/laomai/Temp/content
/bin/cp -rf /home/nas/laomai/obsidian/老麦笔记/post /home/nas/laomai/Temp/content

# 推送到Github
git add .
git commit -m "$msg"
git push -u --force github main

关于将文章内容复制,为什么cp这个命令要在前面加上/bin?其实在终端上输入alias就会明白了。

root@debian:~# alias
alias cp='cp -i'
alias l='ls $LS_OPTIONS -lA'
alias ll='ls $LS_OPTIONS -l'
alias ls='ls $LS_OPTIONS'
alias mv='mv -i'
alias nas='cd /home/nas/laomai/'
alias rm='rm -i'

cp这个命令默认就绑定了覆盖前询问的参数,所以直接使用/bin/cp将覆盖前询问这一步去掉。

八、创建 Crontab 定时任务;

目前为止我一共创建三个脚本,一个是在 Mac 上运行的,两个是在虚拟机上运行的。

Mac:

# 编辑计时器
crontab -e

# 每隔十分钟运行一次脚本
*/10 * * * * /etc/profile;/bin/sh /Users/laomai/.crontab-sh/autoPush.sh > /dev/null 2>&1

虚拟机:

# 编辑计时器
crontab -e

# 每隔五分钟运行一次脚本
*/5 * * * * /etc/profile;/bin/sh /root/.crontab-sh/autoPull.sh > /dev/null 2>&1

# 每隔两小时运行一次脚本
0 */2 * * * /etc/profile;/bin/sh /root/.crontab-sh/buildHugo.sh > /dev/null 2>&1

九、GitHub Actions

在存放 Hugo 程序的 GitHub 仓库上开放 Workflow 的权限,不是 Github 设置,是仓库的设置。

进入仓库 ☞Settings☞Actions☞General☞Workflow permissions☞ 选择 Read and write permissions 与勾选 Allow Github Actions to create and approve pull requests

在 Hugo 程序根目录上新建.github/workflows/main.yml文件,路径要符合 Github Actions 的规则。

添加以下内容:

# This is a basic workflow to help you get started with Actions

name: build laomai.org

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the "main" branch
  push:
    branches: ['main']

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v3
      - name: Hugo setup
        # You may pin to the exact commit or the version.
        # uses: peaceiris/actions-hugo@2e89aa66d0093e4cd14751b3028fc1a179452c2e
        uses: peaceiris/actions-hugo@v2.4.13
        with:
          # The Hugo version to download (if necessary) and use. Example: 0.58.2
          hugo-version: 0.110.0
          # Download (if necessary) and use Hugo extended version. Example: true
          extended: true
      - name: Build Hugo
        run: hugo --minify

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public

十、去掉 MacOS 和群晖系统上多出来的文件与目录;

在 Hugo 程序根目录上添加 Git 的忽略规则,新建.gitignore文件:

public
node_modules
.vscode
.prettierrc
@eaDir
.DS_Store