Skip to content

Instantly share code, notes, and snippets.

@simon-brooke
Last active October 6, 2022 20:46
Show Gist options
  • Save simon-brooke/2185e7da258de24b1466f4d1b5c2b103 to your computer and use it in GitHub Desktop.
Save simon-brooke/2185e7da258de24b1466f4d1b5c2b103 to your computer and use it in GitHub Desktop.
Convert leiningen project.clj into clojure.cli deps.edn
(ns migrate
"
## Leiningen to deps.edn migration tool
I'm as yet unpersuaded of the merits of `deps.edn` vis-a-vis leiningen.
Leiningen puts all the metadata about your project and how to build it
in one place in a clear, well understood and easily-extensible format.
The `deps.edn` format intentionally does not.
Worse, `clojure.cli` uses a subtly but significantly different algorithm
for resolving dependencies from that used by leiningen, meaning that
projects using `deps.edn` do not play nice with leiningen projects.
Worse yet, `clojure.cli` does not provide a standardised means of providing
metadata other than dependencies and paths. This means that the
standardised build automation which makes leiningen projects so easy to
hack on is lost, as each project gets its own idiosyncratic build
scripting using a maze of twisty little build tools, all different.
However, be that as it may, to use projects which are built directly
from git repositories, it's presently easier to use `deps.edn`, so I found
it useful to have a migration tool.
Public domain. No warranty, if it breaks you get to keep all the parts."
(:require [clojure.pprint :refer [pprint]]
[clojure.java.io :refer [writer]])
(:import [java.io FileNotFoundException]))
(defn transform-dependencies
"Transform the vector of pairs format used by leiningen into the map
format used by `deps.edn`. Be wary printing the results of this. There's
some REALLY WEIRD SHIT between the Clojure reader and printer
here, which does not do what you expect!"
[project]
(into {}
(map #(vector (first %) {:mvn/version (second %)})
(:dependencies project))))
(defn transform-paths
"It appears that `deps.edn` wants resource paths included on the paths value."
[project]
(concat (:source-paths project) (:resource-paths project)))
(defn transform
[project deps]
(let [projectmap (apply hash-map (rest project))]
(merge-with deps
(assoc {}
:deps (transform-dependencies projectmap)
:paths (transform-paths projectmap)))))
(defn leiningen->deps
"Read leiningen project file (defaults to `project.clj`), write a `deps.edn` file"
([] (leiningen->deps "project.clj"))
([filename] (leiningen->deps filename "deps.edn"))
([infile outfile]
(let [deps (transform (read-string (slurp infile))
(try (read-string (slurp outfile))
(catch FileNotFoundException _ {})))]
;; thanks to @puredanger for this hint!
(binding [*print-namespace-maps* false]
(pprint deps (writer outfile)))
deps)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment