利用 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,需要:

  1. 创建一个 cloudflare page,指向 life 仓库,如果需要域名还可以让 cloudflare 进行托管和 CDN
  2. 在本地的 life 文件夹中复制 hugo 主题需要的文件(如果要更换主题文件,则重新修改这个文件夹就行),进行适当修改后(可以用在该文件夹用 hugo server 看看怎么样),用 git 同步到 life 仓库:[[Obsidian git教程]]
  3. 生活 文件夹用 git 同步到 生活 仓库
  4. 研究 文件夹的.obsidian 文件复制到 生活 文件夹中,进行 obsidian git commit 和 push(因为之前已经在 研究 中配置好了)
  5. 修改 研究 文件夹的 hook 中的 source_foldertarget_folder 修改为生活和 life 中对应位置
  6. 注意新建博客显示不了需要在 config.toml 中添加 timeZone 信息:解决刚创建的博客无法显示的问题 :: 喜于微 (lillianwho.com)
  7. 注释 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}")