rolfedh-doc-utils 0.1.0__py3-none-any.whl → 0.1.3__py3-none-any.whl
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.
- archive_unused_files.py +35 -0
- archive_unused_images.py +35 -0
- check_scannability.py +109 -0
- doc_utils/file_utils.py +47 -3
- doc_utils/topic_map_parser.py +122 -0
- doc_utils/unused_adoc.py +30 -4
- find_unused_attributes.py +41 -0
- rolfedh_doc_utils-0.1.3.dist-info/METADATA +285 -0
- rolfedh_doc_utils-0.1.3.dist-info/RECORD +17 -0
- rolfedh_doc_utils-0.1.3.dist-info/top_level.txt +5 -0
- rolfedh_doc_utils-0.1.0.dist-info/METADATA +0 -83
- rolfedh_doc_utils-0.1.0.dist-info/RECORD +0 -12
- rolfedh_doc_utils-0.1.0.dist-info/top_level.txt +0 -1
- {rolfedh_doc_utils-0.1.0.dist-info → rolfedh_doc_utils-0.1.3.dist-info}/WHEEL +0 -0
- {rolfedh_doc_utils-0.1.0.dist-info → rolfedh_doc_utils-0.1.3.dist-info}/entry_points.txt +0 -0
- {rolfedh_doc_utils-0.1.0.dist-info → rolfedh_doc_utils-0.1.3.dist-info}/licenses/LICENSE +0 -0
archive_unused_files.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Archive Unused AsciiDoc Files
|
|
3
|
+
|
|
4
|
+
Scans './modules' and './assemblies' for AsciiDoc files not referenced by any other AsciiDoc file in the project. Optionally archives and deletes them.
|
|
5
|
+
|
|
6
|
+
For full documentation and usage examples, see archive_unused_files.md in this directory.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
from doc_utils.unused_adoc import find_unused_adoc
|
|
11
|
+
from doc_utils.file_utils import parse_exclude_list_file
|
|
12
|
+
|
|
13
|
+
def main():
|
|
14
|
+
parser = argparse.ArgumentParser(description='Archive unused AsciiDoc files.')
|
|
15
|
+
parser.add_argument('--archive', action='store_true', help='Move the files to a dated zip in the archive directory.')
|
|
16
|
+
parser.add_argument('--exclude-dir', action='append', default=[], help='Directory to exclude (can be used multiple times).')
|
|
17
|
+
parser.add_argument('--exclude-file', action='append', default=[], help='File to exclude (can be used multiple times).')
|
|
18
|
+
parser.add_argument('--exclude-list', type=str, help='Path to a file containing directories or files to exclude, one per line.')
|
|
19
|
+
args = parser.parse_args()
|
|
20
|
+
|
|
21
|
+
scan_dirs = ['./modules', './modules/rn', './assemblies']
|
|
22
|
+
archive_dir = './archive'
|
|
23
|
+
|
|
24
|
+
exclude_dirs = list(args.exclude_dir)
|
|
25
|
+
exclude_files = list(args.exclude_file)
|
|
26
|
+
|
|
27
|
+
if args.exclude_list:
|
|
28
|
+
list_dirs, list_files = parse_exclude_list_file(args.exclude_list)
|
|
29
|
+
exclude_dirs.extend(list_dirs)
|
|
30
|
+
exclude_files.extend(list_files)
|
|
31
|
+
|
|
32
|
+
find_unused_adoc(scan_dirs, archive_dir, args.archive, exclude_dirs, exclude_files)
|
|
33
|
+
|
|
34
|
+
if __name__ == '__main__':
|
|
35
|
+
main()
|
archive_unused_images.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Archive Unused Image Files
|
|
3
|
+
|
|
4
|
+
Scans './modules' and './assemblies' for image files (e.g., .png, .jpg, .jpeg, .gif, .svg) not referenced by any AsciiDoc file in the project. Optionally archives and deletes them.
|
|
5
|
+
|
|
6
|
+
For full documentation and usage examples, see archive_unused_files.md in this directory.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
from doc_utils.unused_images import find_unused_images
|
|
11
|
+
from doc_utils.file_utils import parse_exclude_list_file
|
|
12
|
+
|
|
13
|
+
def main():
|
|
14
|
+
parser = argparse.ArgumentParser(description='Archive unused image files.')
|
|
15
|
+
parser.add_argument('--archive', action='store_true', help='Move the files to a dated zip in the archive directory.')
|
|
16
|
+
parser.add_argument('--exclude-dir', action='append', default=[], help='Directory to exclude (can be used multiple times).')
|
|
17
|
+
parser.add_argument('--exclude-file', action='append', default=[], help='File to exclude (can be used multiple times).')
|
|
18
|
+
parser.add_argument('--exclude-list', type=str, help='Path to a file containing directories or files to exclude, one per line.')
|
|
19
|
+
args = parser.parse_args()
|
|
20
|
+
|
|
21
|
+
scan_dirs = ['.']
|
|
22
|
+
archive_dir = './archive'
|
|
23
|
+
|
|
24
|
+
exclude_dirs = list(args.exclude_dir)
|
|
25
|
+
exclude_files = list(args.exclude_file)
|
|
26
|
+
|
|
27
|
+
if args.exclude_list:
|
|
28
|
+
list_dirs, list_files = parse_exclude_list_file(args.exclude_list)
|
|
29
|
+
exclude_dirs.extend(list_dirs)
|
|
30
|
+
exclude_files.extend(list_files)
|
|
31
|
+
|
|
32
|
+
find_unused_images(scan_dirs, archive_dir, args.archive, exclude_dirs, exclude_files)
|
|
33
|
+
|
|
34
|
+
if __name__ == '__main__':
|
|
35
|
+
main()
|
check_scannability.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Scannability Checker for AsciiDoc Files
|
|
3
|
+
|
|
4
|
+
This script analyzes AsciiDoc (`.adoc`) files in the current directory to detect scannability issues that affect readability.
|
|
5
|
+
|
|
6
|
+
- Flags sentences that exceed 22 words (default, adjustable with -s)
|
|
7
|
+
- Flags paragraphs with more than 3 sentences (default, adjustable with -p)
|
|
8
|
+
- Excludes code blocks (delimited by ----, ...., or [source] blocks) from analysis
|
|
9
|
+
|
|
10
|
+
When using -o, the script prints the path to the report file; it does not attempt to open the file automatically.
|
|
11
|
+
|
|
12
|
+
For full documentation, see check_scannability.md in this directory.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
import argparse
|
|
18
|
+
from datetime import datetime
|
|
19
|
+
from doc_utils.scannability import check_scannability
|
|
20
|
+
from doc_utils.file_utils import collect_files, parse_exclude_list_file
|
|
21
|
+
|
|
22
|
+
BASE_SENTENCE_WORD_LIMIT = 22
|
|
23
|
+
BASE_PARAGRAPH_SENTENCE_LIMIT = 3
|
|
24
|
+
|
|
25
|
+
def print_help():
|
|
26
|
+
print(__doc__)
|
|
27
|
+
|
|
28
|
+
def main():
|
|
29
|
+
# Manual check for -h or --help to display the full docstring
|
|
30
|
+
if '-h' in sys.argv or '--help' in sys.argv:
|
|
31
|
+
print_help()
|
|
32
|
+
sys.exit(0)
|
|
33
|
+
|
|
34
|
+
parser = argparse.ArgumentParser(add_help=False)
|
|
35
|
+
parser.add_argument('-s', '--max-sentence-length', type=int, default=0, help='Extra words allowed per sentence (default: 0, base: 22)')
|
|
36
|
+
parser.add_argument('-p', '--max-paragraph-sentences', type=int, default=0, help='Extra sentences allowed per paragraph (default: 0, base: 3)')
|
|
37
|
+
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output (show all files, even those without issues)')
|
|
38
|
+
parser.add_argument('-o', '--output', action='store_true', help='Output the report to a timestamped txt file in your home directory')
|
|
39
|
+
parser.add_argument('--exclude-dir', action='append', default=[], help='Directory to exclude (can be used multiple times).')
|
|
40
|
+
parser.add_argument('--exclude-file', action='append', default=[], help='File to exclude (can be used multiple times).')
|
|
41
|
+
parser.add_argument('--exclude-list', type=str, help='Path to a file containing directories or files to exclude, one per line.')
|
|
42
|
+
# Do not add -h/--help to argparse, handled manually above
|
|
43
|
+
args = parser.parse_args()
|
|
44
|
+
|
|
45
|
+
exclude_dirs = list(args.exclude_dir)
|
|
46
|
+
exclude_files = list(args.exclude_file)
|
|
47
|
+
|
|
48
|
+
if args.exclude_list:
|
|
49
|
+
list_dirs, list_files = parse_exclude_list_file(args.exclude_list)
|
|
50
|
+
exclude_dirs.extend(list_dirs)
|
|
51
|
+
exclude_files.extend(list_files)
|
|
52
|
+
adoc_files = collect_files(['.'], {'.adoc'}, exclude_dirs, exclude_files)
|
|
53
|
+
sentence_word_limit = BASE_SENTENCE_WORD_LIMIT + args.max_sentence_length
|
|
54
|
+
paragraph_sentence_limit = BASE_PARAGRAPH_SENTENCE_LIMIT + args.max_paragraph_sentences
|
|
55
|
+
long_sentences, long_paragraphs = check_scannability(
|
|
56
|
+
adoc_files,
|
|
57
|
+
max_sentence_length=sentence_word_limit,
|
|
58
|
+
max_paragraph_sentences=paragraph_sentence_limit
|
|
59
|
+
)
|
|
60
|
+
# Build a report per file
|
|
61
|
+
report_lines = []
|
|
62
|
+
issues_by_file = {}
|
|
63
|
+
for file, line, sent in long_sentences:
|
|
64
|
+
issues_by_file.setdefault(file, []).append(f"Line {line}: Sentence exceeds {sentence_word_limit} words: {sent}")
|
|
65
|
+
for file, line, count in long_paragraphs:
|
|
66
|
+
issues_by_file.setdefault(file, []).append(f"Line {line}: Paragraph exceeds {paragraph_sentence_limit} sentences ({count} sentences)")
|
|
67
|
+
for adoc in adoc_files:
|
|
68
|
+
issues = issues_by_file.get(adoc, [])
|
|
69
|
+
if issues or args.verbose:
|
|
70
|
+
report_lines.append("") # Blank line above each filename
|
|
71
|
+
report_lines.append(f"{adoc}:")
|
|
72
|
+
if issues:
|
|
73
|
+
for issue in issues:
|
|
74
|
+
report_lines.append(" " + issue)
|
|
75
|
+
else:
|
|
76
|
+
report_lines.append(" No scannability issues found.")
|
|
77
|
+
|
|
78
|
+
output = "\n".join(report_lines)
|
|
79
|
+
if args.output:
|
|
80
|
+
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
81
|
+
home_dir = os.path.expanduser("~")
|
|
82
|
+
filename = os.path.join(home_dir, f"{timestamp}.txt")
|
|
83
|
+
now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
84
|
+
pwd = os.getcwd()
|
|
85
|
+
cmd = "python3 " + " ".join([sys.argv[0]] + sys.argv[1:])
|
|
86
|
+
metadata = [
|
|
87
|
+
"Scannability Report",
|
|
88
|
+
"",
|
|
89
|
+
f"Purpose: This report lists scannability issues in .adoc files in the current directory.",
|
|
90
|
+
f"Directory: {pwd}",
|
|
91
|
+
f"Date and Time: {now_str}",
|
|
92
|
+
f"Sentence length limit: {sentence_word_limit} words (22 plus -s/--max-sentence-length {args.max_sentence_length})",
|
|
93
|
+
f"Paragraph sentence limit: {paragraph_sentence_limit} sentences (3 plus -p/--max-paragraph-sentences {args.max_paragraph_sentences})",
|
|
94
|
+
"See check_scannability.md for usage instructions and examples.",
|
|
95
|
+
f"Command: {cmd}",
|
|
96
|
+
"",
|
|
97
|
+
"------------------------------------------------------------",
|
|
98
|
+
"",
|
|
99
|
+
]
|
|
100
|
+
with open(filename, "w", encoding="utf-8") as f:
|
|
101
|
+
f.write("\n".join(metadata))
|
|
102
|
+
f.write(output.lstrip() + "\n")
|
|
103
|
+
print(f"Report written to: {filename}")
|
|
104
|
+
else:
|
|
105
|
+
if output:
|
|
106
|
+
print(output.lstrip())
|
|
107
|
+
|
|
108
|
+
if __name__ == "__main__":
|
|
109
|
+
main()
|
doc_utils/file_utils.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# doc_utils/file_utils.py
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
import re
|
|
5
4
|
import zipfile
|
|
6
5
|
from datetime import datetime
|
|
7
6
|
|
|
@@ -17,8 +16,26 @@ def collect_files(scan_dirs, extensions, exclude_dirs=None, exclude_files=None):
|
|
|
17
16
|
for base_dir in scan_dirs:
|
|
18
17
|
for root, dirs, files in os.walk(base_dir):
|
|
19
18
|
abs_root = os.path.abspath(root)
|
|
20
|
-
#
|
|
21
|
-
|
|
19
|
+
# Check if current root directory should be excluded
|
|
20
|
+
if abs_root in exclude_dirs:
|
|
21
|
+
dirs[:] = [] # Skip this directory entirely
|
|
22
|
+
continue
|
|
23
|
+
# Exclude directories by absolute path and check for any parent directory exclusions
|
|
24
|
+
new_dirs = []
|
|
25
|
+
for d in dirs:
|
|
26
|
+
dir_path = os.path.join(root, d)
|
|
27
|
+
abs_dir_path = os.path.abspath(dir_path)
|
|
28
|
+
if not os.path.islink(dir_path) and abs_dir_path not in exclude_dirs:
|
|
29
|
+
# Also check if any parent of this directory is excluded
|
|
30
|
+
excluded = False
|
|
31
|
+
for exclude_dir in exclude_dirs:
|
|
32
|
+
if abs_dir_path.startswith(exclude_dir + os.sep) or abs_dir_path == exclude_dir:
|
|
33
|
+
excluded = True
|
|
34
|
+
break
|
|
35
|
+
if not excluded:
|
|
36
|
+
new_dirs.append(d)
|
|
37
|
+
dirs[:] = new_dirs
|
|
38
|
+
|
|
22
39
|
for f in files:
|
|
23
40
|
file_path = os.path.normpath(os.path.join(root, f))
|
|
24
41
|
abs_file_path = os.path.abspath(file_path)
|
|
@@ -31,6 +48,33 @@ def collect_files(scan_dirs, extensions, exclude_dirs=None, exclude_files=None):
|
|
|
31
48
|
return list(dict.fromkeys(found_files))
|
|
32
49
|
|
|
33
50
|
|
|
51
|
+
def parse_exclude_list_file(exclude_list_path):
|
|
52
|
+
"""
|
|
53
|
+
Parse an exclusion list file and return lists of directories and files to exclude.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
exclude_list_path: Path to file containing paths to exclude (one per line)
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
tuple: (exclude_dirs, exclude_files) lists
|
|
60
|
+
"""
|
|
61
|
+
exclude_dirs = []
|
|
62
|
+
exclude_files = []
|
|
63
|
+
|
|
64
|
+
if exclude_list_path and os.path.exists(exclude_list_path):
|
|
65
|
+
with open(exclude_list_path, 'r', encoding='utf-8') as excl:
|
|
66
|
+
for line in excl:
|
|
67
|
+
line = line.strip()
|
|
68
|
+
if not line or line.startswith('#'):
|
|
69
|
+
continue
|
|
70
|
+
if os.path.isdir(line):
|
|
71
|
+
exclude_dirs.append(line)
|
|
72
|
+
else:
|
|
73
|
+
exclude_files.append(line)
|
|
74
|
+
|
|
75
|
+
return exclude_dirs, exclude_files
|
|
76
|
+
|
|
77
|
+
|
|
34
78
|
def write_manifest_and_archive(unused_files, archive_dir, manifest_prefix, archive_prefix, archive=False):
|
|
35
79
|
"""
|
|
36
80
|
Write a manifest of unused files and optionally archive and delete them.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# doc_utils/topic_map_parser.py
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import yaml
|
|
5
|
+
import glob
|
|
6
|
+
|
|
7
|
+
def detect_repo_type(base_path='.'):
|
|
8
|
+
"""
|
|
9
|
+
Detect whether the repository uses topic maps (OpenShift-docs style)
|
|
10
|
+
or master.adoc files (traditional style).
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
'topic_map' - if _topic_maps directory with .yml files exists
|
|
14
|
+
'master_adoc' - if master.adoc files are found
|
|
15
|
+
'unknown' - if neither pattern is detected
|
|
16
|
+
"""
|
|
17
|
+
topic_maps_dir = os.path.join(base_path, '_topic_maps')
|
|
18
|
+
|
|
19
|
+
# Check for topic maps
|
|
20
|
+
if os.path.isdir(topic_maps_dir):
|
|
21
|
+
yml_files = glob.glob(os.path.join(topic_maps_dir, '*.yml'))
|
|
22
|
+
if yml_files:
|
|
23
|
+
return 'topic_map'
|
|
24
|
+
|
|
25
|
+
# Check for master.adoc files
|
|
26
|
+
master_files = glob.glob(os.path.join(base_path, '**/master.adoc'), recursive=True)
|
|
27
|
+
if master_files:
|
|
28
|
+
return 'master_adoc'
|
|
29
|
+
|
|
30
|
+
return 'unknown'
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def extract_files_from_topic_map(topic_map_path):
|
|
34
|
+
"""
|
|
35
|
+
Extract all referenced .adoc files from a topic map YAML file.
|
|
36
|
+
|
|
37
|
+
Returns a set of file paths referenced in the topic map.
|
|
38
|
+
"""
|
|
39
|
+
referenced_files = set()
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
with open(topic_map_path, 'r', encoding='utf-8') as f:
|
|
43
|
+
# Use safe_load_all to handle multiple YAML documents
|
|
44
|
+
documents = yaml.safe_load_all(f)
|
|
45
|
+
|
|
46
|
+
for doc in documents:
|
|
47
|
+
if doc is None:
|
|
48
|
+
continue
|
|
49
|
+
|
|
50
|
+
# Process each topic group
|
|
51
|
+
process_topic_group(doc, referenced_files)
|
|
52
|
+
|
|
53
|
+
except Exception as e:
|
|
54
|
+
print(f"Warning: Could not parse topic map {topic_map_path}: {e}")
|
|
55
|
+
|
|
56
|
+
return referenced_files
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def process_topic_group(group, referenced_files, parent_dir=''):
|
|
60
|
+
"""
|
|
61
|
+
Recursively process a topic group to extract all file references.
|
|
62
|
+
"""
|
|
63
|
+
if not isinstance(group, dict):
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
# Get the directory for this group
|
|
67
|
+
current_dir = group.get('Dir', '')
|
|
68
|
+
if parent_dir and current_dir:
|
|
69
|
+
current_dir = os.path.join(parent_dir, current_dir)
|
|
70
|
+
elif parent_dir:
|
|
71
|
+
current_dir = parent_dir
|
|
72
|
+
|
|
73
|
+
# Process topics in this group
|
|
74
|
+
topics = group.get('Topics', [])
|
|
75
|
+
if isinstance(topics, list):
|
|
76
|
+
for topic in topics:
|
|
77
|
+
if isinstance(topic, dict):
|
|
78
|
+
# If topic has a File, add it
|
|
79
|
+
if 'File' in topic:
|
|
80
|
+
file_path = topic['File']
|
|
81
|
+
if current_dir:
|
|
82
|
+
file_path = os.path.join(current_dir, file_path)
|
|
83
|
+
# Add .adoc extension if not present
|
|
84
|
+
if not file_path.endswith('.adoc'):
|
|
85
|
+
file_path += '.adoc'
|
|
86
|
+
referenced_files.add(file_path)
|
|
87
|
+
|
|
88
|
+
# If topic has nested topics (sub-group), process recursively
|
|
89
|
+
if 'Topics' in topic:
|
|
90
|
+
# For nested topics, use the Dir from the topic if present
|
|
91
|
+
sub_dir = topic.get('Dir', '')
|
|
92
|
+
if sub_dir:
|
|
93
|
+
# If topic has its own Dir, append it to current_dir
|
|
94
|
+
if current_dir:
|
|
95
|
+
next_dir = os.path.join(current_dir, sub_dir)
|
|
96
|
+
else:
|
|
97
|
+
next_dir = sub_dir
|
|
98
|
+
else:
|
|
99
|
+
# If no Dir specified, keep current_dir
|
|
100
|
+
next_dir = current_dir
|
|
101
|
+
# Process only the Topics, not the whole topic dict
|
|
102
|
+
process_topic_group({'Topics': topic['Topics']}, referenced_files, next_dir)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_all_topic_map_references(base_path='.'):
|
|
106
|
+
"""
|
|
107
|
+
Get all .adoc files referenced in all topic maps.
|
|
108
|
+
|
|
109
|
+
Returns a set of all referenced file paths.
|
|
110
|
+
"""
|
|
111
|
+
topic_maps_dir = os.path.join(base_path, '_topic_maps')
|
|
112
|
+
all_references = set()
|
|
113
|
+
|
|
114
|
+
if not os.path.isdir(topic_maps_dir):
|
|
115
|
+
return all_references
|
|
116
|
+
|
|
117
|
+
# Process all .yml files in _topic_maps
|
|
118
|
+
for yml_file in glob.glob(os.path.join(topic_maps_dir, '*.yml')):
|
|
119
|
+
references = extract_files_from_topic_map(yml_file)
|
|
120
|
+
all_references.update(references)
|
|
121
|
+
|
|
122
|
+
return all_references
|
doc_utils/unused_adoc.py
CHANGED
|
@@ -3,22 +3,48 @@
|
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
5
|
from .file_utils import collect_files, write_manifest_and_archive
|
|
6
|
+
from .topic_map_parser import detect_repo_type, get_all_topic_map_references
|
|
6
7
|
|
|
7
8
|
def find_unused_adoc(scan_dirs, archive_dir, archive=False, exclude_dirs=None, exclude_files=None):
|
|
9
|
+
# Detect repository type
|
|
10
|
+
repo_type = detect_repo_type()
|
|
11
|
+
print(f"Detected repository type: {repo_type}")
|
|
12
|
+
|
|
13
|
+
# Collect all .adoc files in scan directories
|
|
8
14
|
asciidoc_files = collect_files(scan_dirs, {'.adoc'}, exclude_dirs, exclude_files)
|
|
15
|
+
|
|
16
|
+
# Track which files are referenced
|
|
17
|
+
referenced_files = set()
|
|
18
|
+
|
|
19
|
+
if repo_type == 'topic_map':
|
|
20
|
+
# For OpenShift-docs style repos, get references from topic maps
|
|
21
|
+
topic_references = get_all_topic_map_references()
|
|
22
|
+
# Convert to basenames for comparison
|
|
23
|
+
referenced_files.update(os.path.basename(ref) for ref in topic_references)
|
|
24
|
+
|
|
25
|
+
# Always scan for include:: directives in all .adoc files
|
|
9
26
|
include_pattern = re.compile(r'include::(.+?)\[')
|
|
10
|
-
included_files = set()
|
|
11
27
|
adoc_files = collect_files(['.'], {'.adoc'}, exclude_dirs, exclude_files)
|
|
28
|
+
|
|
12
29
|
for file_path in adoc_files:
|
|
13
30
|
try:
|
|
14
31
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
15
32
|
content = f.read()
|
|
16
33
|
includes = include_pattern.findall(content)
|
|
17
|
-
|
|
34
|
+
# Extract just the filename from the include path
|
|
35
|
+
for include in includes:
|
|
36
|
+
# Handle both relative and absolute includes
|
|
37
|
+
include_basename = os.path.basename(include)
|
|
38
|
+
referenced_files.add(include_basename)
|
|
18
39
|
except Exception as e:
|
|
19
40
|
print(f"Warning: could not read {file_path}: {e}")
|
|
20
|
-
|
|
21
|
-
|
|
41
|
+
|
|
42
|
+
# Find unused files by comparing basenames
|
|
43
|
+
unused_files = [f for f in asciidoc_files if os.path.basename(f) not in referenced_files]
|
|
44
|
+
unused_files = list(dict.fromkeys(unused_files)) # Remove duplicates
|
|
45
|
+
|
|
46
|
+
print(f"Found {len(unused_files)} unused files out of {len(asciidoc_files)} total files in scan directories")
|
|
47
|
+
|
|
22
48
|
return write_manifest_and_archive(
|
|
23
49
|
unused_files, archive_dir, 'to-archive', 'to-archive', archive=archive
|
|
24
50
|
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Find Unused AsciiDoc Attributes
|
|
3
|
+
|
|
4
|
+
Scans a user-specified attributes file (e.g., attributes.adoc) for attribute definitions (e.g., :version: 1.1), then recursively scans all .adoc files in the current directory (ignoring symlinks) for usages of those attributes (e.g., {version}).
|
|
5
|
+
|
|
6
|
+
Any attribute defined but not used in any .adoc file is reported as NOT USED in both the command line output and a timestamped output file.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import os
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from doc_utils.unused_attributes import find_unused_attributes
|
|
13
|
+
|
|
14
|
+
def main():
|
|
15
|
+
parser = argparse.ArgumentParser(description='Find unused AsciiDoc attributes.')
|
|
16
|
+
parser.add_argument('attributes_file', help='Path to the attributes.adoc file to scan for attribute definitions.')
|
|
17
|
+
parser.add_argument('-o', '--output', action='store_true', help='Write results to a timestamped txt file in your home directory.')
|
|
18
|
+
args = parser.parse_args()
|
|
19
|
+
|
|
20
|
+
unused = find_unused_attributes(args.attributes_file, '.')
|
|
21
|
+
|
|
22
|
+
lines = [f":{attr}: NOT USED" for attr in unused]
|
|
23
|
+
output = '\n'.join(lines)
|
|
24
|
+
|
|
25
|
+
if output:
|
|
26
|
+
print('Unused attributes:')
|
|
27
|
+
print(output)
|
|
28
|
+
else:
|
|
29
|
+
print('All attributes are used.')
|
|
30
|
+
|
|
31
|
+
if args.output and output:
|
|
32
|
+
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
|
|
33
|
+
home_dir = os.path.expanduser('~')
|
|
34
|
+
filename = os.path.join(home_dir, f'unused_attributes_{timestamp}.txt')
|
|
35
|
+
with open(filename, 'w', encoding='utf-8') as f:
|
|
36
|
+
f.write('Unused attributes in ' + args.attributes_file + '\n')
|
|
37
|
+
f.write(output + '\n')
|
|
38
|
+
print(f'Results written to: {filename}')
|
|
39
|
+
|
|
40
|
+
if __name__ == '__main__':
|
|
41
|
+
main()
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rolfedh-doc-utils
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: CLI tools for AsciiDoc documentation projects
|
|
5
|
+
Author: Rolfe Dlugy-Hegwer
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 Rolfe Dlugy-Hegwer
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Requires-Python: >=3.8
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: PyYAML>=6.0
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# doc-utils
|
|
35
|
+
|
|
36
|
+
A set of Python utilities and CLI tools to help technical writers maintain AsciiDoc documentation repositories.
|
|
37
|
+
|
|
38
|
+
> ⚠️ **IMPORTANT: Safety First**
|
|
39
|
+
>
|
|
40
|
+
> These tools can modify or delete files in your documentation repository. Always:
|
|
41
|
+
> - **Work in a git branch** - Never run these tools on the main/master branch
|
|
42
|
+
> - **Review all changes carefully** - Use `git diff` or a pull request to verify modifications
|
|
43
|
+
> - **Check your preview builds** - Ensure no documentation errors were introduced
|
|
44
|
+
|
|
45
|
+
## Resources
|
|
46
|
+
|
|
47
|
+
- [PyPI: rolfedh-doc-utils](https://pypi.org/project/rolfedh-doc-utils/)
|
|
48
|
+
- [GitHub repository](https://github.com/rolfedh/doc-utils)
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
### From PyPI
|
|
53
|
+
|
|
54
|
+
On modern Linux distributions, you may encounter an "externally-managed-environment" error. Use one of these methods:
|
|
55
|
+
|
|
56
|
+
**Option 1: pipx (Recommended for CLI tools)**
|
|
57
|
+
```sh
|
|
58
|
+
pipx install rolfedh-doc-utils
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Option 2: pip with --user flag**
|
|
62
|
+
```sh
|
|
63
|
+
pip install --user rolfedh-doc-utils
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Option 3: Traditional pip (may require virtual environment)**
|
|
67
|
+
```sh
|
|
68
|
+
pip install rolfedh-doc-utils
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Upgrading
|
|
72
|
+
|
|
73
|
+
To upgrade to the latest version:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
# If installed with pipx:
|
|
77
|
+
pipx upgrade rolfedh-doc-utils
|
|
78
|
+
|
|
79
|
+
# If installed with pip:
|
|
80
|
+
pip install --upgrade rolfedh-doc-utils # or --user flag if needed
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### For Development
|
|
84
|
+
|
|
85
|
+
If you're developing or testing locally, install the package in editable mode:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
# Clone the repository
|
|
89
|
+
git clone https://github.com/rolfedh/doc-utils.git
|
|
90
|
+
cd doc-utils
|
|
91
|
+
|
|
92
|
+
# Install in editable mode
|
|
93
|
+
pip install -e .
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The following CLI tools are installed:
|
|
97
|
+
|
|
98
|
+
* `check-scannability`
|
|
99
|
+
* `archive-unused-files`
|
|
100
|
+
* `archive-unused-images`
|
|
101
|
+
* `find-unused-attributes`
|
|
102
|
+
|
|
103
|
+
These tools can be run from any directory.
|
|
104
|
+
|
|
105
|
+
### Add to PATH (if needed)
|
|
106
|
+
|
|
107
|
+
By default, CLI tools install to:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
$HOME/.local/bin
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If this directory isn’t in your `PATH`, commands may not run. Append it to your shell configuration:
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc # or ~/.zshrc
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Then reload your shell:
|
|
120
|
+
|
|
121
|
+
```sh
|
|
122
|
+
source ~/.bashrc # or ~/.zshrc
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## CLI Tools Overview
|
|
126
|
+
|
|
127
|
+
### `check-scannability`
|
|
128
|
+
|
|
129
|
+
Scans `.adoc` files in the current directory to report:
|
|
130
|
+
|
|
131
|
+
* Sentences that exceed a length limit (default: 22 words)
|
|
132
|
+
* Paragraphs with too many sentences (default: 3 sentences)
|
|
133
|
+
* Supports exclusion of files and directories
|
|
134
|
+
|
|
135
|
+
➡️ See [`check_scannability.md`](https://github.com/rolfedh/doc-utils/blob/main/check_scannability.md) for details.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### `archive-unused-files`
|
|
140
|
+
|
|
141
|
+
Scans the `./modules` and `./assemblies` directories for `.adoc` files that are not referenced. Optionally archives and deletes them.
|
|
142
|
+
|
|
143
|
+
Works with both:
|
|
144
|
+
- **OpenShift-docs style** repositories (uses `_topic_maps/*.yml` files)
|
|
145
|
+
- **Traditional AsciiDoc** repositories (uses `master.adoc` files)
|
|
146
|
+
|
|
147
|
+
➡️ See [`archive_unused_files.md`](https://github.com/rolfedh/doc-utils/blob/main/archive_unused_files.md).
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### `archive-unused-images`
|
|
152
|
+
|
|
153
|
+
Finds unused image files (e.g., `.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`) in the current directory and optionally archives and deletes them.
|
|
154
|
+
|
|
155
|
+
➡️ See [`archive_unused_images.md`](https://github.com/rolfedh/doc-utils/blob/main/archive_unused_images.md).
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### `find-unused-attributes`
|
|
160
|
+
|
|
161
|
+
Scans an attributes file (e.g., `attributes.adoc`) for unused attribute definitions across all `.adoc` files in the current directory.
|
|
162
|
+
|
|
163
|
+
➡️ See [`find_unused_attributes.md`](https://github.com/rolfedh/doc-utils/blob/main/find_unused_attributes.md).
|
|
164
|
+
|
|
165
|
+
## Best Practices for Safe Usage
|
|
166
|
+
|
|
167
|
+
### Before Running Any Tool:
|
|
168
|
+
|
|
169
|
+
- **Create a feature branch:**
|
|
170
|
+
```sh
|
|
171
|
+
git checkout -b doc-cleanup-$(date +%Y%m%d)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
- **Commit any pending changes:**
|
|
175
|
+
```sh
|
|
176
|
+
git add -A && git commit -m "Save work before cleanup"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- **Run tools in preview mode first:**
|
|
180
|
+
- For archive tools: Run without `--archive` to see what would be affected
|
|
181
|
+
|
|
182
|
+
- **Review all changes and preview builds**
|
|
183
|
+
|
|
184
|
+
- **Only merge after verification:**
|
|
185
|
+
|
|
186
|
+
## Usage
|
|
187
|
+
|
|
188
|
+
To run the tools after installation:
|
|
189
|
+
|
|
190
|
+
```sh
|
|
191
|
+
check-scannability --help
|
|
192
|
+
archive-unused-files --help
|
|
193
|
+
find-unused-attributes attributes.adoc
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Or run them directly from source:
|
|
197
|
+
|
|
198
|
+
```sh
|
|
199
|
+
python3 check_scannability.py
|
|
200
|
+
python3 archive_unused_files.py
|
|
201
|
+
python3 find_unused_attributes.py attributes.adoc
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Directory/File Exclusion
|
|
205
|
+
|
|
206
|
+
All tools support excluding specific directories and files from scanning. You can use these options:
|
|
207
|
+
|
|
208
|
+
1. **`--exclude-dir`** - Exclude specific directories (can be used multiple times):
|
|
209
|
+
```sh
|
|
210
|
+
archive-unused-files --exclude-dir ./modules/temp --exclude-dir ./modules/old
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
2. **`--exclude-file`** - Exclude specific files (can be used multiple times):
|
|
214
|
+
```sh
|
|
215
|
+
check-scannability --exclude-file ./README.adoc --exclude-file ./test.adoc
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
3. **`--exclude-list`** - Point to a text file containing exclusions:
|
|
219
|
+
```sh
|
|
220
|
+
archive-unused-images --exclude-list .docutils-ignore
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
The exclusion file format:
|
|
224
|
+
```
|
|
225
|
+
# Comments are supported
|
|
226
|
+
./modules/deprecated/
|
|
227
|
+
./assemblies/archive/
|
|
228
|
+
./images/temp/
|
|
229
|
+
specific-file.adoc
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Note:** When you exclude a parent directory, all its subdirectories are automatically excluded. Symbolic links are never followed during scanning.
|
|
233
|
+
|
|
234
|
+
## Troubleshooting
|
|
235
|
+
|
|
236
|
+
### ModuleNotFoundError
|
|
237
|
+
|
|
238
|
+
If you see an error like `ModuleNotFoundError: No module named 'find_unused_attributes'`, this typically means:
|
|
239
|
+
|
|
240
|
+
1. The package isn't installed. Run:
|
|
241
|
+
```sh
|
|
242
|
+
pipx install rolfedh-doc-utils # or pip install --user rolfedh-doc-utils
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
2. You're trying to run the script directly without installation. Either:
|
|
246
|
+
- Install the package first (see Installation section)
|
|
247
|
+
- Run the script using Python directly:
|
|
248
|
+
```sh
|
|
249
|
+
python3 find_unused_attributes.py attributes.adoc
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Command not found
|
|
253
|
+
|
|
254
|
+
If the command isn't found after installation, ensure `$HOME/.local/bin` is in your PATH (see "Add to PATH" section above).
|
|
255
|
+
|
|
256
|
+
## Development
|
|
257
|
+
|
|
258
|
+
### Running Tests
|
|
259
|
+
|
|
260
|
+
The project includes a comprehensive test suite. To run tests:
|
|
261
|
+
|
|
262
|
+
```sh
|
|
263
|
+
# Install development dependencies
|
|
264
|
+
pip install -r requirements-dev.txt
|
|
265
|
+
|
|
266
|
+
# Run all tests
|
|
267
|
+
python -m pytest tests/
|
|
268
|
+
|
|
269
|
+
# Run with verbose output
|
|
270
|
+
python -m pytest tests/ -v
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Contributing
|
|
274
|
+
|
|
275
|
+
Contributions are welcome! Please ensure:
|
|
276
|
+
- All tests pass before submitting a PR
|
|
277
|
+
- New features include appropriate tests
|
|
278
|
+
- Code follows PEP 8 style guidelines
|
|
279
|
+
- Documentation is updated as needed
|
|
280
|
+
|
|
281
|
+
See [CONTRIBUTING.md](https://github.com/rolfedh/doc-utils/blob/main/CONTRIBUTING.md) for more details.
|
|
282
|
+
|
|
283
|
+
## License
|
|
284
|
+
|
|
285
|
+
This project is licensed under the terms of the [LICENSE](https://github.com/rolfedh/doc-utils/blob/main/LICENSE).
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
archive_unused_files.py,sha256=MFdAtE8CDthida5H5FhvtEHZWrQAZZoAB-DQkTOc6gs,1537
|
|
2
|
+
archive_unused_images.py,sha256=PG2o3haovYckgfhoPhl6KRG_a9czyZuqlLkzkupKTCY,1526
|
|
3
|
+
check_scannability.py,sha256=gcM-vFXKHGP_yFBz7-V5xbXWhIMmtMzBYIGwP9CFbzI,5140
|
|
4
|
+
find_unused_attributes.py,sha256=fk-K32eoCVHxoj7RiBNgSmX1arBLuwYfdSAOMc-wIx0,1677
|
|
5
|
+
doc_utils/__init__.py,sha256=qqZR3lohzkP63soymrEZPBGzzk6-nFzi4_tSffjmu_0,74
|
|
6
|
+
doc_utils/file_utils.py,sha256=fpTh3xx759sF8sNocdn_arsP3KAv8XA6cTQTAVIZiZg,4247
|
|
7
|
+
doc_utils/scannability.py,sha256=XwlmHqDs69p_V36X7DLjPTy0DUoLszSGqYjJ9wE-3hg,982
|
|
8
|
+
doc_utils/topic_map_parser.py,sha256=4vmOPInoKAFO54qOz4EuK24hHTngI4GXzrw0D_QZzSc,4224
|
|
9
|
+
doc_utils/unused_adoc.py,sha256=aPhq4KQG5VJGCg_cnqyhNWuADGEQA_dtjmvxtf7ylGA,2185
|
|
10
|
+
doc_utils/unused_attributes.py,sha256=HBgmHelqearfWl3TTC2bZGiJytjLADIgiGQUNKqXXPg,1847
|
|
11
|
+
doc_utils/unused_images.py,sha256=P9vcm00BidrLmxhjeczBtiFU-1wgfN5nCYdZjeCH1kM,1329
|
|
12
|
+
rolfedh_doc_utils-0.1.3.dist-info/licenses/LICENSE,sha256=vLxtwMVOJA_hEy8b77niTkdmQI9kNJskXHq0dBS36e0,1075
|
|
13
|
+
rolfedh_doc_utils-0.1.3.dist-info/METADATA,sha256=nTGGOIULiuqFcveMw4kGsHF-NVbe-YK3sbElusT9ku0,8152
|
|
14
|
+
rolfedh_doc_utils-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
+
rolfedh_doc_utils-0.1.3.dist-info/entry_points.txt,sha256=i8LqEsp0KD4YyVI_7wQ1TMgCuag32D7gQes6bLufmtM,216
|
|
16
|
+
rolfedh_doc_utils-0.1.3.dist-info/top_level.txt,sha256=BkaYN3KbtNvLQjs-QGBKCJb5UAtjEbC_IqxSSIN9P-w,95
|
|
17
|
+
rolfedh_doc_utils-0.1.3.dist-info/RECORD,,
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: rolfedh-doc-utils
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: CLI tools for AsciiDoc documentation projects
|
|
5
|
-
Author: Rolfe Dlugy-Hegwer
|
|
6
|
-
License: MIT License
|
|
7
|
-
|
|
8
|
-
Copyright (c) 2025 Rolfe Dlugy-Hegwer
|
|
9
|
-
|
|
10
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
-
in the Software without restriction, including without limitation the rights
|
|
13
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
-
furnished to do so, subject to the following conditions:
|
|
16
|
-
|
|
17
|
-
The above copyright notice and this permission notice shall be included in all
|
|
18
|
-
copies or substantial portions of the Software.
|
|
19
|
-
|
|
20
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
-
SOFTWARE.
|
|
27
|
-
|
|
28
|
-
Requires-Python: >=3.8
|
|
29
|
-
Description-Content-Type: text/markdown
|
|
30
|
-
License-File: LICENSE
|
|
31
|
-
Dynamic: license-file
|
|
32
|
-
|
|
33
|
-
# doc-utils
|
|
34
|
-
|
|
35
|
-
This repository contains modular Python utilities and CLI scripts to help technical writers with documentation tasks.
|
|
36
|
-
|
|
37
|
-
**Purpose:**
|
|
38
|
-
Each script is now a thin CLI wrapper that delegates to reusable modules in the `doc_utils` package. For details on how to use a script, see the initial docstring, comments, or the corresponding Markdown help file.
|
|
39
|
-
|
|
40
|
-
## Current Scripts
|
|
41
|
-
|
|
42
|
-
- **check_scannability.py**
|
|
43
|
-
Checks the scannability of AsciiDoc (`.adoc`) files in the current directory. Reports sentences that are too long and paragraphs that contain too many sentences, based on configurable limits. See [check_scannability.md](check_scannability.md) for usage and examples.
|
|
44
|
-
|
|
45
|
-
- **archive_unused_files.py**
|
|
46
|
-
Scans `./modules` and `./assemblies` for AsciiDoc files not referenced by any other AsciiDoc file in the project. Optionally archives and deletes them. See [archive_unused_files.md](archive_unused_files.md) for usage and examples.
|
|
47
|
-
|
|
48
|
-
- **archive_unused_images.py**
|
|
49
|
-
Scans all directories for image files (e.g., `.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`) not referenced by any AsciiDoc file in the project. Optionally archives and deletes them. See [archive_unused_images.md](archive_unused_images.md) for usage and examples.
|
|
50
|
-
|
|
51
|
-
- **find_unused_attributes.py**
|
|
52
|
-
Scans a user-specified attributes file (e.g., `attributes.adoc`) for attribute definitions (e.g., `:version:`) and recursively scans all `.adoc` files in the current directory for usages (e.g., `{version}`). Reports any attribute that is defined but not used in any `.adoc` file as **NOT USED** in both the command line output and a timestamped output file. See [find_unused_attributes.md](find_unused_attributes.md) for usage and examples.
|
|
53
|
-
|
|
54
|
-
## Modular Python Package
|
|
55
|
-
|
|
56
|
-
The core logic for all scripts is implemented in the `doc_utils/` package. You can import and reuse these utilities in your own scripts or tests:
|
|
57
|
-
|
|
58
|
-
- `doc_utils.file_utils` — file collection, manifest, and archiving utilities
|
|
59
|
-
- `doc_utils.unused_images` — logic for finding and archiving unused images
|
|
60
|
-
- `doc_utils.unused_adoc` — logic for finding and archiving unused AsciiDoc files
|
|
61
|
-
- `doc_utils.scannability` — logic for checking AsciiDoc scannability
|
|
62
|
-
- `doc_utils.unused_attributes` — logic for finding unused AsciiDoc attributes
|
|
63
|
-
|
|
64
|
-
## How to Use
|
|
65
|
-
|
|
66
|
-
1. Open the script you are interested in (for example, `check_scannability.py` or `find_unused_attributes.py`).
|
|
67
|
-
2. Read the top of the script or the corresponding `.md` file for instructions, options, and examples.
|
|
68
|
-
3. Run the script from your terminal as described in the usage section.
|
|
69
|
-
|
|
70
|
-
## Running Tests
|
|
71
|
-
|
|
72
|
-
To run all tests, install the development requirements and run pytest from the project root:
|
|
73
|
-
|
|
74
|
-
```sh
|
|
75
|
-
pip install -r requirements-dev.txt
|
|
76
|
-
pytest
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
All tests and fixtures are located in the `tests/` directory. See `tests/README.md` for details.
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
*For licensing information, see [LICENSE](LICENSE).*
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
doc_utils/__init__.py,sha256=qqZR3lohzkP63soymrEZPBGzzk6-nFzi4_tSffjmu_0,74
|
|
2
|
-
doc_utils/file_utils.py,sha256=ftX4XN4tD2kLPkJzKDXsJUZLBq2R2hTDkK08FqNNqlU,2606
|
|
3
|
-
doc_utils/scannability.py,sha256=XwlmHqDs69p_V36X7DLjPTy0DUoLszSGqYjJ9wE-3hg,982
|
|
4
|
-
doc_utils/unused_adoc.py,sha256=gvP1eClEbVebN2jXA41-bPnbVhYz6JHEIbGZCg8JD0s,1115
|
|
5
|
-
doc_utils/unused_attributes.py,sha256=HBgmHelqearfWl3TTC2bZGiJytjLADIgiGQUNKqXXPg,1847
|
|
6
|
-
doc_utils/unused_images.py,sha256=P9vcm00BidrLmxhjeczBtiFU-1wgfN5nCYdZjeCH1kM,1329
|
|
7
|
-
rolfedh_doc_utils-0.1.0.dist-info/licenses/LICENSE,sha256=vLxtwMVOJA_hEy8b77niTkdmQI9kNJskXHq0dBS36e0,1075
|
|
8
|
-
rolfedh_doc_utils-0.1.0.dist-info/METADATA,sha256=NpSNWXDb4TmGY3rOMOPM-85jF74BLllx4e5mrsmvwQk,4417
|
|
9
|
-
rolfedh_doc_utils-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
10
|
-
rolfedh_doc_utils-0.1.0.dist-info/entry_points.txt,sha256=i8LqEsp0KD4YyVI_7wQ1TMgCuag32D7gQes6bLufmtM,216
|
|
11
|
-
rolfedh_doc_utils-0.1.0.dist-info/top_level.txt,sha256=KeCjW0XQZ4Qx_nIFjNLhIqrL5_mxHhGxSwsZglGWKDk,10
|
|
12
|
-
rolfedh_doc_utils-0.1.0.dist-info/RECORD,,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
doc_utils
|
|
File without changes
|
|
File without changes
|
|
File without changes
|