Skip to content

Commit

Permalink
minor: Add native-image support to fs loader
Browse files Browse the repository at this point in the history
  • Loading branch information
julienvincent committed Jan 19, 2024
1 parent a06305d commit 5ba13c1
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 19 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,15 @@ As an example the following state would execute just fine:
```

Notice the migration with id `"2"` is missing from the provided set, simulating it having been cleaned up. Once the op-log has moved on to `"4"`, the migration with id `"3"` could also theoretically be removed.

## GraalVM Native-Image Compatibility

This tool is fully compatible with graalvm native-image. To properly structure your project you need to make sure your migrations are analysed at build time.

You can either explicitly require each migration and use the `ns` loader or you can use the `fs` loader from a def:

```clj
(def migrations
"Preload migrations to ensure that the `require` statements are analysed during native-image compilation"
(loaders.fs/load-migrations! "migrations")) ;; where the folder `migrations` is on your classpath.
```
43 changes: 24 additions & 19 deletions packages/mallard/src/k16/mallard/loaders/fs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,36 @@
(defn- file->ns
"Extract clojure ns name from a file"
[file]
(->> file
slurp
(->> (slurp file)
(re-find #"^\(ns\s+([^\s);]+)")
second
symbol))
second))

(defn- resolve-migration-files [dir]
(->> (io/file dir)
(->> (or (io/resource dir)
(io/file dir))
io/file
file-seq
(filter #(.isFile ^java.io.File %))
(filter #(str/ends-with? (.getName ^java.io.File %) ".clj"))
(map (fn [file]
{:file file
:path (.getPath ^java.io.File file)
:ns (file->ns file)}))
(sort-by :path)))
{:path (.getPath ^java.io.File file)
:namespace (file->ns file)}))
(sort-by :path)
vec))

(defn load-migrations!
"Given a resource path, attempt to load all migration files found therein."
(defmacro load-migration-files!
"Given a file or resource directory path attempt to load all files found within as migrations.
This is implemented as a macro to allow preloading migrations during native-image compilation. This
also allows loading of migrations when they are bundled as resources within a jar as the full resource
paths are known up front."
[dir]
(let [files (resolve-migration-files dir)]
(->> files
(map (fn [file]
(let [{ns' :ns path :path} file]
(core/load-file path)
{:id (-> (name ns') (str/split #"\.") last)
:run-up! (ns-resolve ns' 'run-up!)
:run-down! (ns-resolve ns' 'run-down!)}))))))
(let [namespaces (resolve-migration-files dir)]
`(do (doseq [namespace# ~namespaces]
(require (symbol namespace#)))

(->> ~namespaces
(map (fn [namespace#]
{:id (-> namespace# (str/split #"\.") last)
:run-up! (resolve (symbol (str namespace# "/run-up!")))
:run-down! (resolve (symbol (str namespace# "/run-down!")))}))))))

0 comments on commit 5ba13c1

Please sign in to comment.