dotx 3.3.1__tar.gz → 3.3.2__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 (40) hide show
  1. {dotx-3.3.1/src/dotx.egg-info → dotx-3.3.2}/PKG-INFO +1 -1
  2. {dotx-3.3.1 → dotx-3.3.2}/pyproject.toml +1 -1
  3. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/commands/database.py +17 -4
  4. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/commands/install_cmd.py +11 -4
  5. {dotx-3.3.1 → dotx-3.3.2/src/dotx.egg-info}/PKG-INFO +1 -1
  6. {dotx-3.3.1 → dotx-3.3.2}/tests/test_cli_database.py +42 -1
  7. {dotx-3.3.1 → dotx-3.3.2}/LICENSE +0 -0
  8. {dotx-3.3.1 → dotx-3.3.2}/MANIFEST.in +0 -0
  9. {dotx-3.3.1 → dotx-3.3.2}/README.md +0 -0
  10. {dotx-3.3.1 → dotx-3.3.2}/setup.cfg +0 -0
  11. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/__init__.py +0 -0
  12. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/always-create +0 -0
  13. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/cli.py +0 -0
  14. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/commands/__init__.py +0 -0
  15. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/commands/path_cmd.py +0 -0
  16. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/commands/progress.py +0 -0
  17. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/commands/uninstall_cmd.py +0 -0
  18. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/database.py +0 -0
  19. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/dotxignore +0 -0
  20. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/hierarchy.py +0 -0
  21. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/ignore.py +0 -0
  22. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/install.py +0 -0
  23. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/installed-schema.sql +0 -0
  24. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/options.py +0 -0
  25. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/plan.py +0 -0
  26. {dotx-3.3.1 → dotx-3.3.2}/src/dotx/uninstall.py +0 -0
  27. {dotx-3.3.1 → dotx-3.3.2}/src/dotx.egg-info/SOURCES.txt +0 -0
  28. {dotx-3.3.1 → dotx-3.3.2}/src/dotx.egg-info/dependency_links.txt +0 -0
  29. {dotx-3.3.1 → dotx-3.3.2}/src/dotx.egg-info/entry_points.txt +0 -0
  30. {dotx-3.3.1 → dotx-3.3.2}/src/dotx.egg-info/requires.txt +0 -0
  31. {dotx-3.3.1 → dotx-3.3.2}/src/dotx.egg-info/top_level.txt +0 -0
  32. {dotx-3.3.1 → dotx-3.3.2}/tests/test_always_create.py +0 -0
  33. {dotx-3.3.1 → dotx-3.3.2}/tests/test_cli.py +0 -0
  34. {dotx-3.3.1 → dotx-3.3.2}/tests/test_ignore.py +0 -0
  35. {dotx-3.3.1 → dotx-3.3.2}/tests/test_ignore_rules.py +0 -0
  36. {dotx-3.3.1 → dotx-3.3.2}/tests/test_install.py +0 -0
  37. {dotx-3.3.1 → dotx-3.3.2}/tests/test_options.py +0 -0
  38. {dotx-3.3.1 → dotx-3.3.2}/tests/test_path_which.py +0 -0
  39. {dotx-3.3.1 → dotx-3.3.2}/tests/test_plan.py +0 -0
  40. {dotx-3.3.1 → dotx-3.3.2}/tests/test_uninstall.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dotx
3
- Version: 3.3.1
3
+ Version: 3.3.2
4
4
  Summary: A command-line tool to install a link-farm to your dotfiles
5
5
  Author-email: Wolf <Wolf@zv.cx>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dotx"
3
- version = "3.3.1"
3
+ version = "3.3.2"
4
4
  description = "A command-line tool to install a link-farm to your dotfiles"
