@@ -480,6 +480,7 @@ def connect(
480480 ssh_key_filename : str | None = "" ,
481481 init_command : str | None = "" ,
482482 unbuffered : bool | None = None ,
483+ password_file : str | None = None ,
483484 ) -> None :
484485 cnf = {
485486 "database" : None ,
@@ -538,9 +539,50 @@ def connect(
538539 # 4. DSN (mysql://user:password)
539540 # 5. cnf (.my.cnf / etc)
540541
542+ def get_password_from_file (password_file : str | None ) -> str | None :
543+ if not password_file :
544+ return None
545+ try :
546+ with open (password_file ) as fp :
547+ password = fp .readline ().strip ()
548+ return password
549+ except FileNotFoundError :
550+ click .secho (f"Password file '{ password_file } ' not found" , err = True , fg = "red" )
551+ sys .exit (1 )
552+ except PermissionError :
553+ click .secho (f"Permission denied reading password file '{ password_file } '" , err = True , fg = "red" )
554+ sys .exit (1 )
555+ except IsADirectoryError :
556+ click .secho (f"Path '{ password_file } ' is a directory, not a file" , err = True , fg = "red" )
557+ sys .exit (1 )
558+ except Exception as e :
559+ click .secho (f"Error reading password file '{ password_file } ': { str (e )} " , err = True , fg = "red" )
560+ sys .exit (1 )
561+
562+ if passwd and '://' in passwd :
563+ is_valid_scheme , _scheme = is_valid_connection_scheme (passwd or '' )
564+ if is_valid_scheme :
565+ click .secho ('Warning: password looks like a DSN. Check the command line.' , err = True , fg = 'yellow' )
566+
567+ # if user passes the --p* flag, ask for the password right away
568+ # to enforce consistency and reduce lag as much as possible
569+ if passwd == "MYCLI_ASK_PASSWORD" :
570+ passwd = click .prompt (f"Enter password for { user } " , hide_input = True , show_default = False , default = '' , type = str , err = True )
571+
572+ # if the passwd is not specified try to set it using the password_file option
573+ if passwd is None and password_file :
574+ password_from_file = get_password_from_file (password_file )
575+ if password_from_file is not None :
576+ passwd = password_from_file
577+
578+ # getting the envvar ourselves because the envvar from a click
579+ # option cannot be an empty string, but a password can be
580+ if passwd is None and os .environ .get ("MYSQL_PWD" ) is not None :
581+ passwd = os .environ .get ("MYSQL_PWD" )
582+
541583 # if no password was found from all of the above sources, ask for a password
542584 if passwd is None :
543- passwd = click .prompt ("Enter password" , hide_input = True , show_default = False , default = '' , type = str , err = True )
585+ passwd = click .prompt (f "Enter password for { user } " , hide_input = True , show_default = False , default = '' , type = str , err = True )
544586
545587 # Connect to the database.
546588 def _connect () -> None :
@@ -1600,54 +1642,6 @@ def cli(
16001642 - mycli mysql://my_user@my_host.com:3306/my_database
16011643
16021644 """
1603-
1604- def get_password_from_file (password_file : str | None ) -> str | None :
1605- if not password_file :
1606- return None
1607- try :
1608- with open (password_file ) as fp :
1609- password = fp .readline ().strip ()
1610- return password
1611- except FileNotFoundError :
1612- click .secho (f"Password file '{ password_file } ' not found" , err = True , fg = "red" )
1613- sys .exit (1 )
1614- except PermissionError :
1615- click .secho (f"Permission denied reading password file '{ password_file } '" , err = True , fg = "red" )
1616- sys .exit (1 )
1617- except IsADirectoryError :
1618- click .secho (f"Path '{ password_file } ' is a directory, not a file" , err = True , fg = "red" )
1619- sys .exit (1 )
1620- except Exception as e :
1621- click .secho (f"Error reading password file '{ password_file } ': { str (e )} " , err = True , fg = "red" )
1622- sys .exit (1 )
1623-
1624- # if user passes the --p* flag, ask for the password right away
1625- # to reduce lag as much as possible
1626- if password == "MYCLI_ASK_PASSWORD" :
1627- password = click .prompt ("Enter password" , hide_input = True , show_default = False , default = '' , type = str , err = True )
1628- # if the password value looks like a DSN, treat it as such and
1629- # prompt for password
1630- elif database is None and password is not None and "://" in password :
1631- # check if the scheme is valid. We do not actually have any logic for these, but
1632- # it will most usefully catch the case where we erroneously catch someone's
1633- # password, and give them an easy error message to follow / report
1634- is_valid_scheme , scheme = is_valid_connection_scheme (password )
1635- if not is_valid_scheme :
1636- click .secho (f"Error: Unknown connection scheme provided for DSN URI ({ scheme } ://)" , err = True , fg = "red" )
1637- sys .exit (1 )
1638- database = password
1639- password = click .prompt ("Enter password" , hide_input = True , show_default = False , default = '' , type = str , err = True )
1640-
1641- # if the passwd is not specified try to set it using the password_file option
1642- if password is None and password_file :
1643- if password_from_file := get_password_from_file (password_file ):
1644- password = password_from_file
1645-
1646- # getting the envvar ourselves because the envvar from a click
1647- # option cannot be an empty string, but a password can be
1648- if password is None and os .environ .get ("MYSQL_PWD" ) is not None :
1649- password = os .environ .get ("MYSQL_PWD" )
1650-
16511645 mycli = MyCli (
16521646 prompt = prompt ,
16531647 logfile = logfile ,
@@ -1880,6 +1874,7 @@ def get_password_from_file(password_file: str | None) -> str | None:
18801874 init_command = combined_init_cmd ,
18811875 unbuffered = unbuffered ,
18821876 charset = charset ,
1877+ password_file = password_file ,
18831878 )
18841879
18851880 if combined_init_cmd :
0 commit comments