rolfedh-doc-utils 0.1.3__tar.gz → 0.1.4__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 (35) hide show
  1. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/PKG-INFO +1 -1
  2. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/doc_utils/topic_map_parser.py +10 -2
  3. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/doc_utils/unused_adoc.py +3 -0
  4. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/doc_utils/unused_images.py +3 -0
  5. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/pyproject.toml +1 -1
  6. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/rolfedh_doc_utils.egg-info/PKG-INFO +1 -1
  7. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/rolfedh_doc_utils.egg-info/SOURCES.txt +2 -0
  8. rolfedh_doc_utils-0.1.4/setup.py +45 -0
  9. rolfedh_doc_utils-0.1.4/tests/test_symlink_handling.py +91 -0
  10. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/LICENSE +0 -0
  11. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/README.md +0 -0
  12. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/archive_unused_files.py +0 -0
  13. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/archive_unused_images.py +0 -0
  14. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/check_scannability.py +0 -0
  15. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/doc_utils/__init__.py +0 -0
  16. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/doc_utils/file_utils.py +0 -0
  17. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/doc_utils/scannability.py +0 -0
  18. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/doc_utils/unused_attributes.py +0 -0
  19. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/find_unused_attributes.py +0 -0
  20. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/rolfedh_doc_utils.egg-info/dependency_links.txt +0 -0
  21. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/rolfedh_doc_utils.egg-info/entry_points.txt +0 -0
  22. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/rolfedh_doc_utils.egg-info/requires.txt +0 -0
  23. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/rolfedh_doc_utils.egg-info/top_level.txt +0 -0
  24. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/setup.cfg +0 -0
  25. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_archive_unused_files.py +0 -0
  26. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_archive_unused_images.py +0 -0
  27. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_check_scannability.py +0 -0
  28. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_cli_entry_points.py +0 -0
  29. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_file_utils.py +0 -0
  30. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_fixture_archive_unused_files.py +0 -0
  31. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_fixture_archive_unused_images.py +0 -0
  32. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_fixture_check_scannability.py +0 -0
  33. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_parse_exclude_list.py +0 -0
  34. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_topic_map_parser.py +0 -0
  35. {rolfedh_doc_utils-0.1.3 → rolfedh_doc_utils-0.1.4}/tests/test_unused_attributes.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rolfedh-doc-utils
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: CLI tools for AsciiDoc documentation projects
5
5
  Author: Rolfe Dlugy-Hegwer
6
6
  License: MIT License
@@ -22,8 +22,16 @@ def detect_repo_type(base_path='.'):
22
22
  if yml_files:
23
23
  return 'topic_map'
24
24
 
25
- # Check for master.adoc files
26
- master_files = glob.glob(os.path.join(base_path, '**/master.adoc'), recursive=True)
25
+ # Check for master.adoc files using os.walk to avoid symlink issues
26
+ master_files = []
27
+ for root, dirs, files in os.walk(base_path):
28
+ # Skip symbolic link directories to prevent infinite recursion
29
+ dirs[:] = [d for d in dirs if not os.path.islink(os.path.join(root, d))]
30
+
31
+ # Check for master.adoc in this directory
32
+ if 'master.adoc' in files:
33
+ master_files.append(os.path.join(root, 'master.adoc'))
34
+
27
35
  if master_files:
28
36
  return 'master_adoc'
29
37
 
@@ -6,6 +6,9 @@ from .file_utils import collect_files, write_manifest_and_archive
6
6
  from .topic_map_parser import detect_repo_type, get_all_topic_map_references
7
7
 
8
8
  def find_unused_adoc(scan_dirs, archive_dir, archive=False, exclude_dirs=None, exclude_files=None):
9
+ # Print safety warning
10
+ print("\n⚠️ SAFETY: Work in a git branch! Run without --archive first to preview.\n")
11
+
9
12
  # Detect repository type
10
13
  repo_type = detect_repo_type()
11
14
  print(f"Detected repository type: {repo_type}")
@@ -7,6 +7,9 @@ from .file_utils import collect_files, write_manifest_and_archive
7
7
  IMAGE_EXTENSIONS = {'.png', '.jpg', '.jpeg', '.gif', '.svg'}
8
8
 
9
9
  def find_unused_images(scan_dirs, archive_dir, archive=False, exclude_dirs=None, exclude_files=None):
10
+ # Print safety warning
11
+ print("\n⚠️ SAFETY: Work in a git branch! Run without --archive first to preview.\n")
12
+
10
13
  image_files = collect_files(scan_dirs, IMAGE_EXTENSIONS, exclude_dirs, exclude_files)
11
14
  adoc_files = collect_files(['.'], {'.adoc'}, exclude_dirs, exclude_files)
12
15
  referenced_images = set()
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rolfedh-doc-utils"
7
- version = "0.1.3"
7
+ version = "0.1.4"
8
8
  description = "CLI tools for AsciiDoc documentation projects"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rolfedh-doc-utils
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: CLI tools for AsciiDoc documentation projects
5
5
  Author: Rolfe Dlugy-Hegwer
6
6
  License: MIT License
@@ -5,6 +5,7 @@ archive_unused_images.py
5
5
  check_scannability.py
6
6
  find_unused_attributes.py
7
7
  pyproject.toml
8
+ setup.py
8
9
  doc_utils/__init__.py
9
10
  doc_utils/file_utils.py
10
11
  doc_utils/scannability.py
@@ -27,5 +28,6 @@ tests/test_fixture_archive_unused_files.py
27
28
  tests/test_fixture_archive_unused_images.py
28
29
  tests/test_fixture_check_scannability.py
29
30
  tests/test_parse_exclude_list.py