5
5
  authors = [
6
6
  { name = "Wolf", email = "Wolf@zv.cx" }
@@ -85,7 +85,7 @@ def register_commands(app: typer.Typer):
85
85
  packages = db.get_all_packages()
86
86
 
87
87
  if not packages:
88
- console.print("[yellow]No packages installed.[/yellow]")
88
+ console.print("[yellow]No packages in database. Run `dotx sync --package-root <dir>` to rebuild from existing symlinks.[/yellow]")
89
89
  return
90
90
 
91
91
  if as_commands:
@@ -100,17 +100,30 @@ def register_commands(app: typer.Typer):
100
100
  table.add_column("Package", style="cyan", no_wrap=True)
101
101
  table.add_column("Files", justify="right", style="magenta")
102
102
  table.add_column("Last Install", style="green")
103
+ table.add_column("Status", style="green")
103
104
 
105
+ missing_count = 0
104
106
  for pkg in packages:
105
107
  # Show full package path (package_root / package_name) as documented
106
- package_path = str(Path(pkg["package_root"]) / pkg["package_name"])
108
+ package_path = Path(pkg["package_root"]) / pkg["package_name"]
107
109
  file_count = str(pkg["file_count"])
108
110
  latest = _format_timestamp(pkg["latest_install"])
109
- table.add_row(package_path, file_count, latest)
111
+
112
+ # Check if source still exists
113
+ if package_path.exists():
114
+ status = "[green]✓[/green]"
115
+ else:
116
+ status = "[yellow]⚠ source missing[/yellow]"
117
+ missing_count += 1
118
+
119
+ table.add_row(str(package_path), file_count, latest, status)
110
120
 
111
121
  console.print()
112
122
  console.print(table)
113
- console.print(f"\n[bold]Total: {len(packages)} package(s)[/bold]\n")
123
+ console.print(f"\n[bold]Total: {len(packages)} package(s)[/bold]")
124
+ if missing_count > 0:
125
+ console.print(f"[yellow]⚠ {missing_count} package(s) have missing source directories. Run `dotx verify` for details.[/yellow]")
126
+ console.print()
114
127
 
115
128
  logger.info("list finished")
116
129
 
@@ -99,11 +99,18 @@ def register_command(app: typer.Typer):
99
99
  if total_dirs:
100
100
  summary_parts.append(f"{total_dirs} dir(s)")
101
101
 
102
- summary = " and ".join(summary_parts) if summary_parts else "nothing"
103
- if is_dry_run(ctx):
104
- console.print(f"\n[yellow][DRY RUN] Would install {summary} from {len(sources)} package(s)[/yellow]")
102
+ if summary_parts:
103
+ summary = " and ".join(summary_parts)
104
+ if is_dry_run(ctx):
105
+ console.print(f"\n[yellow][DRY RUN] Would install {summary} from {len(sources)} package(s)[/yellow]")
106
+ else:
107
+ console.print(f"\n[green]✓ Installed {summary} from {len(sources)} package(s)[/green]")
105
108
  else:
106
- console.print(f"\n[green]✓ Installed {summary} from {len(sources)} package(s)[/green]")
109
+ # Empty package(s) - nothing to install
110
+ if is_dry_run(ctx):
111
+ console.print(f"\n[yellow][DRY RUN] Would install nothing from {len(sources)} package(s) (nothing to record in database)[/yellow]")
112
+ else:
113
+ console.print(f"\n[green]✓ Installed nothing from {len(sources)} package(s) (nothing to record in database)[/green]")
107
114
  else:
108
115
  console.print("[red]✗ Refusing to install - conflicts detected[/red]")
109
116
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dotx
3
- Version: 3.3.1
3
+ Version: 3.3.2
4
4
  Summary: A command-line tool to install a link-farm to your dotfiles
5
5
  Author-email: Wolf <Wolf@zv.cx>
6
6
  License-Expression: MIT
@@ -301,7 +301,7 @@ def test_cli_list_no_packages(tmp_path, monkeypatch):
301
301
  result = runner.invoke(app, ["list"])
302
302
 
303
303
  assert result.exit_code == 0
304
- assert "No packages installed" in result.output
304
+ assert "No packages in database" in result.output
305
305
 
306
306
 
307
307
  def test_cli_list_with_packages(tmp_path, monkeypatch):
@@ -866,3 +866,44 @@ def test_list_shows_correct_package_names_after_install(tmp_path, monkeypatch):
866
866
  result = runner.invoke(app, ["list"])
867
867
  assert result.exit_code == 0, f"list failed: {result.output}"
868
868
  assert "2 package(s)" in result.output # Should show 2 packages
869
+
870
+
871
+ def test_cli_list_shows_missing_source_status(tmp_path, monkeypatch):
872
+ """Test 'dotx list' shows status indicator when source package is missing."""
873
+ import shutil
874
+
875
+ # Override XDG_DATA_HOME
876
+ data_dir = tmp_path / "config"
877
+ data_dir.mkdir()
878
+ monkeypatch.setenv("XDG_DATA_HOME", str(data_dir))
879
+
880
+ # Create and install packages
881
+ source1 = tmp_path / "source1"
882
+ source1.mkdir()
883
+ (source1 / "file1").write_text("content")
884
+
885
+ source2 = tmp_path / "source2"
886
+ source2.mkdir()
887
+ (source2 / "file2").write_text("content")
888
+
889
+ target = tmp_path / "target"
890
+ target.mkdir()
891
+
892
+ runner = CliRunner()
893
+
894
+ # Install both packages
895
+ result = runner.invoke(app, [f"--target={target}", "install", str(source1)])
896
+ assert result.exit_code == 0
897
+ result = runner.invoke(app, [f"--target={target}", "install", str(source2)])
898
+ assert result.exit_code == 0
899
+
900
+ # Delete one source package
901
+ shutil.rmtree(source1)
902
+ assert not source1.exists()
903
+
904
+ # List packages - should show warning for missing source
905
+ result = runner.invoke(app, ["list"])
906
+ assert result.exit_code == 0
907
+ # The warning message at the bottom should be visible
908
+ assert "1 package(s) have missing source directories" in result.output
909
+ assert "dotx verify" in result.output
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes