¿Cómo puedo obtener emacs sql-mode para usar el archivo de configuración de mysql(.my.cnf)?
(3)
Cuando mysql dbname
en el indicador bash, me conecto automáticamente a la base de datos dbname
con el username
, la password
y la información del dbname
incluida en mi archivo .my.cnf
.
Cuando uso Mx sql-mysql
en emacs, me vuelven a solicitar toda esta información.
¿Hay alguna manera de que pueda obtener el modo sql de emacs para usar la información en mi archivo .my.cnf
?
No creo que esto sea posible, pero puedes configurarlo en la configuración del modo en sí:
(setq sql-connection-alist
''((pool-a
(sql-product ''mysql)
(sql-server "1.2.3.4")
(sql-user "me")
(sql-password "mypassword")
(sql-database "thedb")
(sql-port 3306))
(pool-b
(sql-product ''mysql)
(sql-server "1.2.3.4")
(sql-user "me")
(sql-password "mypassword")
(sql-database "thedb")
(sql-port 3307))))
(defun sql-connect-preset (name)
"Connect to a predefined SQL connection listed in `sql-connection-alist''"
(eval `(let ,(cdr (assoc name sql-connection-alist))
(flet ((sql-get-login (&rest what)))
(sql-product-interactive sql-product)))))
(defun sql-pool-a ()
(interactive)
(sql-connect-preset ''pool-a))
Echa un vistazo a este artículo para más información.
Simplemente presiona return, se recogió por defecto.
Claro que es posible. Aunque es bastante complicado.
Aproximadamente, los pasos son:
- Lectura y análisis del archivo ini usando ini.el.
- Fusionando la configuración de los diferentes hosts con la configuración de los clientes porque esta última se aplica globalmente.
- Transformando cada host a un formato adecuado para
sql-connection-alist
- Poblando
sql-connection-alist
- Usando
Mx sql-connect
(¡que se completa automáticamente!)
El siguiente código también incluye un analizador .pgpass, por las dudas. Notarás que la implementación es más simple.
;;; .pgpass parser
(defun read-file (file)
"Returns file as list of lines."
(with-temp-buffer
(insert-file-contents file)
(split-string (buffer-string) "/n" t)))
(defun pgpass-to-sql-connection (config)
"Returns a suitable list for sql-connection-alist from a pgpass file."
(append sql-connection-alist
(let ((server (lambda (host port db user _pass)
(list
(concat db ":" user ":" port ":" host)
(list ''sql-product ''''postgres)
(list ''sql-server host)
(list ''sql-user user)
(list ''sql-port (string-to-number port))
(list ''sql-database db))))
(pgpass-line (lambda (line)
(apply server (split-string line ":" t)))))
(mapcar pgpass-line config))))
;;; .my.cnf parser
;;; Copied verbatim from https://github.com/daniel-ness/ini.el/blob/master/ini.el
(defun ini-decode (ini_text)
;; text -> alist
(interactive)
(if (not (stringp ini_text))
(error "Must be a string"))
(let ((lines (split-string ini_text "/n"))
(section)
(section-list)
(alist))
(dolist (l lines)
;; skip comments
(unless (or (string-match "^;" l)
(string-match "^[ /t]$" l))
;; catch sections
(if (string-match "^//[//(.*//)//]$" l)
(progn
(if section
;; add as sub-list
(setq alist (cons `(,section . ,section-list) alist))
(setq alist section-list))
(setq section (match-string 1 l))
(setq section-list nil)))
;; catch properties
(if (string-match "^//([^/s/t]+//)[/s/t]*=[/s/t]*//(.+//)$" l)
(let ((property (match-string 1 l))
(value (match-string 2 l)))
(progn
(setq section-list (cons `(,property . ,value) section-list)))))))
(if section
;; add as sub-list
(setq alist (cons `(,section . ,section-list) alist))
(setq alist section-list))
alist))
(defun read-ini (file)
"Returns ini file as alist."
(with-temp-buffer
(insert-file-contents file)
(ini-decode (buffer-string))))
(defun filter-alist (wanted-members alist)
"Returns a copy of given alist, with only fields from wanted-members."
(let ((result nil)
(add-if-member (lambda (elt)
(when (member (car elt) wanted-members)
(add-to-list ''result elt t)))))
(mapc add-if-member alist)
result))
(defun merge-alist (original override)
"Returns a union of original and override alist. On key conflict, the latter wins."
(let ((result (copy-alist override))
(add (lambda (elt)
(setq result (add-to-list
''result elt t
(lambda (left right) (equal (car left) (car right))))))))
(mapc add original)
result))
(defun map-alist-keys (f alist)
"Maps on alist''s keys and returns new alist with new keys."
(mapcar
(lambda (elt) (list (funcall f (car elt)) (cdr elt)))
alist))
(defun map-alist-values (f alist)
"Maps on alist''s values and returns new alist with new values."
(mapcar
(lambda (elt) (list (car elt) (funcall f (cdr elt))))
alist))
(defun parse-mycnf-hosts (file-path)
"Returns list of hosts with clients'' section applied to all hosts."
(let ((hosts nil)
(global nil)
(fields ''("user" "host" "database" "password" "port"))
(section-parse (lambda(section)
(if (equal (car section) "client")
(setq global (filter-alist fields (cdr section)))
(let ((host (car section))
(config (filter-alist fields (cdr section))))
(when config (add-to-list ''hosts (cons host config) t))))))
(merge-host-with-global (lambda (host)
(cons (car host) (merge-alist global (cdr host))))))
(mapc section-parse (read-ini file-path))
(mapcar merge-host-with-global hosts)))
(defun mycnf-to-sql-connection (config)
(let ((key-to-sql-connection
(lambda (key)
(cond ((equal key "host") ''sql-server)
((equal key "user") ''sql-user)
((equal key "port") ''sql-port)
((equal key "database") ''sql-database)
((equal key "password") ''sql-password)
(t (error (format "Unknown key %s" key)))))))
(map-alist-values
(apply-partially ''map-alist-keys key-to-sql-connection)
config)))
;;; Actually populating sql-connection-alist
(setq sql-connection-alist
(append
(mycnf-to-sql-connection (parse-mycnf-hosts "~/.my.cnf"))
(pgpass-to-sql-connection (read-file "~/.pgpass"))
))
Con el siguiente .my.cnf
:
[client]
user=me
[host1]
database=db1
host=db.host1.com
[host2]
database=db2
user=notme
host=db.host2.com
Ejecutar la expresión (mycnf-to-sql-connection (parse-mycnf-hosts "~/.my.cnf"))
me da (bastante impreso a mano):
(("host2" ((sql-server "db.host2.com")
(sql-user "notme")
(sql-database "db2")))
("host1" ((sql-server "db.host1.com")
(sql-database "db1")
(sql-user "me"))))
Finalmente, en lugar de usar Mx sql-mysql
, use Mx sql-connect
y podrá conectarse usando el alias, con finalización automática.