ic-code 1.0.0__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.
- ic/__init__.py +29 -0
- ic/cli.py +769 -0
- ic/commands/__init__.py +10 -0
- ic/commands/config.py +699 -0
- ic/compat/__init__.py +241 -0
- ic/compat/cli.py +289 -0
- ic/compat/common.py +243 -0
- ic/config/__init__.py +10 -0
- ic/config/cleanup.py +382 -0
- ic/config/docs_organizer.py +587 -0
- ic/config/external.py +456 -0
- ic/config/manager.py +898 -0
- ic/config/migration.py +628 -0
- ic/config/schema.py +595 -0
- ic/config/secrets.py +437 -0
- ic/config/security.py +462 -0
- ic/core/__init__.py +16 -0
- ic/core/logging.py +311 -0
- ic/core/mcp_manager.py +856 -0
- ic/core/session.py +392 -0
- ic/core/silence_logging.py +67 -0
- ic_code-1.0.0.dist-info/METADATA +354 -0
- ic_code-1.0.0.dist-info/RECORD +27 -0
- ic_code-1.0.0.dist-info/WHEEL +5 -0
- ic_code-1.0.0.dist-info/entry_points.txt +2 -0
- ic_code-1.0.0.dist-info/licenses/LICENSE +21 -0
- ic_code-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Documentation organizer module for IC.
|
|
3
|
+
|
|
4
|
+
This module provides functionality to organize and restructure documentation files.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
import shutil
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Dict, Any, List, Optional, Tuple
|
|
12
|
+
import logging
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DocsOrganizer:
|
|
18
|
+
"""
|
|
19
|
+
Organizes documentation files into a structured docs directory.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
"""Initialize DocsOrganizer."""
|
|
24
|
+
self.docs_dir = Path("docs")
|
|
25
|
+
self.reorganization_history: List[Dict[str, Any]] = []
|
|
26
|
+
self.link_updates: List[Dict[str, Any]] = []
|
|
27
|
+
|
|
28
|
+
def reorganize_docs(self) -> bool:
|
|
29
|
+
"""
|
|
30
|
+
Reorganize all documentation files into docs directory structure.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
True if reorganization was successful
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
# Create docs directory structure
|
|
37
|
+
self._create_docs_structure()
|
|
38
|
+
|
|
39
|
+
# Find all markdown files
|
|
40
|
+
md_files = self._find_markdown_files()
|
|
41
|
+
|
|
42
|
+
# Categorize and move files
|
|
43
|
+
moved_files = []
|
|
44
|
+
for md_file in md_files:
|
|
45
|
+
new_location = self._categorize_and_move_file(md_file)
|
|
46
|
+
if new_location:
|
|
47
|
+
moved_files.append({
|
|
48
|
+
"original_path": str(md_file),
|
|
49
|
+
"new_path": str(new_location),
|
|
50
|
+
"category": self._get_file_category(md_file),
|
|
51
|
+
"size": md_file.stat().st_size if md_file.exists() else 0
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
# Update links in moved files
|
|
55
|
+
self._update_links_in_files(moved_files)
|
|
56
|
+
|
|
57
|
+
# Record reorganization
|
|
58
|
+
self.reorganization_history.extend(moved_files)
|
|
59
|
+
|
|
60
|
+
logger.info(f"Reorganized {len(moved_files)} documentation files")
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
except Exception as e:
|
|
64
|
+
logger.error(f"Failed to reorganize documentation: {e}")
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
def _create_docs_structure(self):
|
|
68
|
+
"""Create the documentation directory structure."""
|
|
69
|
+
structure = {
|
|
70
|
+
"docs": {
|
|
71
|
+
"api": {},
|
|
72
|
+
"guides": {
|
|
73
|
+
"installation": {},
|
|
74
|
+
"configuration": {},
|
|
75
|
+
"usage": {}
|
|
76
|
+
},
|
|
77
|
+
"reference": {
|
|
78
|
+
"aws": {},
|
|
79
|
+
"azure": {},
|
|
80
|
+
"gcp": {},
|
|
81
|
+
"oci": {},
|
|
82
|
+
"ssh": {}
|
|
83
|
+
},
|
|
84
|
+
"development": {
|
|
85
|
+
"architecture": {},
|
|
86
|
+
"contributing": {},
|
|
87
|
+
"testing": {}
|
|
88
|
+
},
|
|
89
|
+
"migration": {},
|
|
90
|
+
"security": {},
|
|
91
|
+
"troubleshooting": {}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
self._create_directory_structure(Path("."), structure)
|
|
96
|
+
|
|
97
|
+
def _create_directory_structure(self, base_path: Path, structure: Dict[str, Any]):
|
|
98
|
+
"""Recursively create directory structure."""
|
|
99
|
+
for name, subdirs in structure.items():
|
|
100
|
+
dir_path = base_path / name
|
|
101
|
+
dir_path.mkdir(exist_ok=True)
|
|
102
|
+
|
|
103
|
+
if isinstance(subdirs, dict) and subdirs:
|
|
104
|
+
self._create_directory_structure(dir_path, subdirs)
|
|
105
|
+
|
|
106
|
+
def _find_markdown_files(self) -> List[Path]:
|
|
107
|
+
"""Find all markdown files in the project."""
|
|
108
|
+
md_files = []
|
|
109
|
+
|
|
110
|
+
# Search patterns
|
|
111
|
+
search_paths = [
|
|
112
|
+
Path(".").glob("*.md"),
|
|
113
|
+
Path(".").glob("**/*.md")
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
# Exclude certain directories
|
|
117
|
+
exclude_dirs = {".git", "node_modules", "__pycache__", ".pytest_cache", "venv", "env"}
|
|
118
|
+
|
|
119
|
+
for pattern in search_paths:
|
|
120
|
+
for md_file in pattern:
|
|
121
|
+
# Skip if in excluded directory
|
|
122
|
+
if any(excluded in md_file.parts for excluded in exclude_dirs):
|
|
123
|
+
continue
|
|
124
|
+
|
|
125
|
+
# Skip if already in docs directory
|
|
126
|
+
if "docs" in md_file.parts and md_file.parts.index("docs") == 0:
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
md_files.append(md_file)
|
|
130
|
+
|
|
131
|
+
# Remove duplicates
|
|
132
|
+
return list(set(md_files))
|
|
133
|
+
|
|
134
|
+
def _categorize_and_move_file(self, md_file: Path) -> Optional[Path]:
|
|
135
|
+
"""Categorize a markdown file and move it to appropriate location."""
|
|
136
|
+
if not md_file.exists():
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
# Determine category based on filename and content
|
|
141
|
+
category = self._get_file_category(md_file)
|
|
142
|
+
|
|
143
|
+
# Determine target directory
|
|
144
|
+
target_dir = self._get_target_directory(category, md_file)
|
|
145
|
+
|
|
146
|
+
# Generate new filename
|
|
147
|
+
new_filename = self._generate_new_filename(md_file, category)
|
|
148
|
+
|
|
149
|
+
# Move file
|
|
150
|
+
new_path = target_dir / new_filename
|
|
151
|
+
|
|
152
|
+
# Ensure target directory exists
|
|
153
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
154
|
+
|
|
155
|
+
# Handle filename conflicts
|
|
156
|
+
counter = 1
|
|
157
|
+
original_new_path = new_path
|
|
158
|
+
while new_path.exists():
|
|
159
|
+
stem = original_new_path.stem
|
|
160
|
+
suffix = original_new_path.suffix
|
|
161
|
+
new_path = target_dir / f"{stem}_{counter}{suffix}"
|
|
162
|
+
counter += 1
|
|
163
|
+
|
|
164
|
+
shutil.move(str(md_file), str(new_path))
|
|
165
|
+
logger.debug(f"Moved {md_file} to {new_path}")
|
|
166
|
+
|
|
167
|
+
return new_path
|
|
168
|
+
|
|
169
|
+
except Exception as e:
|
|
170
|
+
logger.warning(f"Failed to move {md_file}: {e}")
|
|
171
|
+
return None
|
|
172
|
+
|
|
173
|
+
def _get_file_category(self, md_file: Path) -> str:
|
|
174
|
+
"""Determine the category of a markdown file."""
|
|
175
|
+
filename = md_file.name.lower()
|
|
176
|
+
|
|
177
|
+
# Read first few lines to understand content
|
|
178
|
+
try:
|
|
179
|
+
with open(md_file, 'r', encoding='utf-8') as f:
|
|
180
|
+
content = f.read(1000).lower() # First 1000 characters
|
|
181
|
+
except Exception:
|
|
182
|
+
content = ""
|
|
183
|
+
|
|
184
|
+
# Categorize based on filename patterns
|
|
185
|
+
if filename in ['readme.md', 'readme.rst']:
|
|
186
|
+
return "main"
|
|
187
|
+
elif 'install' in filename or 'setup' in filename:
|
|
188
|
+
return "installation"
|
|
189
|
+
elif 'config' in filename or 'configuration' in filename:
|
|
190
|
+
return "configuration"
|
|
191
|
+
elif 'api' in filename or 'reference' in filename:
|
|
192
|
+
return "api"
|
|
193
|
+
elif 'guide' in filename or 'tutorial' in filename or 'howto' in filename:
|
|
194
|
+
return "guides"
|
|
195
|
+
elif 'security' in filename or 'security' in content:
|
|
196
|
+
return "security"
|
|
197
|
+
elif 'migration' in filename or 'migrate' in filename:
|
|
198
|
+
return "migration"
|
|
199
|
+
elif 'troubleshoot' in filename or 'faq' in filename or 'problem' in filename:
|
|
200
|
+
return "troubleshooting"
|
|
201
|
+
elif 'develop' in filename or 'contribute' in filename or 'architecture' in filename:
|
|
202
|
+
return "development"
|
|
203
|
+
elif any(cloud in filename for cloud in ['aws', 'azure', 'gcp', 'oci', 'ssh']):
|
|
204
|
+
# Cloud-specific documentation
|
|
205
|
+
for cloud in ['aws', 'azure', 'gcp', 'oci', 'ssh']:
|
|
206
|
+
if cloud in filename:
|
|
207
|
+
return f"reference_{cloud}"
|
|
208
|
+
return "reference"
|
|
209
|
+
elif 'test' in filename:
|
|
210
|
+
return "development_testing"
|
|
211
|
+
else:
|
|
212
|
+
return "general"
|
|
213
|
+
|
|
214
|
+
def _get_target_directory(self, category: str, md_file: Path) -> Path:
|
|
215
|
+
"""Get target directory based on category."""
|
|
216
|
+
base_docs = self.docs_dir
|
|
217
|
+
|
|
218
|
+
category_mapping = {
|
|
219
|
+
"main": base_docs,
|
|
220
|
+
"installation": base_docs / "guides" / "installation",
|
|
221
|
+
"configuration": base_docs / "guides" / "configuration",
|
|
222
|
+
"api": base_docs / "api",
|
|
223
|
+
"guides": base_docs / "guides" / "usage",
|
|
224
|
+
"security": base_docs / "security",
|
|
225
|
+
"migration": base_docs / "migration",
|
|
226
|
+
"troubleshooting": base_docs / "troubleshooting",
|
|
227
|
+
"development": base_docs / "development",
|
|
228
|
+
"development_testing": base_docs / "development" / "testing",
|
|
229
|
+
"reference_aws": base_docs / "reference" / "aws",
|
|
230
|
+
"reference_azure": base_docs / "reference" / "azure",
|
|
231
|
+
"reference_gcp": base_docs / "reference" / "gcp",
|
|
232
|
+
"reference_oci": base_docs / "reference" / "oci",
|
|
233
|
+
"reference_ssh": base_docs / "reference" / "ssh",
|
|
234
|
+
"reference": base_docs / "reference",
|
|
235
|
+
"general": base_docs
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return category_mapping.get(category, base_docs)
|
|
239
|
+
|
|
240
|
+
def _generate_new_filename(self, md_file: Path, category: str) -> str:
|
|
241
|
+
"""Generate appropriate filename for the new location."""
|
|
242
|
+
original_name = md_file.name
|
|
243
|
+
|
|
244
|
+
# Special handling for README files
|
|
245
|
+
if original_name.lower() in ['readme.md', 'readme.rst']:
|
|
246
|
+
if category == "main":
|
|
247
|
+
return "README.md"
|
|
248
|
+
else:
|
|
249
|
+
return "overview.md"
|
|
250
|
+
|
|
251
|
+
# Clean up filename
|
|
252
|
+
clean_name = original_name.lower()
|
|
253
|
+
|
|
254
|
+
# Remove redundant category prefixes
|
|
255
|
+
category_prefixes = ['aws-', 'azure-', 'gcp-', 'oci-', 'ssh-', 'config-', 'guide-', 'api-']
|
|
256
|
+
for prefix in category_prefixes:
|
|
257
|
+
if clean_name.startswith(prefix):
|
|
258
|
+
clean_name = clean_name[len(prefix):]
|
|
259
|
+
break
|
|
260
|
+
|
|
261
|
+
# Ensure .md extension
|
|
262
|
+
if not clean_name.endswith('.md'):
|
|
263
|
+
clean_name = clean_name.rsplit('.', 1)[0] + '.md'
|
|
264
|
+
|
|
265
|
+
return clean_name
|
|
266
|
+
|
|
267
|
+
def _update_links_in_files(self, moved_files: List[Dict[str, Any]]):
|
|
268
|
+
"""Update links in moved files to reflect new structure."""
|
|
269
|
+
# Create mapping of old paths to new paths
|
|
270
|
+
path_mapping = {
|
|
271
|
+
Path(f["original_path"]): Path(f["new_path"])
|
|
272
|
+
for f in moved_files
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# Update links in each moved file
|
|
276
|
+
for file_info in moved_files:
|
|
277
|
+
new_path = Path(file_info["new_path"])
|
|
278
|
+
if new_path.exists():
|
|
279
|
+
self._update_links_in_single_file(new_path, path_mapping)
|
|
280
|
+
|
|
281
|
+
def _update_links_in_single_file(self, file_path: Path, path_mapping: Dict[Path, Path]):
|
|
282
|
+
"""Update links in a single file."""
|
|
283
|
+
try:
|
|
284
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
285
|
+
content = f.read()
|
|
286
|
+
|
|
287
|
+
original_content = content
|
|
288
|
+
|
|
289
|
+
# Find markdown links: [text](path)
|
|
290
|
+
link_pattern = r'\\[([^\\]]+)\\]\\(([^\\)]+)\\)'
|
|
291
|
+
|
|
292
|
+
def replace_link(match):
|
|
293
|
+
link_text = match.group(1)
|
|
294
|
+
link_path = match.group(2)
|
|
295
|
+
|
|
296
|
+
# Skip external links
|
|
297
|
+
if link_path.startswith(('http://', 'https://', 'mailto:', '#')):
|
|
298
|
+
return match.group(0)
|
|
299
|
+
|
|
300
|
+
# Convert to Path and resolve
|
|
301
|
+
try:
|
|
302
|
+
old_link_path = Path(link_path)
|
|
303
|
+
|
|
304
|
+
# Check if this path was moved
|
|
305
|
+
for old_path, new_path in path_mapping.items():
|
|
306
|
+
if old_link_path.name == old_path.name:
|
|
307
|
+
# Calculate relative path from current file to new location
|
|
308
|
+
relative_path = os.path.relpath(new_path, file_path.parent)
|
|
309
|
+
self.link_updates.append({
|
|
310
|
+
"file": str(file_path),
|
|
311
|
+
"old_link": link_path,
|
|
312
|
+
"new_link": relative_path
|
|
313
|
+
})
|
|
314
|
+
return f"[{link_text}]({relative_path})"
|
|
315
|
+
|
|
316
|
+
return match.group(0)
|
|
317
|
+
|
|
318
|
+
except Exception:
|
|
319
|
+
return match.group(0)
|
|
320
|
+
|
|
321
|
+
# Replace links
|
|
322
|
+
content = re.sub(link_pattern, replace_link, content)
|
|
323
|
+
|
|
324
|
+
# Write back if changed
|
|
325
|
+
if content != original_content:
|
|
326
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
327
|
+
f.write(content)
|
|
328
|
+
logger.debug(f"Updated links in {file_path}")
|
|
329
|
+
|
|
330
|
+
except Exception as e:
|
|
331
|
+
logger.warning(f"Failed to update links in {file_path}: {e}")
|
|
332
|
+
|
|
333
|
+
def create_docs_index(self) -> bool:
|
|
334
|
+
"""
|
|
335
|
+
Create a main index file for the documentation.
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
True if index was created successfully
|
|
339
|
+
"""
|
|
340
|
+
try:
|
|
341
|
+
index_content = self._generate_docs_index_content()
|
|
342
|
+
|
|
343
|
+
index_path = self.docs_dir / "README.md"
|
|
344
|
+
with open(index_path, 'w', encoding='utf-8') as f:
|
|
345
|
+
f.write(index_content)
|
|
346
|
+
|
|
347
|
+
logger.info(f"Created documentation index at {index_path}")
|
|
348
|
+
return True
|
|
349
|
+
|
|
350
|
+
except Exception as e:
|
|
351
|
+
logger.error(f"Failed to create documentation index: {e}")
|
|
352
|
+
return False
|
|
353
|
+
|
|
354
|
+
def _generate_docs_index_content(self) -> str:
|
|
355
|
+
"""Generate content for the documentation index."""
|
|
356
|
+
content = """# IC Documentation
|
|
357
|
+
|
|
358
|
+
Welcome to the IC (Infrastructure CLI) documentation. This documentation has been reorganized to provide better structure and easier navigation.
|
|
359
|
+
|
|
360
|
+
## Quick Start
|
|
361
|
+
|
|
362
|
+
- [Installation Guide](guides/installation/)
|
|
363
|
+
- [Configuration Guide](guides/configuration/)
|
|
364
|
+
- [Usage Examples](guides/usage/)
|
|
365
|
+
|
|
366
|
+
## Documentation Structure
|
|
367
|
+
|
|
368
|
+
### 📚 Guides
|
|
369
|
+
Step-by-step instructions for common tasks:
|
|
370
|
+
- **[Installation](guides/installation/)** - How to install and set up IC
|
|
371
|
+
- **[Configuration](guides/configuration/)** - Configuration management and setup
|
|
372
|
+
- **[Usage](guides/usage/)** - Common usage patterns and examples
|
|
373
|
+
|
|
374
|
+
### 📖 Reference
|
|
375
|
+
Detailed reference documentation for each cloud provider:
|
|
376
|
+
- **[AWS](reference/aws/)** - Amazon Web Services integration
|
|
377
|
+
- **[Azure](reference/azure/)** - Microsoft Azure integration
|
|
378
|
+
- **[GCP](reference/gcp/)** - Google Cloud Platform integration
|
|
379
|
+
- **[OCI](reference/oci/)** - Oracle Cloud Infrastructure integration
|
|
380
|
+
- **[SSH](reference/ssh/)** - SSH management and automation
|
|
381
|
+
|
|
382
|
+
### 🔧 Development
|
|
383
|
+
Information for developers and contributors:
|
|
384
|
+
- **[Architecture](development/architecture/)** - System architecture and design
|
|
385
|
+
- **[Contributing](development/contributing/)** - How to contribute to the project
|
|
386
|
+
- **[Testing](development/testing/)** - Testing guidelines and procedures
|
|
387
|
+
|
|
388
|
+
### 🔒 Security
|
|
389
|
+
Security-related documentation:
|
|
390
|
+
- **[Security Guide](security/)** - Security best practices and configuration
|
|
391
|
+
|
|
392
|
+
### 🚀 Migration
|
|
393
|
+
Migration guides and documentation:
|
|
394
|
+
- **[Migration Guide](migration/)** - Migrating from old configurations
|
|
395
|
+
|
|
396
|
+
### 🛠️ Troubleshooting
|
|
397
|
+
Common issues and solutions:
|
|
398
|
+
- **[Troubleshooting](troubleshooting/)** - Common problems and solutions
|
|
399
|
+
|
|
400
|
+
### 🔌 API Reference
|
|
401
|
+
API documentation and references:
|
|
402
|
+
- **[API Reference](api/)** - Detailed API documentation
|
|
403
|
+
|
|
404
|
+
## Recent Changes
|
|
405
|
+
|
|
406
|
+
This documentation has been reorganized as part of the IC configuration system migration. Key improvements include:
|
|
407
|
+
|
|
408
|
+
- **Better Structure**: Documentation is now organized by topic and purpose
|
|
409
|
+
- **Improved Navigation**: Clear hierarchy and cross-references
|
|
410
|
+
- **Updated Links**: All internal links have been updated to reflect the new structure
|
|
411
|
+
- **Consolidated Content**: Related documentation has been grouped together
|
|
412
|
+
|
|
413
|
+
## Getting Help
|
|
414
|
+
|
|
415
|
+
- Check the [Troubleshooting](troubleshooting/) section for common issues
|
|
416
|
+
- Review the relevant [Reference](reference/) documentation for your cloud provider
|
|
417
|
+
- Look at [Usage Examples](guides/usage/) for practical examples
|
|
418
|
+
|
|
419
|
+
## Contributing to Documentation
|
|
420
|
+
|
|
421
|
+
See the [Contributing Guide](development/contributing/) for information on how to improve this documentation.
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
*This documentation was automatically reorganized on """ + f"{datetime.now().strftime('%Y-%m-%d')}*"
|
|
426
|
+
|
|
427
|
+
return content
|
|
428
|
+
|
|
429
|
+
def create_reorganization_history_document(self) -> bool:
|
|
430
|
+
"""
|
|
431
|
+
Create a document recording the documentation reorganization.
|
|
432
|
+
|
|
433
|
+
Returns:
|
|
434
|
+
True if document was created successfully
|
|
435
|
+
"""
|
|
436
|
+
try:
|
|
437
|
+
history_content = self._generate_reorganization_history_content()
|
|
438
|
+
|
|
439
|
+
history_path = self.docs_dir / "reorganization_history.md"
|
|
440
|
+
with open(history_path, 'w', encoding='utf-8') as f:
|
|
441
|
+
f.write(history_content)
|
|
442
|
+
|
|
443
|
+
logger.info(f"Created reorganization history at {history_path}")
|
|
444
|
+
return True
|
|
445
|
+
|
|
446
|
+
except Exception as e:
|
|
447
|
+
logger.error(f"Failed to create reorganization history: {e}")
|
|
448
|
+
return False
|
|
449
|
+
|
|
450
|
+
def _generate_reorganization_history_content(self) -> str:
|
|
451
|
+
"""Generate reorganization history document content."""
|
|
452
|
+
content = """# Documentation Reorganization History
|
|
453
|
+
|
|
454
|
+
This document records the reorganization of IC documentation files into a structured format.
|
|
455
|
+
|
|
456
|
+
## Overview
|
|
457
|
+
|
|
458
|
+
The documentation has been reorganized to improve discoverability and maintainability. Files have been categorized and moved to appropriate directories within the `docs/` folder.
|
|
459
|
+
|
|
460
|
+
## New Structure
|
|
461
|
+
|
|
462
|
+
```
|
|
463
|
+
docs/
|
|
464
|
+
├── README.md # Main documentation index
|
|
465
|
+
├── api/ # API reference documentation
|
|
466
|
+
├── guides/ # User guides and tutorials
|
|
467
|
+
│ ├── installation/ # Installation guides
|
|
468
|
+
│ ├── configuration/ # Configuration guides
|
|
469
|
+
│ └── usage/ # Usage examples
|
|
470
|
+
├── reference/ # Reference documentation
|
|
471
|
+
│ ├── aws/ # AWS-specific documentation
|
|
472
|
+
│ ├── azure/ # Azure-specific documentation
|
|
473
|
+
│ ├── gcp/ # GCP-specific documentation
|
|
474
|
+
│ ├── oci/ # OCI-specific documentation
|
|
475
|
+
│ └── ssh/ # SSH-specific documentation
|
|
476
|
+
├── development/ # Development documentation
|
|
477
|
+
│ ├── architecture/ # Architecture documentation
|
|
478
|
+
│ ├── contributing/ # Contributing guidelines
|
|
479
|
+
│ └── testing/ # Testing documentation
|
|
480
|
+
├── migration/ # Migration guides
|
|
481
|
+
├── security/ # Security documentation
|
|
482
|
+
└── troubleshooting/ # Troubleshooting guides
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
## File Movements
|
|
486
|
+
|
|
487
|
+
"""
|
|
488
|
+
|
|
489
|
+
if self.reorganization_history:
|
|
490
|
+
# Group by category
|
|
491
|
+
files_by_category = {}
|
|
492
|
+
for file_info in self.reorganization_history:
|
|
493
|
+
category = file_info['category']
|
|
494
|
+
if category not in files_by_category:
|
|
495
|
+
files_by_category[category] = []
|
|
496
|
+
files_by_category[category].append(file_info)
|
|
497
|
+
|
|
498
|
+
for category, files in files_by_category.items():
|
|
499
|
+
content += f"### {category.replace('_', ' ').title()}\n\n"
|
|
500
|
+
|
|
501
|
+
content += "| Original Location | New Location | Size |\n"
|
|
502
|
+
content += "|-------------------|--------------|------|\n"
|
|
503
|
+
|
|
504
|
+
for file_info in files:
|
|
505
|
+
size = self._format_size(file_info['size'])
|
|
506
|
+
content += f"| `{file_info['original_path']}` | `{file_info['new_path']}` | {size} |\n"
|
|
507
|
+
|
|
508
|
+
content += "\n"
|
|
509
|
+
else:
|
|
510
|
+
content += "No file movements recorded.\n\n"
|
|
511
|
+
|
|
512
|
+
# Link updates section
|
|
513
|
+
if self.link_updates:
|
|
514
|
+
content += "## Link Updates\n\n"
|
|
515
|
+
content += "The following internal links were updated to reflect the new structure:\n\n"
|
|
516
|
+
|
|
517
|
+
content += "| File | Old Link | New Link |\n"
|
|
518
|
+
content += "|------|----------|----------|\n"
|
|
519
|
+
|
|
520
|
+
for link_update in self.link_updates:
|
|
521
|
+
content += f"| `{link_update['file']}` | `{link_update['old_link']}` | `{link_update['new_link']}` |\n"
|
|
522
|
+
|
|
523
|
+
content += "\n"
|
|
524
|
+
|
|
525
|
+
content += """## Benefits of Reorganization
|
|
526
|
+
|
|
527
|
+
1. **Improved Discoverability**: Related documentation is grouped together
|
|
528
|
+
2. **Better Navigation**: Clear hierarchy makes it easier to find information
|
|
529
|
+
3. **Consistent Structure**: Standardized organization across all documentation
|
|
530
|
+
4. **Easier Maintenance**: Logical grouping makes updates and maintenance simpler
|
|
531
|
+
5. **Better User Experience**: Users can quickly find the information they need
|
|
532
|
+
|
|
533
|
+
## Accessing Old Locations
|
|
534
|
+
|
|
535
|
+
If you have bookmarks or references to old documentation locations, use this mapping to find the new locations. All content has been preserved - only the organization has changed.
|
|
536
|
+
|
|
537
|
+
## Maintenance
|
|
538
|
+
|
|
539
|
+
- New documentation should be placed in the appropriate category directory
|
|
540
|
+
- Update the main README.md index when adding new major sections
|
|
541
|
+
- Keep the structure consistent with the established patterns
|
|
542
|
+
- Update cross-references when moving or renaming files
|
|
543
|
+
|
|
544
|
+
"""
|
|
545
|
+
|
|
546
|
+
return content
|
|
547
|
+
|
|
548
|
+
def _format_size(self, size_bytes: int) -> str:
|
|
549
|
+
"""Format file size in human-readable format."""
|
|
550
|
+
if size_bytes == 0:
|
|
551
|
+
return "0 B"
|
|
552
|
+
|
|
553
|
+
for unit in ['B', 'KB', 'MB']:
|
|
554
|
+
if size_bytes < 1024:
|
|
555
|
+
return f"{size_bytes:.1f} {unit}"
|
|
556
|
+
size_bytes /= 1024
|
|
557
|
+
|
|
558
|
+
return f"{size_bytes:.1f} GB"
|
|
559
|
+
|
|
560
|
+
def validate_reorganization(self) -> Dict[str, List[str]]:
|
|
561
|
+
"""
|
|
562
|
+
Validate the documentation reorganization.
|
|
563
|
+
|
|
564
|
+
Returns:
|
|
565
|
+
Dictionary of validation results
|
|
566
|
+
"""
|
|
567
|
+
issues = {
|
|
568
|
+
"missing_files": [],
|
|
569
|
+
"broken_links": [],
|
|
570
|
+
"empty_directories": []
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
# Check if moved files exist
|
|
574
|
+
for file_info in self.reorganization_history:
|
|
575
|
+
new_path = Path(file_info["new_path"])
|
|
576
|
+
if not new_path.exists():
|
|
577
|
+
issues["missing_files"].append(file_info["new_path"])
|
|
578
|
+
|
|
579
|
+
# Check for empty directories
|
|
580
|
+
for root, dirs, files in os.walk(self.docs_dir):
|
|
581
|
+
root_path = Path(root)
|
|
582
|
+
if not files and not dirs:
|
|
583
|
+
issues["empty_directories"].append(str(root_path))
|
|
584
|
+
|
|
585
|
+
# TODO: Add broken link detection
|
|
586
|
+
|
|
587
|
+
return issues
|