j@279: (cl:in-package #:amuse-database-admin) j@279: j@287: (defvar *amuse-database* nil j@287: "The default AMuSE-wide database connection is assigned to this j@287: variable. If for any reason, such as testing database interaction, j@287: you do not wish to use the default database, this variable can be j@287: shadowed locally within a particular backend package. For this to j@287: actually work consistantly, all clsql database functions should j@287: specify *amuse-database* explicitally as the :database argument. Not j@287: doing this relies on the value of clsql:*default-database* being the j@287: connection to the correct database, which in most cases will j@287: actually be fine so long as you are not connecting to different j@287: databases.") j@279: j@279: (defun connect-to-database (&key (database-name "amuse") username j@279: use-tunnel (make-default t)) j@279: "Well, slightly more secure I guess. Requires that an option file j@279: exists containing connection-spec s-expressions. If no such file j@279: exists a skeleton file can be created by calling j@279: make-db-option-file (the password still needs to be added j@279: manually). The path is ~/.amuse.lisp. j@279: j@279: A better approach might be to use something like: j@279: http://www.cliki.net/trivial-configuration-parser. Or for slime to j@279: prompt the user for the password something j@279: like (swank::eval-in-emacs `(read-passwd \"Password: \")). However, j@279: this presents other security issues. j@279: j@279: If use-tunnel is t, then regardless of the host specified in the j@279: connection-spec, it will be set to localhost. It is assumed that the j@279: tunnel is already set up. j@279: j@279: When make-default is t, the newly created connection is assigned to j@279: *amuse-database*. If make-default is nil, then the connection is j@279: returned and is expected to be handled by the caller. This is useful j@279: for connecting to different databases within individual j@279: implementations (mainly for testing purposes)." j@279: (if (and make-default j@279: *amuse-database* j@279: (clsql-mysql::is-database-open *amuse-database*)) j@279: (error "A default AMuSE database connection already exists: j@279: ~S" (clsql:database-name *amuse-database*)) j@279: (let ((connection-spec (%get-connection-spec database-name j@279: username))) j@279: (when use-tunnel j@279: (setf (car connection-spec) "127.0.0.1")) j@279: (let ((connection (%get-database-connection connection-spec))) j@279: (when make-default j@279: (setf *amuse-database* connection)) j@279: connection)))) j@279: j@279: (defun disconnect-from-database (&optional (database-connection j@279: *amuse-database*)) j@279: (clsql:disconnect :database database-connection)) j@279: j@279: (defun make-db-option-file (&key database-name host username (port "3306")) j@279: (with-open-file (stream (%make-db-option-file-pathname) :direction :output) j@279: (sb-ext:run-program "chmod" j@279: (list "600" (namestring j@279: (%make-db-option-file-pathname))) j@279: :search t) j@279: (princ " j@279: ;;; Option file containing connection-spec s-expressions for connecting j@279: ;;; to a database from within AMuSE. You can have multiple specifications, j@279: ;;; but they must be uniquely identifiable by database name or a combination j@279: ;;; of database and username. j@279: j@279: ;;; You need to fill in the missing
." stream) j@279: (format stream "~2%(~S ~S ~S \"\" ~S)" j@279: (if host host "") j@279: (if database-name database-name "") j@279: (if username username "") j@279: port)) j@279: (warn "You now need to manually edit ~A." j@279: (namestring (%make-db-option-file-pathname)))) j@279: j@279: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; j@279: ;;; Helper functions j@279: j@279: (defun %get-database-connection (connection-spec) j@279: (clsql:connect connection-spec j@279: :if-exists :old j@279: :database-type :mysql)) j@279: j@279: (defun %get-connection-spec (db-name username) j@279: (let ((option-file (probe-file (%make-db-option-file-pathname)))) j@279: (if option-file j@279: (with-open-file (stream option-file) j@279: (loop for connection-spec = (read stream nil) j@279: while connection-spec j@279: do (destructuring-bind (host db usr pwd prt) j@279: connection-spec j@279: (declare (ignore host pwd prt)) j@279: (when (equal db-name db) j@279: (when (or (null username) j@279: (equal username usr)) j@279: (return connection-spec)))) j@279: finally (error "No connection-spec exists matching j@279: database: ~A and username: ~A" db-name username))) j@279: ;; If file doesn't exist, create it. j@279: (error "~A option file does not exist. j@279: You need to run: amuse-database-admin:make-db-option-file." j@279: (namestring (%make-db-option-file-pathname)))))) j@279: j@279: (defun %make-db-option-file-pathname () j@279: (merge-pathnames (user-homedir-pathname) ".amuse.lisp"))