Skip to content

Commit c5c5c58

Browse files
committed
Support .pgpass files for migra
This eases the whole connection URI setup for developers who make use of the .pgpass file. Signed-off-by: Wesley Schwengle <[email protected]>
1 parent da6671a commit c5c5c58

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

docs/installing_and_connecting.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ The general form is as follows:
2626
:::bash
2727
connectiontype://username:password@databasehostname/databasename?extraparam1=a&extraparam2=b
2828

29+
If you have a .pgpass file in your $HOME dir, you can make use of that as well
30+
as you don't need to enter the password in the connection string:
31+
32+
:::bash
33+
postgresql://username@hostname/databasename
34+
2935
These can be left out if not necessary. For instance, if connecting locally, using your default system username and passwordless "trust" login, only a connection type and database name is required:
3036

3137
:::bash

migra/command.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
from __future__ import print_function, unicode_literals
22

33
import argparse
4+
import pgpasslib
45
import sys
6+
import getpass
7+
58
from contextlib import contextmanager
9+
from sqlalchemy.engine.url import make_url
10+
from sqlbag import S
611

712
from .migra import Migration
813
from .statements import UnsafeMigrationException
@@ -75,14 +80,58 @@ def parse_args(args):
7580
return parser.parse_args(args)
7681

7782

83+
def get_password_from_pgpass(host, port, database, username):
84+
if not host:
85+
host = "localhost"
86+
87+
if not port:
88+
port = 5432
89+
90+
if not username:
91+
username = getpass.getuser()
92+
93+
if not database:
94+
database = username
95+
96+
try:
97+
return pgpasslib.getpass(
98+
host,
99+
port,
100+
database,
101+
username,
102+
)
103+
except pgpasslib.FileNotFound:
104+
return None
105+
106+
return None
107+
108+
109+
def get_password_from_uri(uri):
110+
111+
uri = make_url(uri)
112+
113+
if not uri.password:
114+
password = get_password_from_pgpass(
115+
uri.host, uri.port, uri.database, uri.username
116+
)
117+
if password:
118+
uri.set(password=password)
119+
120+
return uri
121+
122+
78123
def run(args, out=None, err=None):
79124
schema = args.schema
80125
exclude_schema = args.exclude_schema
81126
if not out:
82127
out = sys.stdout # pragma: no cover
83128
if not err:
84129
err = sys.stderr # pragma: no cover
85-
with arg_context(args.dburl_from) as ac0, arg_context(args.dburl_target) as ac1:
130+
131+
db_from = get_password_from_uri(args.dburl_from)
132+
db_to = get_password_from_uri(args.dburl_target)
133+
134+
with arg_context(db_from) as ac0, arg_context(db_to) as ac1:
86135
m = Migration(
87136
ac0,
88137
ac1,

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ six = "*"
1616
# schemainspect = {path="../schemainspect", develop=true}
1717
schemainspect = ">=3.1.1663480743"
1818
psycopg2-binary = { version="*", optional = true }
19+
pgpasslib = "*"
1920

2021
[tool.poetry.dev-dependencies]
2122
sqlbag = "*"

0 commit comments

Comments
 (0)