From bd172412fafaa0386762826677f9929c9c4fc41c Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Sat, 1 Mar 2008 02:42:28 +0000 Subject: [PATCH 1/9] Added support for recursive publication of files. --- org-export-latex.el | 8 ++- org-publish.el | 130 ++++++++++++++++++++++++++------------------ org.el | 18 +++--- 3 files changed, 92 insertions(+), 64 deletions(-) diff --git a/org-export-latex.el b/org-export-latex.el index 19c4e2c84..f98094e64 100644 --- a/org-export-latex.el +++ b/org-export-latex.el @@ -329,7 +329,7 @@ in a window. A non-interactive call will only retunr the buffer." ;;;###autoload (defun org-export-as-latex (arg &optional hidden ext-plist - to-buffer body-only) + to-buffer body-only pub-dir) "Export current buffer to a LaTeX file. If there is an active region, export only the region. The prefix ARG specifies how many levels of the outline should become @@ -344,7 +344,8 @@ buffer. If TO-BUFFER is the symbol `string', don't leave any buffer behind but just return the resulting LaTeX as a string. When BODY-ONLY is set, don't produce the file header and footer, simply return the content of \begin{document}...\end{document}, -without even the \begin{document} and \end{document} commands." +without even the \begin{document} and \end{document} commands. +when PUB-DIR is set, use this as the publishing directory." (interactive "P") ;; Make sure we have a file name when we need it. (when (and (not (or to-buffer body-only)) @@ -375,7 +376,8 @@ without even the \begin{document} and \end{document} commands." (file-name-sans-extension (file-name-nondirectory buffer-file-name)))) (filename (concat (file-name-as-directory - (org-export-directory :LaTeX ext-plist)) + (or pub-dir + (org-export-directory :LaTeX ext-plist))) (file-name-sans-extension (file-name-nondirectory ;sans-extension buffer-file-name)) ".tex")) diff --git a/org-publish.el b/org-publish.el index 5702898ee..5627e1a80 100644 --- a/org-publish.el +++ b/org-publish.el @@ -219,13 +219,13 @@ of output formats. :publishing-function Function to publish file. The default is org-publish-org-to-html, but other values are possible. May also be a - list of functions, in which case + list of functions, in which case each function in the list is invoked in turn. Another property allows you to insert code that prepares a project for publishing. For example, you could call GNU Make on a -certain makefile, to ensure published files are built up to date. +certain makefile, to ensure published files are built up to date. :preparation-function Function to be called before publishing this project. @@ -339,9 +339,8 @@ whether file should be published." ;;;; A hash mapping files to project names -(defvar org-publish-files (make-hash-table :test 'equal) "Hash -table mapping file names to project names.") - +(defvar org-publish-files (make-hash-table :test 'equal) + "Hash table mapping file names to project names.") ;;;; Checking filenames against this hash @@ -353,7 +352,6 @@ table mapping file names to project names.") ;;;; Getting project information out of org-publish-project-alist - (defun org-publish-get-plists (&optional project-name) "Return a list of property lists for project PROJECT-NAME. When argument is not given, return all property lists for all projects." @@ -364,8 +362,6 @@ When argument is not given, return all property lists for all projects." (plists nil) (single nil) (components nil)) - - ;; ;; (while (setq project (pop alist)) ;; what kind of project is it? @@ -386,31 +382,38 @@ When argument is not given, return all property lists for all projects." plists)) - (defun org-publish-get-base-files (plist &optional exclude-regexp) "Return a list of all files in project defined by PLIST. -If EXCLUDE-REGEXP is set, this will be used to filter out -matching filenames." - (let* ((dir (file-name-as-directory (plist-get plist :base-directory))) - (include-list (plist-get plist :include)) - (extension (or (plist-get plist :base-extension) "org")) - (regexp (concat "^[^\\.].*\\.\\(" extension "\\)$")) - (allfiles (directory-files dir t regexp))) - ;; - ;; exclude files - (setq allfiles - (if (not exclude-regexp) - allfiles - (delq nil - (mapcar (lambda (x) - (if (string-match exclude-regexp x) nil x)) - allfiles)))) - ;; - ;; include extra files - (let ((inc nil)) - (while (setq inc (pop include-list)) - (setq allfiles (cons (expand-file-name inc dir) allfiles)))) - + If EXCLUDE-REGEXP is set, this will be used to filter out + matching filenames." + (let* ((base-dir (file-name-as-directory (plist-get plist :base-directory))) + (include-list (plist-get plist :include)) + (recursive-p (plist-get plist :recursive)) + (extension (or (plist-get plist :base-extension) "org")) + (regexp (concat "^[^\\.].*\\.\\(" extension "\\)$")) + alldirs allfiles files dir) + ;; Get all files and directories in base-directory + (setq files (dired-files-attributes base-dir)) + ;; Get all subdirectories if recursive-p + (setq alldirs + (if recursive-p + (delete nil (mapcar (lambda(f) (if (caaddr f) (cadr f))) files)) + (list base-dir))) + (while (setq dir (pop alldirs)) + (setq files (directory-files dir t regexp)) + ;; Exclude files + (setq files + (if (not exclude-regexp) + files + (delq nil + (mapcar (lambda (x) + (if (string-match exclude-regexp x) nil x)) + files)))) + ;; Include extra files + (let ((inc nil)) + (while (setq inc (pop include-list)) + (setq files (cons (expand-file-name inc dir) files)))) + (setq allfiles (append allfiles files))) allfiles)) @@ -430,32 +433,33 @@ nil if not found." (let ((files (org-publish-get-base-files plist))) (if (member (expand-file-name filename) files) (setq found plist)))) + org-publish-plists (org-publish-get-plists)) found)) - ;;;; Pluggable publishing back-end functions -(defun org-publish-org-to-latex (plist filename) +(defun org-publish-org-to-latex (plist filename &optional tmp-pub-dir) "Publish an org file to LaTeX." - (org-publish-org-to "latex" plist filename)) + (org-publish-org-to "latex" plist filename tmp-pub-dir)) -(defun org-publish-org-to-html (plist filename) +(defun org-publish-org-to-html (plist filename &optional tmp-pub-dir) "Publish an org file to HTML." - (org-publish-org-to "html" plist filename)) + (org-publish-org-to "html" plist filename tmp-pub-dir)) -(defun org-publish-org-to (format plist filename) +(defun org-publish-org-to (format plist filename &optional tmp-pub-dir) "Publish an org file to FORMAT. PLIST is the property list for the given project. FILENAME is the filename of the org file to be published." (require 'org) - (let* ((arg (plist-get plist :headline-levels))) - (progn - (find-file filename) - (funcall (intern (concat "org-export-as-" format)) - arg nil plist) - (kill-buffer (current-buffer))))) + (unless (file-exists-p tmp-pub-dir) + (make-directory tmp-pub-dir t)) + (find-file filename) + (funcall (intern (concat "org-export-as-" format)) + (plist-get plist :headline-levels) + nil plist nil nil tmp-pub-dir) + (kill-buffer (current-buffer))) (defun org-publish-attachment (plist filename) @@ -463,11 +467,12 @@ FILENAME is the filename of the org file to be published." PLIST is the property list for the given project. FILENAME is the filename of the file to be published." ;; make sure eshell/cp code is loaded - (eval-and-compile + (eval-and-compile (require 'eshell) (require 'esh-maint) (require 'em-unix)) - (let ((destination (file-name-as-directory (plist-get plist :publishing-directory)))) + (let ((destination (file-name-as-directory + (plist-get plist :publishing-directory)))) (eshell/cp filename destination))) @@ -478,16 +483,25 @@ FILENAME is the filename of the file to be published." "Publish file FILENAME." (let* ((project-name (org-publish-get-project-from-filename filename)) (plist (org-publish-get-plist-from-filename filename)) - (publishing-function (or (plist-get plist :publishing-function) 'org-publish-org-to-html))) + (publishing-function (or (plist-get plist :publishing-function) + 'org-publish-org-to-html)) + (base-dir (file-truename (plist-get plist :base-directory))) + (pub-dir (file-truename (plist-get plist :publishing-directory))) + tmp-pub-dir) (if (not project-name) (error "File %s is not part of any known project" filename)) (when (org-publish-needed-p filename) + (setq tmp-pub-dir + (file-name-directory + (concat pub-dir + (and (string-match (regexp-quote base-dir) f) + (substring f (match-end 0)))))) (if (listp publishing-function) ;; allow chain of publishing functions (mapc (lambda (f) - (funcall f plist filename)) + (funcall f plist filename)) publishing-function) - (funcall publishing-function plist filename)) + (funcall publishing-function plist filename tmp-pub-dir)) (org-publish-update-timestamp filename)))) @@ -495,7 +509,8 @@ FILENAME is the filename of the file to be published." "Publish all files in set defined by PLIST. If :auto-index is set, publish the index too." (let* ((exclude-regexp (plist-get plist :exclude)) - (publishing-function (or (plist-get plist :publishing-function) 'org-publish-org-to-html)) + (publishing-function (or (plist-get plist :publishing-function) + 'org-publish-org-to-html)) (index-p (plist-get plist :auto-index)) (index-filename (or (plist-get plist :index-filename) "index.org")) (index-function (or (plist-get plist :index-function) 'org-publish-org-index)) @@ -506,16 +521,26 @@ FILENAME is the filename of the file to be published." (funcall preparation-function)) (if index-p (funcall index-function plist index-filename)) - (let ((files (org-publish-get-base-files plist exclude-regexp))) + (let ((files (org-publish-get-base-files plist exclude-regexp)) + (base-dir (file-truename (plist-get plist :base-directory))) + (pub-dir (file-truename (plist-get plist :publishing-directory))) + tmp-pub-dir) + ;; (while (setq f (pop files)) + ;; set the right :publishing-directory + (setq tmp-pub-dir + (file-name-directory + (concat pub-dir + (and (string-match (regexp-quote base-dir) f) + (substring f (match-end 0)))))) ;; check timestamps (when (org-publish-needed-p f) (if (listp publishing-function) ;; allow chain of publishing functions (mapc (lambda (func) - (funcall func plist f)) + (funcall func plist f)) publishing-function) - (funcall publishing-function plist f)) + (funcall publishing-function plist f tmp-pub-dir)) (org-publish-update-timestamp f)))))) @@ -530,7 +555,6 @@ default is 'index.org'." (index-buffer (find-buffer-visiting index-filename)) (ifn (file-name-nondirectory index-filename)) (f nil)) - ;; ;; if buffer is already open, kill it to prevent error message (if index-buffer (kill-buffer index-buffer)) diff --git a/org.el b/org.el index c7eab7ea8..d507cbe89 100644 --- a/org.el +++ b/org.el @@ -25221,7 +25221,7 @@ in a window. A non-interactive call will only retunr the buffer." (defvar html-table-tag nil) ; dynamically scoped into this. (defun org-export-as-html (arg &optional hidden ext-plist - to-buffer body-only) + to-buffer body-only pub-dir) "Export the outline as a pretty HTML file. If there is an active region, export only the region. The prefix ARG specifies how many levels of the outline should become @@ -25230,11 +25230,12 @@ lists. When HIDDEN is non-nil, don't display the HTML buffer. EXT-PLIST is a property list with external parameters overriding org-mode's default settings, but still inferior to file-local settings. When TO-BUFFER is non-nil, create a buffer with that -name and export to that buffer. If TO-BUFFER is the symbol `string', -don't leave any buffer behind but just return the resulting HTML as -a string. When BODY-ONLY is set, don't produce the file header and footer, -simply return the content of ..., without even -the body tags themselves." +name and export to that buffer. If TO-BUFFER is the symbol +`string', don't leave any buffer behind but just return the +resulting HTML as a string. When BODY-ONLY is set, don't produce +the file header and footer, simply return the content of +..., without even the body tags themselves. When +PUB-DIR is set, use this as the publishing directory." (interactive "P") ;; Make sure we have a file name when we need it. @@ -25269,7 +25270,8 @@ the body tags themselves." (>= (org-end-of-subtree t t) (region-end)))))) ;; The following two are dynamically scoped into other ;; routines below. - (org-current-export-dir (org-export-directory :html opt-plist)) + (org-current-export-dir + (or pub-dir (org-export-directory :html opt-plist))) (org-current-export-file buffer-file-name) (level 0) (line "") (origline "") txt todo (umax nil) @@ -25284,7 +25286,7 @@ the body tags themselves." (file-name-nondirectory buffer-file-name))) "." html-extension) (file-name-as-directory - (org-export-directory :html opt-plist))))) + (or pub-dir (org-export-directory :html opt-plist)))))) (current-dir (if buffer-file-name (file-name-directory buffer-file-name) default-directory)) From 960449c9e93725f791bd450d3c85fd71339efb09 Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Sun, 2 Mar 2008 00:52:52 +0000 Subject: [PATCH 2/9] Cleaned up the buffer. --- org-publish.el | 159 ++++++++++++++++++++----------------------------- 1 file changed, 65 insertions(+), 94 deletions(-) diff --git a/org-publish.el b/org-publish.el index 5627e1a80..a50d45b88 100644 --- a/org-publish.el +++ b/org-publish.el @@ -3,8 +3,9 @@ ;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. ;; Author: David O'Toole -;; Keywords: hypermedia, outlines -;; Version: 1.80c +;; Maintainer: Bastien Guerry +;; Keywords: hypermedia, outlines, wp +;; Version: 1.80c+ ;; This file is part of GNU Emacs. ;; @@ -26,24 +27,17 @@ ;;; Commentary: ;; Requires at least version 4.27 of org.el -;; -;; The official org-mode website: -;; http://staff.science.uva.nl/~dominik/Tools/org/ -;; -;; Home page for org-publish.el: -;; http://dto.freeshell.org/notebook/OrgMode.html -;; This program extends the HTML publishing support of Emacs Org-mode -;; to allow configurable publishing of related sets of files as a -;; complete website. +;; This program allow configurable publishing of related sets of +;; Org-mode files as a complete website. ;; ;; org-publish.el can do the following: ;; -;; + Publish all one's org-files to html -;; + Upload html, images, attachments and other files to a web server +;; + Publish all one's org-files to HTML or LaTeX +;; + Upload HTML, images, attachments and other files to a web server ;; + Exclude selected private pages from publishing ;; + Publish a clickable index of pages -;; + Manage local timestamps, for publishing only changed files +;; + Manage local timestamps for publishing only changed files ;; + Accept plugin functions to extend range of publishable content ;; ;; Special thanks to the org-mode maintainer Carsten Dominik for his @@ -135,7 +129,6 @@ ;; within emacs. You can always just publish to local folders, and ;; then use the synchronization/upload tool of your choice. - ;;; List of user-visible changes since version 1.27 ;; 1.78: Allow list-valued :publishing-function @@ -158,17 +151,14 @@ ;;; Code: - (eval-when-compile (require 'cl)) - (defgroup org-publish nil "Options for publishing a set of Org-mode and related files." :tag "Org Publishing" :group 'org) - (defcustom org-publish-project-alist nil "Association list to control publishing behavior. Each element of the alist is a publishing 'project.' The CAR of @@ -194,11 +184,11 @@ override everything. Most properties are optional, but some should always be set: - :base-directory Directory containing publishing source files - :base-extension Extension (without the dot!) of source files. - This can be a regular expression. - :publishing-directory Directory (possibly remote) where output - files will be published + :base-directory Directory containing publishing source files + :base-extension Extension (without the dot!) of source files. + This can be a regular expression. + :publishing-directory Directory (possibly remote) where output + files will be published The :exclude property may be used to prevent certain files from being published. Its value may be a string or regexp matching @@ -216,65 +206,63 @@ publishing files in the project. This can be used to extend the set of file types publishable by org-publish, as well as the set of output formats. - :publishing-function Function to publish file. The default is - org-publish-org-to-html, but other - values are possible. May also be a - list of functions, in which case - each function in the list is invoked - in turn. + :publishing-function Function to publish file. The default is + org-publish-org-to-html, but other + values are possible. May also be a + list of functions, in which case + each function in the list is invoked + in turn. Another property allows you to insert code that prepares a project for publishing. For example, you could call GNU Make on a -certain makefile, to ensure published files are built up to date. +certain makefile, to ensure published files are built up to date. - :preparation-function Function to be called before publishing - this project. + :preparation-function Function to be called before publishing + this project. Some properties control details of the Org publishing process, and are equivalent to the corresponding user variables listed in the right column. See the documentation for those variables to learn more about their use and default values. - :language org-export-default-language - :headline-levels org-export-headline-levels - :section-numbers org-export-with-section-numbers - :table-of-contents org-export-with-toc - :emphasize org-export-with-emphasize - :sub-superscript org-export-with-sub-superscripts - :TeX-macros org-export-with-TeX-macros - :fixed-width org-export-with-fixed-width - :tables org-export-with-tables - :table-auto-headline org-export-highlight-first-table-line - :style org-export-html-style - :convert-org-links org-export-html-link-org-files-as-html - :inline-images org-export-html-inline-images - :expand-quoted-html org-export-html-expand - :timestamp org-export-html-with-timestamp - :publishing-directory org-export-publishing-directory - :preamble org-export-html-preamble - :postamble org-export-html-postamble - :auto-preamble org-export-html-auto-preamble - :auto-postamble org-export-html-auto-postamble - :author user-full-name - :email user-mail-address + :language org-export-default-language + :headline-levels org-export-headline-levels + :section-numbers org-export-with-section-numbers + :table-of-contents org-export-with-toc + :emphasize org-export-with-emphasize + :sub-superscript org-export-with-sub-superscripts + :TeX-macros org-export-with-TeX-macros + :fixed-width org-export-with-fixed-width + :tables org-export-with-tables + :table-auto-headline org-export-highlight-first-table-line + :style org-export-html-style + :convert-org-links org-export-html-link-org-files-as-html + :inline-images org-export-html-inline-images + :expand-quoted-html org-export-html-expand + :timestamp org-export-html-with-timestamp + :publishing-directory org-export-publishing-directory + :preamble org-export-html-preamble + :postamble org-export-html-postamble + :auto-preamble org-export-html-auto-preamble + :auto-postamble org-export-html-auto-postamble + :author user-full-name + :email user-mail-address The following properties may be used to control publishing of an index of files or summary page for a given project. - :auto-index Whether to publish an index during - org-publish-current-project or org-publish-all. - :index-filename Filename for output of index. Defaults - to 'index.org' (which becomes 'index.html') - :index-title Title of index page. Defaults to name of file. - :index-function Plugin function to use for generation of index. - Defaults to 'org-publish-org-index', which - generates a plain list of links to all files - in the project. -" + :auto-index Whether to publish an index during + org-publish-current-project or org-publish-all. + :index-filename Filename for output of index. Defaults + to 'index.org' (which becomes 'index.html') + :index-title Title of index page. Defaults to name of file. + :index-function Plugin function to use for generation of index. + Defaults to 'org-publish-org-index', which + generates a plain list of links to all files + in the project." :group 'org-publish :type 'alist) - (defcustom org-publish-use-timestamps-flag t "When non-nil, use timestamp checking to publish only changed files. When nil, do no timestamp checking and always publish all @@ -282,14 +270,12 @@ files." :group 'org-publish :type 'boolean) - (defcustom org-publish-timestamp-directory "~/.org-timestamps/" "Name of directory in which to store publishing timestamps." :group 'org-publish :type 'string) - -;;;; Timestamp-related functions +;;; Timestamp-related functions (defun org-publish-timestamp-filename (filename) "Return path to timestamp file for filename FILENAME." @@ -326,7 +312,6 @@ whether file should be published." rtn)) t)) - (defun org-publish-update-timestamp (filename) "Update publishing timestamp for file FILENAME." (let ((timestamp (org-publish-timestamp-filename filename))) @@ -335,22 +320,24 @@ whether file should be published." (set-file-times timestamp) (call-process "touch" nil 0 nil timestamp)))) - -;;;; A hash mapping files to project names - +;;; A hash mapping files to project names (defvar org-publish-files (make-hash-table :test 'equal) "Hash table mapping file names to project names.") -;;;; Checking filenames against this hash +;; (defvar org-publish-files nil +;; "Alist of files and their parent project.") +;; (defvar org-publish-all-files nil +;; "Alist of all files and their parent projects.") + +;;; Checking filenames against this hash (defun org-publish-validate-link (link &optional directory) (gethash (file-truename (expand-file-name link directory)) org-publish-files)) - -;;;; Getting project information out of org-publish-project-alist +;;; Getting project information out of org-publish-project-alist (defun org-publish-get-plists (&optional project-name) "Return a list of property lists for project PROJECT-NAME. @@ -381,7 +368,6 @@ When argument is not given, return all property lists for all projects." (puthash (file-truename f) (car project) org-publish-files))))) plists)) - (defun org-publish-get-base-files (plist &optional exclude-regexp) "Return a list of all files in project defined by PLIST. If EXCLUDE-REGEXP is set, this will be used to filter out @@ -416,7 +402,6 @@ When argument is not given, return all property lists for all projects." (setq allfiles (append allfiles files))) allfiles)) - (defun org-publish-get-project-from-filename (filename) "Figure out which project a given FILENAME belongs to, if any. Filename should contain full path. Returns name of project, or @@ -424,7 +409,6 @@ nil if not found." (org-publish-get-plists) (gethash (file-truename filename) org-publish-files)) - (defun org-publish-get-plist-from-filename (filename) "Return publishing configuration plist for file FILENAME." (let ((found nil)) @@ -437,8 +421,7 @@ nil if not found." (org-publish-get-plists)) found)) - -;;;; Pluggable publishing back-end functions +;;; Pluggable publishing back-end functions (defun org-publish-org-to-latex (plist filename &optional tmp-pub-dir) "Publish an org file to LaTeX." @@ -461,7 +444,6 @@ FILENAME is the filename of the org file to be published." nil plist nil nil tmp-pub-dir) (kill-buffer (current-buffer))) - (defun org-publish-attachment (plist filename) "Publish a file with no transformation of any kind. PLIST is the property list for the given project. @@ -475,9 +457,7 @@ FILENAME is the filename of the file to be published." (plist-get plist :publishing-directory)))) (eshell/cp filename destination))) - -;;;; Publishing files, sets of files, and indices - +;;; Publishing files, sets of files, and indices (defun org-publish-file (filename) "Publish file FILENAME." @@ -504,7 +484,6 @@ FILENAME is the filename of the file to be published." (funcall publishing-function plist filename tmp-pub-dir)) (org-publish-update-timestamp filename)))) - (defun org-publish-plist (plist) "Publish all files in set defined by PLIST. If :auto-index is set, publish the index too." @@ -543,7 +522,6 @@ FILENAME is the filename of the file to be published." (funcall publishing-function plist f tmp-pub-dir)) (org-publish-update-timestamp f)))))) - (defun org-publish-org-index (plist &optional index-filename) "Create an index of pages in set defined by PLIST. Optionally set the filename of the index with INDEX-FILENAME; @@ -568,9 +546,7 @@ default is 'index.org'." (write-file index-filename) (kill-buffer (current-buffer))))) - -;;;; Interactive publishing functions - +;;; Interactive publishing functions ;;;###autoload (defun org-publish (project-name &optional force) @@ -584,7 +560,6 @@ default is 'index.org'." (plists (org-publish-get-plists project-name))) (mapcar 'org-publish-plist plists)))) - ;;;###autoload (defun org-publish-current-project (&optional force) "Publish the project associated with the current file. @@ -598,7 +573,6 @@ With prefix argument, force publishing all files in project." (error "File %s is not part of any known project" (buffer-file-name))) (org-publish project-name)))) - ;;;###autoload (defun org-publish-current-file (&optional force) "Publish the current file. @@ -609,7 +583,6 @@ With prefix argument, force publish the file." (if force nil org-publish-use-timestamps-flag))) (org-publish-file (buffer-file-name))))) - ;;;###autoload (defun org-publish-all (&optional force) "Publish all projects. @@ -621,8 +594,6 @@ With prefix argument, force publish all files." (plists (org-publish-get-plists))) (mapcar 'org-publish-plist plists)))) - - (provide 'org-publish) ;; arch-tag: 72807f3c-8af0-4a6b-8dca-c3376eb25adb From 837c81ce51d90427bbcc32b06d84505b1a1e6b2a Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Sun, 2 Mar 2008 01:02:41 +0000 Subject: [PATCH 3/9] Use alist instead of a hashtable. --- org-publish.el | 81 +++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/org-publish.el b/org-publish.el index a50d45b88..9fa072863 100644 --- a/org-publish.el +++ b/org-publish.el @@ -209,13 +209,13 @@ of output formats. :publishing-function Function to publish file. The default is org-publish-org-to-html, but other values are possible. May also be a - list of functions, in which case + list of functions, in which case each function in the list is invoked in turn. Another property allows you to insert code that prepares a project for publishing. For example, you could call GNU Make on a -certain makefile, to ensure published files are built up to date. +certain makefile, to ensure published files are built up to date. :preparation-function Function to be called before publishing this project. @@ -322,35 +322,30 @@ whether file should be published." ;;; A hash mapping files to project names -(defvar org-publish-files (make-hash-table :test 'equal) - "Hash table mapping file names to project names.") +(defvar org-publish-files nil + "Alist of files and their parent project.") -;; (defvar org-publish-files nil -;; "Alist of files and their parent project.") - -;; (defvar org-publish-all-files nil -;; "Alist of all files and their parent projects.") +(defvar org-publish-all-files nil + "Alist of all files and their parent projects.") ;;; Checking filenames against this hash -(defun org-publish-validate-link (link &optional directory) - (gethash (file-truename (expand-file-name link directory)) - org-publish-files)) +;; FIXME Is this used somewhere? + +;; (defun org-publish-validate-link (link &optional directory) +;; (gethash (file-truename (expand-file-name link directory)) +;; org-publish-files)) ;;; Getting project information out of org-publish-project-alist (defun org-publish-get-plists (&optional project-name) "Return a list of property lists for project PROJECT-NAME. When argument is not given, return all property lists for all projects." - (let ((alist (if project-name - (list (assoc project-name org-publish-project-alist)) - org-publish-project-alist)) - (project nil) - (plists nil) - (single nil) - (components nil)) - ;; - (while (setq project (pop alist)) + (let ((projects (if project-name + (list (assoc project-name org-publish-project-alist)) + org-publish-project-alist)) + project plists single components) + (while (setq project (pop projects)) ;; what kind of project is it? (if (setq components (plist-get (cdr project) :components)) ;; meta project. annotate each plist with name of enclosing project @@ -359,13 +354,13 @@ When argument is not given, return all property lists for all projects." (mapcar 'org-publish-get-plists components))) ;; normal project (setq single (list (cdr project)))) - ;; (setq plists (append plists single)) (dolist (p single) (let* ((exclude (plist-get p :exclude)) (files (org-publish-get-base-files p exclude))) (dolist (f files) - (puthash (file-truename f) (car project) org-publish-files))))) + (add-to-list 'org-publish-files + (cons (file-truename f) (car project)) t))))) plists)) (defun org-publish-get-base-files (plist &optional exclude-regexp) @@ -396,7 +391,7 @@ When argument is not given, return all property lists for all projects." (if (string-match exclude-regexp x) nil x)) files)))) ;; Include extra files - (let ((inc nil)) + (let (inc) (while (setq inc (pop include-list)) (setq files (cons (expand-file-name inc dir) files)))) (setq allfiles (append allfiles files))) @@ -407,11 +402,11 @@ When argument is not given, return all property lists for all projects." Filename should contain full path. Returns name of project, or nil if not found." (org-publish-get-plists) - (gethash (file-truename filename) org-publish-files)) + (cadr (assoc (file-truename filename) org-publish-files))) (defun org-publish-get-plist-from-filename (filename) "Return publishing configuration plist for file FILENAME." - (let ((found nil)) + (let (found) (mapc (lambda (plist) (let ((files (org-publish-get-base-files plist))) @@ -453,7 +448,7 @@ FILENAME is the filename of the file to be published." (require 'eshell) (require 'esh-maint) (require 'em-unix)) - (let ((destination (file-name-as-directory + (let ((destination (file-name-as-directory (plist-get plist :publishing-directory)))) (eshell/cp filename destination))) @@ -463,7 +458,7 @@ FILENAME is the filename of the file to be published." "Publish file FILENAME." (let* ((project-name (org-publish-get-project-from-filename filename)) (plist (org-publish-get-plist-from-filename filename)) - (publishing-function (or (plist-get plist :publishing-function) + (publishing-function (or (plist-get plist :publishing-function) 'org-publish-org-to-html)) (base-dir (file-truename (plist-get plist :base-directory))) (pub-dir (file-truename (plist-get plist :publishing-directory))) @@ -471,7 +466,7 @@ FILENAME is the filename of the file to be published." (if (not project-name) (error "File %s is not part of any known project" filename)) (when (org-publish-needed-p filename) - (setq tmp-pub-dir + (setq tmp-pub-dir (file-name-directory (concat pub-dir (and (string-match (regexp-quote base-dir) f) @@ -488,14 +483,13 @@ FILENAME is the filename of the file to be published." "Publish all files in set defined by PLIST. If :auto-index is set, publish the index too." (let* ((exclude-regexp (plist-get plist :exclude)) - (publishing-function (or (plist-get plist :publishing-function) + (publishing-function (or (plist-get plist :publishing-function) 'org-publish-org-to-html)) (index-p (plist-get plist :auto-index)) (index-filename (or (plist-get plist :index-filename) "index.org")) (index-function (or (plist-get plist :index-function) 'org-publish-org-index)) (preparation-function (plist-get plist :preparation-function)) - (f nil)) - ;; + file) (when preparation-function (funcall preparation-function)) (if index-p @@ -504,23 +498,22 @@ FILENAME is the filename of the file to be published." (base-dir (file-truename (plist-get plist :base-directory))) (pub-dir (file-truename (plist-get plist :publishing-directory))) tmp-pub-dir) - ;; - (while (setq f (pop files)) + (while (setq file (pop files)) ;; set the right :publishing-directory - (setq tmp-pub-dir + (setq tmp-pub-dir (file-name-directory (concat pub-dir - (and (string-match (regexp-quote base-dir) f) + (and (string-match (regexp-quote base-dir) file) (substring f (match-end 0)))))) ;; check timestamps - (when (org-publish-needed-p f) + (when (org-publish-needed-p file) (if (listp publishing-function) ;; allow chain of publishing functions (mapc (lambda (func) - (funcall func plist f)) + (funcall func plist file)) publishing-function) - (funcall publishing-function plist f tmp-pub-dir)) - (org-publish-update-timestamp f)))))) + (funcall publishing-function plist file tmp-pub-dir)) + (org-publish-update-timestamp file)))))) (defun org-publish-org-index (plist &optional index-filename) "Create an index of pages in set defined by PLIST. @@ -531,14 +524,14 @@ default is 'index.org'." (files (org-publish-get-base-files plist exclude-regexp)) (index-filename (concat dir (or index-filename "index.org"))) (index-buffer (find-buffer-visiting index-filename)) - (ifn (file-name-nondirectory index-filename)) - (f nil)) + (ifn (file-name-nondirectory index-filename)) + file) ;; if buffer is already open, kill it to prevent error message (if index-buffer (kill-buffer index-buffer)) (with-temp-buffer - (while (setq f (pop files)) - (let ((fn (file-name-nondirectory f))) + (while (setq file (pop files)) + (let ((fn (file-name-nondirectory file))) (unless (string= fn ifn) ;; index shouldn't index itself (insert (concat " + [[file:" fn "][" (file-name-sans-extension fn) From b05bc10e6794c902df679b906d8bd6ec3f5633a9 Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Sun, 2 Mar 2008 14:14:52 +0000 Subject: [PATCH 4/9] Cleaned up code. --- org-publish.el | 346 +++++++++++++++++++++++++------------------------ 1 file changed, 179 insertions(+), 167 deletions(-) diff --git a/org-publish.el b/org-publish.el index 9fa072863..bf9a88550 100644 --- a/org-publish.el +++ b/org-publish.el @@ -275,6 +275,8 @@ files." :group 'org-publish :type 'string) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Timestamp-related functions (defun org-publish-timestamp-filename (filename) @@ -284,6 +286,11 @@ files." (setq filename (replace-match "_" nil t filename))) (concat org-publish-timestamp-directory filename ".timestamp")) +;; FIXME removed org-publish-validate-link +;; FIXME deleted org-publish-get-plists-from-filename +;; FIXME deleted org-publish-get-plists + +;; FIXME deleted :parents (defun org-publish-needed-p (filename) "Check whether file should be published. If org-publish-use-timestamps-flag is set to nil, this function always @@ -291,13 +298,11 @@ returns t. Otherwise, check the timestamps folder to determine whether file should be published." (if org-publish-use-timestamps-flag (progn - ;; ;; create folder if needed (if (not (file-exists-p org-publish-timestamp-directory)) (make-directory org-publish-timestamp-directory) (if (not (file-directory-p org-publish-timestamp-directory)) (error "`org-publish-timestamp-directory' must be a directory"))) - ;; ;; check timestamp. ok if timestamp file doesn't exist (let* ((timestamp (org-publish-timestamp-filename filename)) (rtn (file-newer-than-file-p filename timestamp))) @@ -306,10 +311,11 @@ whether file should be published." (if (not (file-exists-p timestamp)) ;; create file (with-temp-buffer - (make-directory (file-name-directory timestamp) :parents) + (make-directory (file-name-directory timestamp) t) (write-file timestamp) (kill-buffer (current-buffer))))) rtn)) + ;; always return `t' is we don't use timestamp t)) (defun org-publish-update-timestamp (filename) @@ -320,57 +326,79 @@ whether file should be published." (set-file-times timestamp) (call-process "touch" nil 0 nil timestamp)))) -;;; A hash mapping files to project names -(defvar org-publish-files nil - "Alist of files and their parent project.") +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mapping files to project names -(defvar org-publish-all-files nil - "Alist of all files and their parent projects.") +;; FIXME annonce renaming +(defvar org-publish-files-alist nil + "Alist of files and their parent project. +Each element of this alist is of the form: -;;; Checking filenames against this hash + (file-name . project-name)") -;; FIXME Is this used somewhere? +;; FIXME annonce this new defun +(defun org-publish-initialize-files-alist (&optional refresh) + "Set `org-publish-files-alist' if it is not set. +Also set it if the optional argument REFRESH is non-nil." + (when (or (not org-publish-files-alist) refresh) + (setq org-publish-files-alist + (org-publish-get-files org-publish-project-alist)))) -;; (defun org-publish-validate-link (link &optional directory) -;; (gethash (file-truename (expand-file-name link directory)) -;; org-publish-files)) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Getting project information out of org-publish-project-alist -(defun org-publish-get-plists (&optional project-name) - "Return a list of property lists for project PROJECT-NAME. -When argument is not given, return all property lists for all projects." - (let ((projects (if project-name - (list (assoc project-name org-publish-project-alist)) - org-publish-project-alist)) - project plists single components) - (while (setq project (pop projects)) - ;; what kind of project is it? - (if (setq components (plist-get (cdr project) :components)) - ;; meta project. annotate each plist with name of enclosing project - (setq single - (apply 'append - (mapcar 'org-publish-get-plists components))) - ;; normal project - (setq single (list (cdr project)))) - (setq plists (append plists single)) - (dolist (p single) - (let* ((exclude (plist-get p :exclude)) - (files (org-publish-get-base-files p exclude))) - (dolist (f files) - (add-to-list 'org-publish-files - (cons (file-truename f) (car project)) t))))) - plists)) +;; FIXME annonce this new defun +(defun org-publish-get-files (projects-alist &optional no-exclusion) + "Return the list of all publishable files for PROJECTS-ALIST. +If NO-EXCLUSION is non-nil, don't exclude files." + (let (all-files) + ;; add all projects + (mapc + (lambda(p) + (let* ((exclude (plist-get p :exclude)) + (files (org-publish-get-base-files p exclude))) + ;; add all files from this project + (mapc (lambda(f) + (add-to-list 'all-files + (cons (file-truename f) (car p)))) + files))) + (org-publish-expand-projects projects-alist)) + all-files)) -(defun org-publish-get-base-files (plist &optional exclude-regexp) - "Return a list of all files in project defined by PLIST. - If EXCLUDE-REGEXP is set, this will be used to filter out - matching filenames." - (let* ((base-dir (file-name-as-directory (plist-get plist :base-directory))) - (include-list (plist-get plist :include)) - (recursive-p (plist-get plist :recursive)) - (extension (or (plist-get plist :base-extension) "org")) +;; ;; FIXME annonce this new defun +(defun org-publish-expand-projects (projects-alist) + "Expand projects contained in PROJECTS-ALIST." + (let (without-component with-component) + (mapcar (lambda(p) + (add-to-list + (if (plist-get (cdr p) :components) + 'with-component 'without-component) p)) + projects-alist) + (delete-dups + (append without-component + (car (mapcar (lambda(p) (org-publish-expand-components p)) + with-component)))))) + +;; FIXME annonce this new defun +(defun org-publish-expand-components (project) + "Expand PROJECT into an alist of its components." + (let* ((components (plist-get (cdr project) :components))) + (delete-dups + (mapcar (lambda(c) (assoc c org-publish-project-alist)) + components)))) + +(defun org-publish-get-base-files (project &optional exclude-regexp) + "Return a list of all files in PROJECT. +If EXCLUDE-REGEXP is set, this will be used to filter out +matching filenames." + (let* ((project-plist (cdr project)) + (base-dir (file-name-as-directory + (plist-get project-plist :base-directory))) + (include-list (plist-get project-plist :include)) + (recursive-p (plist-get project-plist :recursive)) + (extension (or (plist-get project-plist :base-extension) "org")) (regexp (concat "^[^\\.].*\\.\\(" extension "\\)$")) alldirs allfiles files dir) ;; Get all files and directories in base-directory @@ -378,7 +406,7 @@ When argument is not given, return all property lists for all projects." ;; Get all subdirectories if recursive-p (setq alldirs (if recursive-p - (delete nil (mapcar (lambda(f) (if (caaddr f) (cadr f))) files)) + (delq nil (mapcar (lambda(f) (if (caaddr f) (cadr f))) files)) (list base-dir))) (while (setq dir (pop alldirs)) (setq files (directory-files dir t regexp)) @@ -398,47 +426,39 @@ When argument is not given, return all property lists for all projects." allfiles)) (defun org-publish-get-project-from-filename (filename) - "Figure out which project a given FILENAME belongs to, if any. -Filename should contain full path. Returns name of project, or -nil if not found." - (org-publish-get-plists) - (cadr (assoc (file-truename filename) org-publish-files))) + "Return the project FILENAME belongs." + (let* ((project-name (cdr (assoc (file-truename filename) + org-publish-files-alist)))) + (assoc project-name org-publish-project-alist))) -(defun org-publish-get-plist-from-filename (filename) - "Return publishing configuration plist for file FILENAME." - (let (found) - (mapc - (lambda (plist) - (let ((files (org-publish-get-base-files plist))) - (if (member (expand-file-name filename) files) - (setq found plist)))) - org-publish-plists - (org-publish-get-plists)) - found)) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Pluggable publishing back-end functions -(defun org-publish-org-to-latex (plist filename &optional tmp-pub-dir) - "Publish an org file to LaTeX." - (org-publish-org-to "latex" plist filename tmp-pub-dir)) - -(defun org-publish-org-to-html (plist filename &optional tmp-pub-dir) - "Publish an org file to HTML." - (org-publish-org-to "html" plist filename tmp-pub-dir)) - -(defun org-publish-org-to (format plist filename &optional tmp-pub-dir) +(defun org-publish-org-to (format plist filename pub-dir) "Publish an org file to FORMAT. PLIST is the property list for the given project. -FILENAME is the filename of the org file to be published." +FILENAME is the filename of the org file to be published. +PUB-DIR is the publishing directory." (require 'org) - (unless (file-exists-p tmp-pub-dir) - (make-directory tmp-pub-dir t)) + (unless (file-exists-p pub-dir) + (make-directory pub-dir t)) (find-file filename) (funcall (intern (concat "org-export-as-" format)) (plist-get plist :headline-levels) - nil plist nil nil tmp-pub-dir) + nil plist nil nil pub-dir) (kill-buffer (current-buffer))) +(defun org-publish-org-to-latex (plist filename pub-dir) + "Publish an org file to LaTeX. +See `org-publish-org-to' to the list of arguments." + (org-publish-org-to "latex" plist filename pub-dir)) + +(defun org-publish-org-to-html (plist filename pub-dir) + "Publish an org file to HTML. +See `org-publish-org-to' to the list of arguments." + (org-publish-org-to "html" plist filename pub-dir)) + (defun org-publish-attachment (plist filename) "Publish a file with no transformation of any kind. PLIST is the property list for the given project. @@ -452,79 +472,64 @@ FILENAME is the filename of the file to be published." (plist-get plist :publishing-directory)))) (eshell/cp filename destination))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Publishing files, sets of files, and indices -(defun org-publish-file (filename) - "Publish file FILENAME." - (let* ((project-name (org-publish-get-project-from-filename filename)) - (plist (org-publish-get-plist-from-filename filename)) - (publishing-function (or (plist-get plist :publishing-function) - 'org-publish-org-to-html)) - (base-dir (file-truename (plist-get plist :base-directory))) - (pub-dir (file-truename (plist-get plist :publishing-directory))) - tmp-pub-dir) - (if (not project-name) - (error "File %s is not part of any known project" filename)) - (when (org-publish-needed-p filename) +(defun org-publish-file (filename &optional project) + "Publish file FILENAME from PROJECT." + (when (org-publish-needed-p filename) + (let* ((project (or project (org-publish-get-project-from-filename filename))) + (project-plist (cdr project)) + (publishing-function (or (plist-get project-plist :publishing-function) + 'org-publish-org-to-html)) + (base-dir (file-truename (plist-get project-plist :base-directory))) + (pub-dir (file-truename (plist-get project-plist :publishing-directory))) + tmp-pub-dir) + (if (not project) (error "File %s is not part of any known project" filename)) (setq tmp-pub-dir (file-name-directory (concat pub-dir - (and (string-match (regexp-quote base-dir) f) - (substring f (match-end 0)))))) + (and (string-match (regexp-quote base-dir) filename) + (substring filename (match-end 0)))))) (if (listp publishing-function) ;; allow chain of publishing functions (mapc (lambda (f) - (funcall f plist filename)) + (funcall f project-plist filename tmp-pub-dir)) publishing-function) - (funcall publishing-function plist filename tmp-pub-dir)) + (funcall publishing-function project-plist filename tmp-pub-dir)) (org-publish-update-timestamp filename)))) -(defun org-publish-plist (plist) - "Publish all files in set defined by PLIST. - If :auto-index is set, publish the index too." - (let* ((exclude-regexp (plist-get plist :exclude)) - (publishing-function (or (plist-get plist :publishing-function) - 'org-publish-org-to-html)) - (index-p (plist-get plist :auto-index)) - (index-filename (or (plist-get plist :index-filename) "index.org")) - (index-function (or (plist-get plist :index-function) 'org-publish-org-index)) - (preparation-function (plist-get plist :preparation-function)) - file) - (when preparation-function - (funcall preparation-function)) - (if index-p - (funcall index-function plist index-filename)) - (let ((files (org-publish-get-base-files plist exclude-regexp)) - (base-dir (file-truename (plist-get plist :base-directory))) - (pub-dir (file-truename (plist-get plist :publishing-directory))) - tmp-pub-dir) - (while (setq file (pop files)) - ;; set the right :publishing-directory - (setq tmp-pub-dir - (file-name-directory - (concat pub-dir - (and (string-match (regexp-quote base-dir) file) - (substring f (match-end 0)))))) - ;; check timestamps - (when (org-publish-needed-p file) - (if (listp publishing-function) - ;; allow chain of publishing functions - (mapc (lambda (func) - (funcall func plist file)) - publishing-function) - (funcall publishing-function plist file tmp-pub-dir)) - (org-publish-update-timestamp file)))))) +(defun org-publish-projects (projects) + "Publish all files belonging to the PROJECTS alist. +If :auto-index is set, publish the index too." + (mapc + (lambda(project) + (let* ((project-plist (cdr project)) + (exclude-regexp (plist-get project-plist :exclude)) + (index-p (plist-get project-plist :auto-index)) + (index-filename (or (plist-get project-plist :index-filename) + "index.org")) + (index-function (or (plist-get project-plist :index-function) + 'org-publish-org-index)) + (preparation-function (plist-get project-plist :preparation-function)) + (files (org-publish-get-base-files project exclude-regexp)) file) + (when preparation-function (funcall preparation-function)) + (if index-p (funcall index-function project-plist index-filename)) + (while (setq file (pop files)) + (org-publish-file file project)))) + (org-publish-expand-projects projects))) -(defun org-publish-org-index (plist &optional index-filename) - "Create an index of pages in set defined by PLIST. -Optionally set the filename of the index with INDEX-FILENAME; -default is 'index.org'." - (let* ((dir (file-name-as-directory (plist-get plist :base-directory))) - (exclude-regexp (plist-get plist :exclude)) - (files (org-publish-get-base-files plist exclude-regexp)) +(defun org-publish-org-index (project &optional index-filename) + "Create an index of pages in set defined by PROJECT. +Optionally set the filename of the index with INDEX-FILENAME. +Default for INDEX-FILENAME is 'index.org'." + (let* ((dir (file-name-as-directory (plist-get project-plist :base-directory))) + (exclude-regexp (plist-get project-plist :exclude)) + (files (org-publish-get-base-files project exclude-regexp)) (index-filename (concat dir (or index-filename "index.org"))) (index-buffer (find-buffer-visiting index-filename)) - (ifn (file-name-nondirectory index-filename)) + (ifn (file-name-nondirectory index-filename)) file) ;; if buffer is already open, kill it to prevent error message (if index-buffer @@ -539,55 +544,62 @@ default is 'index.org'." (write-file index-filename) (kill-buffer (current-buffer))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Interactive publishing functions ;;;###autoload -(defun org-publish (project-name &optional force) - "Publish the project PROJECT-NAME." - (interactive (list (completing-read "Project name: " org-publish-project-alist - nil t) - current-prefix-arg)) - (save-window-excursion - (let ((org-publish-use-timestamps-flag - (if force nil org-publish-use-timestamps-flag)) - (plists (org-publish-get-plists project-name))) - (mapcar 'org-publish-plist plists)))) - -;;;###autoload -(defun org-publish-current-project (&optional force) - "Publish the project associated with the current file. -With prefix argument, force publishing all files in project." - (interactive "P") - (save-window-excursion - (let ((project-name (org-publish-get-project-from-filename (buffer-file-name))) - (org-publish-use-timestamps-flag - (if force nil org-publish-use-timestamps-flag))) - (if (not project-name) - (error "File %s is not part of any known project" (buffer-file-name))) - (org-publish project-name)))) - -;;;###autoload -(defun org-publish-current-file (&optional force) - "Publish the current file. -With prefix argument, force publish the file." - (interactive "P") +(defun org-publish (project &optional force) + "Publish the project named PROJECT-NAME." + (interactive + (list (progn (completing-read + "Project name: " org-publish-project-alist nil t) + (assoc project-name org-publish-project-alist)) + current-prefix-arg)) (save-window-excursion (let ((org-publish-use-timestamps-flag (if force nil org-publish-use-timestamps-flag))) - (org-publish-file (buffer-file-name))))) + (org-publish-projects (list project))))) ;;;###autoload (defun org-publish-all (&optional force) "Publish all projects. With prefix argument, force publish all files." (interactive "P") + (org-publish-initialize-files-alist) (save-window-excursion (let ((org-publish-use-timestamps-flag - (if force nil org-publish-use-timestamps-flag)) - (plists (org-publish-get-plists))) - (mapcar 'org-publish-plist plists)))) + (if force nil org-publish-use-timestamps-flag))) + (org-publish-projects org-publish-project-alist)))) + +;;;###autoload +(defun org-publish-current-file (&optional force) + "Publish the current file. +With prefix argument, force publish the file." + (interactive "P") + (org-publish-initialize-files-alist) + (save-window-excursion + (let ((org-publish-use-timestamps-flag + (if force nil org-publish-use-timestamps-flag))) + (org-publish-file (buffer-file-name))))) + +;;;###autoload +(defun org-publish-current-project (&optional force) + "Publish the project associated with the current file. +With a prefix argument, force publishing of all files in +the project." + (interactive "P") + (org-publish-initialize-files-alist) + (save-window-excursion + (let ((project (org-publish-get-project-from-filename (buffer-file-name))) + (org-publish-use-timestamps-flag + (if force nil org-publish-use-timestamps-flag))) + (if (not project) + (error "File %s is not part of any known project" (buffer-file-name))) + (org-publish project)))) (provide 'org-publish) + ;; arch-tag: 72807f3c-8af0-4a6b-8dca-c3376eb25adb ;;; org-publish.el ends here From eda5a993cab01acd6878ab6c982b075d2cba167b Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Sun, 2 Mar 2008 19:16:21 +0000 Subject: [PATCH 5/9] *** empty log message *** --- org-publish.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/org-publish.el b/org-publish.el index bf9a88550..1b4ee7e4d 100644 --- a/org-publish.el +++ b/org-publish.el @@ -583,12 +583,17 @@ With prefix argument, force publish the file." (if force nil org-publish-use-timestamps-flag))) (org-publish-file (buffer-file-name))))) +(defvar t1 nil) +(defvar t2 nil) +;; (format-time-string "%S" (subtract-time t2 t1)) + ;;;###autoload (defun org-publish-current-project (&optional force) "Publish the project associated with the current file. With a prefix argument, force publishing of all files in the project." (interactive "P") + (setq t1 (current-time)) (org-publish-initialize-files-alist) (save-window-excursion (let ((project (org-publish-get-project-from-filename (buffer-file-name))) @@ -596,7 +601,8 @@ the project." (if force nil org-publish-use-timestamps-flag))) (if (not project) (error "File %s is not part of any known project" (buffer-file-name))) - (org-publish project)))) + (org-publish project))) + (setq t2 (current-time))) (provide 'org-publish) From 4dcecb97bf4586c26f7e955980caa7e9630ae9a7 Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Sun, 2 Mar 2008 22:49:28 +0000 Subject: [PATCH 6/9] More cleaning. --- org-publish.el | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/org-publish.el b/org-publish.el index 1b4ee7e4d..573b158ff 100644 --- a/org-publish.el +++ b/org-publish.el @@ -151,6 +151,12 @@ ;;; Code: +;; FIXME Mention this in the ChangeLog + +;; - removed org-publish-validate-link +;; - deleted org-publish-get-plists-from-filename +;; - deleted org-publish-get-plists + (eval-when-compile (require 'cl)) @@ -286,11 +292,7 @@ files." (setq filename (replace-match "_" nil t filename))) (concat org-publish-timestamp-directory filename ".timestamp")) -;; FIXME removed org-publish-validate-link -;; FIXME deleted org-publish-get-plists-from-filename -;; FIXME deleted org-publish-get-plists - -;; FIXME deleted :parents +;; FIXME ChangeLog: deleted :parents (defun org-publish-needed-p (filename) "Check whether file should be published. If org-publish-use-timestamps-flag is set to nil, this function always @@ -330,14 +332,14 @@ whether file should be published." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Mapping files to project names -;; FIXME annonce renaming +;; FIXME ChangeLog: renamed from org-publish-files (defvar org-publish-files-alist nil "Alist of files and their parent project. Each element of this alist is of the form: (file-name . project-name)") -;; FIXME annonce this new defun +;; FIXME ChangeLog: new defun (defun org-publish-initialize-files-alist (&optional refresh) "Set `org-publish-files-alist' if it is not set. Also set it if the optional argument REFRESH is non-nil." @@ -349,7 +351,7 @@ Also set it if the optional argument REFRESH is non-nil." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Getting project information out of org-publish-project-alist -;; FIXME annonce this new defun +;; FIXME ChangeLog: new defun (defun org-publish-get-files (projects-alist &optional no-exclusion) "Return the list of all publishable files for PROJECTS-ALIST. If NO-EXCLUSION is non-nil, don't exclude files." @@ -367,7 +369,7 @@ If NO-EXCLUSION is non-nil, don't exclude files." (org-publish-expand-projects projects-alist)) all-files)) -;; ;; FIXME annonce this new defun +;; ;; FIXME ChangeLog: new defun (defun org-publish-expand-projects (projects-alist) "Expand projects contained in PROJECTS-ALIST." (let (without-component with-component) @@ -381,7 +383,7 @@ If NO-EXCLUSION is non-nil, don't exclude files." (car (mapcar (lambda(p) (org-publish-expand-components p)) with-component)))))) -;; FIXME annonce this new defun +;; FIXME ChangeLog: new defun (defun org-publish-expand-components (project) "Expand PROJECT into an alist of its components." (let* ((components (plist-get (cdr project) :components))) @@ -583,17 +585,12 @@ With prefix argument, force publish the file." (if force nil org-publish-use-timestamps-flag))) (org-publish-file (buffer-file-name))))) -(defvar t1 nil) -(defvar t2 nil) -;; (format-time-string "%S" (subtract-time t2 t1)) - ;;;###autoload (defun org-publish-current-project (&optional force) "Publish the project associated with the current file. With a prefix argument, force publishing of all files in the project." (interactive "P") - (setq t1 (current-time)) (org-publish-initialize-files-alist) (save-window-excursion (let ((project (org-publish-get-project-from-filename (buffer-file-name))) @@ -601,8 +598,7 @@ the project." (if force nil org-publish-use-timestamps-flag))) (if (not project) (error "File %s is not part of any known project" (buffer-file-name))) - (org-publish project))) - (setq t2 (current-time))) + (org-publish project)))) (provide 'org-publish) From 8ea076e2de2b3721bd813ea5a2df1b53d0c25055 Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Mon, 3 Mar 2008 10:01:36 +0000 Subject: [PATCH 7/9] Updated org-publish.el (now version 1.81) Updated the ChangeLog and the manual accordingly. --- ChangeLog | 24 ++++++++++++++++ org-publish.el | 76 +++++++++++++++++++------------------------------- org.texi | 22 +++++++++------ 3 files changed, 67 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index 91d7324a9..71d8b6890 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2008-03-03 Bastien Guerry + + * org-publish.el (org-publish-org-to, org-publish-org-to-latex) + (org-publish-org-to-html): New argument `pub-dir' for temporary + publication directory. + (org-publish-projects): Renamed from `org-publish-plists'. + (org-publish, org-publish-all): Use `org-publish-projects'. + (org-publish-all, org-publish-current-file) + (org-publish-files-alist): Renamed from `org-publish-files'. + (org-publish-initialize-files-alist): New defun. + (org-publish-current-project): First initialize the list of + publishable files with`org-publish-initialize-files-alist'. + (org-publish-get-files): New defun. + (org-publish-expand-projects): New defun. + (org-publish-expand-components): New defun. + (org-publish-get-base-files): Get files recursively. + (org-publish-update-timestamp): Create the timestamp file. + (org-publish-needed-p): Removed the code about creating/updating + the timestamp file. + (org-publish-validate-link) + (org-publish-get-plists-from-filename, org-publish-get-plists): + Deleted. + (org-publish-timestamp-directory): Use directory type. + 2008-03-01 Bastien Guerry * org.el (org-dblock-write:columnview, org-columns-capture-view): diff --git a/org-publish.el b/org-publish.el index 573b158ff..b2af0d423 100644 --- a/org-publish.el +++ b/org-publish.el @@ -5,7 +5,7 @@ ;; Author: David O'Toole ;; Maintainer: Bastien Guerry ;; Keywords: hypermedia, outlines, wp -;; Version: 1.80c+ +;; Version: 1.81 ;; This file is part of GNU Emacs. ;; @@ -79,6 +79,7 @@ ;; :publishing-directory "~/public_html" ;; :with-section-numbers nil ;; :table-of-contents nil +;; :recursive t ;; :style ""))) ;;;; More complex example configuration: @@ -110,12 +111,10 @@ ;; :style "" ;; :auto-preamble t ;; :auto-postamble nil) -;; ;; ("images" :base-directory "~/images/" ;; :base-extension "jpg\\|gif\\|png" ;; :publishing-directory "/ssh:user@host:~/html/images/" ;; :publishing-function org-publish-attachment) -;; ;; ("other" :base-directory "~/other/" ;; :base-extension "css" ;; :publishing-directory "/ssh:user@host:~/html/other/" @@ -151,12 +150,6 @@ ;;; Code: -;; FIXME Mention this in the ChangeLog - -;; - removed org-publish-validate-link -;; - deleted org-publish-get-plists-from-filename -;; - deleted org-publish-get-plists - (eval-when-compile (require 'cl)) @@ -279,7 +272,7 @@ files." (defcustom org-publish-timestamp-directory "~/.org-timestamps/" "Name of directory in which to store publishing timestamps." :group 'org-publish - :type 'string) + :type 'directory) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -287,59 +280,52 @@ files." (defun org-publish-timestamp-filename (filename) "Return path to timestamp file for filename FILENAME." - (while (string-match (if (eq system-type 'windows-nt) "~\\|/\\|:" "~\\|/") - filename) + (while (string-match + (if (eq system-type 'windows-nt) "~\\|/\\|:" "~\\|/") filename) (setq filename (replace-match "_" nil t filename))) (concat org-publish-timestamp-directory filename ".timestamp")) -;; FIXME ChangeLog: deleted :parents (defun org-publish-needed-p (filename) - "Check whether file should be published. -If org-publish-use-timestamps-flag is set to nil, this function always -returns t. Otherwise, check the timestamps folder to determine -whether file should be published." + "Return `t' if FILENAME should be published." (if org-publish-use-timestamps-flag - (progn - ;; create folder if needed - (if (not (file-exists-p org-publish-timestamp-directory)) - (make-directory org-publish-timestamp-directory) + (if (file-exists-p org-publish-timestamp-directory) + ;; first handle possible wrong timestamp directory (if (not (file-directory-p org-publish-timestamp-directory)) - (error "`org-publish-timestamp-directory' must be a directory"))) - ;; check timestamp. ok if timestamp file doesn't exist - (let* ((timestamp (org-publish-timestamp-filename filename)) - (rtn (file-newer-than-file-p filename timestamp))) - (if rtn - ;; handle new timestamps - (if (not (file-exists-p timestamp)) - ;; create file - (with-temp-buffer - (make-directory (file-name-directory timestamp) t) - (write-file timestamp) - (kill-buffer (current-buffer))))) - rtn)) - ;; always return `t' is we don't use timestamp + (error "Org publish timestamp: %s is not a directory" + org-publish-timestamp-directory) + ;; there is a timestamp, check if FILENAME is newer + (file-newer-than-file-p + filename (org-publish-timestamp-filename filename)))) + ;; don't use timestamps, always return t t)) (defun org-publish-update-timestamp (filename) - "Update publishing timestamp for file FILENAME." - (let ((timestamp (org-publish-timestamp-filename filename))) - ;; Emacs 21 doesn't have set-file-times - (if (fboundp 'set-file-times) - (set-file-times timestamp) - (call-process "touch" nil 0 nil timestamp)))) + "Update publishing timestamp for file FILENAME. +If there is no timestamp, create one." + (let ((timestamp-file (org-publish-timestamp-filename filename)) + newly-created-timestamp) + (if (not (file-exists-p timestamp-file)) + ;; create timestamp file if needed + (with-temp-buffer + (make-directory (file-name-directory timestamp-file) t) + (write-file timestamp-file) + (setq newly-created-timestamp t))) + ;; Emacs 21 doesn't have `set-file-times' + (if (and (fboundp 'set-file-times) + (not newly-created-timestamp)) + (set-file-times timestamp-file) + (call-process "touch" nil 0 nil timestamp-file)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Mapping files to project names -;; FIXME ChangeLog: renamed from org-publish-files (defvar org-publish-files-alist nil "Alist of files and their parent project. Each element of this alist is of the form: (file-name . project-name)") -;; FIXME ChangeLog: new defun (defun org-publish-initialize-files-alist (&optional refresh) "Set `org-publish-files-alist' if it is not set. Also set it if the optional argument REFRESH is non-nil." @@ -351,7 +337,6 @@ Also set it if the optional argument REFRESH is non-nil." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Getting project information out of org-publish-project-alist -;; FIXME ChangeLog: new defun (defun org-publish-get-files (projects-alist &optional no-exclusion) "Return the list of all publishable files for PROJECTS-ALIST. If NO-EXCLUSION is non-nil, don't exclude files." @@ -369,7 +354,6 @@ If NO-EXCLUSION is non-nil, don't exclude files." (org-publish-expand-projects projects-alist)) all-files)) -;; ;; FIXME ChangeLog: new defun (defun org-publish-expand-projects (projects-alist) "Expand projects contained in PROJECTS-ALIST." (let (without-component with-component) @@ -383,7 +367,6 @@ If NO-EXCLUSION is non-nil, don't exclude files." (car (mapcar (lambda(p) (org-publish-expand-components p)) with-component)))))) -;; FIXME ChangeLog: new defun (defun org-publish-expand-components (project) "Expand PROJECT into an alist of its components." (let* ((components (plist-get (cdr project) :components))) @@ -602,6 +585,5 @@ the project." (provide 'org-publish) - ;; arch-tag: 72807f3c-8af0-4a6b-8dca-c3376eb25adb ;;; org-publish.el ends here diff --git a/org.texi b/org.texi index 931ec002d..49298acf9 100644 --- a/org.texi +++ b/org.texi @@ -7013,14 +7013,16 @@ the two following forms: @end lisp -In both cases, projects are configured by specifying property values. -A project defines the set of files that will be published, as well as -the publishing configuration to use when publishing those files. When -a project takes the second form listed above, the individual members -of the ``components'' property are taken to be components of the -project, which group together files requiring different publishing -options. When you publish such a ``meta-project'' all the components -will also publish. +In both cases, projects are configured by specifying property values. A +project defines the set of files that will be published, as well as the +publishing configuration to use when publishing those files. When a +project takes the second form listed above, the individual members of +the ``components'' property are taken to be components of the project, +which group together files requiring different publishing options. When +you publish such a ``meta-project'' all the components will also be +published. + +For now, components are not allowed to have components themselves. @node Sources and destinations, Selecting files, Project alist, Configuration @subsection Sources and destinations for files @@ -7061,6 +7063,10 @@ extension. @item @code{:include} @tab List of files to be included regardless of @code{:base-extension} and @code{:exclude}. + +@item @code{:recursive} +@tab When non-@code{nil}, the @code{:base-directory} will be recursively +published. @end multitable @node Publishing action, Publishing options, Selecting files, Configuration From 571b8c0be2f47f25211ee79fc339d881623c1c06 Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Mon, 3 Mar 2008 10:12:51 +0000 Subject: [PATCH 8/9] Silence the byte-compiler for org-publish.el. --- org-publish.el | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/org-publish.el b/org-publish.el index b2af0d423..4d454917e 100644 --- a/org-publish.el +++ b/org-publish.el @@ -153,6 +153,8 @@ (eval-when-compile (require 'cl)) +(require 'dired-aux) + (defgroup org-publish nil "Options for publishing a set of Org-mode and related files." :tag "Org Publishing" @@ -357,11 +359,11 @@ If NO-EXCLUSION is non-nil, don't exclude files." (defun org-publish-expand-projects (projects-alist) "Expand projects contained in PROJECTS-ALIST." (let (without-component with-component) - (mapcar (lambda(p) - (add-to-list - (if (plist-get (cdr p) :components) - 'with-component 'without-component) p)) - projects-alist) + (mapc (lambda(p) + (add-to-list + (if (plist-get (cdr p) :components) + 'with-component 'without-component) p)) + projects-alist) (delete-dups (append without-component (car (mapcar (lambda(p) (org-publish-expand-components p)) @@ -489,7 +491,7 @@ FILENAME is the filename of the file to be published." "Publish all files belonging to the PROJECTS alist. If :auto-index is set, publish the index too." (mapc - (lambda(project) + (lambda (project) (let* ((project-plist (cdr project)) (exclude-regexp (plist-get project-plist :exclude)) (index-p (plist-get project-plist :auto-index)) @@ -500,7 +502,7 @@ If :auto-index is set, publish the index too." (preparation-function (plist-get project-plist :preparation-function)) (files (org-publish-get-base-files project exclude-regexp)) file) (when preparation-function (funcall preparation-function)) - (if index-p (funcall index-function project-plist index-filename)) + (if index-p (funcall index-function project index-filename)) (while (setq file (pop files)) (org-publish-file file project)))) (org-publish-expand-projects projects))) @@ -509,7 +511,9 @@ If :auto-index is set, publish the index too." "Create an index of pages in set defined by PROJECT. Optionally set the filename of the index with INDEX-FILENAME. Default for INDEX-FILENAME is 'index.org'." - (let* ((dir (file-name-as-directory (plist-get project-plist :base-directory))) + (let* ((project-plist (cdr project)) + (dir (file-name-as-directory + (plist-get project-plist :base-directory))) (exclude-regexp (plist-get project-plist :exclude)) (files (org-publish-get-base-files project exclude-regexp)) (index-filename (concat dir (or index-filename "index.org"))) @@ -534,17 +538,17 @@ Default for INDEX-FILENAME is 'index.org'." ;;; Interactive publishing functions ;;;###autoload -(defun org-publish (project &optional force) +(defun org-publish (project-name &optional force) "Publish the project named PROJECT-NAME." (interactive (list (progn (completing-read - "Project name: " org-publish-project-alist nil t) - (assoc project-name org-publish-project-alist)) + "Project name: " org-publish-project-alist nil t)) current-prefix-arg)) (save-window-excursion (let ((org-publish-use-timestamps-flag (if force nil org-publish-use-timestamps-flag))) - (org-publish-projects (list project))))) + (org-publish-projects + (list (assoc project-name org-publish-project-alist)))))) ;;;###autoload (defun org-publish-all (&optional force) @@ -585,5 +589,6 @@ the project." (provide 'org-publish) + ;; arch-tag: 72807f3c-8af0-4a6b-8dca-c3376eb25adb ;;; org-publish.el ends here From 2222e5a2493005ffe4d044500885e95f53b56ff6 Mon Sep 17 00:00:00 2001 From: Bastien Guerry Date: Mon, 3 Mar 2008 10:31:45 +0000 Subject: [PATCH 9/9] Fix `org-load-default-extensions': don't throw an error. --- ChangeLog | 3 +++ org.el | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 71d8b6890..e6625b56d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2008-03-03 Bastien Guerry + * org.el (org-load-default-extensions): Don't throw an error when + a feature cannot be loaded, send a message instead. + * org-publish.el (org-publish-org-to, org-publish-org-to-latex) (org-publish-org-to-html): New argument `pub-dir' for temporary publication directory. diff --git a/org.el b/org.el index 4c9663d6a..af6632dcf 100644 --- a/org.el +++ b/org.el @@ -172,8 +172,11 @@ will be autoloaded when needed, preloading is not necessary." (const :tag " Apple Mail message links under OS X (org-mac-message.el)" org-mac-message))) (defun org-load-default-extensions () - "Load all extensions that are listed in `org-default-extensions'." - (mapc 'require org-default-extensions)) + "Load all extensions listed in `org-default-extensions'." + (mapc (lambda (ext) + (condition-case nil (require ext) + (error (message "Feature `%s' is not known" ext)))) + org-default-extensions)) ;; FIXME: Needs a separate group... (defcustom org-completion-fallback-command 'hippie-expand