ndev-stack 0.3.16__tar.gz → 0.3.17__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/PKG-INFO +1 -1
  2. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/__init__.py +1 -1
  3. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/db.py +114 -4
  4. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev_stack.egg-info/PKG-INFO +1 -1
  5. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/pyproject.toml +1 -1
  6. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/tests/test_opensuse_compat.py +14 -0
  7. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/README.md +0 -0
  8. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/__main__.py +0 -0
  9. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/cli.py +0 -0
  10. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/__init__.py +0 -0
  11. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/config.py +0 -0
  12. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/constants.py +0 -0
  13. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/distro.py +0 -0
  14. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/github.py +0 -0
  15. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/logger.py +0 -0
  16. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/manifest.py +0 -0
  17. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/__init__.py +0 -0
  18. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/base.py +0 -0
  19. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/builtin/mailpit/manifest.json +0 -0
  20. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/builtin/mailpit/module.py +0 -0
  21. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/builtin/mongodb/manifest.json +0 -0
  22. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/builtin/mongodb/module.py +0 -0
  23. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/builtin/postgres/manifest.json +0 -0
  24. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/builtin/postgres/module.py +0 -0
  25. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/builtin/redis/manifest.json +0 -0
  26. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/builtin/redis/module.py +0 -0
  27. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/modules/manager.py +0 -0
  28. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/common/utils.py +0 -0
  29. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/__init__.py +0 -0
  30. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/chroot/manager.py +0 -0
  31. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/chroot/packages.py +0 -0
  32. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/chroot/shell.py +0 -0
  33. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/cli.py +0 -0
  34. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/available.py +0 -0
  35. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/clean.py +0 -0
  36. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/ctl.py +0 -0
  37. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/current.py +0 -0
  38. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/doctor.py +0 -0
  39. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/grok.py +0 -0
  40. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/install.py +0 -0
  41. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/list.py +0 -0
  42. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/logs.py +0 -0
  43. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/mailpit.py +0 -0
  44. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/modules.py +0 -0
  45. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/mongodb.py +0 -0
  46. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/postgres.py +0 -0
  47. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/reload.py +0 -0
  48. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/restart.py +0 -0
  49. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/setup.py +0 -0
  50. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/start.py +0 -0
  51. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/status.py +0 -0
  52. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/stop.py +0 -0
  53. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/uninstall.py +0 -0
  54. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/update.py +0 -0
  55. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/upgrade.py +0 -0
  56. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/use.py +0 -0
  57. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/commands/vhost.py +0 -0
  58. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/php/builder.py +0 -0
  59. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/php/downloader.py +0 -0
  60. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/php/extensions.py +0 -0
  61. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/php/installer.py +0 -0
  62. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/php/resolver.py +0 -0
  63. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/php/templates.py +0 -0
  64. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/runtime/fpm.py +0 -0
  65. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/runtime/mailpit.py +0 -0
  66. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/runtime/nginx_helper.py +0 -0
  67. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/runtime/pma.py +0 -0
  68. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/runtime/process.py +0 -0
  69. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/runtime/services.py +0 -0
  70. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/runtime/sockets.py +0 -0
  71. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/runtime/upgrade.py +0 -0
  72. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/linux/tui.py +0 -0
  73. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/main.py +0 -0
  74. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/tui.py +0 -0
  75. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/__init__.py +0 -0
  76. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/bin/shim.exe +0 -0
  77. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/cli.py +0 -0
  78. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/commands/__init__.py +0 -0
  79. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/__init__.py +0 -0
  80. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/db.py +0 -0
  81. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/elevate.py +0 -0
  82. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/ext.py +0 -0
  83. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/fcgi.py +0 -0
  84. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/grok.py +0 -0
  85. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/logs.py +0 -0
  86. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/mailpit.py +0 -0
  87. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/mkcert.py +0 -0
  88. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/paths.py +0 -0
  89. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/php.py +0 -0
  90. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/pma.py +0 -0
  91. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/redis_core.py +0 -0
  92. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/services.py +0 -0
  93. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/setup.py +0 -0
  94. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/shim.py +0 -0
  95. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/upgrade.py +0 -0
  96. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/core/vhost.py +0 -0
  97. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/templates/vhost.conf.tmpl +0 -0
  98. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/templates/vhost_ssl.conf.tmpl +0 -0
  99. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev/win/tui.py +0 -0
  100. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev_stack.egg-info/SOURCES.txt +0 -0
  101. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev_stack.egg-info/dependency_links.txt +0 -0
  102. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev_stack.egg-info/entry_points.txt +0 -0
  103. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev_stack.egg-info/requires.txt +0 -0
  104. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/ndev_stack.egg-info/top_level.txt +0 -0
  105. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/setup.cfg +0 -0
  106. {ndev_stack-0.3.16 → ndev_stack-0.3.17}/tests/test_shim.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ndev-stack
