Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Babashka script to port posts from jekyll/octopress format to cryogen
(require '[clojure.java.io :as io]
'[clojure.string :as string]
'[clojure.tools.cli :refer [parse-opts]])
(def cli-options
[["-o" "--out DIR" "Output directory"
:default "out"]
["-s" "--source SOURCE" "Source directory"
:default "source/_posts"]
["-h" "--help"]])
(def frontmatter-delimiter "---")
(defn files-in-dir
"Returns a list of all files in a given path"
[path]
(->> (io/file path)
file-seq
(filter #(.isFile %))))
(defn output-key?
"Checks the given key against a list of known keys. Returns true if the key is in the list."
[key]
(let [good-keys #{:title :date :author :tags :toc :toc-class :draft? :klipse :layout :description}]
(contains? good-keys key)))
(defn normalise-frontmatter-key-pair
"Normalise the key/value pairs from frontmatter.
- Converts keys to keywords
- Replaces :status with :draft?
- If key is :layout, make value a keyword
- Have draft? status as a boolean, driven based on \"publish\" being true
- Strip single quotes from any :date keys value"
[key value]
(let [normal-key (let [keyword-key (-> key
(string/replace #":$" "")
keyword)]
(cond
(= :status keyword-key) :draft?
:else keyword-key))
normal-value (cond
(= :layout normal-key) (keyword value)
(= :draft? normal-key) (get {"publish" false} value true)
(= :date normal-key) (string/replace value #"'" "")
:else value)]
[normal-key
normal-value]))
(defn normalise-filename
"Function to change the name of the output files.
- Rename from .markdown to .md"
[name]
(-> name
(string/replace #"markdown$" "md")))
(defn convert-file
[path]
(with-open [reader (io/reader path)]
(reduce (fn [acc line]
(if (:in-frontmatter? acc)
(if (= frontmatter-delimiter line)
(-> acc
(assoc :output (conj (:output acc) (:frontmatter acc) "\n"))
(assoc :in-frontmatter? false))
(let [components (string/split line #"\s+")
[key value] (normalise-frontmatter-key-pair (first components)
(string/join " " (rest components)))]
(if (output-key? key)
(-> acc
(assoc :frontmatter (merge (:frontmatter acc) {key value})))
acc)))
(if (= frontmatter-delimiter line)
(-> acc
(assoc :in-frontmatter? true))
(-> acc
(assoc :output (conj (:output acc) line "\n"))))))
{:output []
:frontmatter {}
:in-frontmatter? false} (line-seq reader))))
(let [options (:options (parse-opts *command-line-args* cli-options))
source-dir (:source options)
output-dir (:out options)
files (files-in-dir source-dir)]
(run! (fn [file]
(let [content (apply str (:output (convert-file file)))
name (.getName file)
output-name (str output-dir "/" (normalise-filename name))]
(io/make-parents output-name)
(spit output-name content)))
files))
@rickerbh

This comment has been minimized.

Copy link
Owner Author

@rickerbh rickerbh commented Jul 26, 2020

It's a bit of a mess, but for a once-use I wasn't going to refactor it too much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment