diff --git a/src/metabase/plugins.clj b/src/metabase/plugins.clj index 156030adb0be86172d09b72e2218962ad0b370cd..893736cebb3e4a320ea64e8355828d2f5b28bdc0 100644 --- a/src/metabase/plugins.clj +++ b/src/metabase/plugins.clj @@ -10,18 +10,48 @@ [metabase.util :as u] [metabase.util.i18n :refer [trs]] [yaml.core :as yaml]) - (:import java.nio.file.Path)) + (:import java.io.File + [java.nio.file Files Path])) (defn- plugins-dir-filename ^String [] (or (env/env :mb-plugins-dir) - (str (System/getProperty "user.dir") "/plugins"))) - -(defn- ^Path plugins-dir - "Get a `Path` to the Metabase plugins directory, creating it if needed." - [] - (let [path (files/get-path (plugins-dir-filename))] - (files/create-dir-if-not-exists! path) - path)) + (str (System/getProperty "user.dir") + File/separator + "plugins"))) + +;; logic for determining plugins dir -- see below +(defonce ^:private plugins-dir* + (delay + (let [filename (plugins-dir-filename)] + (try + ;; attempt to create <current-dir>/plugins if it doesn't already exist. Check that the directory is readable. + (u/prog1 (files/get-path filename) + (files/create-dir-if-not-exists! <>) + (assert (Files/isWritable <>) + (str (trs "Metabase does not have permissions to write to plugins directory {0}" filename)))) + ;; If we couldn't create the directory, or the directory is not writable, fall back to a temporary directory + ;; rather than failing to launch entirely. Log instructions for what should be done to fix the problem. + (catch Throwable e + (log/warn + e + (trs "Metabase cannot use the plugins directory {0}" filename) + "\n" + (trs "Please make sure the directory exists and that Metabase has permission to write to it.") + (trs "You can change the directory Metabase uses for modules by setting the environment variable MB_PLUGINS_DIR.") + (trs "Falling back to a temporary directory for now.")) + ;; Check whether the fallback temporary directory is writable. If it's not, there's no way for us to + ;; gracefully proceed here. Throw an Exception detailing the critical issues. + (u/prog1 (files/get-path (System/getProperty "java.io.tmpdir")) + (assert (Files/isWritable <>) + (str (trs "Metabase cannot write to temporary directory. Please set MB_PLUGINS_DIR to a writable directory and restart Metabase."))))))))) + +;; Actual logic is wrapped in a delay rather than a normal function so we don't log the error messages more than once +;; in cases where we have to fall back to the system temporary directory +(defn- plugins-dir + "Get a `Path` to the Metabase plugins directory, creating it if needed. If it cannot be created for one reason or + another, or if we do not have write permissions for it, use a temporary directory instead." + ^Path [] + @plugins-dir*) (defn- extract-system-modules! [] (when (io/resource "modules")