前言
在快节奏的工作和生活中,记录想法、笔记和日记是一项非常有价值的习惯。jrnl 就是这样一款工具,它让你无需离开终端就能收集你的想法和笔记,支持自然语言日期解析、标签管理、加密保护等强大功能。
本文将详细介绍如何将 jrnl 从 Python 生态系统移植到开源鸿蒙PC平台,包括技术选型、适配策略、构建过程以及实际使用案例。
一、项目介绍
1.1 jrnl 是什么?
jrnl 是一个简单而强大的命令行日记应用,具有以下特点:
- 命令行界面: 完全在终端中操作,无需离开命令行环境
- 自然语言日期: 支持 "yesterday"、"last monday" 等自然语言日期格式
- 标签系统 : 使用
@符号添加标签,方便分类和搜索 - 加密保护: 支持 AES 加密,保护隐私内容
- 多日记支持: 可以管理多个独立的日记(如工作日记、个人日记)
- 富文本输出: 使用 rich 库提供美观的格式化输出
- 多种导出格式: 支持 JSON、YAML、XML、Markdown 等格式导出
- 强大的搜索: 支持按日期、标签、内容等条件搜索
1.2 项目基本信息
- 项目名称: jrnl
- 原始版本: 4.2.1
- 鸿蒙化版本: 4.2.2
- 许可证: GPL-3.0-only
- 源码仓库: https://github.com/jrnl-org/jrnl
- 官方网站: https://jrnl.sh
- 目标平台: OpenHarmony PC (aarch64-linux-ohos)
1.3 核心依赖
jrnl 依赖以下 Python 模块:
- colorama (>=0.4): 终端颜色支持
- cryptography (>=3.0): AES 加密库
- keyring (>=21.0): 密钥环集成,用于安全存储密码
- parsedatetime (>=2.6): 自然语言日期时间解析
- python-dateutil (>=2.8): 日期时间工具库
- pyxdg (>=0.27.0): XDG 基础目录规范支持
- ruamel.yaml (>=0.17.22): YAML 解析和生成
- ruamel.yaml.clib (>=0.2.12): ruamel.yaml 的 C 库加速
- rich (>=14.1.0,<14.2.0): 富文本格式化库
- tzlocal (>=4.0): 本地时区支持
二、技术选型与适配策略
2.1 项目类型分析
jrnl 是一个纯 Python 项目,使用 Poetry 进行依赖管理,这意味着:
- 无需编译: 不需要 C/C++ 编译器,只需要 Python 运行时
- 依赖管理: 使用 pip 管理依赖,需要安装多个 Python 模块
- 运行时要求: 必须在目标系统上安装 Python 3.10+ 运行时(比许多其他工具要求更高)
2.2 适配挑战
将 jrnl 移植到鸿蒙PC平台面临以下挑战:
- Python 版本要求高: 需要 Python 3.10+,比许多其他工具要求更高
- 依赖较多: 有 10+ 个核心依赖,包括 cryptography 等包含原生扩展的库
- 运行时检测: 需要自动检测目标系统上的 Python 3.10+ 运行时
- 模块路径管理: 确保 Python 模块路径正确设置
- 依赖安装: 在交叉编译环境中安装 pip 依赖可能失败
- 路径适配: 适配鸿蒙PC的文件系统路径结构
2.3 适配方案
方案一:运行时包装脚本
创建一个 shell 脚本作为入口,自动检测 Python 运行时并执行主程序:
bash
#!/bin/sh
# jrnl main executable script
# This script runs jrnl using Python 3
# 查找 python3 可执行文件
if command -v python3 >/dev/null 2>&1; then
PYTHON_CMD="python3"
elif [ -f "/data/app/base.org/base_1.0/sysroot/bin/python3" ]; then
PYTHON_CMD="/data/app/base.org/base_1.0/sysroot/bin/python3"
# ... 其他路径 ...
fi
# 设置 PYTHONPATH
export PYTHONPATH="${INSTALL_DIR}/lib/python3/site-packages"
# 执行 jrnl
exec "${PYTHON_CMD}" -c "
import sys
sys.path.insert(0, '${PYTHON_PATH}')
from jrnl.main import run
sys.exit(run())
" "$@"
优点:
- 灵活性强,可以适应不同的 Python 安装位置
- 不需要修改原始代码
- 符合 Unix/Linux 系统的常见做法
缺点:
- 需要额外的包装脚本
- 运行时检测可能增加启动时间
方案二:静态依赖打包
将所有依赖打包到安装目录中,避免运行时依赖问题:
bash
# 安装依赖到目标目录
pip3 install --target=${INSTALL_PATH}/lib/python3/site-packages \
--no-deps --force-reinstall \
colorama cryptography keyring parsedatetime python-dateutil \
pyxdg ruamel.yaml rich tzlocal
优点:
- 依赖完整,避免运行时缺失
- 适合离线环境
缺点:
- 包体积较大(约 11MB)
- 交叉编译时可能失败
- cryptography 等包含原生扩展的库可能需要特殊处理
方案三:依赖版本隔离
通过 PYTHONPATH 管理,避免与系统 Python 包冲突:
python
# 移除 base.hnp 的路径
base_paths_to_remove = [
'/data/app/base.org/base_1.0/lib/python3/site-packages',
'/data/app/base.org/base_1.0/sysroot/lib/python3/site-packages',
]
sys.path = [p for p in sys.path if p not in base_paths_to_remove]
# 确保我们的路径在最前面
sys.path.insert(0, our_path)
优点:
- 避免版本冲突
- 确保使用正确的依赖版本
缺点:
- 需要额外的路径管理逻辑
2.4 最终方案
采用运行时包装脚本 + 静态依赖打包 + 依赖版本隔离的组合方案:
- 构建时: 使用 pip3 安装依赖到目标目录(尽可能完整)
- 运行时: 使用包装脚本检测 Python 3.10+ 并执行主程序
- 路径管理: 通过 PYTHONPATH 隔离依赖,避免版本冲突
- 容错处理: 如果依赖安装失败,提供手动安装指导
三、构建脚本设计
3.1 构建脚本结构
bash
#!/bin/bash
# jrnl OpenHarmony build script
# jrnl is a Python CLI tool for collecting your thoughts and notes
set -e
export JRNL_INSTALL_HNP_PATH=${HNP_PUBLIC_PATH}/jrnl.org/jrnl_4.2.2
# 创建安装目录
mkdir -p ${JRNL_INSTALL_HNP_PATH}/bin
mkdir -p ${JRNL_INSTALL_HNP_PATH}/lib/python3/site-packages
mkdir -p ${JRNL_INSTALL_HNP_PATH}/share/doc/jrnl
# 检查 Python 环境(要求 3.10+)
if ! command -v python3 &> /dev/null; then
echo "Error: Python 3.10+ is not installed."
exit 1
fi
# 安装 Python 依赖
pip3 install --target=${JRNL_INSTALL_HNP_PATH}/lib/python3/site-packages \
--no-deps --force-reinstall \
colorama cryptography keyring parsedatetime python-dateutil \
pyxdg ruamel.yaml rich tzlocal || {
echo "Warning: Some dependencies may have failed to install"
}
# 复制 Python 包文件
cp -r jrnl ${JRNL_INSTALL_HNP_PATH}/lib/python3/site-packages/
# 创建启动脚本
cat > ${JRNL_INSTALL_HNP_PATH}/bin/jrnl << 'EOF'
#!/bin/sh
# ... 包装脚本内容 ...
EOF
chmod +x ${JRNL_INSTALL_HNP_PATH}/bin/jrnl
# 打包HNP和tar.gz
${HNP_TOOL} pack -i ${JRNL_INSTALL_HNP_PATH} -o ${ARCHIVE_PATH}/
tar -zvcf ${ARCHIVE_PATH}/ohos_jrnl_4.2.2.tar.gz jrnl_4.2.2/
3.2 关键步骤说明
步骤1: 环境检测(Python 3.10+)
bash
# 检查 Python 环境
if ! command -v python3 &> /dev/null; then
echo "Error: Python 3.10+ is not installed."
exit 1
fi
PYTHON_VERSION=$(python3 --version 2>&1 | awk '{print $2}' | cut -d. -f1,2)
REQUIRED_VERSION="3.10"
if [ "$(printf '%s\n' "$REQUIRED_VERSION" "$PYTHON_VERSION" | sort -V | head -n1)" != "$REQUIRED_VERSION" ]; then
echo "Error: Python version $PYTHON_VERSION is too old. Requires >= $REQUIRED_VERSION"
exit 1
fi
步骤2: 依赖安装
bash
# 安装 jrnl 的核心依赖
pip3 install --target=${JRNL_INSTALL_HNP_PATH}/lib/python3/site-packages \
--no-deps --force-reinstall \
"colorama>=0.4" \
"cryptography>=3.0" \
"keyring>=21.0" \
"parsedatetime>=2.6" \
"python-dateutil>=2.8" \
"pyxdg>=0.27.0" \
"ruamel.yaml>=0.17.22" \
"ruamel.yaml.clib>=0.2.12" \
"rich>=14.1.0,<14.2.0" \
"tzlocal>=4.0" || {
echo "Warning: Some dependencies may have failed to install"
}
注意事项:
- 使用
--no-deps标志,手动安装所有依赖 - 使用
||容错处理,避免构建失败 - cryptography 等包含原生扩展的库可能在交叉编译时失败
步骤3: 文件复制
bash
# 复制 Python 包文件
cp -r jrnl ${JRNL_INSTALL_HNP_PATH}/lib/python3/site-packages/
步骤4: 创建包装脚本
bash
# 创建启动脚本
cat > ${JRNL_INSTALL_HNP_PATH}/bin/jrnl << 'EOF'
#!/bin/sh
# ... 包装脚本内容(包含 Python 检测和路径管理)...
EOF
chmod +x ${JRNL_INSTALL_HNP_PATH}/bin/jrnl
步骤5: 打包
bash
# 打包HNP和tar.gz
${HNP_TOOL} pack -i ${JRNL_INSTALL_HNP_PATH} -o ${ARCHIVE_PATH}/
tar -zvcf ${ARCHIVE_PATH}/ohos_jrnl_4.2.2.tar.gz jrnl_4.2.2/
四、构建过程实战
4.1 环境准备
bash
# 1. 确保已安装 OpenHarmony SDK
export OHOS_SDK=/Users/lijiajun/ohos-sdk
# 2. 确保已安装 Python 3.10+ 和 pip3
python3 --version # Python 3.14.2
pip3 --version # pip 25.3
# 3. 进入构建目录
cd /Users/lijiajun/ohos-sdk/HarmonyOSPC/build
4.2 执行构建
bash
# 执行构建脚本
./build.sh --sdk /Users/lijiajun/ohos-sdk
4.3 构建输出
Build in: <Darwin ...> by cross tool chains.
python : Python 3.9.13
CC : /Users/lijiajun/ohos-sdk/native/llvm/bin/clang
...
Installation prefix: /Users/lijiajun/ohos-sdk/HarmonyOSPC/build/hnp/data/service/hnp/jrnl.org/jrnl_4.2.2
Python version: Python 3.14.2
pip version: pip 25.3
Installing Python dependencies...
Installing jrnl...
jrnl installed successfully
Installation path: /Users/lijiajun/ohos-sdk/HarmonyOSPC/build/hnp/data/service/hnp/jrnl.org/jrnl_4.2.2
Packing HNP package...
[INFO][HNP][hnp_pack.c:116]PackHnp end. ...
Creating tar.gz archive...
Build completed successfully!
4.4 构建产物
bash
# 查看构建产物
ls -lh output/
# -rw-r--r-- 1 user staff 11M jrnl.hnp
# -rw-r--r-- 1 user staff 11M ohos_jrnl_4.2.2.tar.gz
五、安装与使用
5.1 安装 jrnl
方式一:使用 HNP 包安装
bash
# 在 OpenHarmony PC 上安装
hnp install jrnl.hnp
# 或使用 tar.gz 包
tar -xzf ohos_jrnl_4.2.2.tar.gz
cp -r jrnl_4.2.2/* /data/service/hnp/jrnl.org/jrnl_4.2.2/
# 添加到 PATH(可选)
export PATH=$PATH:/data/service/hnp/jrnl.org/jrnl_4.2.2/bin
方式二:手动安装
bash
# 复制文件到安装目录
mkdir -p /data/service/hnp/jrnl.org/jrnl_4.2.2
cp -r jrnl_4.2.2/* /data/service/hnp/jrnl.org/jrnl_4.2.2/
# 确保可执行权限
chmod +x /data/service/hnp/jrnl.org/jrnl_4.2.2/bin/jrnl
# 添加到 PATH
export PATH=$PATH:/data/service/hnp/jrnl.org/jrnl_4.2.2/bin
5.2 前置要求
重要: jrnl 需要 Python 3.10+ 运行时环境。
bash
# 检查 Python 是否已安装
python3 --version
# 如果未安装或版本过低,请先安装 Python 3.10+
# Python 3.13.5 已适配鸿蒙PC,可以从 HNP 仓库安装
5.3 使用示例
示例1: 创建基本条目
bash
# 创建今天的条目
jrnl Had a great day working on my project.
输出效果:
- 在默认日记文件中创建新条目
- 自动添加当前时间戳
- 条目格式:
[2024-12-10 17:50] Had a great day working on my project.
示例2: 使用自然语言日期
bash
# 创建昨天的条目
jrnl yesterday: Called in sick. Used the time to clean the house and write my book.
输出效果:
- 条目时间戳为昨天的时间
- 格式:
[2024-12-09 17:50] Called in sick. Used the time to clean the house and write my book.
示例3: 指定具体时间
bash
# 创建指定时间的条目
jrnl last monday at 3pm: Met with the team to discuss the project.
输出效果:
- 条目时间戳为上周一 15:00
- 格式:
[2024-12-02 15:00] Met with the team to discuss the project.
示例4: 使用标签
bash
# 添加标签
jrnl Had a wonderful day at the @beach with @Tom and @Anna.
输出效果:
- 条目包含标签
@beach、@Tom、@Anna - 可以通过标签搜索这些条目
示例5: 标记重要条目
bash
# 标记为收藏
jrnl *: Best day of my life.
输出效果:
- 条目被标记为收藏(starred)
- 可以通过
-starred选项查看所有收藏条目
示例6: 查看日记
bash
# 查看所有条目
jrnl
# 查看最近 5 条
jrnl -n 5
# 查看今天的条目
jrnl -on today
输出效果:
- 显示格式化的日记条目
- 使用 rich 库提供美观的输出
- 支持分页和滚动
示例7: 搜索条目
bash
# 搜索包含特定文本的条目
jrnl -contains "project"
# 搜索特定日期的条目
jrnl -on "2024-12-10"
# 搜索日期范围
jrnl -from "2024-12-01" -to "2024-12-31"
输出效果:
- 显示匹配的条目
- 高亮搜索关键词
- 支持多个搜索条件组合
示例8: 按标签搜索
bash
# 查看所有带标签的条目
jrnl -tagged
# 查看特定标签的条目
jrnl @work
# 查看收藏的条目
jrnl -starred
输出效果:
- 显示匹配标签的条目
- 支持多个标签组合搜索
- 支持排除特定标签
示例9: 导出日记
bash
# 方式1: 使用重定向导出到当前目录(推荐)
jrnl --format json > journal.json
jrnl --format yaml > journal.yaml
jrnl --format markdown > journal.md
# 方式2: 使用 --file 参数导出到指定文件
jrnl --format json --file /home/user/journal.json
jrnl --format yaml --file /home/user/journal.yaml
jrnl --format markdown --file /home/user/journal.md
# 方式3: 使用 --file 参数导出到目录(每个条目一个文件)
jrnl --format markdown --file /home/user/exports/
# 会在 /home/user/exports/ 目录下为每个条目创建单独的文件
# 文件名格式: YYYY-MM-DD_entry-title.md
输出效果:
- 方式1和方式2: 生成单个文件,包含所有条目
- 方式3: 在指定目录下为每个条目生成单独的文件
- JSON/YAML 格式便于程序处理
- Markdown 格式便于阅读和分享
查看导出文件:
bash
# 查看当前工作目录(使用重定向时文件保存在这里)
pwd
# 查看导出的文件(单个文件方式)
ls -lh journal.*
cat journal.json
cat journal.yaml
cat journal.md
# 查看导出目录中的文件(每个条目一个文件的方式)
ls -lh /home/user/exports/
cat /home/user/exports/2025-12-10_had-a-great-day-working-on-my-project.md
# 或者使用文本编辑器打开
nano journal.json
vim journal.md
重要注意事项:
-
--file和>重定向不能同时使用- ⚠️ 错误示例 :
jrnl --format markdown > journal.md --file /path/to/dir(这是错误的) - ✅ 正确示例 :
jrnl --format markdown > journal.md或jrnl --format markdown --file journal.md
- ⚠️ 错误示例 :
-
文件保存位置
- 使用
>重定向时,文件会保存在当前工作目录 - 使用
--file参数时:- 如果指定的是文件路径,会导出为单个文件
- 如果指定的是目录路径 (以
/结尾),会为每个条目创建单独的文件
- 使用
-
文件覆盖
- 如果文件已存在,
>会覆盖原文件,使用>>可以追加内容
- 如果文件已存在,
示例10: 编辑条目
bash
# 编辑今天的条目
jrnl -on today --edit
输出效果:
- 打开配置的外部编辑器
- 可以修改、添加或删除条目
- 保存后自动更新日记文件
示例11: 多日记管理
bash
# 创建工作日记
jrnl work: Started new project today.
# 查看工作日记
jrnl work
# 在特定日记中搜索
jrnl work -contains "meeting"
输出效果:
- 创建独立的
work日记 - 可以同时管理多个日记
- 每个日记有独立的文件
示例12: 加密日记
bash
# 加密日记
jrnl --encrypt
输出效果:
- 提示输入密码
- 日记文件被加密存储
- 后续访问需要输入密码
六、实际应用场景
6.1 个人日记
场景: 记录日常生活、想法和感受
bash
# 记录今天的活动
jrnl Had a productive day. Finished the project and went for a walk.
# 记录重要时刻
jrnl *: Got promoted today! Feeling amazing!
# 记录带标签的活动
jrnl Went to @gym and had @lunch with @friends.
# 查看今天的条目
jrnl -on today
价值:
- 快速记录想法,无需打开复杂的应用
- 标签系统便于分类和查找
- 收藏功能标记重要时刻
6.2 工作日志
场景: 记录工作相关的条目
bash
# 创建工作日记
jrnl work: Completed the feature implementation.
# 记录会议
jrnl work: Attended @meeting with @team to discuss @project roadmap.
# 查看工作日记
jrnl work -n 10
# 导出工作日志
jrnl work --format json > work_log.json
价值:
- 独立的工作日记,与个人日记分离
- 便于追踪工作进度和会议记录
- 可以导出用于报告和分析
6.3 学习笔记
场景: 记录学习内容和进度
bash
# 记录学习内容
jrnl study: Learned about Python decorators today. @python @programming
# 记录学习进度
jrnl study -contains "Python" -n 5
# 查看学习统计
jrnl study --tags
价值:
- 快速记录学习要点
- 标签系统便于按主题分类
- 搜索功能快速查找相关内容
6.4 项目管理
场景: 跟踪项目进度和里程碑
bash
# 记录项目里程碑
jrnl project: Completed @milestone1. Next: @milestone2
# 查看项目相关条目
jrnl -tagged project
# 导出项目日志
jrnl -tagged project --format json > project_log.json
价值:
- 追踪项目进度
- 记录重要决策和里程碑
- 便于生成项目报告
6.5 健康追踪
场景: 记录健康相关数据
bash
# 记录锻炼
jrnl health: Ran 5km today. Feeling great! @exercise @running
# 记录饮食
jrnl health: Had a healthy @meal with lots of vegetables.
# 查看健康相关条目
jrnl health -tagged exercise
# 查看本月健康记录
jrnl health -month "december"
价值:
- 追踪健康习惯
- 记录锻炼和饮食
- 便于分析健康趋势
七、技术难点与解决方案
7.1 难点1: Python 版本要求高
问题: jrnl 需要 Python 3.10+,比许多其他工具要求更高
解决方案: 在构建脚本和运行时都进行版本检查:
bash
# 构建时检查
REQUIRED_VERSION="3.10"
if [ "$(printf '%s\n' "$REQUIRED_VERSION" "$PYTHON_VERSION" | sort -V | head -n1)" != "$REQUIRED_VERSION" ]; then
echo "Error: Python version $PYTHON_VERSION is too old. Requires >= $REQUIRED_VERSION"
exit 1
fi
# 运行时检查(在包装脚本中)
# Python 3.10+ 特性检查
7.2 难点2: 依赖较多且复杂
问题: jrnl 有 10+ 个核心依赖,包括 cryptography 等包含原生扩展的库
解决方案:
- 分步安装依赖,允许部分失败
- 提供手动安装指导
- 在文档中说明依赖要求
bash
# 安装核心依赖
pip3 install --target=${INSTALL_PATH} \
--no-deps --force-reinstall \
colorama cryptography keyring ... || {
echo "Warning: Some dependencies may have failed to install"
}
7.3 难点3: cryptography 原生扩展
问题: cryptography 包含 C 扩展,交叉编译时可能失败
解决方案:
- 允许 cryptography 安装失败
- 在文档中说明加密功能可能受限
- 提供在目标系统上重新安装的指导
7.4 难点4: keyring 系统集成
问题: keyring 可能需要系统密钥环服务支持
解决方案:
- 允许 keyring 安装失败
- jrnl 会在 keyring 不可用时回退到手动输入密码
- 在文档中说明 keyring 的限制
八、性能优化建议
8.1 依赖优化
bash
# 只安装生产依赖
pip3 install --production
# 移除不必要的依赖
pip3 prune --production
8.2 启动优化
bash
# 使用 exec 减少进程开销
exec "${PYTHON_CMD}" -c "..."
8.3 路径缓存
bash
# 缓存 Python 路径,避免重复查找
if [ -z "$JRNL_PYTHON_PATH" ]; then
JRNL_PYTHON_PATH=$(find_python_runtime)
export JRNL_PYTHON_PATH
fi
九、总结
9.1 适配成果
通过本次适配,我们成功将 jrnl 移植到开源鸿蒙PC平台:
- ✅ 构建系统: 集成 HNP 包管理系统
- ✅ 运行时检测: 自动检测 Python 3.10+ 运行时
- ✅ 依赖管理: 完整的 pip 依赖安装
- ✅ 版本隔离: 避免与系统 Python 包冲突
- ✅ 文档完善: 详细的安装和使用文档
- ✅ 实际应用: 多个实际使用场景验证
9.2 技术亮点
- 灵活的运行时检测: 支持多种 Python 安装位置
- 依赖版本隔离: 避免与系统包冲突
- 容错的依赖安装: 允许部分依赖安装失败
- 完整的文档: 包含安装、使用、故障排除等完整文档
- 实际应用验证: 多个实际场景验证工具可用性
9.3 经验总结
- Python 项目适配: 需要重点关注运行时检测和模块路径管理
- 高版本要求: Python 3.10+ 的要求需要特别处理
- 复杂依赖: 多个依赖和原生扩展需要容错处理
- 文档重要性: 详细的文档对用户使用至关重要
- 实际验证: 通过实际场景验证工具可用性
9.4 未来改进方向
- 依赖优化: 进一步优化依赖安装,减少包体积
- 性能优化: 优化启动速度和运行时性能
- 功能扩展: 考虑添加更多实用功能
- 社区贡献: 回馈开源社区,分享适配经验