rolfedh-doc-utils 0.1.19__tar.gz → 0.1.21__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 (52) hide show
  1. {rolfedh_doc_utils-0.1.19/rolfedh_doc_utils.egg-info → rolfedh_doc_utils-0.1.21}/PKG-INFO +21 -6
  2. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/README.md +20 -5
  3. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/archive_unused_files.py +2 -0
  4. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/archive_unused_images.py +2 -0
  5. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/check_scannability.py +2 -0
  6. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/format_asciidoc_spacing.py +7 -1
  7. rolfedh_doc_utils-0.1.21/doc_utils/version.py +8 -0
  8. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/version_check.py +29 -1
  9. rolfedh_doc_utils-0.1.21/doc_utils_cli.py +148 -0
  10. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/extract_link_attributes.py +2 -0
  11. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/find_unused_attributes.py +2 -0
  12. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/format_asciidoc_spacing.py +2 -0
  13. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/pyproject.toml +3 -2
  14. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/replace_link_attributes.py +2 -0
  15. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21/rolfedh_doc_utils.egg-info}/PKG-INFO +21 -6
  16. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/rolfedh_doc_utils.egg-info/SOURCES.txt +4 -1
  17. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/rolfedh_doc_utils.egg-info/entry_points.txt +1 -0
  18. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/rolfedh_doc_utils.egg-info/top_level.txt +1 -0
  19. rolfedh_doc_utils-0.1.21/tests/test_version_check.py +97 -0
  20. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/validate_links.py +2 -0
  21. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/LICENSE +0 -0
  22. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/__init__.py +0 -0
  23. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/extract_link_attributes.py +0 -0
  24. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/file_utils.py +0 -0
  25. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/replace_link_attributes.py +0 -0
  26. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/scannability.py +0 -0
  27. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/spinner.py +0 -0
  28. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/topic_map_parser.py +0 -0
  29. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/unused_adoc.py +0 -0
  30. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/unused_attributes.py +0 -0
  31. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/unused_images.py +0 -0
  32. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/doc_utils/validate_links.py +0 -0
  33. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/rolfedh_doc_utils.egg-info/dependency_links.txt +0 -0
  34. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/rolfedh_doc_utils.egg-info/requires.txt +0 -0
  35. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/setup.cfg +0 -0
  36. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/setup.py +0 -0
  37. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_archive_unused_files.py +0 -0
  38. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_archive_unused_images.py +0 -0
  39. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_auto_discovery.py +0 -0
  40. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_check_scannability.py +0 -0
  41. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_cli_entry_points.py +0 -0
  42. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_extract_link_attributes.py +0 -0
  43. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_file_utils.py +0 -0
  44. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_fixture_archive_unused_files.py +0 -0
  45. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_fixture_archive_unused_images.py +0 -0
  46. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_fixture_check_scannability.py +0 -0
  47. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_parse_exclude_list.py +0 -0
  48. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_replace_link_attributes.py +0 -0
  49. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_symlink_handling.py +0 -0
  50. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_topic_map_parser.py +0 -0
  51. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_unused_attributes.py +0 -0
  52. {rolfedh_doc_utils-0.1.19 → rolfedh_doc_utils-0.1.21}/tests/test_validate_links.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rolfedh-doc-utils
3
- Version: 0.1.19
3
+ Version: 0.1.21
4
4
  Summary: CLI tools for AsciiDoc documentation projects
5
5
  Author: Rolfe Dlugy-Hegwer
6
6
  License: MIT License
@@ -57,6 +57,9 @@ These tools can modify or delete files. **Always:**
57
57
  # Install
58
58
  pipx install rolfedh-doc-utils
59
59
 
60
+ # Verify installation
61
+ doc-utils --version
62
+
60
63
  # Upgrade to latest version
61
64
  pipx upgrade rolfedh-doc-utils