3
- Version: 0.3.16
3
+ Version: 0.3.17
4
4
  Summary: Cross-platform developer stack manager for PHP, FastCGI/PHP-FPM, MariaDB, Redis, PostgreSQL, MongoDB, Nginx, SSL, and Mailpit on Linux and Windows
5
5
  Author-email: Ankit Karan <ankit.karan99@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/ankitkaran99/ndev
@@ -1,7 +1,7 @@
1
1
  """
2
2
  ndev: Fast, cross-platform PHP developer environment for Windows and Linux.
3
3
  """
4
- __version__ = "0.3.16"
4
+ __version__ = "0.3.17"
5
5
 
6
6
  from . import common as common
7
7
  from .common.logger import logger as logger
@@ -47,13 +47,20 @@ def run_wizard():
47
47
  console.print(" 1) Create Database")
48
48
  console.print(" 2) Drop Database")
49
49
  console.print(" 3) Export Database (mysqldump)")
50
- console.print(" 4) Create User")
51
- console.print(" 5) Drop User")
52
- op_choice = typer.prompt("Choice [1-5]", default=1, type=int)
50
+ console.print(" 4) Import Database (.sql file)")
51
+ console.print(" 5) Create User")
52
+ console.print(" 6) Drop User")
53
+ op_choice = typer.prompt("Choice [1-6]", default=1, type=int)
53
54
 
54
- action_map = {1: "create-db", 2: "drop-db", 3: "export-db", 4: "create-user", 5: "drop-user"}
55
+ action_map = {1: "create-db", 2: "drop-db", 3: "export-db", 4: "import-db", 5: "create-user", 6: "drop-user"}
55
56
  action = action_map.get(op_choice, "create-db")
56
57
 
58
+ if action == "import-db":
59
+ sql_file = typer.prompt("Path to .sql file to import").strip()
60
+ target_db = typer.prompt("Database name (optional, press Enter to skip)", default="")
61
+ execute_import_db(host, port, admin_user, admin_password, sql_file, target_db or None)
62
+ return
63
+
57
64
  target_name = typer.prompt("Database/Username")
58
65
  if not target_name:
59
66
  logger.error("Target name is required.")
