diff --git a/changelog.md b/changelog.md index 3644bcf2..1442ac0f 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,7 @@ Bug Fixes -------- * Refactor completions for special commands, with minor casing fixes. * Raise `--password-file` higher in the precedence of password specification. +* Fix regression: show username in password prompt. Internal diff --git a/mycli/main.py b/mycli/main.py index 0e3e37d3..bf91020d 100755 --- a/mycli/main.py +++ b/mycli/main.py @@ -480,6 +480,7 @@ def connect( ssh_key_filename: str | None = "", init_command: str | None = "", unbuffered: bool | None = None, + password_file: str | None = None, ) -> None: cnf = { "database": None, @@ -538,9 +539,43 @@ def connect( # 4. DSN (mysql://user:password) # 5. cnf (.my.cnf / etc) + def get_password_from_file(password_file: str | None) -> str | None: + if not password_file: + return None + try: + with open(password_file) as fp: + password = fp.readline().strip() + return password + except FileNotFoundError: + click.secho(f"Password file '{password_file}' not found", err=True, fg="red") + sys.exit(1) + except PermissionError: + click.secho(f"Permission denied reading password file '{password_file}'", err=True, fg="red") + sys.exit(1) + except IsADirectoryError: + click.secho(f"Path '{password_file}' is a directory, not a file", err=True, fg="red") + sys.exit(1) + except Exception as e: + click.secho(f"Error reading password file '{password_file}': {str(e)}", err=True, fg="red") + sys.exit(1) + + if passwd == "MYCLI_ASK_PASSWORD": + passwd = click.prompt(f"Enter password for {user}", hide_input=True, show_default=False, default='', type=str, err=True) + + # if the passwd is not specified try to set it using the password_file option + if passwd is None and password_file: + password_from_file = get_password_from_file(password_file) + if password_from_file is not None: + passwd = password_from_file + + # getting the envvar ourselves because the envvar from a click + # option cannot be an empty string, but a password can be + if passwd is None and os.environ.get("MYSQL_PWD") is not None: + passwd = os.environ.get("MYSQL_PWD") + # if no password was found from all of the above sources, ask for a password if passwd is None: - passwd = click.prompt("Enter password", hide_input=True, show_default=False, default='', type=str, err=True) + passwd = click.prompt(f"Enter password for {user}", hide_input=True, show_default=False, default='', type=str, err=True) # Connect to the database. def _connect() -> None: @@ -1600,34 +1635,7 @@ def cli( - mycli mysql://my_user@my_host.com:3306/my_database """ - - def get_password_from_file(password_file: str | None) -> str | None: - if not password_file: - return None - try: - with open(password_file) as fp: - password = fp.readline().strip() - return password - except FileNotFoundError: - click.secho(f"Password file '{password_file}' not found", err=True, fg="red") - sys.exit(1) - except PermissionError: - click.secho(f"Permission denied reading password file '{password_file}'", err=True, fg="red") - sys.exit(1) - except IsADirectoryError: - click.secho(f"Path '{password_file}' is a directory, not a file", err=True, fg="red") - sys.exit(1) - except Exception as e: - click.secho(f"Error reading password file '{password_file}': {str(e)}", err=True, fg="red") - sys.exit(1) - - # if user passes the --p* flag, ask for the password right away - # to reduce lag as much as possible - if password == "MYCLI_ASK_PASSWORD": - password = click.prompt("Enter password", hide_input=True, show_default=False, default='', type=str, err=True) - # if the password value looks like a DSN, treat it as such and - # prompt for password - elif database is None and password is not None and "://" in password: + if database is None and password is not None and "://" in password: # check if the scheme is valid. We do not actually have any logic for these, but # it will most usefully catch the case where we erroneously catch someone's # password, and give them an easy error message to follow / report @@ -1636,17 +1644,7 @@ def get_password_from_file(password_file: str | None) -> str | None: click.secho(f"Error: Unknown connection scheme provided for DSN URI ({scheme}://)", err=True, fg="red") sys.exit(1) database = password - password = click.prompt("Enter password", hide_input=True, show_default=False, default='', type=str, err=True) - - # if the passwd is not specified try to set it using the password_file option - if password is None and password_file: - if password_from_file := get_password_from_file(password_file): - password = password_from_file - - # getting the envvar ourselves because the envvar from a click - # option cannot be an empty string, but a password can be - if password is None and os.environ.get("MYSQL_PWD") is not None: - password = os.environ.get("MYSQL_PWD") + password = "MYCLI_ASK_PASSWORD" mycli = MyCli( prompt=prompt, @@ -1880,6 +1878,7 @@ def get_password_from_file(password_file: str | None) -> str | None: init_command=combined_init_cmd, unbuffered=unbuffered, charset=charset, + password_file=password_file, ) if combined_init_cmd: diff --git a/test/test_main.py b/test/test_main.py index 451277a4..eb7b0683 100644 --- a/test/test_main.py +++ b/test/test_main.py @@ -11,7 +11,8 @@ from click.testing import CliRunner from pymysql.err import OperationalError -from mycli.main import MyCli, cli, is_valid_connection_scheme, thanks_picker +from mycli.main import MyCli, cli, thanks_picker +from mycli.packages.parseutils import is_valid_connection_scheme import mycli.packages.special from mycli.packages.special.main import COMMANDS as SPECIAL_COMMANDS from mycli.sqlexecute import ServerInfo, SQLExecute