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
You can’t perform that action at this time.