Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding additional configurable options #44

Merged
merged 2 commits into from Mar 22, 2014
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 16 additions & 11 deletions src/coleslaw.lisp
Expand Up @@ -16,10 +16,16 @@
(:documentation "The url to the object, without the domain."))

(defmethod page-url :around ((object t))
(let ((result (call-next-method)))
(let ((result (call-next-method))
(extension (if (string-equal (pageext *config*) "/")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused by this change and see no reason why we wouldn't just use the page-ext from the config. The extension clause in the let and the corresponding when can be removed and extension in the call to make-pathname just becomes (page-ext *config*). Is there any reason that is insufficient?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverted. this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revision: reverted the when form, but left a revision to this statement.

This might be kind of hacky, but, if you specify a page-ext of /, then the template thinks that everything ends in a slash, and coleslaw just puts an .html extension. Then you can tell your web server to drop the extensions seamlessly, and everything works perfectly. The old behavior is preserved, and with one if form (and some web server config) ayou can get pretty urls with minimal change.

"html"
(pageext *config*))))
(when (string= (char extension 0) ".")
(setf extension (string-trim "." extension)))
(if (pathname-type result)
result
(make-pathname :type "html" :defaults result))))
(make-pathname :type extension :defaults result)
)))

(defun page-path (object)
"The path to store OBJECT at once rendered."
Expand All @@ -46,16 +52,14 @@ Additional args to render CONTENT can be passed via RENDER-ARGS."

(defun compile-blog (staging)
"Compile the blog to a STAGING directory as specified in .coleslawrc."
(when (probe-file staging)
(run-program "rm -R ~a" staging))
(ensure-directories-exist staging)
(with-current-directory staging
(dolist (dir (list (app-path "themes/~a/css" (theme *config*))
(app-path "themes/~a/img" (theme *config*))
(app-path "themes/~a/js" (theme *config*))
(merge-pathnames "static" (repo *config*))))
(when (probe-file dir)
(run-program "cp -R ~a ." dir)))
(run-program "rsync --delete -raz ~a ." dir)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is rsync preferable here? If we're going this route, we should note that we depend on rsync in the README.

(do-ctypes (publish (make-keyword ctype)))
(render-indices)
(update-symlink "index.html" "1.html")
Expand Down Expand Up @@ -88,9 +92,10 @@ Additional args to render CONTENT can be passed via RENDER-ARGS."
(defun preview (path &optional (content-type 'post))
"Render the content at PATH under user's configured repo and save it to
~/tmp.html. Load the user's config and theme if necessary."
(unless *config*
(load-config nil)
(compile-theme (theme *config*)))
(let* ((file (rel-path (repo *config*) path))
(content (construct content-type (read-content file))))
(write-page "~/tmp.html" (render-page content))))
(let ((current-working-directory (cl-fad:pathname-directory-pathname path)))
(unless *config*
(load-config (namestring current-working-directory))
(compile-theme (theme *config*)))
(let* ((file (rel-path (repo *config*) path))
(content (construct content-type (read-content file))))
(write-page "tmp.html" (render-page content)))))
37 changes: 24 additions & 13 deletions src/config.lisp
@@ -1,17 +1,20 @@
(in-package :coleslaw)

(defclass blog ()
((author :initarg :author :accessor author)
(deploy-dir :initarg :deploy-dir :accessor deploy-dir)
(domain :initarg :domain :accessor domain)
(feeds :initarg :feeds :accessor feeds)
(license :initarg :license :accessor license)
(plugins :initarg :plugins :accessor plugins)
(repo :initarg :repo :accessor repo)
(sitenav :initarg :sitenav :accessor sitenav)
(staging-dir :initarg :staging-dir :accessor staging-dir)
(title :initarg :title :accessor title)
(theme :initarg :theme :accessor theme)))
((author :initarg :author :accessor author)
(deploy-dir :initarg :deploy-dir :accessor deploy-dir)
(domain :initarg :domain :accessor domain)
(feeds :initarg :feeds :accessor feeds)
(license :initarg :license :accessor license)
(plugins :initarg :plugins :accessor plugins)
(repo :initarg :repo :accessor repo)
(sitenav :initarg :sitenav :accessor sitenav)
(staging-dir :initarg :staging-dir :accessor staging-dir)
(postsdir :initarg :postsdir :accessor postsdir :initform "posts")
(separator :initarg :separator :accessor separator :initform ";;;;;")
(pageext :initarg :pageext :accessor pageext :initform ".html")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer content-dir instead of postsdir and page-ext to pageext. It would also be nice if the alphabetical order was maintained.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I chose the unhyphenated names so that I could use them in the templates, which seemed to produce some error at my attempt, but perhaps I was doing something wrong: is this consistent with your expectation of how the templating environment works

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, you have to camel case the names for the lookup to occur correctly. So, e.g. postsDir or pageExt.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we ok with camel casing for this purpose? Just the accessors? Is there some way to add camel case aliases that I'm not aware of?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, I wasn't clear enough. In the template, you should refer to the names camel-cased. They should stay hyphenated on the lisp side.

(title :initarg :title :accessor title)
(theme :initarg :theme :accessor theme)))

(define-condition unknown-config-section-error (error)
((text :initarg :text :reader text)))
Expand All @@ -37,10 +40,18 @@ are in the plugins folder in coleslaw's source directory."
(destructuring-bind (name &rest args) plugin
(apply 'enable-plugin (plugin-path name) args)))))

(defun load-config (&optional config-key (dir (user-homedir-pathname)))
(defun discover-config-path (&optional (path ""))
(let ((default-path (make-pathname :directory (namestring (user-homedir-pathname)) :name ".coleslawrc"))
(custom-path (make-pathname :directory path :name ".coleslawrc")))
(cond
((file-exists-p custom-path) custom-path)
((file-exists-p default-path) default-path))))

(defun load-config (config-key)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this feature but discover-config-path should have a docstring. I would also prefer we use rel-path in the let clauses, e.g. (rel-path (user-homedir-pathname) ".coleslawrc") and a simple if conditional to check for the custom-path with the default as the else case.

"Load the coleslaw configuration from DIR/.coleslawrc, using CONFIG-KEY
if necessary. DIR is ~ by default."
(with-open-file (in (merge-pathnames ".coleslawrc" dir))

(with-open-file (in (discover-config-path config-key))
(let ((config-form (read in)))
(if (symbolp (car config-form))
;; Single site config: ignore CONFIG-KEY.
Expand Down
4 changes: 2 additions & 2 deletions src/content.lisp
Expand Up @@ -51,10 +51,10 @@
(read-tags (str)
(mapcar #'make-tag (cl-ppcre:split "," str))))
(with-open-file (in file)
(unless (string= (read-line in) ";;;;;")
(unless (string= (read-line in) (separator *config*))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice idea. I'm not sure why I didn't think of it earlier. :)

(error "The provided file lacks the expected header."))
(let ((meta (loop for line = (read-line in nil)
until (string= line ";;;;;")
until (string= line (separator *config*))
appending (list (field-name line)
(aref (parse-field line) 0))))
(content (slurp-remainder in)))
Expand Down
1 change: 1 addition & 0 deletions src/packages.lisp
Expand Up @@ -5,6 +5,7 @@
#:make-keyword
#:mappend
#:compose)
(:import-from :cl-fad #:file-exists-p)
(:import-from :closure-template #:compile-template)
(:export #:main
#:preview
Expand Down
23 changes: 14 additions & 9 deletions src/posts.lisp
Expand Up @@ -2,24 +2,29 @@

(defclass post (content)
((title :initform nil :initarg :title :accessor post-title)
(author :initform nil :initarg :author :accessor post-author)
(format :initform nil :initarg :format :accessor post-format)))

(defmethod initialize-instance :after ((object post) &key)
(with-accessors ((title post-title)
(author post-author)
(format post-format)
(text content-text)) object
(setf (content-slug object) (slugify title)
format (make-keyword (string-upcase format))
text (render-content text format)
author (if author
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer (or author (author *config*)) here. I'm also not sure whether I'd prefer the author slot to be on the POST or CONTENT class but I'm okay to leave it on POST for now.

author
(author *config*)))))

(defmethod render ((object post) &key prev next)
(funcall (theme-fn 'post) (list :config *config*
:post object
:prev prev
:next next)))

(defmethod page-url ((object post))
(format nil "posts/~a" (content-slug object)))

(defmethod initialize-instance :after ((object post) &key)
(with-accessors ((title post-title)
(format post-format)
(text content-text)) object
(setf (content-slug object) (slugify title)
format (make-keyword (string-upcase format))
text (render-content text format))))
(format nil "~a/~a" (postsdir *config*) (content-slug object)))

(defmethod publish ((content-type (eql :post)))
(loop for (next post prev) on (append '(nil) (by-date (find-all 'post)))
Expand Down