summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--changelog.rst2
-rw-r--r--pgcli/main.py54
-rw-r--r--pgcli/pgclirc5
-rw-r--r--tests/test_main.py48
5 files changed, 104 insertions, 6 deletions
diff --git a/AUTHORS b/AUTHORS
index 18953bd8..4c2ab3f0 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -106,6 +106,7 @@ Contributors:
* George Thomas(thegeorgeous)
* Yoni Nakache(lazydba247)
* Gantsev Denis
+ * Stephano Paraskeva
Creator:
--------
diff --git a/changelog.rst b/changelog.rst
index c197de2f..134f5a59 100644
--- a/changelog.rst
+++ b/changelog.rst
@@ -7,6 +7,8 @@ Features:
* Add `__main__.py` file to execute pgcli as a package directly (#1123).
* Add support for ANSI escape sequences for coloring the prompt (#1122).
* Add support for partitioned tables (relkind "p").
+* Add support for `pg_service.conf` files
+* Add config option show_bottom_toolbar.
Bug fixes:
diff --git a/pgcli/main.py b/pgcli/main.py
index 60cb6f8d..a2128619 100644
--- a/pgcli/main.py
+++ b/pgcli/main.py
@@ -1,5 +1,8 @@
+import platform
import warnings
+from os.path import expanduser
+from configobj import ConfigObj
from pgspecial.namedqueries import NamedQueries
warnings.filterwarnings("ignore", category=UserWarning, module="psycopg2")
@@ -211,6 +214,7 @@ class PGCli(object):
self.decimal_format = c["data_formats"]["decimal"]
self.float_format = c["data_formats"]["float"]
self.initialize_keyring()
+ self.show_bottom_toolbar = c["main"].as_bool("show_bottom_toolbar")
self.pgspecial.pset_pager(
self.config["main"].as_bool("enable_pager") and "on" or "off"
@@ -470,6 +474,21 @@ class PGCli(object):
def connect_dsn(self, dsn, **kwargs):
self.connect(dsn=dsn, **kwargs)
+ def connect_service(self, service, user):
+ service_config, file = parse_service_info(service)
+ if service_config is None:
+ click.secho(
+ "service '%s' was not found in %s" % (service, file), err=True, fg="red"
+ )
+ exit(1)
+ self.connect(
+ database=service_config.get("dbname"),
+ host=service_config.get("host"),
+ user=user or service_config.get("user"),
+ port=service_config.get("port"),
+ passwd=service_config.get("password"),
+ )
+
def connect_uri(self, uri):
kwargs = psycopg2.extensions.parse_dsn(uri)
remap = {"dbname": "database", "password": "passwd"}
@@ -793,7 +812,7 @@ class PGCli(object):
reserve_space_for_menu=self.min_num_menu_lines,
message=get_message,
prompt_continuation=get_continuation,
- bottom_toolbar=get_toolbar_tokens,
+ bottom_toolbar=get_toolbar_tokens if self.show_bottom_toolbar else None,
complete_style=complete_style,
input_processors=[
# Highlight matching brackets while editing.
@@ -1249,7 +1268,11 @@ def cli(
username = dbname
database = dbname_opt or dbname or ""
user = username_opt or username
-
+ service = None
+ if database.startswith("service="):
+ service = database[8:]
+ elif os.getenv("PGSERVICE") is not None:
+ service = os.getenv("PGSERVICE")
# because option --list or -l are not supposed to have a db name
if list_databases:
database = "postgres"
@@ -1270,10 +1293,10 @@ def cli(
pgcli.dsn_alias = dsn
elif "://" in database:
pgcli.connect_uri(database)
- elif "=" in database:
+ elif "=" in database and service is None:
pgcli.connect_dsn(database, user=user)
- elif os.environ.get("PGSERVICE", None):
- pgcli.connect_dsn("service={0}".format(os.environ["PGSERVICE"]))
+ elif service is not None:
+ pgcli.connect_service(service, user)
else:
pgcli.connect(database, host, user, port)
@@ -1447,5 +1470,26 @@ def format_output(title, cur, headers, status, settings):
return output
+def parse_service_info(service):
+ service = service or os.getenv("PGSERVICE")
+ service_file = os.getenv("PGSERVICEFILE")
+ if not service_file:
+ # try ~/.pg_service.conf (if that exists)
+ if platform.system() == "Windows":
+ service_file = os.getenv("PGSYSCONFDIR") + "\\pg_service.conf"
+ elif os.getenv("PGSYSCONFDIR"):
+ service_file = os.path.join(os.getenv("PGSYSCONFDIR"), ".pg_service.conf")
+ else:
+ service_file = expanduser("~/.pg_service.conf")
+ if not service:
+ # nothing to do
+ return None, service_file
+ service_file_config = ConfigObj(service_file)
+ if service not in service_file_config:
+ return None, service_file
+ service_conf = service_file_config.get(service)
+ return service_conf, service_file
+
+
if __name__ == "__main__":
cli()
diff --git a/pgcli/pgclirc b/pgcli/pgclirc
index 220677dd..4918606c 100644
--- a/pgcli/pgclirc
+++ b/pgcli/pgclirc
@@ -86,6 +86,9 @@ search_path_filter = False
# Timing of sql statments and table rendering.
timing = True
+# Show/hide the informational toolbar with function keymap at the footer.
+show_bottom_toolbar = True
+
# Table format. Possible values: psql, plain, simple, grid, fancy_grid, pipe,
# ascii, double, github, orgtbl, rst, mediawiki, html, latex, latex_booktabs,
# textile, moinmoin, jira, vertical, tsv, csv.
@@ -142,7 +145,7 @@ null_string = '<null>'
# manage pager on startup
enable_pager = True
-# Use keyring to automatically save and load password in a secure manner
+# Use keyring to automatically save and load password in a secure manner
keyring = True
# Custom colors for the completion menu, toolbar, etc.
diff --git a/tests/test_main.py b/tests/test_main.py
index 044181b1..9b85a34b 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -282,6 +282,54 @@ def test_quoted_db_uri(tmpdir):
)
+def test_pg_service_file(tmpdir):
+
+ with mock.patch.object(PGCli, "connect") as mock_connect:
+ cli = PGCli(pgclirc_file=str(tmpdir.join("rcfile")))
+ with open(tmpdir.join(".pg_service.conf").strpath, "w") as service_conf:
+ service_conf.write(
+ """[myservice]
+ host=a_host
+ user=a_user
+ port=5433
+ password=much_secure
+ dbname=a_dbname
+
+ [my_other_service]
+ host=b_host
+ user=b_user
+ port=5435
+ dbname=b_dbname
+ """
+ )
+ os.environ["PGSERVICEFILE"] = tmpdir.join(".pg_service.conf").strpath
+ cli.connect_service("myservice", "another_user")
+ mock_connect.assert_called_with(
+ database="a_dbname",
+ host="a_host",
+ user="another_user",
+ port="5433",
+ passwd="much_secure",
+ )
+
+ with mock.patch.object(PGExecute, "__init__") as mock_pgexecute:
+ mock_pgexecute.return_value = None
+ cli = PGCli(pgclirc_file=str(tmpdir.join("rcfile")))
+ os.environ["PGPASSWORD"] = "very_secure"
+ cli.connect_service("my_other_service", None)
+ mock_pgexecute.assert_called_with(
+ "b_dbname",
+ "b_user",
+ "very_secure",
+ "b_host",
+ "5435",
+ "",
+ application_name="pgcli",
+ )
+ del os.environ["PGPASSWORD"]
+ del os.environ["PGSERVICEFILE"]
+
+
def test_ssl_db_uri(tmpdir):
with mock.patch.object(PGCli, "connect") as mock_connect:
cli = PGCli(pgclirc_file=str(tmpdir.join("rcfile")))