利用 git hook 实现自动同步
这段 python 代码实现在 obsidian 中同步 published 值为 true 的文档,并发布到自动化 hugo 构建的 cloudflare page 上。
来源于:lillianwho.com/posts/obsidian-hugo-cloudflare/
只不过我把 hugo 文件夹和个人笔记严格区分开,用 obsidian git 进行自动化 commit 的时候触发一个 pre-commit hook,这个 hook 将 published 值为 true 的笔记同步到 hugo 文件夹,并在 hugo 文件夹执行 git commit 和 push。相当于一个 commit 操作时,发生了两次 commit ,一次是 OB 笔记的提交,然后是 OB 笔记同步到 Hugo 文件,然后 Hugo 文件提交到 cloudflare 中,由 Hugo 文件所在的库来实现网页。
具体工作流
如果我想要创建一个关于生活的 page,需要:
- 创建一个 cloudflare page,指向
life
仓库,如果需要域名还可以让 cloudflare 进行托管和 CDN - 在本地的
life
文件夹中复制 hugo 主题需要的文件(如果要更换主题文件,则重新修改这个文件夹就行),进行适当修改后(可以用在该文件夹用hugo server
看看怎么样),用 git 同步到life
仓库:[[Obsidian git教程]] - 在
生活
文件夹用 git 同步到生活
仓库 - 将
研究
文件夹的.obsidian 文件复制到生活
文件夹中,进行 obsidian git commit 和 push(因为之前已经在研究
中配置好了) - 修改
研究
文件夹的 hook 中的source_folder
和target_folder
修改为生活和 life 中对应位置 - 注意新建博客显示不了需要在 config.toml 中添加 timeZone 信息:解决刚创建的博客无法显示的问题 :: 喜于微 (lillianwho.com)
- 注释 footer.html 中的 bber 还有 wormhole,在 single.html 中,把阅读更多的链接替换成 qoclub.site
pre-commit hook 代码如下
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import glob
import shutil
import yaml
import pathlib
import logging
import os
import subprocess
import datetime
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
now = datetime.datetime.now()
now_str = now.strftime("%Y-%m-%d %H:%M:%S")
commit_msg = f"linqy@OS4ever: {now_str}"
# 源文件夹和目标文件夹的路径
source_folder = pathlib.Path(r'E:\03 Backups\Onedrive\OneDrive - 华南师范大学\桌面\笔记汇总\研究')
target_folder = pathlib.Path(r"E:\01 Ongoing\Note\hugo\content\posts")
# 要同步的子文件夹列表
subfolders_to_sync = ['文献笔记', '软件代码', '材料合成', '表征处理']
skip_folder = pathlib.Path(r"E:\03 Backups\Onedrive\OneDrive - 华南师范大学\桌面\笔记汇总\研究\软件代码\OB模板")
# 遍历源文件夹中的所有子文件夹
for subfolder_name in subfolders_to_sync:
subfolder_path = source_folder / subfolder_name
md_files = glob.glob(str(subfolder_path / "**" / "*.md"), recursive=True) # **表示递归遍历所有子文件夹
for file_path in md_files: # 遍历子文件夹中的所有文件
file_path = pathlib.Path(file_path)
if file_path.parent == skip_folder: # 如果是跳过的文件夹
continue
with open(file_path, encoding="utf-8") as f:
content = f.read()
# 检查published值是否为true
yaml_start = content.index("---")
yaml_end = content.index("---", yaml_start + 3)
yaml_content = content[yaml_start + 3:yaml_end]
yaml_dict = yaml.safe_load(yaml_content)
if "published" in yaml_dict and yaml_dict["published"] == True:
relative_folder = file_path.parent.relative_to(subfolder_path)
target_subfolder = target_folder / subfolder_name / relative_folder # 获取目标文件的完整路径
target_subfolder.mkdir(parents=True, exist_ok=True)
shutil.copy2(file_path, target_subfolder) # 复制
elif "published" in yaml_dict and yaml_dict["published"] == False:
relative_folder = file_path.parent.relative_to(subfolder_path)
target_subfolder = target_folder / subfolder_name / relative_folder
target_file = target_subfolder / file_path.name
if target_file.exists():
target_file.unlink() # 删除
# 删除目标文件夹中不存在于源文件夹中的文件和文件夹
for root, dirs, files in os.walk(target_folder):
for dir_name in dirs:
# 获取文件夹的完整路径
dir_path = pathlib.Path(root) / dir_name
# 获取相对路径,并获取父文件夹的名称
rel_dir_path = dir_path.relative_to(target_folder)
parent_dir_name = rel_dir_path.parts[0]
# 检查文件夹是否不存在于源文件夹中,并且是否位于保留的子文件夹中
if not (source_folder / rel_dir_path).exists() and parent_dir_name in subfolders_to_sync:
# 删除文件夹
shutil.rmtree(dir_path)
for file_name in files:
# 获取文件的完整路径
if file_name == "_index.md": # 跳过_index.md文件
continue
file_path = pathlib.Path(root) / file_name
# 获取相对路径,并获取父文件夹的名称
rel_file_path = file_path.relative_to(target_folder)
parent_dir_name = rel_file_path.parts[0]
# 检查文件是否不存在于源文件夹中,并且是否位于保留的子文件夹中
if not (source_folder / rel_file_path).exists() and parent_dir_name in subfolders_to_sync:
# 删除文件
file_path.unlink()
os.chdir(r"E:\01 Ongoing\Note\hugo")
try:
subprocess.run(["git", "add", "."], check=True)
subprocess.run(["git", "commit", "-m", commit_msg], check=True)
subprocess.run(["git", "push"], check=True)
logging.info("Git commands executed successfully")
except subprocess.CalledProcessError as e:
logging.error(f"Git commands failed with error code {e.returncode}")