관련노트

메타노트

Overview

Denote 노트를 Hugo로 내보내는 통합 시스템. dblock 업데이트와 export를 하나의 워크플로우로 관리.

주요 기능

  • 통합 관리: dblock 갱신 + Hugo export를 단일 스크립트로
  • Daemon 기반: 패키지 로딩 1회, 18x 성능 향상
  • Unicode 완벽 지원: NBSP(U+00A0), 한글, 특수문자 안전 처리
  • Bibliography 통합: Citar/org-cite로 인용 링크 자동 생성
  • 메모리 관리: 주기적 GC로 2000+ 파일 안정 처리

성능

작업파일 수시간속도
dblock (순차)530~11초50 files/sec
export (병렬 2 daemon)1,976~33분1.0 files/sec
export (병렬 4 daemon)1,976~18분1.8 files/sec

배포 파이프라인

┌─────────────────────────────────────────────────────────────┐
│                    Digital Garden Pipeline                   │
├─────────────────────────────────────────────────────────────┤
│  1. dblock 갱신     ~/org/meta → denote-links 업데이트      │
│         ↓                                                    │
│  2. Hugo export     ~/org/{meta,bib,notes} → markdown       │
│         ↓                                                    │
│  3. 후처리          clean-run.sh (secretlint, sed)          │
│         ↓                                                    │
│  4. 배포            Quartz build → GitHub Pages              │
└─────────────────────────────────────────────────────────────┘

Architecture

파일 구조 (v2.0 - 통합)

doomemacs-config/
├── bin/
│   ├── denote-export.sh          # 통합 wrapper (dblock + export)
│   ├── denote-export-parallel.py # Python 병렬 처리
│   ├── denote-export.el          # 통합 Elisp (daemon/dblock/export)
│   │
│   ├── [DELETED] denote-export-batch.el      # obsolete
│   ├── [DELETED] denote-export-server.el     # → denote-export.el
│   ├── [DELETED] denote-dblock-batch.el      # → denote-export.el
│   └── [DELETED] denote-dblock-update.sh     # → denote-export.sh

├── lisp/
│   └── denote-export.el          # Interactive export 설정

└── docs/
    ├── 20251221T120044--denote-export-unified-system.org  # 이 문서
    ├── [LEGACY] 20251027T092900--denote-export-system.org
    └── [LEGACY] 20251110T190854--denote-dblock-update-system.org

통합 el 파일 구조

;;; bin/denote-export.el --- Unified Denote Export System
 
;;;; 1. 초기화
;; - gc-cons-threshold (most-positive-fixnum → 16MB)
;; - UI 비활성화 (daemon용)
;; - package.el 비활성화 (ELPA 방지)
 
;;;; 2. Doom 패키지 로딩
;; - find-straight-build-dir (버전 무관)
;; - load-path + autoloads 설정
 
;;;; 3. 필수 패키지 require
;; Built-in: org, ox, cl-lib, seq, json, browse-url
;; Doom: dash, denote, ox-hugo, citar, parsebib
;; Org-cite: oc, oc-basic, oc-csl
;; Denote: denote-regexp → denote-org-extras → denote-explore
 
;;;; 4. 설정 로딩
;; - +user-info.el (config-bibfiles, user-hugo-blog-dir)
;; - lisp/denote-export.el
;; - Bibliography 초기화
;; - 매크로 확장 설정
 
;;;; 5. Helper 함수들
;; - extract-denote-id-from-filename
;; - get-org-hugo-section-from-path
 
;;;; 6. Dblock 함수들
;; - denote-dblock-update-file
;; - denote-dblock-update-directory
 
;;;; 7. Export 함수들
;; - denote-export-file
;; - denote-export-batch-files
;; - denote-export-directory
 
;;;; 8. 메모리 관리
;; - denote-export-file-counter
;; - denote-export-gc-interval (50 files)
;; - gc-cons-threshold 리셋 (16MB)
 
;;;; 9. Server 시작
;; - denote-export-server-ready = t
;; - (server-start)

처리 흐름

dblock

export

all

denote-export.sh

명령어

싱글 데몬 시작

denote-dblock-update-directory

org-update-all-dblocks

데몬 종료

멀티 데몬 시작 N개

Python ProcessPoolExecutor

Round-robin 파일 분배

denote-export-file × N

ox-hugo + Denote ID rename

데몬 정리

dblock → export 순차

~/repos/gh/notes/content/

clean-run.sh 후처리

Usage

명령어 구조

denote-export.sh <command> [options]
 
Commands:
  dblock [dir]           # dblock 업데이트 (싱글 데몬)
  export <target> [n]    # Hugo export (멀티 데몬)
  all [n]                # dblock + export 전체
 
Targets (export):
  all                    # meta, bib, notes 순차
  meta                   # ~/org/meta
  bib                    # ~/org/bib
  notes                  # ~/org/notes
  test                   # ~/org/test (빠른 검증)
  run <dir>              # 커스텀 디렉토리
 
Options:
  n                      # 데몬 개수 (기본: 2)

기본 사용법

