From 69b6d43f6c0297afa1f72e4ee8660e9c1d0a2ed9 Mon Sep 17 00:00:00 2001 From: Kuba Suder Date: Wed, 23 Oct 2024 18:10:28 +0200 Subject: [PATCH 1/5] added --mysql-socket option for unix socket path --- README.md | 1 + docs/README.rst | 1 + src/sqlite3_to_mysql/cli.py | 3 +++ src/sqlite3_to_mysql/transporter.py | 3 +++ src/sqlite3_to_mysql/types.py | 2 ++ 5 files changed, 10 insertions(+) diff --git a/README.md b/README.md index 0ee34a2..bbdf1e4 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ Options: --mysql-password TEXT MySQL password -h, --mysql-host TEXT MySQL host. Defaults to localhost. -P, --mysql-port INTEGER MySQL port. Defaults to 3306. + --mysql-socket TEXT Path to MySQL unix socket file. -S, --skip-ssl Disable MySQL connection encryption. -i, --mysql-insert-method [DEFAULT|IGNORE|UPDATE] MySQL insert method. DEFAULT will throw diff --git a/docs/README.rst b/docs/README.rst index cfdf8e1..5da0526 100644 --- a/docs/README.rst +++ b/docs/README.rst @@ -29,6 +29,7 @@ Connection Options - ``-h, --mysql-host TEXT``: MySQL host. Defaults to localhost. - ``-P, --mysql-port INTEGER``: MySQL port. Defaults to 3306. - ``-S, --skip-ssl``: Disable MySQL connection encryption. +- ``--mysql-socket TEXT``: Path to MySQL unix socket file. Transfer Options """""""""""""""" diff --git a/src/sqlite3_to_mysql/cli.py b/src/sqlite3_to_mysql/cli.py index 7391256..216db50 100644 --- a/src/sqlite3_to_mysql/cli.py +++ b/src/sqlite3_to_mysql/cli.py @@ -62,6 +62,7 @@ @click.option("--mysql-password", default=None, help="MySQL password") @click.option("-h", "--mysql-host", default="localhost", help="MySQL host. Defaults to localhost.") @click.option("-P", "--mysql-port", type=int, default=3306, help="MySQL port. Defaults to 3306.") +@click.option("--mysql-socket", default=None, help="Path to MySQL unix socket file.") @click.option("-S", "--skip-ssl", is_flag=True, help="Disable MySQL connection encryption.") @click.option( "-i", @@ -137,6 +138,7 @@ def cli( mysql_database: str, mysql_host: str, mysql_port: int, + mysql_socket: str, skip_ssl: bool, mysql_insert_method: str, mysql_truncate_tables: bool, @@ -183,6 +185,7 @@ def cli( mysql_database=mysql_database, mysql_host=mysql_host, mysql_port=mysql_port, + mysql_socket=mysql_socket, mysql_ssl_disabled=skip_ssl, mysql_insert_method=mysql_insert_method, mysql_truncate_tables=mysql_truncate_tables, diff --git a/src/sqlite3_to_mysql/transporter.py b/src/sqlite3_to_mysql/transporter.py index 6e034b5..1b2b02a 100644 --- a/src/sqlite3_to_mysql/transporter.py +++ b/src/sqlite3_to_mysql/transporter.py @@ -74,6 +74,8 @@ def __init__(self, **kwargs: tx.Unpack[SQLite3toMySQLParams]): self._mysql_port = kwargs.get("mysql_port", 3306) or 3306 + self._mysql_socket = str(kwargs.get("mysql_socket")) if kwargs.get("mysql_socket") else None + self._sqlite_tables = kwargs.get("sqlite_tables") or tuple() self._without_foreign_keys = bool(self._sqlite_tables) or bool(kwargs.get("without_foreign_keys", False)) @@ -143,6 +145,7 @@ def __init__(self, **kwargs: tx.Unpack[SQLite3toMySQLParams]): password=self._mysql_password, host=self._mysql_host, port=self._mysql_port, + unix_socket=self._mysql_socket, ssl_disabled=self._mysql_ssl_disabled, use_pure=True, charset=self._mysql_charset, diff --git a/src/sqlite3_to_mysql/types.py b/src/sqlite3_to_mysql/types.py index d6082f4..4411357 100644 --- a/src/sqlite3_to_mysql/types.py +++ b/src/sqlite3_to_mysql/types.py @@ -20,6 +20,7 @@ class SQLite3toMySQLParams(tx.TypedDict): mysql_password: t.Optional[t.Union[str, bool]] mysql_host: t.Optional[str] mysql_port: t.Optional[int] + mysql_socket: t.Optional[str] mysql_ssl_disabled: t.Optional[bool] chunk: t.Optional[int] quiet: t.Optional[bool] @@ -49,6 +50,7 @@ class SQLite3toMySQLAttributes: _mysql_password: t.Optional[str] _mysql_host: str _mysql_port: int + _mysql_socket: str _mysql_ssl_disabled: bool _chunk_size: t.Optional[int] _quiet: bool From fe082f4d65bbdc39472656351649506780588163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 13 Jul 2025 14:56:29 +0100 Subject: [PATCH 2/5] :bug: validate mysql_socket existence and update type hints --- src/sqlite3_to_mysql/cli.py | 4 ++-- src/sqlite3_to_mysql/transporter.py | 9 ++++++++- src/sqlite3_to_mysql/types.py | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/sqlite3_to_mysql/cli.py b/src/sqlite3_to_mysql/cli.py index 216db50..4a94cbf 100644 --- a/src/sqlite3_to_mysql/cli.py +++ b/src/sqlite3_to_mysql/cli.py @@ -62,7 +62,7 @@ @click.option("--mysql-password", default=None, help="MySQL password") @click.option("-h", "--mysql-host", default="localhost", help="MySQL host. Defaults to localhost.") @click.option("-P", "--mysql-port", type=int, default=3306, help="MySQL port. Defaults to 3306.") -@click.option("--mysql-socket", default=None, help="Path to MySQL unix socket file.") +@click.option("--mysql-socket", type=click.Path(exists=True), default=None, help="Path to MySQL unix socket file.") @click.option("-S", "--skip-ssl", is_flag=True, help="Disable MySQL connection encryption.") @click.option( "-i", @@ -138,7 +138,7 @@ def cli( mysql_database: str, mysql_host: str, mysql_port: int, - mysql_socket: str, + mysql_socket: t.Optional[str], skip_ssl: bool, mysql_insert_method: str, mysql_truncate_tables: bool, diff --git a/src/sqlite3_to_mysql/transporter.py b/src/sqlite3_to_mysql/transporter.py index 4eabc11..c87fe6c 100644 --- a/src/sqlite3_to_mysql/transporter.py +++ b/src/sqlite3_to_mysql/transporter.py @@ -75,7 +75,14 @@ def __init__(self, **kwargs: tx.Unpack[SQLite3toMySQLParams]): self._mysql_port = kwargs.get("mysql_port", 3306) or 3306 - self._mysql_socket = str(kwargs.get("mysql_socket")) if kwargs.get("mysql_socket") else None + if kwargs.get("mysql_socket") is not None: + if not os.path.exists(str(kwargs.get("mysql_socket"))): + raise FileNotFoundError("MySQL socket does not exist") + else: + self._mysql_socket = realpath(str(kwargs.get("mysql_socket"))) + self._mysql_port = None + else: + self._mysql_socket = None self._sqlite_tables = kwargs.get("sqlite_tables") or tuple() diff --git a/src/sqlite3_to_mysql/types.py b/src/sqlite3_to_mysql/types.py index 4411357..1a491eb 100644 --- a/src/sqlite3_to_mysql/types.py +++ b/src/sqlite3_to_mysql/types.py @@ -20,7 +20,7 @@ class SQLite3toMySQLParams(tx.TypedDict): mysql_password: t.Optional[t.Union[str, bool]] mysql_host: t.Optional[str] mysql_port: t.Optional[int] - mysql_socket: t.Optional[str] + mysql_socket: t.Optional[t.Union[str, "os.PathLike[t.Any]"]] mysql_ssl_disabled: t.Optional[bool] chunk: t.Optional[int] quiet: t.Optional[bool] @@ -49,8 +49,8 @@ class SQLite3toMySQLAttributes: _mysql_user: str _mysql_password: t.Optional[str] _mysql_host: str - _mysql_port: int - _mysql_socket: str + _mysql_port: t.Optional[int] + _mysql_socket: t.Optional[t.Union[str, "os.PathLike[t.Any]"]] _mysql_ssl_disabled: bool _chunk_size: t.Optional[int] _quiet: bool From d2aaf33a40dbdc4db0ed3871e8b377592f8536b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 13 Jul 2025 15:24:35 +0100 Subject: [PATCH 3/5] :sparkles: add shorthand option `-k` for `--mysql-socket` and update README --- README.md | 2 +- src/sqlite3_to_mysql/cli.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8fc82c6..60b34d0 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Options: --mysql-password TEXT MySQL password -h, --mysql-host TEXT MySQL host. Defaults to localhost. -P, --mysql-port INTEGER MySQL port. Defaults to 3306. - --mysql-socket TEXT Path to MySQL unix socket file. + -k, --mysql-socket PATH Path to MySQL unix socket file. -S, --skip-ssl Disable MySQL connection encryption. -i, --mysql-insert-method [DEFAULT|IGNORE|UPDATE] MySQL insert method. DEFAULT will throw diff --git a/src/sqlite3_to_mysql/cli.py b/src/sqlite3_to_mysql/cli.py index 4a94cbf..6a2570c 100644 --- a/src/sqlite3_to_mysql/cli.py +++ b/src/sqlite3_to_mysql/cli.py @@ -62,7 +62,13 @@ @click.option("--mysql-password", default=None, help="MySQL password") @click.option("-h", "--mysql-host", default="localhost", help="MySQL host. Defaults to localhost.") @click.option("-P", "--mysql-port", type=int, default=3306, help="MySQL port. Defaults to 3306.") -@click.option("--mysql-socket", type=click.Path(exists=True), default=None, help="Path to MySQL unix socket file.") +@click.option( + "-k", + "--mysql-socket", + type=click.Path(exists=True), + default=None, + help="Path to MySQL unix socket file.", +) @click.option("-S", "--skip-ssl", is_flag=True, help="Disable MySQL connection encryption.") @click.option( "-i", From 168a2f598e54c49d0667bbcf463c076522011efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 13 Jul 2025 15:28:58 +0100 Subject: [PATCH 4/5] :white_check_mark: add test assertions for `mysql_socket` configuration --- tests/unit/types_test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/types_test.py b/tests/unit/types_test.py index f1fdcba..0a3c5cd 100644 --- a/tests/unit/types_test.py +++ b/tests/unit/types_test.py @@ -23,6 +23,7 @@ def test_sqlite3_to_mysql_params_typing(self) -> None: "mysql_password": "password", "mysql_host": "localhost", "mysql_port": 3306, + "mysql_socket": "/var/run/mysqld/mysqld.sock", "mysql_ssl_disabled": True, "chunk": 1000, "quiet": False, @@ -50,6 +51,7 @@ def test_sqlite3_to_mysql_params_typing(self) -> None: assert params["mysql_password"] == "password" assert params["mysql_host"] == "localhost" assert params["mysql_port"] == 3306 + assert params["mysql_socket"] == "/var/run/mysqld/mysqld.sock" assert params["mysql_ssl_disabled"] is True assert params["chunk"] == 1000 assert params["quiet"] is False @@ -90,6 +92,7 @@ def __init__(self) -> None: self._mysql_password = "password" self._mysql_host = "localhost" self._mysql_port = 3306 + self._mysql_socket = "/var/run/mysqld/mysqld.sock" self._mysql_ssl_disabled = True self._chunk_size = 1000 self._quiet = False @@ -129,6 +132,7 @@ def __init__(self) -> None: assert instance._mysql_password == "password" assert instance._mysql_host == "localhost" assert instance._mysql_port == 3306 + assert instance._mysql_socket == "/var/run/mysqld/mysqld.sock" assert instance._mysql_ssl_disabled is True assert instance._chunk_size == 1000 assert instance._quiet is False From 2ad89e1224317ba2eb339a468349cbcdbfe432fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 13 Jul 2025 16:19:42 +0100 Subject: [PATCH 5/5] :bug: prevent simultaneous use of mysql_port and mysql_socket in CLI options --- src/sqlite3_to_mysql/cli.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sqlite3_to_mysql/cli.py b/src/sqlite3_to_mysql/cli.py index 6a2570c..e20c477 100644 --- a/src/sqlite3_to_mysql/cli.py +++ b/src/sqlite3_to_mysql/cli.py @@ -165,6 +165,9 @@ def cli( """Transfer SQLite to MySQL using the provided CLI options.""" click.echo(_copyright_header) try: + if mysql_port and mysql_socket: + raise click.ClickException("Error: Can only specify either -P/--mysql-port or -k/--mysql-socket, not both.") + if mysql_collation: charset_collations: t.Tuple[str, ...] = tuple( cs.collation for cs in mysql_supported_character_sets(mysql_charset.lower())