Org Publish로 익스포트 자동화하기

2020년 7월 3일 수정

Org Publish는 Emacs에서 Org Mode로 작성된 .org 문서들로 정적 웹사이트를 만들 수 있게 자동화 해주는 도구다. 특정 디렉토리 안의 .org 파일들을 .html 파일로 익스포트 해서 원하는 디렉터리로 복사해 준다. 그리고 각종 CSS나 스크립트, 이미지 등의 파일도 자동으로 복사해 준다.

시작하기

설명을 시작하기에 앞서 아래와 같은 디렉터리에서 글을 쓴다고 가정하자.

~/org/
    static/
        style.css
    img/
        someimage.jpg
    index.org
    foobar.org
    ...

위 구조는 .org 파일로 글을 쓸 ~/org 디렉터리, CSSJavascript 파일을 넣기 위핸 ~/org/static 디렉터리, 그리고 이미지를 넣기 위핸 ~/org/img 디렉터리로 구성되어 있다고 치자.

이제 위의 디렉터리 구조를 아래와 같은 디렉터리 구조로 익스포트 하는 것을 목적으로 삼자.

~/web/
    static/
        style.css
    img/
        someimage.jpg
    index.html
    foobar.html
    ...

.org 파일 확장자가 .html 로 바뀐 거 빼곤 이름과 배치가 동일하다. 즉 이대로 원하는 서버에 올리면 그대로 정적 웹사이트가 서빙될 수 있는 형태다.

이제 이 목적에 맞게 Org Publish를 설정해보자.

필요한 모듈들

Org Publish는 다행히도 별도로 설치할 필요가 없다. Emacs이맥스에 이미 빌트인 되어있는 Org Mode의 모듈이기 때문이다. 다만 필요한 몇몇 모듈은 자동으로 로딩되지 않기 때문에 명시적으로 로드해야 할 수도 있다.