62
65
  ```
@@ -75,14 +78,26 @@ pip install -e .
75
78
 
76
79
  ## 🛠️ Available Tools
77
80
 
81
+ ### Quick Reference
82
+
83
+ Run `doc-utils` to see all available tools and their descriptions:
84
+
85
+ ```bash
86
+ doc-utils --help # Show comprehensive help
87
+ doc-utils --list # List all tools
88
+ doc-utils --version # Show version
89
+ ```
90
+
91
+ ### Individual Tools
92
+
78
93
  **Note:** Commands use hyphens (`-`), while Python files use underscores (`_`). After installing with pipx, use the hyphenated commands directly.
79
94
 
80
95
  | Tool | Description | Usage |
81
96
  |------|-------------|-------|
82
- | **`validate-links`** [EXPERIMENTAL] | Validates all links in documentation, with URL transposition for preview environments | `validate-links --transpose "https://prod--https://preview"` |
97
+ | **`validate-links`** | Validates all links in documentation, with URL transposition for preview environments | `validate-links --transpose "https://prod--https://preview"` |
83
98
  | **`extract-link-attributes`** | Extracts link/xref macros with attributes into reusable definitions | `extract-link-attributes --dry-run` |
84
99
  | **`replace-link-attributes`** | Resolves Vale LinkAttribute issues by replacing attributes in link URLs | `replace-link-attributes --dry-run` |
85
- | **`format-asciidoc-spacing`** [EXPERIMENTAL] | Standardizes spacing after headings and around includes | `format-asciidoc-spacing --dry-run modules/` |
100
+ | **`format-asciidoc-spacing`** | Standardizes spacing after headings and around includes | `format-asciidoc-spacing --dry-run modules/` |
86
101
  | **`check-scannability`** | Analyzes readability (sentence/paragraph length) | `check-scannability --max-words 25` |
87
102
  | **`archive-unused-files`** | Finds and archives unreferenced .adoc files | `archive-unused-files` (preview)<br>`archive-unused-files --archive` (execute) |
88
103
  | **`archive-unused-images`** | Finds and archives unreferenced images | `archive-unused-images` (preview)<br>`archive-unused-images --archive` (execute) |
@@ -197,11 +212,11 @@ Before submitting PRs:
197
212
 
198
213
  ### 🔔 Update Notifications
199
214
 
200
- All tools now check for updates automatically and notify you when a new version is available:
215
+ All tools automatically check for updates and notify you when a new version is available. The notification will recommend the appropriate upgrade command based on how you installed the package:
201
216
 
202
217
  ```
203
- 📦 Update available: 0.1.15 → 0.1.16
204
- Run: pip install --upgrade rolfedh-doc-utils
218
+ 📦 Update available: 0.1.19 → 0.1.20
219
+ Run: pipx upgrade rolfedh-doc-utils
205
220
  ```
206
221
 
207
222
  To disable update checks, set the environment variable:
@@ -24,6 +24,9 @@ These tools can modify or delete files. **Always:**
24
24
  # Install
25
25
  pipx install rolfedh-doc-utils
26
26
 
27
+ # Verify installation
28
+ doc-utils --version
29
+
27
30
  # Upgrade to latest version
28
31
  pipx upgrade rolfedh-doc-utils
29
32
  ```
@@ -42,14 +45,26 @@ pip install -e .
42
45
 
43
46
  ## 🛠️ Available Tools
44
47
 
48
+ ### Quick Reference
49
+
50
+ Run `doc-utils` to see all available tools and their descriptions:
51
+
52
+ ```bash
53
+ doc-utils --help # Show comprehensive help
54
+ doc-utils --list # List all tools
55
+ doc-utils --version # Show version
56
+ ```
57
+
58
+ ### Individual Tools
59
+
45
60
  **Note:** Commands use hyphens (`-`), while Python files use underscores (`_`). After installing with pipx, use the hyphenated commands directly.
46
61
 
47
62
  | Tool | Description | Usage |
48
63
  |------|-------------|-------|
49
- | **`validate-links`** [EXPERIMENTAL] | Validates all links in documentation, with URL transposition for preview environments | `validate-links --transpose "https://prod--https://preview"` |
64
+ | **`validate-links`** | Validates all links in documentation, with URL transposition for preview environments | `validate-links --transpose "https://prod--https://preview"` |
50
65
  | **`extract-link-attributes`** | Extracts link/xref macros with attributes into reusable definitions | `extract-link-attributes --dry-run` |
51
66
  | **`replace-link-attributes`** | Resolves Vale LinkAttribute issues by replacing attributes in link URLs | `replace-link-attributes --dry-run` |
52
- | **`format-asciidoc-spacing`** [EXPERIMENTAL] | Standardizes spacing after headings and around includes | `format-asciidoc-spacing --dry-run modules/` |
67
+ | **`format-asciidoc-spacing`** | Standardizes spacing after headings and around includes | `format-asciidoc-spacing --dry-run modules/` |
53
68
  | **`check-scannability`** | Analyzes readability (sentence/paragraph length) | `check-scannability --max-words 25` |