@@ -163,6 +170,66 @@ def execute_export_db(
163
170
  raise typer.Exit(code=1)
164
171
  sys.stdout.write(res.stdout)
165
172
 
173
+ def execute_import_db(
174
+ host: str,
175
+ port: int,
176
+ user: str,
177
+ password: Optional[str],
178
+ sql_file: str,
179
+ database: Optional[str] = None,
180
+ ):
181
+ sql_path = Path(sql_file).expanduser().resolve()
182
+ if not sql_path.exists():
183
+ logger.error(f"SQL file not found: {sql_path}")
184
+ raise typer.Exit(code=1)
185
+
186
+ client = which_binary("mariadb") or which_binary("mysql") or "mysql"
187
+ if not shutil.which(client):
188
+ logger.error(f"MySQL / MariaDB client ({client}) not found in PATH.")
189
+ raise typer.Exit(code=1)
190
+
191
+ # Resolve password if not provided
192
+ if password is None and user == "root":
193
+ res = subprocess.run([client, "-h", host, "-P", str(port), "-u", "root", "--password=root", "-e", "SELECT 1;"], capture_output=True)
194
+ if res.returncode == 0:
195
+ password = "root"
196
+ else:
197
+ res_blank = subprocess.run([client, "-h", host, "-P", str(port), "-u", "root", "-e", "SELECT 1;"], capture_output=True)
198
+ if res_blank.returncode == 0:
199
+ password = ""
200
+ else:
201
+ password = "root"
202
+
203
+ # If target database specified, ensure it exists
204
+ if database:
205
+ create_sql = f"CREATE DATABASE IF NOT EXISTS `{database}`;"
206
+ res_create = execute_sql_mysql(host, port, user, password, create_sql)
207
+ if res_create.returncode != 0:
208
+ logger.error(f"Failed to ensure database '{database}' exists: {res_create.stderr}")
209
+ raise typer.Exit(code=1)
210
+
211
+ cmd = [client, "-h", host, "-P", str(port), "-u", user]
212
+ if password:
213
+ cmd.append(f"--password={password}")
214
+ if database:
215
+ cmd.append(database)
216
+
217
+ target_desc = f"database '{database}'" if database else "MariaDB / MySQL"
218
+ console.print(f"[bold yellow]Importing '{sql_path.name}' ({sql_path.stat().st_size:,} bytes) into {target_desc}...[/bold yellow]")
219
+
220
+ try:
221
+ with open(sql_path, "r", encoding="utf-8", errors="ignore") as f:
222
+ res = subprocess.run(cmd, stdin=f, capture_output=True, text=True)
223
+ except Exception as e:
224
+ logger.error(f"Failed to read SQL file '{sql_path}': {e}")
225
+ raise typer.Exit(code=1)
226
+
227
+ if res.returncode != 0:
228
+ logger.error(f"MySQL Import Error:\n{res.stderr.strip()}")
229
+ raise typer.Exit(code=1)
230
+
231
+ console.print(f"[bold green]✓ Successfully imported '{sql_path.name}' into {target_desc}![/bold green]")
232
+
166
233
  def execute_create_user(host: str, port: int, user: str, password: Optional[str], new_user: str, new_pass: str, grant_db: Optional[str], user_host: str):
167
234
  logger.info(f"Creating user '{new_user}' on MySQL...")
168
235
  if not shutil.which("mysql"):
@@ -276,6 +343,49 @@ def export_db_cmd(
276
343
  triggers=triggers
277
344
  )
278
345
 
346
+ @db_app.command("import")
347
+ @db_app.command("import-db")
348
+ def import_db_cmd(
349
+ target: Optional[str] = typer.Argument(None, help="Path to .sql file OR database name"),
350
+ file_or_db: Optional[str] = typer.Argument(None, help="Path to .sql file if database name was specified first, or database name"),
351
+ database: Optional[str] = typer.Option(None, "--database", "-d", "--name", "-n", help="Target database name (optional if SQL dump contains CREATE DATABASE / USE)"),
352
+ host: str = typer.Option("localhost", "--host", "-h", help="Database host"),
353
+ port: int = typer.Option(3306, "--port", "-P", help="Database port"),
354
+ user: str = typer.Option("root", "--user", "-u", help="Admin username"),
355
+ password: Optional[str] = typer.Option(None, "--password", "-p", help="Admin password (default: root)"),
356
+ ):
357
+ """Import a SQL dump file into MariaDB/MySQL."""
358
+ sql_file = None
359
+ target_db = database
360
+
361
+ if target:
362
+ p_target = Path(target).expanduser()
363
+ if p_target.exists() or target.endswith(".sql"):
364
+ sql_file = str(p_target)
365
+ if file_or_db and not target_db:
366
+ target_db = file_or_db
367
+ else:
368
+ target_db = target
369
+ if file_or_db:
370
+ sql_file = str(Path(file_or_db).expanduser())
371
+ elif file_or_db:
372
+ sql_file = str(Path(file_or_db).expanduser())
373
+
374
+ if not sql_file:
375
+ sql_file = typer.prompt("Path to .sql file").strip()
376
+ if not sql_file:
377
+ logger.error("SQL file path is required.")
378
+ raise typer.Exit(code=1)
379
+
380
+ execute_import_db(
381
+ host=host,
382
+ port=port,
383
+ user=user,
384
+ password=password,
385
+ sql_file=sql_file,
386
+ database=target_db,
387
+ )
388
+
279
389
  @db_app.command("create-user")
280
390
  def create_user_cmd(
281
391
  username: str = typer.Argument(None, help="Username"),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ndev-stack
3
- Version: 0.3.16
3
+ Version: 0.3.17
4
4
  Summary: Cross-platform developer stack manager for PHP, FastCGI/PHP-FPM, MariaDB, Redis, PostgreSQL, MongoDB, Nginx, SSL, and Mailpit on Linux and Windows
5
5
  Author-email: Ankit Karan <ankit.karan99@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/ankitkaran99/ndev
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ndev-stack"
7
- version = "0.3.16"
7
+ version = "0.3.17"
8
8
  description = "Cross-platform developer stack manager for PHP, FastCGI/PHP-FPM, MariaDB, Redis, PostgreSQL, MongoDB, Nginx, SSL, and Mailpit on Linux and Windows"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -573,6 +573,20 @@ class TestDatabaseCommands(unittest.TestCase):
573
573
  self.assertIn("sudo", mock_run.call_args[0][0])
574
574
  self.assertIn("set-root-password", mock_run.call_args[0][0])
575
575
 
576
+ def test_import_db_cmd(self):
577
+ import tempfile
578
+ from ndev.linux.commands.db import import_db_cmd
579
+ with tempfile.NamedTemporaryFile(suffix=".sql") as tf:
580
+ tf.write(b"SELECT 1;\n")
581
+ tf.flush()
582
+ with patch("subprocess.run") as mock_run:
583
+ mock_run.return_value = subprocess.CompletedProcess(args=[], returncode=0)
584
+ import_db_cmd(target=tf.name, database="testdb", user="root", password="root")
585
+ # Ensure subprocess.run was invoked with mysql/mariadb and the target database
586
+ cmd_args = mock_run.call_args[0][0]
587
+ self.assertIn("testdb", cmd_args)
588
+ self.assertIn("--password=root", cmd_args)
589
+
576
590
 
577
591
  class TestTuiEnsureSudo(unittest.TestCase):
578
592
  def test_ensure_sudo_when_not_needed(self):
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes