Skip to content

Commit 7a059a6

Browse files
authored
Merge pull request #795 from dbcli/default-socket-location
try more default socket paths
2 parents 43140ba + 977e409 commit 7a059a6

File tree

4 files changed

+76
-12
lines changed

4 files changed

+76
-12
lines changed

mycli/config.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import io
12
import shutil
3+
from copy import copy
24
from io import BytesIO, TextIOWrapper
35
import logging
46
import os
57
from os.path import exists
68
import struct
79
import sys
10+
from typing import Union
811

912
from configobj import ConfigObj, ConfigObjError
1013
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
@@ -58,13 +61,50 @@ def read_config_file(f, list_values=True):
5861
return config
5962

6063

64+
def get_included_configs(config_file: Union[str, io.TextIOWrapper]) -> list:
65+
"""Get a list of configuration files that are included into config_path
66+
with !includedir directive.
67+
68+
"Normal" configs should be passed as file paths. The only exception
69+
is .mylogin which is decoded into a stream. However, it never
70+
contains include directives and so will be ignored by this
71+
function.
72+
73+
"""
74+
if not isinstance(config_file, str) or not os.path.isfile(config_file):
75+
return []
76+
included_configs = []
77+
78+
try:
79+
with open(config_file) as f:
80+
include_directives = filter(
81+
lambda s: s.startswith('!includedir'),
82+
f
83+
)
84+
dirs = map(lambda s: s.strip().split()[-1], include_directives)
85+
dirs = filter(os.path.isdir, dirs)
86+
for dir in dirs:
87+
for filename in os.listdir(dir):
88+
if filename.endswith('.cnf'):
89+
included_configs.append(os.path.join(dir, filename))
90+
except (PermissionError, UnicodeDecodeError):
91+
pass
92+
return included_configs
93+
94+
6195
def read_config_files(files, list_values=True):
6296
"""Read and merge a list of config files."""
6397

6498
config = ConfigObj(list_values=list_values)
65-
66-
for _file in files:
99+
_files = copy(files)
100+
while _files:
101+
_file = _files.pop(0)
67102
_config = read_config_file(_file, list_values=list_values)
103+
104+
# expand includes only if we were able to parse config
105+
# (otherwise we'll just encounter the same errors again)
106+
if config is not None:
107+
_files = get_included_configs(_file) + _files
68108
if bool(_config) is True:
69109
config.merge(_config)
70110
config.filename = _config.filename

mycli/main.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import re
77
import fileinput
88
from collections import namedtuple
9+
from pwd import getpwuid
910
from time import time
1011
from datetime import datetime
1112
from random import choice
@@ -48,7 +49,7 @@
4849
from .lexer import MyCliLexer
4950
from .__init__ import __version__
5051
from .compat import WIN
51-
from .packages.filepaths import dir_path_exists
52+
from .packages.filepaths import dir_path_exists, guess_socket_location
5253

5354
import itertools
5455

@@ -317,7 +318,7 @@ def read_my_cnf_files(self, files, keys):
317318
"""
318319
cnf = read_config_files(files, list_values=False)
319320

320-
sections = ['client']
321+
sections = ['client', 'mysqld']
321322
if self.login_path and self.login_path != 'client':
322323
sections.append(self.login_path)
323324

@@ -382,10 +383,11 @@ def connect(self, database='', user='', passwd='', host='', port='',
382383
# Fall back to config values only if user did not specify a value.
383384

384385
database = database or cnf['database']
385-
if port or host:
386+
# Socket interface not supported for SSH connections
387+
if port or host or ssh_host or ssh_port:
386388
socket = ''
387389
else:
388-
socket = socket or cnf['socket']
390+
socket = socket or cnf['socket'] or guess_socket_location()
389391
user = user or cnf['user'] or os.getenv('USER')
390392
host = host or cnf['host']
391393
port = port or cnf['port']
@@ -430,11 +432,11 @@ def _connect():
430432
raise e
431433

432434
try:
433-
if (socket is host is port is None) and not WIN:
434-
# Try a sensible default socket first (simplifies auth)
435-
# If we get a connection error, try tcp/ip localhost
435+
if not WIN and socket:
436+
socket_owner = getpwuid(os.stat(socket).st_uid).pw_name
437+
self.echo(
438+
f"Connecting to socket {socket}, owned by user {socket_owner}")
436439
try:
437-
socket = '/var/run/mysqld/mysqld.sock'
438440
_connect()
439441
except OperationalError as e:
440442
# These are "Can't open socket" and 2x "Can't connect"

mycli/packages/filepaths.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
import os
2+
import platform
3+
4+
5+
if os.name == "posix":
6+
if platform.system() == "Darwin":
7+
DEFAULT_SOCKET_DIRS = ("/tmp",)
8+
else:
9+
DEFAULT_SOCKET_DIRS = ("/var/run", "/var/lib")
10+
else:
11+
DEFAULT_SOCKET_DIRS = ()
212

313

414
def list_path(root_dir):
515
"""List directory if exists.
616
7-
:param dir: str
17+
:param root_dir: str
818
:return: list
919
1020
"""
@@ -81,3 +91,16 @@ def dir_path_exists(path):
8191
8292
"""
8393
return os.path.exists(os.path.dirname(path))
94+
95+
96+
def guess_socket_location():
97+
"""Try to guess the location of the default mysql socket file."""
98+
socket_dirs = filter(os.path.exists, DEFAULT_SOCKET_DIRS)
99+
for directory in socket_dirs:
100+
for r, dirs, files in os.walk(directory, topdown=True):
101+
for filename in files:
102+
name, ext = os.path.splitext(filename)
103+
if name.startswith("mysql") and ext in ('.socket', '.sock'):
104+
return os.path.join(r, filename)
105+
dirs[:] = [d for d in dirs if d.startswith("mysql")]
106+
return None

mycli/sqlexecute.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ def run(self, statement):
191191
if not cur.nextset() or (not cur.rowcount and cur.description is None):
192192
break
193193

194-
195194
def get_result(self, cursor):
196195
"""Get the current result's data from the cursor."""
197196
title = headers = None

0 commit comments

Comments
 (0)