54
69
  | **`archive-unused-files`** | Finds and archives unreferenced .adoc files | `archive-unused-files` (preview)<br>`archive-unused-files --archive` (execute) |
55
70
  | **`archive-unused-images`** | Finds and archives unreferenced images | `archive-unused-images` (preview)<br>`archive-unused-images --archive` (execute) |
@@ -164,11 +179,11 @@ Before submitting PRs:
164
179
 
165
180
  ### 🔔 Update Notifications
166
181
 
167
- All tools now check for updates automatically and notify you when a new version is available:
182
+ All tools automatically check for updates and notify you when a new version is available. The notification will recommend the appropriate upgrade command based on how you installed the package:
168
183
 
169
184
  ```
170
- 📦 Update available: 0.1.15 → 0.1.16
171
- Run: pip install --upgrade rolfedh-doc-utils
185
+ 📦 Update available: 0.1.19 → 0.1.20
186
+ Run: pipx upgrade rolfedh-doc-utils
172
187
  ```
173
188
 
174
189
  To disable update checks, set the environment variable:
@@ -11,6 +11,7 @@ import argparse
11
11
  from doc_utils.unused_adoc import find_unused_adoc
12
12
  from doc_utils.version_check import check_version_on_startup
13
13
  from doc_utils.file_utils import parse_exclude_list_file
14
+ from doc_utils.version import __version__
14
15
 
15
16
  from doc_utils.spinner import Spinner
16
17
  def main():
@@ -25,6 +26,7 @@ def main():
25
26
  parser.add_argument('--exclude-dir', action='append', default=[], help='Directory to exclude (can be used multiple times).')
26
27
  parser.add_argument('--exclude-file', action='append', default=[], help='File to exclude (can be used multiple times).')
27
28
  parser.add_argument('--exclude-list', type=str, help='Path to a file containing directories or files to exclude, one per line.')
29
+ parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
28
30
  args = parser.parse_args()
29
31
 
30
32
  # Use provided scan directories or None for auto-discovery
@@ -10,6 +10,7 @@ import argparse
10
10
  from doc_utils.unused_images import find_unused_images
11
11
  from doc_utils.version_check import check_version_on_startup
12
12
  from doc_utils.file_utils import parse_exclude_list_file
13
+ from doc_utils.version import __version__
13
14
 
14
15
  from doc_utils.spinner import Spinner
15
16
  def main():
@@ -20,6 +21,7 @@ def main():
20
21
  parser.add_argument('--exclude-dir', action='append', default=[], help='Directory to exclude (can be used multiple times).')
21
22
  parser.add_argument('--exclude-file', action='append', default=[], help='File to exclude (can be used multiple times).')
22
23
  parser.add_argument('--exclude-list', type=str, help='Path to a file containing directories or files to exclude, one per line.')
24
+ parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
23
25
  args = parser.parse_args()
24
26
 
25
27
  scan_dirs = ['.']
@@ -19,6 +19,7 @@ from datetime import datetime
19
19
  from doc_utils.scannability import check_scannability
20
20
  from doc_utils.version_check import check_version_on_startup
21
21
  from doc_utils.file_utils import collect_files, parse_exclude_list_file
22
+ from doc_utils.version import __version__
22
23
 
23
24
  from doc_utils.spinner import Spinner
24
25
  BASE_SENTENCE_WORD_LIMIT = 22
@@ -43,6 +44,7 @@ def main():
43
44
  parser.add_argument('--exclude-dir', action='append', default=[], help='Directory to exclude (can be used multiple times).')
44
45
  parser.add_argument('--exclude-file', action='append', default=[], help='File to exclude (can be used multiple times).')
45
46
  parser.add_argument('--exclude-list', type=str, help='Path to a file containing directories or files to exclude, one per line.')
47
+ parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
46
48
  # Do not add -h/--help to argparse, handled manually above
47
49
  args = parser.parse_args()
48
50
 
@@ -175,8 +175,14 @@ def process_file(file_path: Path, dry_run: bool = False, verbose: bool = False)
175
175
 
176
176
  # Check if current line is an include directive
177
177
  elif re.match(r'^include::', current_line):
178
- # Skip special handling if we're inside a conditional block
178
+ # Handle includes inside conditional blocks
179
179
  if in_conditional:
180
+ # Add blank line between consecutive includes within conditional blocks
181
+ if prev_line and re.match(r'^include::', prev_line):
182
+ new_lines.append("")
183
+ changes_made = True
184
+ if verbose:
185
+ messages.append(" Added blank line between includes in conditional block")
180
186
  new_lines.append(current_line)
