Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ TBD
Features
--------
* Deprecate reading configuration values from `my.cnf` files.
* Add `--checkup` mode to show unconfigured new features.


Bug Fixes
Expand Down
69 changes: 52 additions & 17 deletions mycli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,10 @@ def __init__(
# Load config.
config_files: list[str | IO[str]] = self.system_config_files + [myclirc] + [self.pwd_config_file]
c = self.config = read_config_files(config_files)
# this parallel config exists only to compare with my.cnf and can be removed with my.cnf support
# this parallel config exists to
# * compare with my.cnf
# * support the --checkup feature
self.config_without_package_defaults = read_config_files(config_files, ignore_package_defaults=True)
for toplevel in ['main', 'connection']:
if not self.config_without_package_defaults.get(toplevel):
self.config_without_package_defaults[toplevel] = {}
self.multi_line = c["main"].as_bool("multi_line")
self.key_bindings = c["main"]["key_bindings"]
special.set_timing_enabled(c["main"].as_bool("timing"))
Expand Down Expand Up @@ -520,14 +519,15 @@ def connect(
host = host or cnf["host"]
port = port or cnf["port"]
ssl_config: dict[str, Any] = ssl or {}
user_connection_config = self.config_without_package_defaults.get('connection', {})

int_port = port and int(port)
if not int_port:
int_port = 3306
if not host or host == "localhost":
socket = (
socket
or self.config_without_package_defaults["connection"].get("default_socket")
or user_connection_config.get("default_socket")
or cnf["socket"]
or cnf["default_socket"]
or guess_socket_location()
Expand All @@ -554,7 +554,7 @@ def connect(
use_local_infile = False
for local_infile_option in (
local_infile,
self.config_without_package_defaults['connection'].get('default_local_infile'),
user_connection_config.get('default_local_infile'),
cnf['local_infile'],
cnf['local-infile'],
cnf['loose_local_infile'],
Expand All @@ -568,16 +568,16 @@ def connect(
pass

# temporary my.cnf override mappings
if 'default_ssl_ca' in self.config_without_package_defaults['connection']:
cnf['ssl-ca'] = self.config_without_package_defaults['connection']['default_ssl_ca'] or None
if 'default_ssl_cert' in self.config_without_package_defaults['connection']:
cnf['ssl-cert'] = self.config_without_package_defaults['connection']['default_ssl_cert'] or None
if 'default_ssl_key' in self.config_without_package_defaults['connection']:
cnf['ssl-key'] = self.config_without_package_defaults['connection']['default_ssl_key'] or None
if 'default_ssl_cipher' in self.config_without_package_defaults['connection']:
cnf['ssl-cipher'] = self.config_without_package_defaults['connection']['default_ssl_cipher'] or None
if 'default_ssl_verify_server_cert' in self.config_without_package_defaults['connection']:
cnf['ssl-verify-server-cert'] = self.config_without_package_defaults['connection']['default_ssl_verify_server_cert'] or None
if 'default_ssl_ca' in user_connection_config:
cnf['ssl-ca'] = user_connection_config.get('default_ssl_ca') or None
if 'default_ssl_cert' in user_connection_config:
cnf['ssl-cert'] = user_connection_config.get('default_ssl_cert') or None
if 'default_ssl_key' in user_connection_config:
cnf['ssl-key'] = user_connection_config.get('default_ssl_key') or None
if 'default_ssl_cipher' in user_connection_config:
cnf['ssl-cipher'] = user_connection_config.get('default_ssl_cipher') or None
if 'default_ssl_verify_server_cert' in user_connection_config:
cnf['ssl-verify-server-cert'] = user_connection_config.get('default_ssl_verify_server_cert') or None

# todo: rewrite the merge method using self.config['connection'] instead of cnf, after removing my.cnf support
ssl_config_or_none: dict[str, Any] | None = self.merge_ssl_with_cnf(ssl_config, cnf)
Expand Down Expand Up @@ -1624,6 +1624,7 @@ def get_last_query(self) -> str | None:
default=None,
help='Store and retrieve passwords from the system keyring: true/false/reset.',
)
@click.option("--checkup", is_flag=True, help="Run a checkup on your config file.")
@click.pass_context
def cli(
ctx: click.Context,
Expand Down Expand Up @@ -1677,6 +1678,7 @@ def cli(
batch_format: str | None,
throttle: float,
use_keyring_cli_opt: str | None,
checkup: bool,
) -> None:
"""A MySQL terminal client with auto-completion and syntax highlighting.

Expand Down Expand Up @@ -1743,6 +1745,10 @@ def get_password_from_file(password_file: str | None) -> str | None:
myclirc=myclirc,
)

if checkup:
do_config_checkup(mycli)
sys.exit(0)

if csv and batch_format not in [None, 'csv']:
click.secho("Conflicting --csv and --format arguments.", err=True, fg="red")
sys.exit(1)
Expand Down Expand Up @@ -1993,7 +1999,8 @@ def get_password_from_file(password_file: str | None) -> str | None:
and mycli.my_cnf[mycnf_section_name].get(mycnf_item_name.replace('-', '_')) is None
):
continue
if mycli.config_without_package_defaults[myclirc_section_name].get(myclirc_item_name) is None:
user_section = mycli.config_without_package_defaults.get(myclirc_section_name, {})
if user_section.get(myclirc_item_name) is None:
cnf_value = mycli.my_cnf[mycnf_section_name].get(mycnf_item_name)
if cnf_value is None:
cnf_value = mycli.my_cnf[mycnf_section_name].get(mycnf_item_name.replace('-', '_'))
Expand Down Expand Up @@ -2217,5 +2224,33 @@ def read_ssh_config(ssh_config_path: str):
return ssh_config


def do_config_checkup(mycli: MyCli) -> None:
did_output = False

if not list(mycli.config.keys()):
print('\nThe local ~/,myclirc is missing or empty.\n')
did_output = True
else:
for section_name in mycli.config.keys():
if section_name not in mycli.config_without_package_defaults:
if not did_output:
print('\nMissing in user ~/.myclirc:\n')
print(f'The entire section:\n\n [{section_name}]\n')
did_output = True
continue
for item_name in mycli.config[section_name]:
if item_name not in mycli.config_without_package_defaults[section_name]:
if not did_output:
print('\nMissing in user ~/.myclirc:\n')
print(f'The item:\n\n [{section_name}]\n {item_name} =\n')
did_output = True
if did_output:
print(
'For more info on new features, see the commentary and defaults at:\n\n * https://github.com/dbcli/mycli/blob/main/mycli/myclirc\n'
)
else:
print('User configuration all up to date!')


if __name__ == "__main__":
cli()