# 전체 배포 (권장)
./bin/denote-export.sh all
 
# dblock만 갱신 (meta)
./bin/denote-export.sh dblock
./bin/denote-export.sh dblock ~/org/meta
 
# export만 (특정 디렉토리)
./bin/denote-export.sh export meta 4
./bin/denote-export.sh export notes 2
 
# 커스텀 디렉토리
./bin/denote-export.sh export run ~/custom/path 4

후처리

cd ~/repos/gh/notes/
./clean-run.sh
 
# 또는 개별 실행
./lint.sh              # secretlint 검증
./change-text.sh       # sed 치환
npx quartz build       # 정적 사이트 생성

Technical Details

패키지 로딩 (핵심)

Doom Emacs의 straight.el 패키지를 batch/daemon 모드에서 로딩하는 방법:

;; 1. ELPA 완전 비활성화 (중요!)
(setq package-enable-at-startup nil)
(setq package-archives nil)
(fset 'package-initialize #'ignore)
(fset 'package-install (lambda (&rest _)
  (error "ELPA is disabled! Use Doom's straight packages only")))
 
;; 2. straight build 디렉토리 찾기 (버전 무관)
(defun find-straight-build-dir ()
  (let ((base (expand-file-name ".local/straight/" doom-emacs-dir)))
    (when (file-directory-p base)
      (car (sort (directory-files base t "^build-")
                 #'file-newer-than-file-p)))))
 
;; 3. 패키지 디렉토리 + autoloads 로딩
(let ((build-dir (find-straight-build-dir)))
  (dolist (pkg-dir (directory-files build-dir t "^[^.]" t))
    (add-to-list 'load-path pkg-dir)
    ;; autoloads 파일도 로딩 (중요!)
    (let ((autoload (expand-file-name
                     (concat (file-name-nondirectory pkg-dir)
                             "-autoloads.el")
                     pkg-dir)))
      (when (file-exists-p autoload)
        (load autoload nil t)))))

필수 패키지 목록

카테고리패키지용도
Built-inorg, oxOrg-mode export
Built-incl-lib, seq리스트 처리
Built-injson, browse-url유틸리티
Doomdash함수형 유틸
DoomdenoteDenote 코어
Doomox-hugoHugo 변환
Doomcitar, parsebib서지 관리
Org-citeoc, oc-basic, oc-csl인용 처리
Denotedenote-regexp정규식 (의존성)
Denotedenote-org-extrasdblock 함수
Denotedenote-explore매크로

dblock vs Export 차이

항목dblockexport
파일 의존성상호 참조 (스캔 필요)독립적
병목I/O (디렉토리 스캔)CPU (마크다운 변환)
병렬 효과오히려 느려짐4-8배 향상
권장 방식순차 (싱글 데몬)병렬 (멀티 데몬)
처리 속도50 files/sec1-2 files/sec

Unicode 안전 처리

파일명에 NBSP(U+00A0) 등 특수문자가 있을 때 쉘 quoting 문제 발생:

# ❌ 쉘 명령어로 파일 전달 시 깨짐
subprocess.run(['emacs', '--eval', f'(export "{filepath}")'])
 
# ✅ Python에서 파일 목록 생성, Elisp에서 직접 처리
org_files = sorted(directory.glob("*.org"))  # Python 유니코드 완벽 지원
for file in org_files:
    # emacsclient로 파일 경로 전달
    elisp_cmd = f'(denote-export-file "{file}")'

메모리 관리

2000+ 파일 처리 시 메모리 누수 방지:

;; 1. 초기화 시 GC 비활성화 (빠른 로딩)
(setq gc-cons-threshold most-positive-fixnum)
 
;; 2. 초기화 완료 후 GC 리셋 (16MB)
(setq gc-cons-threshold (* 16 1024 1024))
(garbage-collect)
 
;; 3. 주기적 GC (50 파일마다)
(defvar denote-export-gc-interval 50)
(defvar denote-export-file-counter 0)
 
(defun denote-export-file (file)
  (setq denote-export-file-counter (1+ denote-export-file-counter))
  (when (zerop (mod denote-export-file-counter denote-export-gc-interval))
    (garbage-collect))
 
  ;; 4. 버퍼 정리 (unwind-protect)
  (let ((buf (find-file-noselect file)))
    (unwind-protect
        (with-current-buffer buf
          ;; export 로직
          )
      ;; 항상 버퍼 정리
      (when (buffer-live-p buf)
        (kill-buffer buf)))))

데몬 라이프사이클

# 시작
subprocess.Popen(['emacs', '--quick',
                  f'--daemon={daemon_name}',
                  '--load', 'denote-export.el'])
 
# 준비 대기 (ready flag 체크)
while not ready:
    result = subprocess.run(
        ['emacsclient', '-s', daemon_name,
         '--eval', "(boundp 'denote-export-server-ready)"])
    if 't' in result.stdout:
        ready = True
 
# 종료
subprocess.run(['emacsclient', '-s', daemon_name,
                '--eval', '(kill-emacs)'])
 
# 강제 정리 (interrupt 시)
subprocess.run(['pkill', '-f', 'denote-export-daemon'])

Configuration

.dir-locals.el 설정

;; ~/org/meta/.dir-locals.el
((org-mode . ((org-hugo-section . "meta")
              (org-hugo-base-dir . "~/repos/gh/notes/"))))
 
;; ~/org/notes/.dir-locals.el
((org-mode . ((org-hugo-section . "notes")
              (org-hugo-base-dir . "~/repos/gh/notes/"))))
 
;; ~/org/bib/.dir-locals.el
((org-mode . ((org-hugo-section . "bib")
              (org-hugo-base-dir . "~/repos/gh/notes/"))))

+user-info.el 설정

;; Bibliography 파일 경로
(defvar config-bibfiles
  '("~/org/bib/references.bib"
    "~/org/bib/books.bib"))
 
;; Hugo 블로그 디렉토리
(defvar user-hugo-blog-dir
  (expand-file-name "~/repos/gh/notes/"))
 
;; Org 디렉토리
(defvar user-org-directory
  (expand-file-name "~/org/"))

데몬 개수 권장값

시스템 메모리권장 데몬 수비고
8GB2기본값
16GB4안정적
32GB+8최대 성능

Troubleshooting

데몬 좀비 프로세스

# 상태 확인
ps aux | grep denote-export-daemon
 
# 강제 종료
pkill -f "denote-export-daemon"
 
# 소켓 정리
rm -f /tmp/emacs$(id -u)/denote-export-daemon-*

패키지 로딩 실패

# 에러: "dash not found in Doom"
# 해결: Doom 패키지 재빌드
doom sync
doom build

dblock 업데이트 에러

에러: "Error during update of dynamic block"
 
원인:
- denote-org-extras 미로딩 (seq 누락 등)
- denote-directory 미설정
 
해결:
1. denote-export.el에서 (require 'seq) 확인
2. (setq denote-directory "~/org/") 확인

Export 실패 (개별 파일)

;; 테스트
(find-file "~/org/notes/test.org")
(org-hugo-export-to-md)
 
;; 로그 확인
(switch-to-buffer "*Messages*")

Ctrl+C 인터럽트 후 정리

# Python 스크립트는 signal handler로 자동 정리
# 만약 남아있다면:
pkill -f "denote-export-daemon"

Migration from Legacy

기존 파일 매핑

기존 파일새 파일비고
denote-export-server.eldenote-export.elrename + 통합
denote-dblock-batch.eldenote-export.el함수 통합
denote-export-batch.el(삭제)obsolete
denote-dblock-update.shdenote-export.shdblock 명령 통합

명령어 매핑

기존 명령새 명령
./denote-dblock-update.sh ~/org/meta./denote-export.sh dblock
./denote-export.sh meta 4./denote-export.sh export meta 4
(수동 순차)./denote-export.sh all

Performance History

v1.0 → v2.0 개선

버전방식1962 파일 시간속도
v1.0Batch 순차~10시간0.05 files/sec
v1.3Daemon 순차~2.5시간0.22 files/sec
v1.4Daemon 병렬(4)~18분1.8 files/sec
v2.0통합 + 최적화~15분 (예상)2.0+ files/sec

개선 포인트 (v2.0)

  • 패키지 로딩 통합 (dblock + export 동일 환경)
  • seq 패키지 누락 수정
  • 데몬 라이프사이클 통합 관리
  • 메모리 관리 일원화

Changelog

[2025-12-21 Sun] v2.0.0 - Unified System

주요 변경

  • denote-export.el 통합 (server + dblock)
  • denote-export.sh에 dblock 명령 추가
  • obsolete 파일 삭제 (batch.el, dblock-update.sh)
  • 패키지 로딩 버그 수정 (seq 누락)

파일 구조 개선

  • 8개 → 4개 파일로 단순화
  • 단일 el 파일로 관리 용이성 향상
  • 문서 통합

[2025-12-17 Wed] v1.5.x - Memory Management

  • gc-cons-threshold 리셋 (16MB)
  • 주기적 GC (50 파일마다)
  • 기본 데몬 4 → 2개로 감소 (안정성)

[2025-10-29 Wed] v1.4.0 - Production Ready

  • server-start 누락 해결
  • Unicode 파일명 완벽 지원
  • 1961 파일 100% 성공률

[2025-10-28 Tue] v1.3.0 - Server Mode

  • Daemon 방식 도입 (18x 성능 향상)
  • 파일명 기반 Denote ID 추출
  • 디렉토리 기반 Section 자동 결정

References

Legacy Documents

이 문서는 다음 문서들을 통합/대체합니다:

  • [Denote Export System (Legacy)]
  • [Denote dblock Update System (Legacy)]

License

GPLv3

지식베이스 퍼블리싱의 새로운 패러다임:

  • Denote: 파일명 기반 PKM (DB 불필요)
  • ox-hugo: Org → Hugo 변환
  • Daemon: 빠른 배치 처리
  • Unicode: 한글 제목, 특수문자 완벽 지원