(require 'ox-publish)
(require 'ox-html)
(require 'ox-rss)

참고로 마지막의 ox-rss 모듈은 RSS를 만들기 위한 것이 아니면 필요가 없는데 나중에 필요할지도 몰라서 일단 넣어둔 상태다. 따라서 이 글에서는 꼭 필요하진 않다.

이제 본격적으로 설정 스크립트를 작성해보자.

기본 설정

Org Publish의 프로젝트 설정은 org-publish-project-alist 라는 리스트로 대부분 설정할 수 있다. 아래는 위의 목적대로 작성한 스크립트다.

(setq org-publish-project-alist
      '(("doc"
         :base-directory "~/org"
         :base-extension "org"

         :publishing-directory "~/web/"

         :recursive t

         :with-toc nil
         :with-title t
         :with-date t
         :section-numbers nil
         :html-doctype "html5"
         :html-html5-fancy t
         :html-head-include-default-style nil
         :html-head-include-scripts nil
         :htmlized-source t)
        ("static"
         :base-directory "~/org/static"
         :base-extension "css\\|js\\|png\\|jpg\\|jpeg\\|gif"
         :publishing-directory "~/web/static"
         :recursive t
         :publishing-function org-publish-attachment)
        ("img"
         :base-directory "~/org/img"
         :base-extension "png\\|jpg\\|jpeg\\|gif"
         :publishing-directory "~/web/img"
         :recursive t
         :publishing-function org-publish-attachment)))

위 설정에는 doc, static, img 의 세 가지 프로젝트가 정의되어 있다. 일단 이름은 마음대로 지을 수 있지만 가급적 디렉터리 이름과 동일하게 지었다.

doc 프로젝트의 내용은 .org 파일들이 위치하는 디렉터리에 대한 설정이다.

  • base-extension 에 명시된 확장자의 파일들을 publishing-directory 에 익스포트한다.
  • htmlized-sourcenil 이 아니기 때문에 익스포트는 HTML 형식으로 한다.

그 외에 여러 옵션이 있는데 이는 Org Mode의 Export 옵션 그 자체이기도 하니 일단 생략한다.

나머지 staticimg 프로젝트의 내용은 특정한 확장자의 파일들을 그대로 복사하도록 하기 위한 규칙이다. publishing-function 에 명시한 org-publish-attachment 함수는 말 그대로 첨부용 파일을 그대로 복사하는 용도다.

Publish 해보기

이제 실제로 편찬(publish)을 해보자. 단순하게 org-publish-all 함수를 실행시키면 된다.

M-x org-publish-all

참고로 Doom Emacs의 경우 M-x 대신 SPC : 단축키를 이용해도 동일하다.

어쨌거나 이 함수는 등록된 모든 프로젝트의 설정에 맞게 익스포트 하거나 추가하거나 수정한 파일을 자동으로 복사한다.

별 문제가 없다면 이 명령 만으로 목적대로 원하는 디렉터리에 HTML 파일들과 함께 이미지 등의 정적 파일들도 복사된다.

당연하겠지만 org-publish-all 함수나 혹은 아래에 소개할 org-publish 함수는 새로 추가된 파일이나 변경된 파일만 작업을 수행한다.

프로젝트 그룹화하기

org-publish-all 함수의 경우 등록된 모든 프로젝트를 대상으로 익스포트 및 복사 작업을 수행한다. 하지만 만약 필요한 일부 프로젝트만 골라서 익스포트 하려면 org-publish 함수를 이용할 수 있다. 예를 들어 아래 커맨드를 실행시키면 doc 프로젝트만 publish 된다.

(org-publish "doc")

참고로 Doom Emacs의 경우는 SPC ; 를 누르면 Emacs Lisp 코드를 즉석에서 입력해서 실행시킬 수 있는 프롬프트가 뜨니 여기서 위 코드를 입력해보자.

이렇게 개별 프로젝트를 출력할 수도 있는데, 프로젝트를 그룹으로 묶으면 한 프로젝트의 연관 프로젝트도 모조리 자동으로 출력되게 할 수 있다.

(setq org-publish-project-alist
      '(("doc"
         :base-directory "~/org"
         ;; ...
         )
        ("static"
         :base-directory "~/org/static"
         ;; ...
         )
        ("img"
         :base-directory "~/org/img"
         ;; ...
         )
        ("web" :components ("doc" "static" "img"))))

생략한 코드가 많은데, 그냥 앞서 설정했던 내용에서 마지막 web 을 정의하는 한 줄이 더 추가되었다고 치자. 이 코드의 의미는 web 프로젝트는 doc, static, img 라는 세 가지 컴포넌트로 구성되어 있다라는 것이다.

이제 아래 커맨드 한 줄이면 doc, static, img 세 프로젝트 모두 publish 된다.

(org-publish "web")

이런 식으로 그룹화를 할 수 있다. 하지만 꼭 할 필요 없이 위의 org-publish-all 함수를 사용하는 게 더 편할 수 있다.

전부 새로 퍼블리시 하기

굳이 그룹화를 소개한 것은 이 항목 때문이다. org-publish-all 함수는 변경되거나 새로 추가된 파일만 업데이트를 하는데, 만약 설정을 바꾸는 바람에 모든 파일을 다시 익스포트해야 한다면 이 함수가 좀 불만스러울 수 있다.

대신 이 경우 다음 명령어 한 방에 해결이 될 수도 있다.

(org-publish "PROJECT_NAME" t)

org-publish 함수의 두 번째 매개변수로 nil 이 아닌 값이 들어오게 되면 파일의 변동 여부를 검사하지 않고 지정된 퍼블리시 함수를 이용해 퍼블리시를 하게 된다.

만약 프로젝트를 그룹으로 묶어뒀다면 이 커맨드 하나로 모든 것을 강제로 새로 익스포트 할 수 있게 된다.

물론 이 기능을 자주 쓸 일은 없을지도 모르고, 또 .org 파일을 HTML로 출력하는 작업이 가장 자주 필요할거라 그룹화가 꼭 필요한 건 아니다. 편한대로 사용하자.