181
187
  else:
182
188
  # Check if this is an attribute include (contains "attribute" in the path)
@@ -0,0 +1,8 @@
1
+ """Version information for doc-utils."""
2
+
3
+ # This should match the version in pyproject.toml
4
+ __version__ = "0.1.21"
5
+
6
+ def get_version():
7
+ """Return the current version string."""
8
+ return __version__
@@ -136,6 +136,26 @@ def check_for_update(force_check: bool = False) -> Optional[str]:
136
136
  return None
137
137
 
138
138
 
139
+ def detect_install_method() -> str:
140
+ """
141
+ Detect how the package was installed.
142
+
143
+ Returns:
144
+ 'pipx', 'pip', or 'unknown'
145
+ """
146
+ # Check if running from pipx venv
147
+ if 'pipx' in sys.prefix:
148
+ return 'pipx'
149
+
150
+ # Check PIPX_HOME environment variable
151
+ pipx_home = os.environ.get('PIPX_HOME') or os.path.join(Path.home(), '.local', 'pipx')
152
+ if pipx_home and str(Path(sys.prefix)).startswith(str(Path(pipx_home))):
153
+ return 'pipx'
154
+
155
+ # Default to pip
156
+ return 'pip'
157
+
158
+
139
159
  def show_update_notification(latest_version: str, current_version: str = None):
140
160
  """Show update notification to user."""
141
161
  if not current_version:
@@ -144,9 +164,17 @@ def show_update_notification(latest_version: str, current_version: str = None):
144
164
  except Exception:
145
165
  current_version = 'unknown'
146
166
 
167
+ # Detect installation method and recommend appropriate upgrade command
168
+ install_method = detect_install_method()
169
+
147
170
  # Use stderr to avoid interfering with tool output
148
171
  print(f"\n📦 Update available: {current_version} → {latest_version}", file=sys.stderr)
149
- print(f" Run: pip install --upgrade rolfedh-doc-utils", file=sys.stderr)
172
+
173
+ if install_method == 'pipx':
174
+ print(f" Run: pipx upgrade rolfedh-doc-utils", file=sys.stderr)
175
+ else:
176
+ print(f" Run: pip install --upgrade rolfedh-doc-utils", file=sys.stderr)
177
+
150
178
  print("", file=sys.stderr)
151
179
 
