Refill some copyright headers.
[bpt/emacs.git] / lisp / org / org-publish.el
CommitLineData
9542795a 1;;; org-publish.el --- publish related org-mode files as a website
e9bffc61
GM
2;; Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
3;; Free Software Foundation, Inc.
9542795a
CD
4
5;; Author: David O'Toole <dto@gnu.org>
c8d0cf5c 6;; Maintainer: Carsten Dominik <carsten DOT dominik AT gmail DOT com>
699b9291 7;; Keywords: hypermedia, outlines, wp
acedf35c 8;; Version: 7.4
9542795a 9
514a6ce6
CD
10;; This file is part of GNU Emacs.
11;;
b1fc2b50 12;; GNU Emacs is free software: you can redistribute it and/or modify
9542795a 13;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
9542795a 16
514a6ce6 17;; GNU Emacs is distributed in the hope that it will be useful,
9542795a
CD
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
b1fc2b50 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
9542795a 24
9542795a
CD
25;;; Commentary:
26
699b9291
CD
27;; This program allow configurable publishing of related sets of
28;; Org-mode files as a complete website.
9542795a
CD
29;;
30;; org-publish.el can do the following:
31;;
c8d0cf5c 32;; + Publish all one's org-files to HTML or PDF
699b9291 33;; + Upload HTML, images, attachments and other files to a web server
9542795a 34;; + Exclude selected private pages from publishing
ed21c5c8 35;; + Publish a clickable sitemap of pages
699b9291 36;; + Manage local timestamps for publishing only changed files
9542795a
CD
37;; + Accept plugin functions to extend range of publishable content
38;;
c8d0cf5c 39;; Documentation for publishing is in the manual.
9542795a
CD
40
41;;; Code:
42
ed21c5c8
CD
43
44(defun org-publish-sanitize-plist (plist)
45 (mapcar (lambda (x)
46 (or (cdr (assq x '((:index-filename . :sitemap-filename)
47 (:index-title . :sitemap-title)
48 (:index-function . :sitemap-function)
49 (:index-style . :sitemap-style)
50 (:auto-index . :auto-sitemap))))
51 x))
52 plist))
53
9542795a
CD
54(eval-when-compile
55 (require 'cl))
b349f79f
CD
56(require 'org)
57(require 'org-exp)
9542795a 58
1e63a7fb
GM
59(eval-and-compile
60 (unless (fboundp 'declare-function)
61 (defmacro declare-function (fn file &optional arglist fileonly))))
62
9542795a 63(defgroup org-publish nil
b349f79f
CD
64 "Options for publishing a set of Org-mode and related files."
65 :tag "Org Publishing"
66 :group 'org)
9542795a 67
9542795a
CD
68(defcustom org-publish-project-alist nil
69 "Association list to control publishing behavior.
70Each element of the alist is a publishing 'project.' The CAR of
50243adf 71each element is a string, uniquely identifying the project. The
9542795a
CD
72CDR of each element is in one of the following forms:
73
afe98dfa
CD
741. A well-formed property list with an even number of elements, alternating
75 keys and values, specifying parameters for the publishing process.
9542795a 76
afe98dfa 77 (:property value :property value ... )
9542795a 78
afe98dfa
CD
792. A meta-project definition, specifying of a list of sub-projects:
80
81 (:components (\"project-1\" \"project-2\" ...))
9542795a
CD
82
83When the CDR of an element of org-publish-project-alist is in
84this second form, the elements of the list after :components are
85taken to be components of the project, which group together files
50243adf
JB
86requiring different publishing options. When you publish such a
87project with \\[org-publish], the components all publish.
9542795a
CD
88
89When a property is given a value in org-publish-project-alist, its
90setting overrides the value of the corresponding user variable
50243adf 91\(if any) during publishing. However, options set within a file
9542795a
CD
92override everything.
93
94Most properties are optional, but some should always be set:
95
699b9291
CD
96 :base-directory Directory containing publishing source files
97 :base-extension Extension (without the dot!) of source files.
afe98dfa
CD
98 This can be a regular expression. If not given,
99 \"org\" will be used as default extension.
699b9291
CD
100 :publishing-directory Directory (possibly remote) where output
101 files will be published
9542795a
CD
102
103The :exclude property may be used to prevent certain files from
50243adf 104being published. Its value may be a string or regexp matching
9542795a
CD
105file names you don't want to be published.
106
50243adf 107The :include property may be used to include extra files. Its
b349f79f
CD
108value may be a list of filenames to include. The filenames are
109considered relative to the base directory.
9542795a
CD
110
111When both :include and :exclude properties are given values, the
112exclusion step happens first.
113
114One special property controls which back-end function to use for
50243adf 115publishing files in the project. This can be used to extend the
9542795a
CD
116set of file types publishable by org-publish, as well as the set
117of output formats.
118
50243adf
JB
119 :publishing-function Function to publish file. The default is
120 `org-publish-org-to-html', but other
121 values are possible. May also be a
699b9291
CD
122 list of functions, in which case
123 each function in the list is invoked
124 in turn.
9542795a
CD
125
126Another property allows you to insert code that prepares a
50243adf 127project for publishing. For example, you could call GNU Make on a
699b9291 128certain makefile, to ensure published files are built up to date.
9542795a 129
699b9291 130 :preparation-function Function to be called before publishing
ed21c5c8
CD
131 this project. This may also be a list
132 of functions.
b349f79f 133 :completion-function Function to be called after publishing
ed21c5c8
CD
134 this project. This may also be a list
135 of functions.
9542795a
CD
136
137Some properties control details of the Org publishing process,
138and are equivalent to the corresponding user variables listed in
50243adf 139the right column. See the documentation for those variables to
9542795a
CD
140learn more about their use and default values.
141
50243adf
JB
142 :language `org-export-default-language'
143 :headline-levels `org-export-headline-levels'
144 :section-numbers `org-export-with-section-numbers'
145 :table-of-contents `org-export-with-toc'
146 :emphasize `org-export-with-emphasize'
147 :sub-superscript `org-export-with-sub-superscripts'
148 :TeX-macros `org-export-with-TeX-macros'
149 :fixed-width `org-export-with-fixed-width'
150 :tables `org-export-with-tables'
151 :table-auto-headline `org-export-highlight-first-table-line'
152 :style `org-export-html-style'
153 :convert-org-links `org-export-html-link-org-files-as-html'
154 :inline-images `org-export-html-inline-images'
155 :expand-quoted-html `org-export-html-expand'
156 :timestamp `org-export-html-with-timestamp'
157 :publishing-directory `org-export-publishing-directory'
158 :preamble `org-export-html-preamble'
159 :postamble `org-export-html-postamble'
160 :auto-preamble `org-export-html-auto-preamble'
161 :auto-postamble `org-export-html-auto-postamble'
162 :author `user-full-name'
163 :email `user-mail-address'
9542795a 164
ed21c5c8
CD
165The following properties may be used to control publishing of a
166sitemap of files or summary page for a given project.
9542795a 167
ed21c5c8 168 :auto-sitemap Whether to publish a sitemap during
50243adf 169 `org-publish-current-project' or `org-publish-all'.
ed21c5c8 170 :sitemap-filename Filename for output of sitemap. Defaults
c8d0cf5c 171 to 'sitemap.org' (which becomes 'sitemap.html').
ed21c5c8
CD
172 :sitemap-title Title of sitemap page. Defaults to name of file.
173 :sitemap-function Plugin function to use for generation of sitemap.
174 Defaults to `org-publish-org-sitemap', which
699b9291 175 generates a plain list of links to all files
2c3ad40d 176 in the project.
ed21c5c8 177 :sitemap-style Can be `list' (sitemap is just an itemized list
ff4be292 178 of the titles of the files involved) or
2c3ad40d 179 `tree' (the directory structure of the source
ed21c5c8 180 files is reflected in the sitemap). Defaults to
86fbb8ca
CD
181 `tree'.
182
183 If you create a sitemap file, adjust the sorting like this:
184
185 :sitemap-sort-folders Where folders should appear in the sitemap.
186 Set this to `first' (default) or `last' to
187 display folders first or last, respectively.
188 Any other value will mix files and folders.
189 :sitemap-alphabetically The site map is normally sorted alphabetically.
190 Set this explicitly to nil to turn off sorting.
191 :sitemap-ignore-case Should sorting be case-sensitive? Default nil.
192
193The following properties control the creation of a concept index.
194
afe98dfa
CD
195 :makeindex Create a concept index.
196
197Other properties affecting publication.
198
199 :body-only Set this to 't' to publish only the body of the
200 documents, excluding everything outside and
201 including the <body> tags in HTML, or
202 \begin{document}..\end{document} in LaTeX."
9542795a
CD
203 :group 'org-publish
204 :type 'alist)
205
9542795a 206(defcustom org-publish-use-timestamps-flag t
86fbb8ca 207 "Non-nil means use timestamp checking to publish only changed files.
50243adf 208When nil, do no timestamp checking and always publish all files."
9542795a
CD
209 :group 'org-publish
210 :type 'boolean)
211
ff4be292 212(defcustom org-publish-timestamp-directory (convert-standard-filename
71d35b24 213 "~/.org-timestamps/")
9542795a
CD
214 "Name of directory in which to store publishing timestamps."
215 :group 'org-publish
699b9291 216 :type 'directory)
9542795a 217
c8d0cf5c 218(defcustom org-publish-list-skipped-files t
ed21c5c8 219 "Non-nil means show message about files *not* published."
c8d0cf5c
CD
220 :group 'org-publish
221 :type 'boolean)
222
699b9291
CD
223(defcustom org-publish-before-export-hook nil
224 "Hook run before export on the Org file.
c8d0cf5c 225The hook may modify the file in arbitrary ways before publishing happens.
8bfe682a 226The original version of the buffer will be restored after publishing."
699b9291
CD
227 :group 'org-publish
228 :type 'hook)
9542795a 229
699b9291
CD
230(defcustom org-publish-after-export-hook nil
231 "Hook run after export on the exported buffer.
c8d0cf5c 232Any changes made by this hook will be saved."
699b9291
CD
233 :group 'org-publish
234 :type 'hook)
9542795a 235
86fbb8ca
CD
236(defcustom org-publish-sitemap-sort-alphabetically t
237 "Should sitemaps be sorted alphabetically by default?
238
239You can overwrite this default per project in your
240`org-publish-project-alist', using `:sitemap-alphabetically'."
241 :group 'org-publish
242 :type 'boolean)
243
244(defcustom org-publish-sitemap-sort-folders 'first
245 "A symbol, denoting if folders are sorted first in sitemaps.
246Possible values are `first', `last', and nil.
247If `first', folders will be sorted before files.
248If `last', folders are sorted to the end after the files.
249Any other value will not mix files and folders.
250
251You can overwrite this default per project in your
252`org-publish-project-alist', using `:sitemap-sort-folders'."
253 :group 'org-publish
254 :type 'symbol)
255
256(defcustom org-publish-sitemap-sort-ignore-case nil
257 "Sort sitemaps case insensitively by default?
258
259You can overwrite this default per project in your
260`org-publish-project-alist', using `:sitemap-ignore-case'."
261 :group 'org-publish
262 :type 'boolean)
263
699b9291
CD
264;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
265;;; Timestamp-related functions
9542795a 266
c8d0cf5c 267(defun org-publish-timestamp-filename (filename &optional pub-dir pub-func)
9542795a 268 "Return path to timestamp file for filename FILENAME."
c8d0cf5c
CD
269 (setq filename (concat filename "::" (or pub-dir "") "::"
270 (format "%s" (or pub-func ""))))
86fbb8ca 271 (concat "X" (if (fboundp 'sha1) (sha1 filename) (md5 filename))))
9542795a 272
c8d0cf5c 273(defun org-publish-needed-p (filename &optional pub-dir pub-func true-pub-dir)
86fbb8ca
CD
274 "Return t if FILENAME should be published in PUB-DIR using PUB-FUNC.
275TRUE-PUB-DIR is where the file will truly end up. Currently we are not using
c8d0cf5c
CD
276this - maybe it can eventually be used to check if the file is present at
277the target location, and how old it is. Right ow we cannot do this, because
278we do not know under what file name the file will be stored - the publishing
279function can still decide about that independently."
2c3ad40d
CD
280 (let ((rtn
281 (if org-publish-use-timestamps-flag
86fbb8ca
CD
282 (org-publish-cache-file-needs-publishing
283 filename pub-dir pub-func)
2c3ad40d
CD
284 ;; don't use timestamps, always return t
285 t)))
286 (if rtn
c8d0cf5c
CD
287 (message "Publishing file %s using `%s'" filename pub-func)
288 (when org-publish-list-skipped-files
289 (message "Skipping unmodified file %s" filename)))
2c3ad40d 290 rtn))
9542795a 291
c8d0cf5c 292(defun org-publish-update-timestamp (filename &optional pub-dir pub-func)
699b9291
CD
293 "Update publishing timestamp for file FILENAME.
294If there is no timestamp, create one."
86fbb8ca
CD
295 (let ((key (org-publish-timestamp-filename filename pub-dir pub-func))
296 (stamp (org-publish-cache-ctime-of-src filename)))
297 (org-publish-cache-set key stamp)))
c8d0cf5c
CD
298
299(defun org-publish-remove-all-timestamps ()
86fbb8ca 300 "Remove all files in the timestamp directory."
c8d0cf5c
CD
301 (let ((dir org-publish-timestamp-directory)
302 files)
303 (when (and (file-exists-p dir)
304 (file-directory-p dir))
86fbb8ca
CD
305 (mapc 'delete-file (directory-files dir 'full "[^.]\\'"))
306 (org-publish-reset-cache))))
c8d0cf5c 307
699b9291
CD
308
309;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
86fbb8ca 310;;;
699b9291 311
20908596
CD
312(defvar org-publish-initial-buffer nil
313 "The buffer `org-publish' has been called from.")
314(defvar org-publish-temp-files nil
315 "Temporary list of files to be published.")
316
86fbb8ca
CD
317;; Here, so you find the variable right before it's used the first time:
318(defvar org-publish-cache nil
319 "This will cache timestamps and titles for files in publishing projects.
320Blocks could hash sha1 values here.")
699b9291 321
93b62de8 322
699b9291
CD
323;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
324;;; Compatibility aliases
325
326;; Delete-dups is not in Emacs <22
327(if (fboundp 'delete-dups)
328 (defalias 'org-publish-delete-dups 'delete-dups)
329 (defun org-publish-delete-dups (list)
330 "Destructively remove `equal' duplicates from LIST.
331Store the result in LIST and return it. LIST must be a proper list.
332Of several `equal' occurrences of an element in LIST, the first
333one is kept.
334
335This is a compatibility function for Emacsen without `delete-dups'."
336 ;; Code from `subr.el' in Emacs 22:
337 (let ((tail list))
338 (while tail
339 (setcdr tail (delete (car tail) (cdr tail)))
340 (setq tail (cdr tail))))
341 list))
342
1e63a7fb 343(declare-function org-publish-delete-dups "org-publish" (list))
ed21c5c8 344(declare-function find-lisp-find-files "find-lisp" (directory regexp))
1e63a7fb 345
699b9291
CD
346;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
347;;; Getting project information out of org-publish-project-alist
348
699b9291 349(defun org-publish-expand-projects (projects-alist)
621f83e4
CD
350 "Expand projects in PROJECTS-ALIST.
351This splices all the components into the list."
352 (let ((rest projects-alist) rtn p components)
353 (while (setq p (pop rest))
354 (if (setq components (plist-get (cdr p) :components))
355 (setq rest (append
356 (mapcar (lambda (x) (assoc x org-publish-project-alist))
357 components)
358 rest))
359 (push p rtn)))
360 (nreverse (org-publish-delete-dups (delq nil rtn)))))
ff4be292 361
86fbb8ca
CD
362
363(defvar sitemap-alphabetically)
364(defvar sitemap-sort-folders)
365(defvar sitemap-ignore-case)
366(defvar sitemap-requested)
367(defun org-publish-compare-directory-files (a b)
368 "Predicate for `sort', that sorts folders-first/last and alphabetically."
369 (let ((retval t))
370 (when (or sitemap-alphabetically sitemap-sort-folders)
371 ;; First we sort alphabetically:
372 (when sitemap-alphabetically
373 (let* ((adir (file-directory-p a))
374 (aorg (and (string-match "\\.org$" a) (not adir)))
375 (bdir (file-directory-p b))
376 (borg (and (string-match "\\.org$" b) (not bdir)))
377 (A (if aorg
378 (concat (file-name-directory a)
379 (org-publish-find-title a)) a))
380 (B (if borg
381 (concat (file-name-directory b)
382 (org-publish-find-title b)) b)))
383 (setq retval (if sitemap-ignore-case
384 (not (string-lessp (upcase B) (upcase A)))
385 (not (string-lessp B A))))))
386
387 ;; Directory-wise wins:
388 (when sitemap-sort-folders
389 ;; a is directory, b not:
390 (cond
391 ((and (file-directory-p a) (not (file-directory-p b)))
392 (setq retval (equal sitemap-sort-folders 'first)))
393 ;; a is not a directory, but b is:
394 ((and (not (file-directory-p a)) (file-directory-p b))
395 (setq retval (equal sitemap-sort-folders 'last))))))
396 retval))
397
20908596
CD
398(defun org-publish-get-base-files-1 (base-dir &optional recurse match skip-file skip-dir)
399 "Set `org-publish-temp-files' with files from BASE-DIR directory.
400If RECURSE is non-nil, check BASE-DIR recursively. If MATCH is
401non-nil, restrict this list to the files matching the regexp
402MATCH. If SKIP-FILE is non-nil, skip file matching the regexp
403SKIP-FILE. If SKIP-DIR is non-nil, don't check directories
33306645 404matching the regexp SKIP-DIR when recursing through BASE-DIR."
20908596 405 (mapc (lambda (f)
93b62de8 406 (let ((fd-p (file-directory-p f))
20908596
CD
407 (fnd (file-name-nondirectory f)))
408 (if (and fd-p recurse
409 (not (string-match "^\\.+$" fnd))
410 (if skip-dir (not (string-match skip-dir fnd)) t))
411 (org-publish-get-base-files-1 f recurse match skip-file skip-dir)
412 (unless (or fd-p ;; this is a directory
413 (and skip-file (string-match skip-file fnd))
93b62de8 414 (not (file-exists-p (file-truename f)))
20908596 415 (not (string-match match fnd)))
86fbb8ca 416
20908596 417 (pushnew f org-publish-temp-files)))))
86fbb8ca
CD
418 (if sitemap-requested
419 (sort (directory-files base-dir t (unless recurse match))
420 'org-publish-compare-directory-files)
421 (directory-files base-dir t (unless recurse match)))))
20908596 422
699b9291
CD
423(defun org-publish-get-base-files (project &optional exclude-regexp)
424 "Return a list of all files in PROJECT.
9542795a
CD
425If EXCLUDE-REGEXP is set, this will be used to filter out
426matching filenames."
699b9291
CD
427 (let* ((project-plist (cdr project))
428 (base-dir (file-name-as-directory
429 (plist-get project-plist :base-directory)))
33306645
CD
430 (include-list (plist-get project-plist :include))
431 (recurse (plist-get project-plist :recursive))
432 (extension (or (plist-get project-plist :base-extension) "org"))
86fbb8ca
CD
433 ;; sitemap-... variables are dynamically scoped for
434 ;; org-publish-compare-directory-files:
435 (sitemap-requested
436 (plist-get project-plist :auto-sitemap))
437 (sitemap-sort-folders
438 (if (plist-member project-plist :sitemap-sort-folders)
439 (plist-get project-plist :sitemap-sort-folders)
440 org-publish-sitemap-sort-folders))
441 (sitemap-alphabetically
442 (if (plist-member project-plist :sitemap-alphabetically)
443 (plist-get project-plist :sitemap-alphabetically)
444 org-publish-sitemap-sort-alphabetically))
445 (sitemap-ignore-case
446 (if (plist-member project-plist :sitemap-ignore-case)
447 (plist-get project-plist :sitemap-ignore-case)
448 org-publish-sitemap-sort-ignore-case))
c8d0cf5c
CD
449 (match (if (eq extension 'any)
450 "^[^\\.]"
451 (concat "^[^\\.].*\\.\\(" extension "\\)$"))))
86fbb8ca
CD
452 ;; Make sure sitemap-sort-folders' has an accepted value
453 (unless (memq sitemap-sort-folders '(first last))
454 (setq sitemap-sort-folders nil))
455
20908596
CD
456 (setq org-publish-temp-files nil)
457 (org-publish-get-base-files-1 base-dir recurse match
458 ;; FIXME distinguish exclude regexp
459 ;; for skip-file and skip-dir?
460 exclude-regexp exclude-regexp)
b349f79f 461 (mapc (lambda (f)
ff4be292 462 (pushnew
b349f79f
CD
463 (expand-file-name (concat base-dir f))
464 org-publish-temp-files))
465 include-list)
20908596 466 org-publish-temp-files))
9542795a 467
c8d0cf5c 468(defun org-publish-get-project-from-filename (filename &optional up)
86fbb8ca
CD
469 "Return the project that FILENAME belongs to."
470 (let* ((filename (expand-file-name filename))
471 project-name)
472
473 (catch 'p-found
474 (dolist (prj org-publish-project-alist)
475 (unless (plist-get (cdr prj) :components)
476 ;; [[info:org:Selecting%20files]] shows how this is supposed to work:
477 (let* ((r (plist-get (cdr prj) :recursive))
afe98dfa
CD
478 (b (expand-file-name (file-name-as-directory
479 (plist-get (cdr prj) :base-directory))))
86fbb8ca
CD
480 (x (or (plist-get (cdr prj) :base-extension) "org"))
481 (e (plist-get (cdr prj) :exclude))
482 (i (plist-get (cdr prj) :include))
483 (xm (concat "^" b (if r ".+" "[^/]+") "\\.\\(" x "\\)$")))
484 (when (or
afe98dfa
CD
485 (and
486 i
487 (member filename
488 (mapcar
489 (lambda (file) (expand-file-name file b))
490 i)))
86fbb8ca
CD
491 (and
492 (not (and e (string-match e filename)))
493 (string-match xm filename)))
494 (setq project-name (car prj))
495 (throw 'p-found project-name))))))
c8d0cf5c
CD
496 (when up
497 (dolist (prj org-publish-project-alist)
498 (if (member project-name (plist-get (cdr prj) :components))
499 (setq project-name (car prj)))))
699b9291 500 (assoc project-name org-publish-project-alist)))
daa89d0f 501
699b9291
CD
502;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
503;;; Pluggable publishing back-end functions
daa89d0f 504
699b9291 505(defun org-publish-org-to (format plist filename pub-dir)
daa89d0f
CD
506 "Publish an org file to FORMAT.
507PLIST is the property list for the given project.
699b9291
CD
508FILENAME is the filename of the org file to be published.
509PUB-DIR is the publishing directory."
03f3cf35 510 (require 'org)
699b9291
CD
511 (unless (file-exists-p pub-dir)
512 (make-directory pub-dir t))
71d35b24
CD
513 (let ((visiting (find-buffer-visiting filename)))
514 (save-excursion
515 (switch-to-buffer (or visiting (find-file filename)))
516 (let* ((plist (cons :buffer-will-be-killed (cons t plist)))
517 (init-buf (current-buffer))
518 (init-point (point))
519 (init-buf-string (buffer-string))
520 export-buf-or-file)
521 ;; run hooks before exporting
522 (run-hooks 'org-publish-before-export-hook)
523 ;; export the possibly modified buffer
524 (setq export-buf-or-file
525 (funcall (intern (concat "org-export-as-" format))
526 (plist-get plist :headline-levels)
afe98dfa
CD
527 nil plist nil
528 (plist-get plist :body-only)
529 pub-dir))
71d35b24
CD
530 (when (and (bufferp export-buf-or-file)
531 (buffer-live-p export-buf-or-file))
532 (set-buffer export-buf-or-file)
533 ;; run hooks after export and save export
ed21c5c8
CD
534 (progn (run-hooks 'org-publish-after-export-hook)
535 (if (buffer-modified-p) (save-buffer)))
71d35b24
CD
536 (kill-buffer export-buf-or-file))
537 ;; maybe restore buffer's content
538 (set-buffer init-buf)
539 (when (buffer-modified-p init-buf)
540 (erase-buffer)
541 (insert init-buf-string)
542 (save-buffer)
543 (goto-char init-point))
544 (unless visiting
545 (kill-buffer init-buf))))))
699b9291 546
ed21c5c8
CD
547(defmacro org-publish-with-aux-preprocess-maybe (&rest body)
548 "Execute BODY with a modified hook to preprocess for index."
549 `(let ((org-export-preprocess-after-headline-targets-hook
550 (if (plist-get project-plist :makeindex)
551 (cons 'org-publish-aux-preprocess
552 org-export-preprocess-after-headline-targets-hook)
553 org-export-preprocess-after-headline-targets-hook)))
554 ,@body))
555
556(defvar project-plist)
699b9291
CD
557(defun org-publish-org-to-latex (plist filename pub-dir)
558 "Publish an org file to LaTeX.
559See `org-publish-org-to' to the list of arguments."
ed21c5c8
CD
560 (org-publish-with-aux-preprocess-maybe
561 (org-publish-org-to "latex" plist filename pub-dir)))
699b9291 562
71d35b24
CD
563(defun org-publish-org-to-pdf (plist filename pub-dir)
564 "Publish an org file to PDF (via LaTeX).
565See `org-publish-org-to' to the list of arguments."
ed21c5c8
CD
566 (org-publish-with-aux-preprocess-maybe
567 (org-publish-org-to "pdf" plist filename pub-dir)))
71d35b24 568
699b9291
CD
569(defun org-publish-org-to-html (plist filename pub-dir)
570 "Publish an org file to HTML.
571See `org-publish-org-to' to the list of arguments."
ed21c5c8
CD
572 (org-publish-with-aux-preprocess-maybe
573 (org-publish-org-to "html" plist filename pub-dir)))
699b9291 574
c8d0cf5c
CD
575(defun org-publish-org-to-org (plist filename pub-dir)
576 "Publish an org file to HTML.
577See `org-publish-org-to' to the list of arguments."
578 (org-publish-org-to "org" plist filename pub-dir))
579
afe98dfa
CD
580(defun org-publish-org-to-ascii (plist filename pub-dir)
581 "Publish an org file to ASCII.
582See `org-publish-org-to' to the list of arguments."
583 (org-publish-with-aux-preprocess-maybe
584 (org-publish-org-to "ascii" plist filename pub-dir)))
585
586(defun org-publish-org-to-latin1 (plist filename pub-dir)
587 "Publish an org file to Latin-1.
588See `org-publish-org-to' to the list of arguments."
589 (org-publish-with-aux-preprocess-maybe
590 (org-publish-org-to "latin1" plist filename pub-dir)))
591
592(defun org-publish-org-to-utf8 (plist filename pub-dir)
593 "Publish an org file to UTF-8.
594See `org-publish-org-to' to the list of arguments."
595 (org-publish-with-aux-preprocess-maybe
596 (org-publish-org-to "utf8" plist filename pub-dir)))
597
699b9291 598(defun org-publish-attachment (plist filename pub-dir)
9542795a 599 "Publish a file with no transformation of any kind.
699b9291 600See `org-publish-org-to' to the list of arguments."
93b62de8 601 ;; make sure eshell/cp code is loaded
afe98dfa
CD
602 (unless (file-directory-p pub-dir)
603 (make-directory pub-dir t))
604 (or (equal (expand-file-name (file-name-directory filename))
605 (file-name-as-directory (expand-file-name pub-dir)))
c8d0cf5c
CD
606 (copy-file filename
607 (expand-file-name (file-name-nondirectory filename) pub-dir)
608 t)))
699b9291
CD
609
610;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
611;;; Publishing files, sets of files, and indices
612
86fbb8ca
CD
613(defun org-publish-file (filename &optional project no-cache)
614 "Publish file FILENAME from PROJECT.
615If NO-CACHE is not nil, do not initialize org-publish-cache and
616write it to disk. This is needed, since this function is used to
617publish single files, when entire projects are published.
618See `org-publish-projects'."
c8d0cf5c
CD
619 (let* ((project
620 (or project
621 (or (org-publish-get-project-from-filename filename)
86fbb8ca
CD
622 (error "File %s not part of any known project"
623 (abbreviate-file-name filename)))))
c8d0cf5c 624 (project-plist (cdr project))
afe98dfa 625 (ftname (expand-file-name filename))
c8d0cf5c
CD
626 (publishing-function
627 (or (plist-get project-plist :publishing-function)
628 'org-publish-org-to-html))
afe98dfa
CD
629 (base-dir
630 (file-name-as-directory
631 (expand-file-name
632 (or (plist-get project-plist :base-directory)
633 (error "Project %s does not have :base-directory defined"
634 (car project))))))
635 (pub-dir
636 (file-name-as-directory
637 (file-truename
638 (or (plist-get project-plist :publishing-directory)
639 (error "Project %s does not have :publishing-directory defined"
640 (car project))))))
c8d0cf5c 641 tmp-pub-dir)
86fbb8ca
CD
642
643 (unless no-cache
644 (org-publish-initialize-cache (car project)))
645
c8d0cf5c
CD
646 (setq tmp-pub-dir
647 (file-name-directory
648 (concat pub-dir
649 (and (string-match (regexp-quote base-dir) ftname)
650 (substring ftname (match-end 0))))))
651 (if (listp publishing-function)
652 ;; allow chain of publishing functions
653 (mapc (lambda (f)
654 (when (org-publish-needed-p filename pub-dir f tmp-pub-dir)
655 (funcall f project-plist filename tmp-pub-dir)
656 (org-publish-update-timestamp filename pub-dir f)))
657 publishing-function)
658 (when (org-publish-needed-p filename pub-dir publishing-function
659 tmp-pub-dir)
660 (funcall publishing-function project-plist filename tmp-pub-dir)
661 (org-publish-update-timestamp
86fbb8ca
CD
662 filename pub-dir publishing-function)))
663 (unless no-cache (org-publish-write-cache-file))))
699b9291
CD
664
665(defun org-publish-projects (projects)
666 "Publish all files belonging to the PROJECTS alist.
ed21c5c8
CD
667If :auto-sitemap is set, publish the sitemap too.
668If :makeindex is set, also produce a file theindex.org."
699b9291
CD
669 (mapc
670 (lambda (project)
86fbb8ca
CD
671 ;; Each project uses it's own cache file:
672 (org-publish-initialize-cache (car project))
b349f79f
CD
673 (let*
674 ((project-plist (cdr project))
675 (exclude-regexp (plist-get project-plist :exclude))
ed21c5c8
CD
676 (sitemap-p (plist-get project-plist :auto-sitemap))
677 (sitemap-filename (or (plist-get project-plist :sitemap-filename)
678 "sitemap.org"))
679 (sitemap-function (or (plist-get project-plist :sitemap-function)
680 'org-publish-org-sitemap))
b349f79f
CD
681 (preparation-function (plist-get project-plist :preparation-function))
682 (completion-function (plist-get project-plist :completion-function))
683 (files (org-publish-get-base-files project exclude-regexp)) file)
ed21c5c8
CD
684 (when preparation-function (run-hooks 'preparation-function))
685 (if sitemap-p (funcall sitemap-function project sitemap-filename))
699b9291 686 (while (setq file (pop files))
86fbb8ca 687 (org-publish-file file project t))
ed21c5c8
CD
688 (when (plist-get project-plist :makeindex)
689 (org-publish-index-generate-theindex.inc
690 (plist-get project-plist :base-directory))
691 (org-publish-file (expand-file-name
692 "theindex.org"
693 (plist-get project-plist :base-directory))
86fbb8ca
CD
694 project t))
695 (when completion-function (run-hooks 'completion-function))
696 (org-publish-write-cache-file)))
699b9291
CD
697 (org-publish-expand-projects projects)))
698
ed21c5c8 699(defun org-publish-org-sitemap (project &optional sitemap-filename)
86fbb8ca 700 "Create a sitemap of pages in set defined by PROJECT.
ed21c5c8
CD
701Optionally set the filename of the sitemap with SITEMAP-FILENAME.
702Default for SITEMAP-FILENAME is 'sitemap.org'."
699b9291
CD
703 (let* ((project-plist (cdr project))
704 (dir (file-name-as-directory
705 (plist-get project-plist :base-directory)))
b349f79f
CD
706 (localdir (file-name-directory dir))
707 (indent-str (make-string 2 ?\ ))
699b9291 708 (exclude-regexp (plist-get project-plist :exclude))
b349f79f 709 (files (nreverse (org-publish-get-base-files project exclude-regexp)))
ed21c5c8
CD
710 (sitemap-filename (concat dir (or sitemap-filename "sitemap.org")))
711 (sitemap-title (or (plist-get project-plist :sitemap-title)
712 (concat "Sitemap for project " (car project))))
713 (sitemap-style (or (plist-get project-plist :sitemap-style)
2c3ad40d 714 'tree))
ed21c5c8
CD
715 (visiting (find-buffer-visiting sitemap-filename))
716 (ifn (file-name-nondirectory sitemap-filename))
717 file sitemap-buffer)
718 (with-current-buffer (setq sitemap-buffer
719 (or visiting (find-file sitemap-filename)))
ff4be292 720 (erase-buffer)
ed21c5c8 721 (insert (concat "#+TITLE: " sitemap-title "\n\n"))
699b9291 722 (while (setq file (pop files))
b349f79f
CD
723 (let ((fn (file-name-nondirectory file))
724 (link (file-relative-name file dir))
725 (oldlocal localdir))
ed21c5c8
CD
726 ;; sitemap shouldn't list itself
727 (unless (equal (file-truename sitemap-filename)
ff4be292 728 (file-truename file))
ed21c5c8
CD
729 (if (eq sitemap-style 'list)
730 (message "Generating list-style sitemap for %s" sitemap-title)
731 (message "Generating tree-style sitemap for %s" sitemap-title)
2c3ad40d
CD
732 (setq localdir (concat (file-name-as-directory dir)
733 (file-name-directory link)))
734 (unless (string= localdir oldlocal)
735 (if (string= localdir dir)
736 (setq indent-str (make-string 2 ?\ ))
737 (let ((subdirs
738 (split-string
739 (directory-file-name
740 (file-name-directory
741 (file-relative-name localdir dir))) "/"))
93b62de8
CD
742 (subdir "")
743 (old-subdirs (split-string
744 (file-relative-name oldlocal dir) "/")))
2c3ad40d 745 (setq indent-str (make-string 2 ?\ ))
93b62de8
CD
746 (while (string= (car old-subdirs) (car subdirs))
747 (setq indent-str (concat indent-str (make-string 2 ?\ )))
748 (pop old-subdirs)
749 (pop subdirs))
2c3ad40d
CD
750 (dolist (d subdirs)
751 (setq subdir (concat subdir d "/"))
93b62de8
CD
752 (insert (concat indent-str " + " d "\n"))
753 (setq indent-str (make-string
2c3ad40d
CD
754 (+ (length indent-str) 2) ?\ )))))))
755 ;; This is common to 'flat and 'tree
b349f79f 756 (insert (concat indent-str " + [[file:" link "]["
2c3ad40d 757 (org-publish-find-title file)
ff4be292
CD
758 "]]\n")))))
759 (save-buffer))
ed21c5c8 760 (or visiting (kill-buffer sitemap-buffer))))
9542795a 761
b349f79f 762(defun org-publish-find-title (file)
86fbb8ca
CD
763 "Find the title of FILE in project."
764 (or
765 (org-publish-cache-get-file-property file :title nil t)
766 (let* ((visiting (find-buffer-visiting file))
93b62de8
CD
767 (buffer (or visiting (find-file-noselect file)))
768 title)
81ad75af 769 (with-current-buffer buffer
93b62de8
CD
770 (let* ((opt-plist (org-combine-plists (org-default-export-plist)
771 (org-infile-export-plist))))
772 (setq title
773 (or (plist-get opt-plist :title)
774 (and (not
775 (plist-get opt-plist :skip-before-1st-heading))
776 (org-export-grab-title-from-buffer))
777 (file-name-nondirectory (file-name-sans-extension file))))))
778 (unless visiting
779 (kill-buffer buffer))
86fbb8ca
CD
780 (org-publish-cache-set-file-property file :title title)
781 title)))
b349f79f 782
699b9291
CD
783;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
784;;; Interactive publishing functions
9542795a 785
71d35b24 786;;;###autoload
20908596 787(defalias 'org-publish-project 'org-publish)
9542795a
CD
788
789;;;###autoload
699b9291
CD
790(defun org-publish (project &optional force)
791 "Publish PROJECT."
c8d0cf5c
CD
792 (interactive
793 (list
54a0dee5 794 (assoc (org-icompleting-read
c8d0cf5c
CD
795 "Publish project: "
796 org-publish-project-alist nil t)
797 org-publish-project-alist)
798 current-prefix-arg))
20908596 799 (setq org-publish-initial-buffer (current-buffer))
9542795a 800 (save-window-excursion
c8d0cf5c 801 (let* ((org-publish-use-timestamps-flag
699b9291 802 (if force nil org-publish-use-timestamps-flag)))
86fbb8ca
CD
803 (org-publish-projects
804 (if (stringp project)
805 ;; If this function is called in batch mode,
806 ;; project is still a string here.
807 (list (assoc project org-publish-project-alist))
808 (list project))))))
9542795a
CD
809
810;;;###autoload
699b9291
CD
811(defun org-publish-all (&optional force)
812 "Publish all projects.
c8d0cf5c
CD
813With prefix argument, remove all files in the timestamp
814directory and force publishing all files."
9542795a 815 (interactive "P")
c8d0cf5c
CD
816 (when force
817 (org-publish-remove-all-timestamps))
9542795a 818 (save-window-excursion
699b9291
CD
819 (let ((org-publish-use-timestamps-flag
820 (if force nil org-publish-use-timestamps-flag)))
821 (org-publish-projects org-publish-project-alist))))
9542795a 822
ed21c5c8 823
9542795a
CD
824;;;###autoload
825(defun org-publish-current-file (&optional force)
826 "Publish the current file.
827With prefix argument, force publish the file."
828 (interactive "P")
829 (save-window-excursion
830 (let ((org-publish-use-timestamps-flag
699b9291 831 (if force nil org-publish-use-timestamps-flag)))
9542795a
CD
832 (org-publish-file (buffer-file-name)))))
833
9542795a 834;;;###autoload
699b9291
CD
835(defun org-publish-current-project (&optional force)
836 "Publish the project associated with the current file.
837With a prefix argument, force publishing of all files in
838the project."
9542795a
CD
839 (interactive "P")
840 (save-window-excursion
c8d0cf5c 841 (let ((project (org-publish-get-project-from-filename (buffer-file-name) 'up))
699b9291
CD
842 (org-publish-use-timestamps-flag
843 (if force nil org-publish-use-timestamps-flag)))
844 (if (not project)
845 (error "File %s is not part of any known project" (buffer-file-name)))
86fbb8ca 846 ;; FIXME: force is not used here?
699b9291 847 (org-publish project))))
d5098885 848
ed21c5c8
CD
849
850;;; Index generation
851
852(defvar backend) ; dynamically scoped
853(defun org-publish-aux-preprocess ()
854 "Find index entries and write them to an .orgx file."
855 (let ((case-fold-search t)
856 entry index target)
857 (goto-char (point-min))
858 (while
859 (and
860 (re-search-forward "^[ \t]*#\\+index:[ \t]*\\(.*?\\)[ \t]*$" nil t)
861 (> (match-end 1) (match-beginning 1)))
862 (setq entry (match-string 1))
863 (when (eq backend 'latex)
864 (replace-match (format "\\index{%s}" entry) t t))
865 (save-excursion
86fbb8ca 866 (ignore-errors (org-back-to-heading t))
ed21c5c8
CD
867 (setq target (get-text-property (point) 'target))
868 (setq target (or (cdr (assoc target org-export-preferred-target-alist))
869 (cdr (assoc target org-export-id-target-alist))
86fbb8ca 870 target ""))
ed21c5c8
CD
871 (push (cons entry target) index)))
872 (with-temp-file
873 (concat (file-name-sans-extension org-current-export-file) ".orgx")
874 (dolist (entry (nreverse index))
875 (insert (format "INDEX: (%s) %s\n" (cdr entry) (car entry)))))))
876
877(defun org-publish-index-generate-theindex.inc (directory)
878 "Generate the index from all .orgx files in the current directory and below."
879 (require 'find-lisp)
880 (let* ((fulldir (file-name-as-directory
881 (expand-file-name directory)))
882 (full-files (find-lisp-find-files directory "\\.orgx\\'"))
883 (re (concat "\\`" fulldir))
884 (files (mapcar (lambda (f) (if (string-match re f)
885 (substring f (match-end 0))
886 f))
887 full-files))
888 (default-directory directory)
889 index origfile buf target entry ibuffer
86fbb8ca 890 main last-main letter last-letter file sub link tgext)
ed21c5c8
CD
891 ;; `files' contains the list of relative file names
892 (dolist (file files)
893 (setq origfile (substring file 0 -1))
894 (setq buf (find-file-noselect file))
895 (with-current-buffer buf
896 (goto-char (point-min))
897 (while (re-search-forward "^INDEX: (\\(.*?\\)) \\(.*\\)" nil t)
898 (setq target (match-string 1)
899 entry (match-string 2))
900 (push (list entry origfile target) index)))
901 (kill-buffer buf))
902 (setq index (sort index (lambda (a b) (string< (downcase (car a))
903 (downcase (car b))))))
904 (setq ibuffer (find-file-noselect (expand-file-name "theindex.inc" directory)))
905 (with-current-buffer ibuffer
906 (erase-buffer)
907 (insert "* Index\n")
908 (setq last-letter nil)
909 (dolist (idx index)
910 (setq entry (car idx) file (nth 1 idx) target (nth 2 idx))
86fbb8ca
CD
911 (if (and (stringp target) (string-match "\\S-" target))
912 (setq tgext (concat "::#" target))
913 (setq tgext ""))
ed21c5c8
CD
914 (setq letter (upcase (substring entry 0 1)))
915 (when (not (equal letter last-letter))
916 (insert "** " letter "\n")
917 (setq last-letter letter))
918 (if (string-match "!" entry)
919 (setq main (substring entry 0 (match-beginning 0))
920 sub (substring entry (match-end 0)))
921 (setq main nil sub nil last-main nil))
922 (when (and main (not (equal main last-main)))
923 (insert " - " main "\n")
924 (setq last-main main))
86fbb8ca 925 (setq link (concat "[[file:" file tgext "]"
ed21c5c8
CD
926 "[" (or sub entry) "]]"))
927 (if (and main sub)
928 (insert " - " link "\n")
929 (insert " - " link "\n")))
930 (save-buffer))
931 (kill-buffer ibuffer)
932
933 (let ((index-file (expand-file-name "theindex.org" directory)))
934 (unless (file-exists-p index-file)
935 (setq ibuffer (find-file-noselect index-file))
936 (with-current-buffer ibuffer
937 (erase-buffer)
938 (insert "\n\n#+include: \"theindex.inc\"\n\n")
939 (save-buffer))
940 (kill-buffer ibuffer)))))
941
4fbd4750 942
86fbb8ca
CD
943;; Caching functions:
944
945(defun org-publish-write-cache-file (&optional free-cache)
946 "Write `org-publish-cache' to file.
947If FREE-CACHE, empty the cache."
948 (unless org-publish-cache
949 (error "%s" "`org-publish-write-cache-file' called, but no cache present"))
950
951 (let ((cache-file (org-publish-cache-get ":cache-file:")))
952 (unless cache-file
953 (error
954 "%s" "Cannot find cache-file name in `org-publish-write-cache-file'"))
955 (with-temp-file cache-file
956 (let ((print-level nil)
957 (print-length nil))
958 (insert "(setq org-publish-cache (make-hash-table :test 'equal :weakness nil :size 100))\n")
959 (maphash (lambda (k v)
960 (insert
961 (format (concat "(puthash %S "
962 (if (or (listp v) (symbolp v))
963 "'" "")
964 "%S org-publish-cache)\n") k v)))
965 org-publish-cache)))
966 (when free-cache (org-publish-reset-cache))))
967
968(defun org-publish-initialize-cache (project-name)
969 "Initialize the projects cache if not initialized yet and return it."
970
971 (unless project-name
972 (error "%s%s" "Cannot initialize `org-publish-cache' without projects name"
973 " in `org-publish-initialize-cache'"))
974
975 (unless (file-exists-p org-publish-timestamp-directory)
976 (make-directory org-publish-timestamp-directory t))
977 (if (not (file-directory-p org-publish-timestamp-directory))
978 (error "Org publish timestamp: %s is not a directory"
979 org-publish-timestamp-directory))
980
981 (unless (and org-publish-cache
982 (string= (org-publish-cache-get ":project:") project-name))
983 (let* ((cache-file (concat
984 (expand-file-name org-publish-timestamp-directory)
985 project-name
986 ".cache"))
987 (cexists (file-exists-p cache-file)))
988
989 (when org-publish-cache
990 (org-publish-reset-cache))
991
992 (if cexists
993 (load-file cache-file)
994 (setq org-publish-cache
995 (make-hash-table :test 'equal :weakness nil :size 100))
996 (org-publish-cache-set ":project:" project-name)
997 (org-publish-cache-set ":cache-file:" cache-file))
998 (unless cexists (org-publish-write-cache-file nil))))
999 org-publish-cache)
1000
1001(defun org-publish-reset-cache ()
1002 "Empty org-publish-cache and reset it nil."
1003 (message "%s" "Resetting org-publish-cache")
1004 (if (hash-table-p org-publish-cache)
1005 (clrhash org-publish-cache))
1006 (setq org-publish-cache nil))
1007
1008(defun org-publish-cache-file-needs-publishing (filename &optional pub-dir pub-func)
1009 "Check the timestamp of the last publishing of FILENAME.
1010Return `t', if the file needs publishing"
1011 (unless org-publish-cache
1012 (error "%s" "`org-publish-cache-file-needs-publishing' called, but no cache present"))
1013 (let* ((key (org-publish-timestamp-filename filename pub-dir pub-func))
1014 (pstamp (org-publish-cache-get key)))
1015 (if (null pstamp)
1016 t
1017 (let ((ctime (org-publish-cache-ctime-of-src filename)))
1018 (< pstamp ctime)))))
1019
1020(defun org-publish-cache-set-file-property (filename property value &optional project-name)
1021 "Set the VALUE for a PROPERTY of file FILENAME in publishing cache to VALUE.
1022Use cache file of PROJECT-NAME. If the entry does not exist, it will be
1023created. Return VALUE."
1024 ;; Evtl. load the requested cache file:
1025 (if project-name (org-publish-initialize-cache project-name))
1026 (let ((pl (org-publish-cache-get filename)))
1027 (if pl
1028 (progn
1029 (plist-put pl property value)
1030 value)
1031 (org-publish-cache-get-file-property
1032 filename property value nil project-name))))
1033
1034(defun org-publish-cache-get-file-property
1035 (filename property &optional default no-create project-name)
1036 "Return the value for a PROPERTY of file FILENAME in publishing cache.
1037Use cache file of PROJECT-NAME. Return the value of that PROPERTY or
1038DEFAULT, if the value does not yet exist.
1039If the entry will be created, unless NO-CREATE is not nil."
1040 ;; Evtl. load the requested cache file:
1041 (if project-name (org-publish-initialize-cache project-name))
1042 (let ((pl (org-publish-cache-get filename))
1043 (retval nil))
1044 (if pl
1045 (if (plist-member pl property)
1046 (setq retval (plist-get pl property))
1047 (setq retval default))
1048 ;; no pl yet:
1049 (unless no-create
1050 (org-publish-cache-set filename (list property default)))
1051 (setq retval default))
1052 retval))
1053
1054(defun org-publish-cache-get (key)
1055 "Return the value stored in `org-publish-cache' for key KEY.
1056Returns nil, if no value or nil is found, or the cache does not
1057exist."
1058 (unless org-publish-cache
1059 (error "%s" "`org-publish-cache-get' called, but no cache present"))
1060 (gethash key org-publish-cache))
1061
1062(defun org-publish-cache-set (key value)
1063 "Store KEY VALUE pair in `org-publish-cache'.
1064Returns value on success, else nil."
1065 (unless org-publish-cache
1066 (error "%s" "`org-publish-cache-set' called, but no cache present"))
1067 (puthash key value org-publish-cache))
1068
1069(defun org-publish-cache-ctime-of-src (filename)
1070 "Get the files ctime as integer."
1071 (let ((src-attr (file-attributes filename)))
1072 (+
1073 (lsh (car (nth 5 src-attr)) 16)
1074 (cadr (nth 5 src-attr)))))
1075
1076
1077
1078(provide 'org-publish)
699b9291 1079
b349f79f 1080
9542795a 1081;;; org-publish.el ends here