org-roam-migrate.el (6711B)
1 ;;; org-roam-migrate.el --- Migration utilities from v1 to v2 -*- coding: utf-8; lexical-binding: t; -*- 2 3 ;; Copyright © 2020-2022 Jethro Kuan <jethrokuan95@gmail.com> 4 5 ;; Author: Jethro Kuan <jethrokuan95@gmail.com> 6 ;; URL: https://github.com/org-roam/org-roam 7 ;; Keywords: org-mode, roam, convenience 8 ;; Version: 2.2.2 9 ;; Package-Requires: ((emacs "26.1") (dash "2.13") (org "9.4") (emacsql "3.0.0") (emacsql-sqlite "1.0.0") (magit-section "3.0.0")) 10 11 ;; This file is NOT part of GNU Emacs. 12 13 ;; This program is free software; you can redistribute it and/or modify 14 ;; it under the terms of the GNU General Public License as published by 15 ;; the Free Software Foundation; either version 3, or (at your option) 16 ;; any later version. 17 ;; 18 ;; This program is distributed in the hope that it will be useful, 19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 ;; GNU General Public License for more details. 22 ;; 23 ;; You should have received a copy of the GNU General Public License 24 ;; along with GNU Emacs; see the file COPYING. If not, write to the 25 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26 ;; Boston, MA 02110-1301, USA. 27 28 ;;; Commentary: 29 ;; 30 ;; This is a special library provided for the v1 users of this package. It's 31 ;; purpose is to ease the transition from v1 to v2, by providing migration 32 ;; utilities to convert from v1 notes to v2 nodes. 33 ;; 34 ;;; Code: 35 (require 'org-roam) 36 37 ;;; Migration wizard (v1 -> v2) 38 ;;;###autoload 39 (defun org-roam-migrate-wizard () 40 "Migrate all notes from to be compatible with Org-roam v2. 41 1. Convert all notes from v1 format to v2. 42 2. Rebuild the cache. 43 3. Replace all file links with ID links." 44 (interactive) 45 (when (yes-or-no-p "Org-roam will now convert all your notes from v1 to v2. 46 This will take a while. Are you sure you want to do this?") 47 ;; Back up notes 48 (let ((backup-dir (expand-file-name "org-roam.bak" 49 (file-name-directory (directory-file-name org-roam-directory))))) 50 (message "Backing up files to %s" backup-dir) 51 (copy-directory org-roam-directory backup-dir)) 52 53 ;; Upgrade database to v2 54 (org-roam-db-sync 'force) 55 56 ;; Convert v1 to v2 57 (dolist (f (org-roam-list-files)) 58 (org-roam-with-file f nil 59 (org-roam-migrate-v1-to-v2))) 60 61 ;; Rebuild cache 62 (org-roam-db-sync 'force) 63 64 ;;Replace all file links with ID links 65 (dolist (f (org-roam-list-files)) 66 (org-roam-with-file f nil 67 (org-roam-migrate-replace-file-links-with-id) 68 (save-buffer))))) 69 70 (defun org-roam-migrate-v1-to-v2 () 71 "Convert the current buffer to v2 format." 72 ;; Create file level ID 73 (org-with-point-at 1 74 (org-id-get-create)) 75 ;; Replace roam_key into properties drawer roam_ref 76 (when-let* ((refs (mapcan #'split-string-and-unquote 77 (cdar (org-collect-keywords '("roam_key")))))) 78 (let ((case-fold-search t)) 79 (org-with-point-at 1 80 (dolist (ref refs) 81 (org-roam-ref-add ref)) 82 (while (re-search-forward "^#\\+roam_key:" (point-max) t) 83 (beginning-of-line) 84 (kill-line 1))))) 85 86 ;; Replace roam_alias into properties drawer roam_aliases 87 (when-let* ((aliases (mapcan #'split-string-and-unquote 88 (cdar (org-collect-keywords '("roam_alias")))))) 89 (dolist (alias aliases) 90 (org-roam-alias-add alias))) 91 (let ((case-fold-search t)) 92 (org-with-point-at 1 93 (while (re-search-forward "^#\\+roam_alias:" (point-max) t) 94 (beginning-of-line) 95 (kill-line 1)))) 96 97 ;; Replace #+roam_tags into #+filetags 98 (org-with-point-at 1 99 (let* ((roam-tags (org-roam-migrate-get-prop-list "ROAM_TAGS")) 100 (file-tags (cl-mapcan (lambda (value) 101 (cl-mapcan 102 (lambda (k) (org-split-string k ":")) 103 (split-string value))) 104 (org-roam-migrate-get-prop-list "FILETAGS"))) 105 (tags (append roam-tags file-tags)) 106 (tags (seq-map (lambda (tag) 107 (replace-regexp-in-string 108 "[^[:alnum:]_@#%]" 109 "_" 110 tag)) tags)) 111 (tags (seq-uniq tags))) 112 (when tags 113 (org-roam-migrate-prop-set "filetags" (org-make-tag-string tags)))) 114 (let ((case-fold-search t)) 115 (org-with-point-at 1 116 (while (re-search-forward "^#\\+roam_tags:" (point-max) t) 117 (beginning-of-line) 118 (kill-line 1))))) 119 (save-buffer)) 120 121 (defun org-roam-migrate-get-prop-list (keyword) 122 "Return prop list for KEYWORD." 123 (let ((re (format "^#\\+%s:[ \t]*\\([^\n]+\\)" (upcase keyword))) 124 lst) 125 (goto-char (point-min)) 126 (while (re-search-forward re 2048 t) 127 (setq lst (append lst (split-string-and-unquote 128 (buffer-substring-no-properties 129 (match-beginning 1) (match-end 1)))))) 130 lst)) 131 132 (defun org-roam-migrate-prop-set (name value) 133 "Set a file property called NAME to VALUE in buffer file. 134 If the property is already set, replace its value." 135 (setq name (downcase name)) 136 (org-with-point-at 1 137 (let ((case-fold-search t)) 138 (if (re-search-forward (concat "^#\\+" name ":\\(.*\\)") 139 (point-max) t) 140 (replace-match (concat "#+" name ": " value) 'fixedcase) 141 (while (and (not (eobp)) 142 (looking-at "^[#:]")) 143 (if (save-excursion (end-of-line) (eobp)) 144 (progn 145 (end-of-line) 146 (insert "\n")) 147 (forward-line) 148 (beginning-of-line))) 149 (insert "#+" name ": " value "\n"))))) 150 151 (defun org-roam-migrate-replace-file-links-with-id () 152 "Replace all file: links with ID links in current buffer." 153 (org-with-point-at 1 154 (while (re-search-forward org-link-bracket-re nil t) 155 (let* ((mdata (match-data)) 156 (path (match-string 1)) 157 (desc (match-string 2))) 158 (when (string-prefix-p "file:" path) 159 (setq path (expand-file-name (substring path 5))) 160 (when-let ((node-id (caar (org-roam-db-query [:select [id] :from nodes 161 :where (= file $s1) 162 :and (= level 0)] path)))) 163 (set-match-data mdata) 164 (replace-match (org-link-make-string (concat "id:" node-id) 165 desc) nil t))))))) 166 167 (provide 'org-roam-migrate) 168 ;;; org-roam-migrate.el ends here