rolfedh-doc-utils 0.1.40__tar.gz → 0.1.41__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.
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/PKG-INFO +1 -1
- rolfedh_doc_utils-0.1.41/doc_utils/insert_abstract_role.py +220 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/version.py +1 -1
- rolfedh_doc_utils-0.1.41/insert_abstract_role.py +163 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/pyproject.toml +3 -2
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/rolfedh_doc_utils.egg-info/PKG-INFO +1 -1
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/rolfedh_doc_utils.egg-info/SOURCES.txt +2 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/rolfedh_doc_utils.egg-info/entry_points.txt +1 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/rolfedh_doc_utils.egg-info/top_level.txt +1 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/LICENSE +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/README.md +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/callout_lib/__init__.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/callout_lib/converter_bullets.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/callout_lib/converter_comments.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/callout_lib/converter_deflist.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/callout_lib/detector.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/callout_lib/table_parser.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/check_published_links.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/check_source_directives.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/convert_callouts_interactive.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/convert_callouts_to_deflist.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/convert_freemarker_to_asciidoc.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/convert_tables_to_deflists.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/__init__.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/convert_freemarker_to_asciidoc.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/duplicate_content.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/duplicate_includes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/extract_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/file_utils.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/format_asciidoc_spacing.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/inventory_conditionals.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/missing_source_directive.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/replace_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/scannability.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/spinner.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/topic_map_parser.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/unused_adoc.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/validate_links.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/version_check.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/warnings_report.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils_cli.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/extract_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/find_duplicate_content.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/find_duplicate_includes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/find_unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/format_asciidoc_spacing.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/inventory_conditionals.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/replace_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/rolfedh_doc_utils.egg-info/dependency_links.txt +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/rolfedh_doc_utils.egg-info/requires.txt +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/setup.cfg +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/setup.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_auto_discovery.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_cli_entry_points.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_convert_tables_to_deflists.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_extract_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_file_utils.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_fixture_archive_unused_files.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_fixture_archive_unused_images.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_fixture_check_scannability.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_inventory_conditionals.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_parse_exclude_list.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_replace_link_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_symlink_handling.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_table_callout_conversion.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_table_parser.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_topic_map_parser.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_unused_attributes.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_validate_links.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_version_check.py +0 -0
- {rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/validate_links.py +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Insert abstract role - ensures AsciiDoc files have [role="_abstract"] above the first paragraph.
|
|
3
|
+
|
|
4
|
+
Core logic for adding the [role="_abstract"] attribute required for DITA short description conversion.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import List, Tuple, Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def find_first_paragraph_after_title(lines: List[str]) -> Optional[int]:
|
|
13
|
+
"""
|
|
14
|
+
Find the line index of the first paragraph after the document title.
|
|
15
|
+
|
|
16
|
+
The first paragraph is the first non-empty line that:
|
|
17
|
+
- Comes after a level 1 heading (= Title)
|
|
18
|
+
- Is not an attribute definition (starts with :)
|
|
19
|
+
- Is not a comment (starts with //)
|
|
20
|
+
- Is not a block attribute (starts with [)
|
|
21
|
+
- Is not another heading
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
lines: List of lines from the file (without trailing newlines)
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Line index of the first paragraph, or None if not found
|
|
28
|
+
"""
|
|
29
|
+
title_found = False
|
|
30
|
+
title_index = -1
|
|
31
|
+
|
|
32
|
+
for i, line in enumerate(lines):
|
|
33
|
+
# Check for level 1 heading (document title)
|
|
34
|
+
if re.match(r'^=\s+[^=]', line):
|
|
35
|
+
title_found = True
|
|
36
|
+
title_index = i
|
|
37
|
+
continue
|
|
38
|
+
|
|
39
|
+
# Only look for first paragraph after we've found the title
|
|
40
|
+
if not title_found:
|
|
41
|
+
continue
|
|
42
|
+
|
|
43
|
+
# Skip empty lines
|
|
44
|
+
if re.match(r'^\s*$', line):
|
|
45
|
+
continue
|
|
46
|
+
|
|
47
|
+
# Skip attribute definitions
|
|
48
|
+
if re.match(r'^:', line):
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
# Skip comments (single line)
|
|
52
|
+
if re.match(r'^//', line):
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
# Skip block attributes like [role=...], [id=...], etc.
|
|
56
|
+
if re.match(r'^\[', line):
|
|
57
|
+
continue
|
|
58
|
+
|
|
59
|
+
# Skip other headings
|
|
60
|
+
if re.match(r'^=+\s+', line):
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
# Skip include directives
|
|
64
|
+
if re.match(r'^include::', line):
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
# This is the first paragraph
|
|
68
|
+
return i
|
|
69
|
+
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def has_abstract_role(lines: List[str], paragraph_index: int) -> bool:
|
|
74
|
+
"""
|
|
75
|
+
Check if there's already a [role="_abstract"] before the paragraph.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
lines: List of lines from the file
|
|
79
|
+
paragraph_index: Index of the first paragraph
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
True if [role="_abstract"] already exists before the paragraph
|
|
83
|
+
"""
|
|
84
|
+
# Look at the lines immediately before the paragraph
|
|
85
|
+
for i in range(paragraph_index - 1, -1, -1):
|
|
86
|
+
line = lines[i].strip()
|
|
87
|
+
|
|
88
|
+
# Skip empty lines
|
|
89
|
+
if not line:
|
|
90
|
+
continue
|
|
91
|
+
|
|
92
|
+
# Found abstract role
|
|
93
|
+
if re.match(r'^\[role=["\']_abstract["\']\]$', line):
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
# If we hit any other non-empty content, stop looking
|
|
97
|
+
# (could be attribute, heading, etc.)
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
return False
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def process_file(file_path: Path, dry_run: bool = False, verbose: bool = False) -> Tuple[bool, List[str]]:
|
|
104
|
+
"""
|
|
105
|
+
Process a single AsciiDoc file to add [role="_abstract"] if needed.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
file_path: Path to the file to process
|
|
109
|
+
dry_run: If True, show what would be changed without modifying
|
|
110
|
+
verbose: If True, show detailed output
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Tuple of (changes_made, messages) where messages is a list of verbose output
|
|
114
|
+
"""
|
|
115
|
+
messages = []
|
|
116
|
+
|
|
117
|
+
if verbose:
|
|
118
|
+
messages.append(f"Processing: {file_path}")
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
122
|
+
lines = f.readlines()
|
|
123
|
+
except (IOError, UnicodeDecodeError) as e:
|
|
124
|
+
raise IOError(f"Error reading {file_path}: {e}")
|
|
125
|
+
|
|
126
|
+
# Remove trailing newlines from lines for processing
|
|
127
|
+
lines = [line.rstrip('\n\r') for line in lines]
|
|
128
|
+
|
|
129
|
+
# Find the first paragraph after the title
|
|
130
|
+
paragraph_index = find_first_paragraph_after_title(lines)
|
|
131
|
+
|
|
132
|
+
if paragraph_index is None:
|
|
133
|
+
if verbose:
|
|
134
|
+
messages.append(" No paragraph found after title")
|
|
135
|
+
return False, messages
|
|
136
|
+
|
|
137
|
+
# Check if abstract role already exists
|
|
138
|
+
if has_abstract_role(lines, paragraph_index):
|
|
139
|
+
if verbose:
|
|
140
|
+
messages.append(" [role=\"_abstract\"] already present")
|
|
141
|
+
return False, messages
|
|
142
|
+
|
|
143
|
+
# Insert [role="_abstract"] before the first paragraph
|
|
144
|
+
# We need to add it with a blank line before it if there isn't one
|
|
145
|
+
new_lines = lines[:paragraph_index]
|
|
146
|
+
|
|
147
|
+
# Check if we need to add a blank line before the role
|
|
148
|
+
if paragraph_index > 0 and lines[paragraph_index - 1].strip():
|
|
149
|
+
new_lines.append('')
|
|
150
|
+
|
|
151
|
+
new_lines.append('[role="_abstract"]')
|
|
152
|
+
new_lines.extend(lines[paragraph_index:])
|
|
153
|
+
|
|
154
|
+
if verbose:
|
|
155
|
+
preview = lines[paragraph_index][:60] + "..." if len(lines[paragraph_index]) > 60 else lines[paragraph_index]
|
|
156
|
+
messages.append(f" Adding [role=\"_abstract\"] before line {paragraph_index + 1}: {preview}")
|
|
157
|
+
|
|
158
|
+
if not dry_run:
|
|
159
|
+
try:
|
|
160
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
161
|
+
for line in new_lines:
|
|
162
|
+
f.write(line + '\n')
|
|
163
|
+
except IOError as e:
|
|
164
|
+
raise IOError(f"Error writing {file_path}: {e}")
|
|
165
|
+
|
|
166
|
+
return True, messages
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def find_adoc_files(path: Path, exclude_dirs: List[str] = None, exclude_files: List[str] = None) -> List[Path]:
|
|
170
|
+
"""
|
|
171
|
+
Find all .adoc files in the given path.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
path: File or directory path to search
|
|
175
|
+
exclude_dirs: List of directory paths to exclude
|
|
176
|
+
exclude_files: List of file paths to exclude
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
List of Path objects for .adoc files
|
|
180
|
+
"""
|
|
181
|
+
exclude_dirs = exclude_dirs or []
|
|
182
|
+
exclude_files = exclude_files or []
|
|
183
|
+
|
|
184
|
+
# Normalize exclusion paths to absolute
|
|
185
|
+
exclude_dirs_abs = [Path(d).resolve() for d in exclude_dirs]
|
|
186
|
+
exclude_files_abs = [Path(f).resolve() for f in exclude_files]
|
|
187
|
+
|
|
188
|
+
adoc_files = []
|
|
189
|
+
|
|
190
|
+
if path.is_file():
|
|
191
|
+
if path.suffix == '.adoc':
|
|
192
|
+
path_abs = path.resolve()
|
|
193
|
+
if path_abs not in exclude_files_abs:
|
|
194
|
+
adoc_files.append(path)
|
|
195
|
+
elif path.is_dir():
|
|
196
|
+
for adoc_path in path.rglob('*.adoc'):
|
|
197
|
+
# Skip symlinks
|
|
198
|
+
if adoc_path.is_symlink():
|
|
199
|
+
continue
|
|
200
|
+
|
|
201
|
+
path_abs = adoc_path.resolve()
|
|
202
|
+
|
|
203
|
+
# Check if file is excluded
|
|
204
|
+
if path_abs in exclude_files_abs:
|
|
205
|
+
continue
|
|
206
|
+
|
|
207
|
+
# Check if any parent directory is excluded
|
|
208
|
+
skip = False
|
|
209
|
+
for exclude_dir in exclude_dirs_abs:
|
|
210
|
+
try:
|
|
211
|
+
path_abs.relative_to(exclude_dir)
|
|
212
|
+
skip = True
|
|
213
|
+
break
|
|
214
|
+
except ValueError:
|
|
215
|
+
pass
|
|
216
|
+
|
|
217
|
+
if not skip:
|
|
218
|
+
adoc_files.append(adoc_path)
|
|
219
|
+
|
|
220
|
+
return sorted(adoc_files)
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
insert-abstract-role - Insert [role="_abstract"] above the first paragraph after the title.
|
|
4
|
+
|
|
5
|
+
Ensures AsciiDoc files have the [role="_abstract"] attribute required for DITA short description
|
|
6
|
+
conversion, as enforced by the AsciiDocDITA.ShortDescription vale rule.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from doc_utils.insert_abstract_role import process_file, find_adoc_files
|
|
14
|
+
from doc_utils.version_check import check_version_on_startup
|
|
15
|
+
from doc_utils.version import __version__
|
|
16
|
+
from doc_utils.file_utils import parse_exclude_list_file
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Colors for output
|
|
20
|
+
class Colors:
|
|
21
|
+
RED = '\033[0;31m'
|
|
22
|
+
GREEN = '\033[0;32m'
|
|
23
|
+
YELLOW = '\033[1;33m'
|
|
24
|
+
NC = '\033[0m' # No Color
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def print_colored(message: str, color: str = Colors.NC) -> None:
|
|
28
|
+
"""Print message with color"""
|
|
29
|
+
print(f"{color}{message}{Colors.NC}")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def main():
|
|
33
|
+
# Check for updates (non-blocking, won't interfere with tool operation)
|
|
34
|
+
check_version_on_startup()
|
|
35
|
+
|
|
36
|
+
parser = argparse.ArgumentParser(
|
|
37
|
+
description="Insert [role=\"_abstract\"] above the first paragraph after the document title",
|
|
38
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
39
|
+
epilog="""
|
|
40
|
+
Insert [role="_abstract"] above the first paragraph after the document title in AsciiDoc files.
|
|
41
|
+
This attribute is required for DITA short description conversion.
|
|
42
|
+
|
|
43
|
+
The tool identifies the first paragraph after a level 1 heading (= Title) and inserts
|
|
44
|
+
the [role="_abstract"] attribute on the line immediately before it.
|
|
45
|
+
|
|
46
|
+
Examples:
|
|
47
|
+
%(prog)s # Process all .adoc files in current directory
|
|
48
|
+
%(prog)s modules/ # Process all .adoc files in modules/
|
|
49
|
+
%(prog)s modules/rn/my-release-note.adoc # Process single file
|
|
50
|
+
%(prog)s --dry-run modules/ # Preview changes without modifying
|
|
51
|
+
%(prog)s --exclude-dir .archive modules/ # Exclude .archive directories
|
|
52
|
+
"""
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
parser.add_argument(
|
|
56
|
+
'path',
|
|
57
|
+
nargs='?',
|
|
58
|
+
default='.',
|
|
59
|
+
help='File or directory to process (default: current directory)'
|
|
60
|
+
)
|
|
61
|
+
parser.add_argument(
|
|
62
|
+
'-n', '--dry-run',
|
|
63
|
+
action='store_true',
|
|
64
|
+
help='Show what would be changed without modifying files'
|
|
65
|
+
)
|
|
66
|
+
parser.add_argument(
|
|
67
|
+
'-v', '--verbose',
|
|
68
|
+
action='store_true',
|
|
69
|
+
help='Show detailed output'
|
|
70
|
+
)
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
'--exclude-dir',
|
|
73
|
+
action='append',
|
|
74
|
+
default=[],
|
|
75
|
+
help='Directory to exclude (can be specified multiple times)'
|
|
76
|
+
)
|
|
77
|
+
parser.add_argument(
|
|
78
|
+
'--exclude-file',
|
|
79
|
+
action='append',
|
|
80
|
+
default=[],
|
|
81
|
+
help='File to exclude (can be specified multiple times)'
|
|
82
|
+
)
|
|
83
|
+
parser.add_argument(
|
|
84
|
+
'--exclude-list',
|
|
85
|
+
help='Path to file containing list of files/directories to exclude (one per line)'
|
|
86
|
+
)
|
|
87
|
+
parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
|
|
88
|
+
|
|
89
|
+
args = parser.parse_args()
|
|
90
|
+
|
|
91
|
+
# Convert path to Path object
|
|
92
|
+
target_path = Path(args.path)
|
|
93
|
+
|
|
94
|
+
# Check if path exists
|
|
95
|
+
if not target_path.exists():
|
|
96
|
+
print_colored(f"Error: Path does not exist: {target_path}", Colors.RED)
|
|
97
|
+
sys.exit(1)
|
|
98
|
+
|
|
99
|
+
# Parse exclusion list file if provided
|
|
100
|
+
exclude_dirs = list(args.exclude_dir)
|
|
101
|
+
exclude_files = list(args.exclude_file)
|
|
102
|
+
|
|
103
|
+
if args.exclude_list:
|
|
104
|
+
list_dirs, list_files = parse_exclude_list_file(args.exclude_list)
|
|
105
|
+
exclude_dirs.extend(list_dirs)
|
|
106
|
+
exclude_files.extend(list_files)
|
|
107
|
+
|
|
108
|
+
# Display dry-run mode message
|
|
109
|
+
if args.dry_run:
|
|
110
|
+
print_colored("DRY RUN MODE - No files will be modified", Colors.YELLOW)
|
|
111
|
+
|
|
112
|
+
# Find all AsciiDoc files
|
|
113
|
+
adoc_files = find_adoc_files(target_path, exclude_dirs, exclude_files)
|
|
114
|
+
|
|
115
|
+
if not adoc_files:
|
|
116
|
+
if target_path.is_file():
|
|
117
|
+
print_colored(f"Warning: {target_path} is not an AsciiDoc file (.adoc)", Colors.YELLOW)
|
|
118
|
+
print(f"Processed 0 AsciiDoc file(s)")
|
|
119
|
+
print("Insert abstract role complete!")
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
# Process each file
|
|
123
|
+
files_processed = 0
|
|
124
|
+
files_modified = 0
|
|
125
|
+
|
|
126
|
+
for file_path in adoc_files:
|
|
127
|
+
try:
|
|
128
|
+
changes_made, messages = process_file(file_path, args.dry_run, args.verbose)
|
|
129
|
+
|
|
130
|
+
# Print verbose messages
|
|
131
|
+
if args.verbose:
|
|
132
|
+
for msg in messages:
|
|
133
|
+
print(msg)
|
|
134
|
+
|
|
135
|
+
if changes_made:
|
|
136
|
+
files_modified += 1
|
|
137
|
+
if args.dry_run:
|
|
138
|
+
print_colored(f"Would modify: {file_path}", Colors.YELLOW)
|
|
139
|
+
else:
|
|
140
|
+
print_colored(f"Modified: {file_path}", Colors.GREEN)
|
|
141
|
+
elif args.verbose:
|
|
142
|
+
print(f" No changes needed for: {file_path}")
|
|
143
|
+
|
|
144
|
+
files_processed += 1
|
|
145
|
+
|
|
146
|
+
except KeyboardInterrupt:
|
|
147
|
+
print_colored("\nOperation cancelled by user", Colors.YELLOW)
|
|
148
|
+
sys.exit(1)
|
|
149
|
+
except IOError as e:
|
|
150
|
+
print_colored(f"{e}", Colors.RED)
|
|
151
|
+
except Exception as e:
|
|
152
|
+
print_colored(f"Unexpected error processing {file_path}: {e}", Colors.RED)
|
|
153
|
+
|
|
154
|
+
print(f"Processed {files_processed} AsciiDoc file(s)")
|
|
155
|
+
if args.dry_run and files_modified > 0:
|
|
156
|
+
print(f"Would modify {files_modified} file(s)")
|
|
157
|
+
elif files_modified > 0:
|
|
158
|
+
print(f"Modified {files_modified} file(s)")
|
|
159
|
+
print("Insert abstract role complete!")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
if __name__ == "__main__":
|
|
163
|
+
main()
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rolfedh-doc-utils"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.41"
|
|
8
8
|
description = "CLI tools for AsciiDoc documentation projects"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -33,10 +33,11 @@ convert-freemarker-to-asciidoc = "convert_freemarker_to_asciidoc:main"
|
|
|
33
33
|
inventory-conditionals = "inventory_conditionals:main"
|
|
34
34
|
find-duplicate-content = "find_duplicate_content:main"
|
|
35
35
|
find-duplicate-includes = "find_duplicate_includes:main"
|
|
36
|
+
insert-abstract-role = "insert_abstract_role:main"
|
|
36
37
|
|
|
37
38
|
[tool.setuptools.packages.find]
|
|
38
39
|
where = ["."]
|
|
39
40
|
include = ["doc_utils*", "callout_lib*"]
|
|
40
41
|
|
|
41
42
|
[tool.setuptools]
|
|
42
|
-
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", "convert_callouts_to_deflist", "convert_callouts_interactive", "check_source_directives", "convert_tables_to_deflists", "check_published_links", "convert_freemarker_to_asciidoc", "inventory_conditionals", "find_duplicate_content", "find_duplicate_includes"]
|
|
43
|
+
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", "convert_callouts_to_deflist", "convert_callouts_interactive", "check_source_directives", "convert_tables_to_deflists", "check_published_links", "convert_freemarker_to_asciidoc", "inventory_conditionals", "find_duplicate_content", "find_duplicate_includes", "insert_abstract_role"]
|
{rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/rolfedh_doc_utils.egg-info/SOURCES.txt
RENAMED
|
@@ -15,6 +15,7 @@ find_duplicate_content.py
|
|
|
15
15
|
find_duplicate_includes.py
|
|
16
16
|
find_unused_attributes.py
|
|
17
17
|
format_asciidoc_spacing.py
|
|
18
|
+
insert_abstract_role.py
|
|
18
19
|
inventory_conditionals.py
|
|
19
20
|
pyproject.toml
|
|
20
21
|
replace_link_attributes.py
|
|
@@ -33,6 +34,7 @@ doc_utils/duplicate_includes.py
|
|
|
33
34
|
doc_utils/extract_link_attributes.py
|
|
34
35
|
doc_utils/file_utils.py
|
|
35
36
|
doc_utils/format_asciidoc_spacing.py
|
|
37
|
+
doc_utils/insert_abstract_role.py
|
|
36
38
|
doc_utils/inventory_conditionals.py
|
|
37
39
|
doc_utils/missing_source_directive.py
|
|
38
40
|
doc_utils/replace_link_attributes.py
|
{rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/rolfedh_doc_utils.egg-info/entry_points.txt
RENAMED
|
@@ -14,6 +14,7 @@ find-duplicate-content = find_duplicate_content:main
|
|
|
14
14
|
find-duplicate-includes = find_duplicate_includes:main
|
|
15
15
|
find-unused-attributes = find_unused_attributes:main
|
|
16
16
|
format-asciidoc-spacing = format_asciidoc_spacing:main
|
|
17
|
+
insert-abstract-role = insert_abstract_role:main
|
|
17
18
|
inventory-conditionals = inventory_conditionals:main
|
|
18
19
|
replace-link-attributes = replace_link_attributes:main
|
|
19
20
|
validate-links = validate_links:main
|
|
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
|
{rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/doc_utils/convert_freemarker_to_asciidoc.py
RENAMED
|
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
|
{rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/rolfedh_doc_utils.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_convert_tables_to_deflists.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_fixture_archive_unused_files.py
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_fixture_archive_unused_images.py
RENAMED
|
File without changes
|
{rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_fixture_check_scannability.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rolfedh_doc_utils-0.1.40 → rolfedh_doc_utils-0.1.41}/tests/test_table_callout_conversion.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|