152
180
 
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ doc-utils - CLI tools for AsciiDoc documentation projects
4
+
5
+ Main entry point that provides a hub for all doc-utils tools.
6
+ """
7
+
8
+ import argparse
9
+ import sys
10
+ from doc_utils.version import __version__
11
+ from doc_utils.version_check import check_version_on_startup
12
+
13
+
14
+ # Tool definitions with descriptions
15
+ TOOLS = [
16
+ {
17
+ 'name': 'validate-links',
18
+ 'description': 'Validates all links in documentation with URL transposition',
19
+ 'example': 'validate-links --transpose "https://prod--https://preview"'
20
+ },
21
+ {
22
+ 'name': 'extract-link-attributes',
23
+ 'description': 'Extracts link/xref macros with attributes into reusable definitions',
24
+ 'example': 'extract-link-attributes --dry-run'
25
+ },
26
+ {
27
+ 'name': 'replace-link-attributes',
28
+ 'description': 'Resolves Vale LinkAttribute issues by replacing attributes in link URLs',
29
+ 'example': 'replace-link-attributes --dry-run'
30
+ },
31
+ {
32
+ 'name': 'format-asciidoc-spacing',
33
+ 'description': 'Standardizes spacing after headings and around includes',
34
+ 'example': 'format-asciidoc-spacing --dry-run modules/'
35
+ },
36
+ {
37
+ 'name': 'check-scannability',
38
+ 'description': 'Analyzes document readability by checking sentence/paragraph length',
39
+ 'example': 'check-scannability --max-sentence-length 5'
40
+ },
41
+ {
42
+ 'name': 'archive-unused-files',
43
+ 'description': 'Finds and optionally archives unreferenced AsciiDoc files',
44
+ 'example': 'archive-unused-files # preview\narchive-unused-files --archive # execute'
45
+ },
46
+ {
47
+ 'name': 'archive-unused-images',
48
+ 'description': 'Finds and optionally archives unreferenced image files',
49
+ 'example': 'archive-unused-images # preview\narchive-unused-images --archive # execute'
50
+ },
51
+ {
52
+ 'name': 'find-unused-attributes',
53
+ 'description': 'Identifies unused attribute definitions in AsciiDoc files',
54
+ 'example': 'find-unused-attributes # auto-discovers attributes files'
55
+ },
56
+ ]
57
+
58
+
59
+ def print_tools_list():
60
+ """Print a formatted list of all available tools."""
61
+ print("\n🛠️ Available Tools:\n")
62
+
63
+ for tool in TOOLS:
64
+ # Print tool name and description
65
+ experimental = " [EXPERIMENTAL]" if "[EXPERIMENTAL]" in tool['description'] else ""
66
+ desc = tool['description'].replace(" [EXPERIMENTAL]", "")
67
+ print(f" {tool['name']}{experimental}")
68
+ print(f" {desc}")
69
+ print()
70
+
71
+
72
+ def print_help():
73
+ """Print comprehensive help information."""
74
+ print(f"doc-utils v{__version__}")
75
+ print("\nCLI tools for maintaining clean, consistent AsciiDoc documentation repositories.")
76
+
77
+ print_tools_list()
78
+
79
+ print("📚 Usage:")
80
+ print(" doc-utils --version Show version information")
81
+ print(" doc-utils --list List all available tools")
82
+ print(" doc-utils --help Show this help message")
83
+ print(" <tool-name> --help Show help for a specific tool")
84
+ print()
85
+ print("📖 Documentation:")
86
+ print(" https://rolfedh.github.io/doc-utils/")
87
+ print()
88
+ print("💡 Examples:")
89
+ print(" find-unused-attributes")
90
+ print(" check-scannability --max-sentence-length 5")
91
+ print(" format-asciidoc-spacing --dry-run modules/")
92
+ print()
93
+ print("⚠️ Safety First:")
94
+ print(" Always work in a git branch and review changes with 'git diff'")
95
+ print()
96
+
97
+
98
+ def main():
99
+ """Main entry point for doc-utils command."""
100
+ # Check for updates (non-blocking)
101
+ check_version_on_startup()
102
+
103
+ parser = argparse.ArgumentParser(
104
+ description='doc-utils - CLI tools for AsciiDoc documentation projects',
105
+ add_help=False # We'll handle help ourselves
106
+ )
107
+
108
+ parser.add_argument(
109
+ '--version',
110
+ action='version',
111
+ version=f'doc-utils {__version__}'
112
+ )
113
+
114
+ parser.add_argument(
115
+ '--list',
116
+ action='store_true',
117
+ help='List all available tools'
118
+ )
119
+
120
+ parser.add_argument(
121
+ '--help', '-h',
122
+ action='store_true',
123
+ help='Show this help message'
124
+ )
125
+
126
+ # Parse known args to allow for future expansion
127
+ args, remaining = parser.parse_known_args()
128
+
129
+ # Handle flags
130
+ if args.list:
131
+ print_tools_list()
132
+ return 0
133
+
134
+ if args.help or len(sys.argv) == 1:
135
+ print_help()
136
+ return 0
137
+
138
+ # If we get here with remaining args, show help
139
+ if remaining:
140
+ print(f"doc-utils: unknown command or option: {' '.join(remaining)}")
141
+ print("\nRun 'doc-utils --help' for usage information.")
142
+ return 1
143
+
144
+ return 0
145
+
146
+
147
+ if __name__ == '__main__':
148
+ sys.exit(main())
@@ -11,6 +11,7 @@ import argparse
11
11
  import sys
12
12
  from doc_utils.extract_link_attributes import extract_link_attributes
13
13
  from doc_utils.version_check import check_version_on_startup
14
+ from doc_utils.version import __version__
14
15
 
15
16
 
16
17
  def main():
@@ -86,6 +87,7 @@ Examples:
86
87
  default='both',
87
88
  help='Type of macros to process: link, xref, or both (default: both)'
88
89
  )
90
+ parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
89
91
 
90
92
  args = parser.parse_args()
91
93
 
@@ -15,6 +15,7 @@ from datetime import datetime
15
15
  from doc_utils.unused_attributes import find_unused_attributes, find_attributes_files, select_attributes_file, comment_out_unused_attributes
16
16
  from doc_utils.spinner import Spinner
17
17
  from doc_utils.version_check import check_version_on_startup
18
+ from doc_utils.version import __version__
18
19
 
19
20
  def main():
20
21
  # Check for updates (non-blocking, won't interfere with tool operation)
@@ -27,6 +28,7 @@ def main():
27
28
  )
28
29
  parser.add_argument('-o', '--output', action='store_true', help='Write results to a timestamped txt file in your home directory.')
29
30
  parser.add_argument('-c', '--comment-out', action='store_true', help='Comment out unused attributes in the attributes file with "// Unused".')
31
+ parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
30
32
  args = parser.parse_args()
31
33
 
32
34
  # Determine which attributes file to use
@@ -11,6 +11,7 @@ from pathlib import Path
11
11
 
12
12
  from doc_utils.format_asciidoc_spacing import process_file, find_adoc_files
13
13
  from doc_utils.version_check import check_version_on_startup
14
+ from doc_utils.version import __version__
14
15
 
15
16
 
16
17
  from doc_utils.spinner import Spinner
@@ -63,6 +64,7 @@ Examples:
63
64
  action='store_true',
64
65
  help='Show detailed output'
65
66
  )
67
+ parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
66
68
 
67
69
  args = parser.parse_args()
68
70
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rolfedh-doc-utils"
7
- version = "0.1.19"
7
+ version = "0.1.21"
8
8
  description = "CLI tools for AsciiDoc documentation projects"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -15,6 +15,7 @@ authors = [
15
15
  dependencies = ["PyYAML>=6.0"]
16
16
 
17
17
  [project.scripts]
18
+ doc-utils = "doc_utils_cli:main"
18
19
  check-scannability = "check_scannability:main"
19
20
  archive-unused-files = "archive_unused_files:main"
20
21
  archive-unused-images = "archive_unused_images:main"
@@ -29,4 +30,4 @@ where = ["."]
29
30
  include = ["doc_utils*"]
30
31
 
31
32
  [tool.setuptools]
32
- py-modules = ["find_unused_attributes", "check_scannability", "archive_unused_files", "archive_unused_images", "format_asciidoc_spacing", "replace_link_attributes", "extract_link_attributes", "validate_links"]
33
+ py-modules = ["doc_utils_cli", "find_unused_attributes", "check_scannability", "archive_unused_files", "archive_unused_images", "format_asciidoc_spacing", "replace_link_attributes", "extract_link_attributes", "validate_links"]
@@ -20,6 +20,7 @@ from doc_utils.replace_link_attributes import (
20
20
  find_adoc_files
21
21
  )
22
22
  from doc_utils.version_check import check_version_on_startup
23
+ from doc_utils.version import __version__
23
24
  from doc_utils.spinner import Spinner
24
25
 
25
26
 
@@ -111,6 +112,7 @@ def main():
111
112
  default='both',
112
113
  help='Type of macros to process: link, xref, or both (default: both)'
113
114
  )
115
+ parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
114
116
 
115
117
  args = parser.parse_args()
116
118
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rolfedh-doc-utils
3
- Version: 0.1.19
3
+ Version: 0.1.21
4
4
  Summary: CLI tools for AsciiDoc documentation projects
5
5
  Author: Rolfe Dlugy-Hegwer
6
6
  License: MIT License
@@ -57,6 +57,9 @@ These tools can modify or delete files. **Always:**
57
57
  # Install
58
58
  pipx install rolfedh-doc-utils
59
59
 
60
+ # Verify installation
61
+ doc-utils --version
62
+
60
63
  # Upgrade to latest version
61
64
  pipx upgrade rolfedh-doc-utils
62
65
  ```
@@ -75,14 +78,26 @@ pip install -e .
75
78
 
76
79
  ## 🛠️ Available Tools
77
80
 
81
+ ### Quick Reference
82
+
83
+ Run `doc-utils` to see all available tools and their descriptions:
84
+
85
+ ```bash
86
+ doc-utils --help # Show comprehensive help
87
+ doc-utils --list # List all tools
88
+ doc-utils --version # Show version
89
+ ```
90
+
91
+ ### Individual Tools
92
+
78
93
  **Note:** Commands use hyphens (`-`), while Python files use underscores (`_`). After installing with pipx, use the hyphenated commands directly.
79
94
 
80
95
  | Tool | Description | Usage |
81
96
  |------|-------------|-------|
82
- | **`validate-links`** [EXPERIMENTAL] | Validates all links in documentation, with URL transposition for preview environments | `validate-links --transpose "https://prod--https://preview"` |
97
+ | **`validate-links`** | Validates all links in documentation, with URL transposition for preview environments | `validate-links --transpose "https://prod--https://preview"` |
83
98
  | **`extract-link-attributes`** | Extracts link/xref macros with attributes into reusable definitions | `extract-link-attributes --dry-run` |
84
99
  | **`replace-link-attributes`** | Resolves Vale LinkAttribute issues by replacing attributes in link URLs | `replace-link-attributes --dry-run` |
85
- | **`format-asciidoc-spacing`** [EXPERIMENTAL] | Standardizes spacing after headings and around includes | `format-asciidoc-spacing --dry-run modules/` |
100
+ | **`format-asciidoc-spacing`** | Standardizes spacing after headings and around includes | `format-asciidoc-spacing --dry-run modules/` |
86
101
  | **`check-scannability`** | Analyzes readability (sentence/paragraph length) | `check-scannability --max-words 25` |
87
102
  | **`archive-unused-files`** | Finds and archives unreferenced .adoc files | `archive-unused-files` (preview)<br>`archive-unused-files --archive` (execute) |
88
103
  | **`archive-unused-images`** | Finds and archives unreferenced images | `archive-unused-images` (preview)<br>`archive-unused-images --archive` (execute) |
@@ -197,11 +212,11 @@ Before submitting PRs:
197
212
 
198
213
  ### 🔔 Update Notifications
199
214
 
200
- All tools now check for updates automatically and notify you when a new version is available:
215
+ All tools automatically check for updates and notify you when a new version is available. The notification will recommend the appropriate upgrade command based on how you installed the package:
201
216
 
202
217
  ```
203
- 📦 Update available: 0.1.15 → 0.1.16
204
- Run: pip install --upgrade rolfedh-doc-utils
218
+ 📦 Update available: 0.1.19 → 0.1.20
219
+ Run: pipx upgrade rolfedh-doc-utils
205
220
  ```
206
221
 
207
222
  To disable update checks, set the environment variable:
@@ -3,6 +3,7 @@ README.md
3
3
  archive_unused_files.py
4
4
  archive_unused_images.py
5
5
  check_scannability.py
6
+ doc_utils_cli.py
6
7
  extract_link_attributes.py
7
8
  find_unused_attributes.py
8
9
  format_asciidoc_spacing.py
@@ -22,6 +23,7 @@ doc_utils/unused_adoc.py
22
23
  doc_utils/unused_attributes.py
23
24
  doc_utils/unused_images.py
24
25
  doc_utils/validate_links.py
26
+ doc_utils/version.py
25
27
  doc_utils/version_check.py
26
28
  rolfedh_doc_utils.egg-info/PKG-INFO
27
29
  rolfedh_doc_utils.egg-info/SOURCES.txt
@@ -44,4 +46,5 @@ tests/test_replace_link_attributes.py
44
46
  tests/test_symlink_handling.py
45
47
  tests/test_topic_map_parser.py
46
48
  tests/test_unused_attributes.py
47
- tests/test_validate_links.py
49
+ tests/test_validate_links.py
50
+ tests/test_version_check.py
@@ -2,6 +2,7 @@
2
2
  archive-unused-files = archive_unused_files:main
3
3
  archive-unused-images = archive_unused_images:main
4
4
  check-scannability = check_scannability:main
5
+ doc-utils = doc_utils_cli:main
5
6
  extract-link-attributes = extract_link_attributes:main
6
7
  find-unused-attributes = find_unused_attributes:main
7
8
  format-asciidoc-spacing = format_asciidoc_spacing:main
@@ -2,6 +2,7 @@ archive_unused_files
2
2
  archive_unused_images
3
3
  check_scannability
4
4
  doc_utils
5
+ doc_utils_cli
5
6
  extract_link_attributes
6
7
  find_unused_attributes
7
8
  format_asciidoc_spacing
@@ -0,0 +1,97 @@
1
+ """Tests for version_check module."""
2
+ import sys
3
+ import os
4
+ from unittest.mock import patch
5
+ import pytest
6
+
7
+ from doc_utils.version_check import (
8
+ detect_install_method,
9
+ parse_version,
10
+ show_update_notification,
11
+ )
12
+
13
+
14
+ class TestDetectInstallMethod:
15
+ """Tests for install method detection."""
16
+
17
+ def test_detect_pipx_from_prefix(self):
18
+ """Test detection when sys.prefix contains 'pipx'."""
19
+ with patch('sys.prefix', '/home/user/.local/pipx/venvs/rolfedh-doc-utils'):
20
+ assert detect_install_method() == 'pipx'
21
+
22
+ def test_detect_pipx_from_env(self):
23
+ """Test detection from PIPX_HOME environment variable."""
24
+ with patch('sys.prefix', '/home/user/.local/share/pipx/venvs/rolfedh-doc-utils'):
25
+ with patch.dict(os.environ, {'PIPX_HOME': '/home/user/.local/share/pipx'}):
26
+ assert detect_install_method() == 'pipx'
27
+
28
+ def test_detect_pip(self):
29
+ """Test detection defaults to pip."""
30
+ with patch('sys.prefix', '/usr'):
31
+ # Clear PIPX_HOME if set
32
+ env = {k: v for k, v in os.environ.items() if k != 'PIPX_HOME'}
33
+ with patch.dict(os.environ, env, clear=True):
34
+ assert detect_install_method() == 'pip'
35
+
36
+ def test_detect_pip_user(self):
37
+ """Test detection for pip --user installations."""
38
+ with patch('sys.prefix', '/home/user/.local'):
39
+ # Clear PIPX_HOME if set
40
+ env = {k: v for k, v in os.environ.items() if k != 'PIPX_HOME'}
41
+ with patch.dict(os.environ, env, clear=True):
42
+ assert detect_install_method() == 'pip'
43
+
44
+
45
+ class TestParseVersion:
46
+ """Tests for version parsing."""
47
+
48
+ def test_parse_simple_version(self):
49
+ """Test parsing simple semantic version."""
50
+ assert parse_version('0.1.19') == (0, 1, 19)
51
+
52
+ def test_parse_version_with_prerelease(self):
53
+ """Test parsing version with pre-release suffix."""
54
+ assert parse_version('0.1.19-dev') == (0, 1, 19)
55
+
56
+ def test_parse_version_with_build(self):
57
+ """Test parsing version with build metadata."""
58
+ assert parse_version('0.1.19+g1234567') == (0, 1, 19)
59
+
60
+ def test_parse_invalid_version(self):
61
+ """Test parsing invalid version returns (0,)."""
62
+ assert parse_version('invalid') == (0,)
63
+
64
+ def test_version_comparison(self):
65
+ """Test that parsed versions can be compared."""
66
+ assert parse_version('0.1.20') > parse_version('0.1.19')
67
+ assert parse_version('0.2.0') > parse_version('0.1.99')
68
+ assert parse_version('1.0.0') > parse_version('0.99.99')
69
+
70
+
71
+ class TestShowUpdateNotification:
72
+ """Tests for update notification display."""
73
+
74
+ def test_show_notification_pipx(self, capsys):
75
+ """Test notification recommends pipx for pipx installations."""
76
+ with patch('doc_utils.version_check.detect_install_method', return_value='pipx'):
77
+ show_update_notification('0.1.20', '0.1.19')
78
+ captured = capsys.readouterr()
79
+ assert 'pipx upgrade' in captured.err
80
+ assert 'pip install' not in captured.err
81
+
82
+ def test_show_notification_pip(self, capsys):
83
+ """Test notification recommends pip for pip installations."""
84
+ with patch('doc_utils.version_check.detect_install_method', return_value='pip'):
85
+ show_update_notification('0.1.20', '0.1.19')
86
+ captured = capsys.readouterr()
87
+ assert 'pip install --upgrade' in captured.err
88
+ assert 'pipx' not in captured.err
89
+
90
+ def test_notification_includes_versions(self, capsys):
91
+ """Test notification includes both current and latest versions."""
92
+ with patch('doc_utils.version_check.detect_install_method', return_value='pip'):
93
+ show_update_notification('0.1.20', '0.1.19')
94
+ captured = capsys.readouterr()
95
+ assert '0.1.19' in captured.err
96
+ assert '0.1.20' in captured.err
97
+ assert '📦' in captured.err
@@ -13,6 +13,7 @@ import sys
13
13
  import json
14
14
  from doc_utils.validate_links import LinkValidator, parse_transpositions, format_results
15
15
  from doc_utils.version_check import check_version_on_startup
16
+ from doc_utils.version import __version__
16
17
  from doc_utils.spinner import Spinner
17
18
 
18
19
 
@@ -132,6 +133,7 @@ Examples:
132
133
  action='store_true',
133
134
  help='Exit with error code if broken links are found'
134
135
  )
136
+ parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
135
137
 
136
138
  args = parser.parse_args()
137
139