31
+ tests/test_symlink_handling.py
30
32
  tests/test_topic_map_parser.py
31
33
  tests/test_unused_attributes.py
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Setup script for doc-utils package.
4
+ This file is only needed if we want to customize the installation process.
5
+ """
6
+
7
+ from setuptools import setup
8
+ from setuptools.command.install import install
9
+ from setuptools.command.develop import develop
10
+ from setuptools.command.egg_info import egg_info
11
+
12
+ def custom_post_install():
13
+ """Display safety message after installation."""
14
+ print("\n" + "="*60)
15
+ print("✅ doc-utils installed successfully!")
16
+ print("\n⚠️ IMPORTANT: Safety First")
17
+ print(" • Work in a git branch (never main/master)")
18
+ print(" • Run without --archive first to preview")
19
+ print(" • Review changes with git diff")
20
+ print("="*60 + "\n")
21
+
22
+ class CustomInstallCommand(install):
23
+ """Customized setuptools install command."""
24
+ def run(self):
25
+ install.run(self)
26
+ custom_post_install()
27
+
28
+ class CustomDevelopCommand(develop):
29
+ """Customized setuptools develop command."""
30
+ def run(self):
31
+ develop.run(self)
32
+ custom_post_install()
33
+
34
+ class CustomEggInfoCommand(egg_info):
35
+ """Customized setuptools egg_info command."""
36
+ def run(self):
37
+ egg_info.run(self)
38
+
39
+ setup(
40
+ cmdclass={
41
+ 'install': CustomInstallCommand,
42
+ 'develop': CustomDevelopCommand,
43
+ 'egg_info': CustomEggInfoCommand,
44
+ },
45
+ )
@@ -0,0 +1,91 @@
1
+ """Test that topic_map_parser handles symbolic links correctly without freezing."""
2
+
3
+ import os
4
+ import tempfile
5
+ import pytest
6
+ from doc_utils.topic_map_parser import detect_repo_type
7
+
8
+
9
+ def test_detect_repo_type_with_circular_symlinks(tmp_path):
10
+ """Test that detect_repo_type doesn't freeze with circular symbolic links."""
11
+
12
+ # Create a directory structure with circular symlinks
13
+ modules_dir = tmp_path / "modules"
14
+ modules_dir.mkdir()
15
+
16
+ # Create a master.adoc file in modules
17
+ (modules_dir / "master.adoc").write_text("= Test Doc\n")
18
+
19
+ # Create a circular symlink: modules/modules -> ../modules
20
+ circular_link = modules_dir / "modules"
21
+ try:
22
+ os.symlink("../../modules", str(circular_link))
23
+ except OSError:
24
+ pytest.skip("Cannot create symbolic links on this system")
25
+
26
+ # This should not freeze - it should skip the symlink
27
+ repo_type = detect_repo_type(str(tmp_path))
28
+ assert repo_type == "master_adoc"
29
+
30
+
31
+ def test_detect_repo_type_with_nested_circular_symlinks(tmp_path):
32
+ """Test detection with nested directories containing circular symlinks."""
33
+
34
+ # Create nested structure
35
+ (tmp_path / "assemblies").mkdir()
36
+ modules_dir = tmp_path / "modules"
37
+ modules_dir.mkdir()
38
+
39
+ # Create master.adoc
40
+ (tmp_path / "master.adoc").write_text("= Main Doc\n")
41
+
42
+ # Create archive directory with circular symlinks (similar to real case)
43
+ archive_dir = tmp_path / ".archive" / "archived-content" / "modules"
44
+ archive_dir.mkdir(parents=True)
45
+
46
+ try:
47
+ # Create circular symlink in archive
48
+ os.symlink("../../modules", str(archive_dir / "modules"))
49
+ except OSError:
50
+ pytest.skip("Cannot create symbolic links on this system")
51
+
52
+ # Should detect master_adoc without freezing
53
+ repo_type = detect_repo_type(str(tmp_path))
54
+ assert repo_type == "master_adoc"
55
+
56
+
57
+ def test_detect_repo_type_skips_symlink_directories(tmp_path):
58
+ """Test that symlinked directories are skipped during traversal."""
59
+
60
+ # Create main directories
61
+ real_dir = tmp_path / "real_modules"
62
+ real_dir.mkdir()
63
+ (real_dir / "master.adoc").write_text("= Real Master\n")
64
+
65
+ # Create a symlink to real_dir
66
+ linked_dir = tmp_path / "linked_modules"
67
+ try:
68
+ os.symlink(str(real_dir), str(linked_dir))
69
+ except OSError:
70
+ pytest.skip("Cannot create symbolic links on this system")
71
+
72
+ # The function should find the master.adoc in real_dir but not traverse linked_dir
73
+ repo_type = detect_repo_type(str(tmp_path))
74
+ assert repo_type == "master_adoc"
75
+
76
+ # Test that symlinked directories are not traversed
77
+ only_symlink_path = tmp_path / "only_symlink_test"
78
+ only_symlink_path.mkdir()
79
+
80
+ # Create a directory outside that contains master.adoc
81
+ external_dir = tmp_path / "external"
82
+ external_dir.mkdir()
83
+ (external_dir / "master.adoc").write_text("= External Master\n")
84
+
85
+ # Create only a symlink to it inside our test directory
86
+ symlinked_dir = only_symlink_path / "linked_dir"
87
+ os.symlink(str(external_dir), str(symlinked_dir))
88
+
89
+ # Should not find master.adoc since it's only accessible via symlink
90
+ repo_type = detect_repo_type(str(only_symlink_path))
91
+ assert repo_type == "unknown"