Skip to content
Snippets Groups Projects
Unverified Commit f5101e69 authored by Cam Saul's avatar Cam Saul
Browse files

Move command-line commands into metabase.cmd

parent 775b75cc
Branches
Tags
No related merge requests found
(ns metabase.cmd
"Functions for commands that can be ran from the command-line with `lein` or the Metabase JAR. These are ran as
follows:
<metabase> <command> <options>
for example, running the `migrate` command and passing it `force` can be done using one of the following ways:
lein run migrate force
java -jar metabase.jar migrate force
Logic below translates resolves the command itself to a function marked with `^:command` metadata and calls the
function with arguments as appropriate.
You can see what commands are available by running the command `help`. This command uses the docstrings and arglists
associated with each command's entrypoint function to generate descriptions for each command."
(:require [clojure.string :as str]
[metabase
[config :as config]
[db :as mdb]
[util :as u]]))
(defn ^:command migrate
"Run database migrations. Valid options for DIRECTION are `up`, `force`, `down-one`, `print`, or `release-locks`."
[direction]
(mdb/migrate! (keyword direction)))
(defn ^:command load-from-h2
"Transfer data from existing H2 database to the newly created MySQL or Postgres DB specified by env vars."
([]
(load-from-h2 nil))
([h2-connection-string]
(require 'metabase.cmd.load-from-h2)
(binding [mdb/*disable-data-migrations* true]
((resolve 'metabase.cmd.load-from-h2/load-from-h2!) h2-connection-string))))
(defn ^:command profile
"Start Metabase the usual way and exit. Useful for profiling Metabase launch time."
[]
;; override env var that would normally make Jetty block forever
(intern 'environ.core 'env (assoc environ.core/env :mb-jetty-join "false"))
(u/profile "start-normally" ((resolve 'metabase.core/start-normally))))
(defn ^:command reset-password
"Reset the password for a user with EMAIL-ADDRESS."
[email-address]
(require 'metabase.cmd.reset-password)
((resolve 'metabase.cmd.reset-password/reset-password!) email-address))
(defn ^:command help
"Show this help message listing valid Metabase commands."
[]
(println "Valid commands are:")
(doseq [[symb varr] (sort (ns-interns 'metabase.cmd))
:when (:command (meta varr))]
(println symb (str/join " " (:arglists (meta varr))))
(println "\t" (when-let [dox (:doc (meta varr))]
(str/replace dox #"\s+" " ")))) ; replace newlines or multiple spaces with single spaces
(println "\nSome other commands you might find useful:\n")
(println "java -cp metabase.jar org.h2.tools.Shell -url jdbc:h2:/path/to/metabase.db")
(println "\tOpen an SQL shell for the Metabase H2 DB"))
(defn ^:command version
"Print version information about Metabase and the current system."
[]
(println "Metabase version:" config/mb-version-info)
(println "\nOS:"
(System/getProperty "os.name")
(System/getProperty "os.version")
(System/getProperty "os.arch"))
(println "\nJava version:"
(System/getProperty "java.vm.name")
(System/getProperty "java.version"))
(println "\nCountry:" (System/getProperty "user.country"))
(println "System timezone:" (System/getProperty "user.timezone"))
(println "Language:" (System/getProperty "user.language"))
(println "File encoding:" (System/getProperty "file.encoding")))
(defn ^:command api-documentation
"Generate a markdown file containing documentation for all API endpoints. This is written to a file called
`docs/api-documentation.md`."
[]
(require 'metabase.cmd.endpoint-dox)
((resolve 'metabase.cmd.endpoint-dox/generate-dox!)))
;;; ------------------------------------------------ Running Commands ------------------------------------------------
(defn- cmd->fn [command-name]
(or (when (seq command-name)
(when-let [varr (ns-resolve 'metabase.cmd (symbol command-name))]
(when (:command (meta varr))
@varr)))
(do (println (u/format-color 'red "Unrecognized command: %s" command-name))
(help)
(System/exit 1))))
(defn run-cmd
"Run `cmd` with `args`. This is a function above. e.g. `lein run metabase migrate force` becomes
`(migrate \"force\")`."
[cmd args]
(try (apply (cmd->fn cmd) args)
(catch Throwable e
(.printStackTrace e)
(println (u/format-color 'red "Command failed with exception: %s" (.getMessage e)))
(System/exit 1)))
(System/exit 0))
......@@ -2,9 +2,7 @@
(ns metabase.core
(:gen-class)
(:require [cheshire.core :as json]
[clojure
[pprint :as pprint]
[string :as s]]
[clojure.pprint :as pprint]
[clojure.tools.logging :as log]
environ.core
[medley.core :as m]
......@@ -255,86 +253,9 @@
(log/error "Metabase Initialization FAILED: " (.getMessage e))
(System/exit 1))))
;;; ---------------------------------------- Special Commands ----------------------------------------
(defn ^:command migrate
"Run database migrations. Valid options for DIRECTION are `up`, `force`, `down-one`, `print`, or `release-locks`."
[direction]
(mdb/migrate! (keyword direction)))
(defn ^:command load-from-h2
"Transfer data from existing H2 database to the newly created MySQL or Postgres DB specified by env vars."
([]
(load-from-h2 nil))
([h2-connection-string]
(require 'metabase.cmd.load-from-h2)
(binding [mdb/*disable-data-migrations* true]
((resolve 'metabase.cmd.load-from-h2/load-from-h2!) h2-connection-string))))
(defn ^:command profile
"Start Metabase the usual way and exit. Useful for profiling Metabase launch time."
[]
;; override env var that would normally make Jetty block forever
(intern 'environ.core 'env (assoc environ.core/env :mb-jetty-join "false"))
(u/profile "start-normally" (start-normally)))
(defn ^:command reset-password
"Reset the password for a user with EMAIL-ADDRESS."
[email-address]
(require 'metabase.cmd.reset-password)
((resolve 'metabase.cmd.reset-password/reset-password!) email-address))
(defn ^:command help
"Show this help message listing valid Metabase commands."
[]
(println "Valid commands are:")
(doseq [[symb varr] (sort (ns-interns 'metabase.core))
:when (:command (meta varr))]
(println symb (s/join " " (:arglists (meta varr))))
(println "\t" (:doc (meta varr))))
(println "\nSome other commands you might find useful:\n")
(println "java -cp metabase.jar org.h2.tools.Shell -url jdbc:h2:/path/to/metabase.db")
(println "\tOpen an SQL shell for the Metabase H2 DB"))
(defn ^:command version
"Print version information about Metabase and the current system."
[]
(println "Metabase version:" config/mb-version-info)
(println "\nOS:"
(System/getProperty "os.name")
(System/getProperty "os.version")
(System/getProperty "os.arch"))
(println "\nJava version:"
(System/getProperty "java.vm.name")
(System/getProperty "java.version"))
(println "\nCountry:" (System/getProperty "user.country"))
(println "System timezone:" (System/getProperty "user.timezone"))
(println "Language:" (System/getProperty "user.language"))
(println "File encoding:" (System/getProperty "file.encoding")))
(defn ^:command api-documentation
"Generate a markdown file containing documentation for all API endpoints. This is written to a file called `docs/api-documentation.md`."
[]
(require 'metabase.cmd.endpoint-dox)
((resolve 'metabase.cmd.endpoint-dox/generate-dox!)))
(defn- cmd->fn [command-name]
(or (when (seq command-name)
(when-let [varr (ns-resolve 'metabase.core (symbol command-name))]
(when (:command (meta varr))
@varr)))
(do (println (u/format-color 'red "Unrecognized command: %s" command-name))
(help)
(System/exit 1))))
(defn- run-cmd [cmd & args]
(try (apply (cmd->fn cmd) args)
(catch Throwable e
(.printStackTrace e)
(println (u/format-color 'red "Command failed with exception: %s" (.getMessage e)))
(System/exit 1)))
(System/exit 0))
(defn- run-cmd [cmd args]
(require 'metabase.cmd)
((resolve 'metabase.cmd/run-cmd) cmd args))
;;; ---------------------------------------- App Entry Point ----------------------------------------
......@@ -343,5 +264,5 @@
"Launch Metabase in standalone mode."
[& [cmd & args]]
(if cmd
(apply run-cmd cmd args) ; run a command like `java -jar metabase.jar migrate release-locks` or `lein run migrate release-locks`
(start-normally))) ; with no command line args just start Metabase normally
(run-cmd cmd args) ; run a command like `java -jar metabase.jar migrate release-locks` or `lein run migrate release-locks`
(start-normally))) ; with no command line args just start Metabase normally
......@@ -12,7 +12,7 @@
[metabase.core.initialization-status :as init-status]
[metabase.models.setting :as setting]))
;; # ---------------------------------------- EXPECTAIONS FRAMEWORK SETTINGS ------------------------------
;;; ---------------------------------------- Expectations Framework Settings -----------------------------------------
;; ## GENERAL SETTINGS
......@@ -61,16 +61,19 @@
(< (count e) (count a)) "actual is larger than expected"
(> (count e) (count a)) "expected is larger than actual"))))
;; # ------------------------------ FUNCTIONS THAT GET RUN ON TEST SUITE START / STOP ------------------------------
;; `test-startup` function won't work for loading the drivers because they need to be available at evaluation time for some of the unit tests work work properly
;;; ------------------------------- Functions That Get Ran On Test Suite Start / Stop --------------------------------
;; `test-startup` function won't work for loading the drivers because they need to be available at evaluation time for
;; some of the unit tests work work properly
(driver/find-and-load-drivers!)
(defn test-startup
{:expectations-options :before-run}
[]
;; We can shave about a second from unit test launch time by doing the various setup stages in on different threads
;; Start Jetty in the BG so if test setup fails we have an easier time debugging it -- it's trickier to debug things on a BG thread
;; Start Jetty in the BG so if test setup fails we have an easier time debugging it -- it's trickier to debug things
;; on a BG thread
(let [start-jetty! (future (core/start-jetty!))]
(try
......@@ -79,8 +82,8 @@
(setting/set! :site-name "Metabase Test")
(init-status/set-complete!)
;; make sure the driver test extensions are loaded before running the tests. :reload them because otherwise we get wacky 'method in protocol not implemented' errors
;; when running tests against an individual namespace
;; make sure the driver test extensions are loaded before running the tests. :reload them because otherwise we
;; get wacky 'method in protocol not implemented' errors when running tests against an individual namespace
(doseq [engine (keys (driver/available-drivers))
:let [driver-test-ns (symbol (str "metabase.test.data." (name engine)))]]
(u/ignore-exceptions
......@@ -101,10 +104,8 @@
(core/stop-jetty!))
(defn call-with-test-scaffolding
"Runs `test-startup` and ensures `test-teardown` is always
called. This function is useful for running a test (or test
namespace) at the repl with the appropriate environment setup for
the test to pass."
"Runs `test-startup` and ensures `test-teardown` is always called. This function is useful for running a test (or test
namespace) at the repl with the appropriate environment setup for the test to pass."
[f]
(try
(test-startup)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment