oct
Loading...
Searching...
No Matches
source_exporter Namespace Reference

Functions

list[str] _scan_content_for_secrets (str content, str rel_path)
list[str] _get_cached_secret_warnings (str abs_path, str content, str rel_path)
dict load_exporter_config (Path root)
bool should_skip_dirname (str dirname, dict cfg)
bool _is_never_export_file (str filename)
List[Path] collect_recursive_files (Path folder, dict cfg)
Tuple[int, int, int] get_file_stats (Path path)
Iterator[Path] walk_included_dirs (Path start, dict cfg)
Tuple[int, List[Path]] clean_matching_dirs (Path root, str kind, Callable[[str], bool] matches, bool dry_run=False)
Tuple[int, List[Path]] clean_source_dirs (Path root, bool dry_run=False)
Tuple[int, List[Path]] clean_pycache_dirs (Path root, bool dry_run=False)
Path _make_safe_output_path (Path out_dir, str dotpath, dict cfg, str prefix="_source")
Tuple[int, int, int, int, list] write_source_file_for_dir (Path folder, Path output_path, Path root, dict cfg, bool warn_secrets=False, bool block_secrets=False, set[Path]|None diff_filter=None)
None run_exporter (Path root, list[str] args)

Variables

 _SECRET_ASSIGN_RE
dict _secret_scan_cache = {}
set _scanned_secret_paths = set()
dict _EXTENSION_PROFILES
list INCLUDE_EXTENSIONS = [ext for exts in _EXTENSION_PROFILES.values() for ext in exts]
tuple HEADER_TEXT
str SEPARATOR_FILE = "##### File name {num:02d}: {path}\n"
str SEPARATOR_SUBDIR = "####### Subdirectory name {num:02d}: {dirname}\n"
str ROOT_HEADER = "####### Root directory: .\n\n"
int _MAX_SAFE_PATH_LEN = 240
str _CONFIG_FILENAME = "_oct_exporter_config.json"

Detailed Description

Purpose
-------
Provide a unified, Option C‑compliant source‑exporting tool that collects,
combines, and consolidates all source‑code files in a project into structured
inspection files. This enables fast review, debugging, auditing, and
cross‑project comparison.

Responsibilities
----------------
- Walk a project directory tree while respecting exclusion rules.
- Collect all source files with supported extensions.
- Generate per‑directory `_source.<path>.txt` files.
- Generate a root‑level `_full_source.<root>.txt` file.
- Support `--clean` to remove all `_source_code-*` directories.
- Remove export and cache directories for real: clear the read-only
  attribute on anything that refuses, count only what is gone, and name
  what could not be removed (2026-09-07; `oct clean` used to report
  "Removed N" while every read-only directory survived).
- Support `--verbose` to print per‑file statistics.
- Integrate cleanly with the OCT CLI as `oct export-source`.
- Handle I/O errors (including Windows MAX_PATH) gracefully: warn and continue.

Diagnostics
-----------
Domain: OCT-EXPORTER
Levels:
    L2 - lifecycle
    L3 - semantic details
    L4 - deep tracing

Contracts
---------
- Must not modify project files except inside `_source_code-*` directories.
- Must accept any directory as a valid export root.
- Must remain deterministic and safe for large projects.
- Must not require external dependencies beyond the standard library.
- Must never crash on a recoverable I/O error; warn and continue instead.

Dependencies
------------
- oct.core.exclusions (the shared exclusion rules)
- fnmatch (stdlib glob matching for exclusion patterns)
- hashlib (stdlib digest for the MAX_PATH-safe output names)
- json (stdlib config parsing)
- os (stdlib directory walk)
- re (stdlib shallow secret guard)
- sys (stdlib interpreter version and streams)
- datetime (stdlib export timestamp)
- pathlib (stdlib paths)
- oct.core.diagnostics (_dbg structured logger)
- oct.tools.fs_remove (remove_tree_force for read-only-safe directory removal; re-exported)
- oct.core.git (lazy; git_diff_name_only for the --diff filter)
- oct.tools.secret_scanner (lazy; the shared secret-name heuristics for the content guard)

Function Documentation

◆ _get_cached_secret_warnings()

list[str] source_exporter._get_cached_secret_warnings ( str abs_path,
str content,
str rel_path )
protected
Return (cached or computed) secret warnings for ``abs_path``.

Definition at line 120 of file source_exporter.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _is_never_export_file()

bool source_exporter._is_never_export_file ( str filename)
protected
Check if a file matches NEVER_EXPORT_FILE_PATTERNS (§6b Secret Hygiene).

Definition at line 277 of file source_exporter.py.

Here is the caller graph for this function:

◆ _make_safe_output_path()

Path source_exporter._make_safe_output_path ( Path out_dir,
str dotpath,
dict cfg,
str prefix = "_source" )
protected
Build the output file path, truncating the dotpath if the full path would
exceed the Windows MAX_PATH limit (~260 chars). A short MD5 hash suffix is
appended when truncation is applied to ensure uniqueness.

Definition at line 374 of file source_exporter.py.

Here is the caller graph for this function:

◆ _scan_content_for_secrets()

list[str] source_exporter._scan_content_for_secrets ( str content,
str rel_path )
protected
Scan ``content`` for likely hardcoded secrets. Returns warning strings.

Uses the same name-heuristics as the linter (``_SECRET_NAME_PATTERNS``).
Empty list means no warnings. The ``rel_path`` is embedded in each
warning for user attribution.

Definition at line 86 of file source_exporter.py.

Here is the caller graph for this function:

◆ clean_matching_dirs()

Tuple[int, List[Path]] source_exporter.clean_matching_dirs ( Path root,
str kind,
Callable[[str], bool] matches,
bool dry_run = False )
Remove every directory under *root* whose name satisfies *matches*.

Returns ``(removed, failed)``: *removed* counts directories that are
gone (or would be, under *dry_run*), *failed* lists the ones still
present afterwards. Both are printed; a failure is never silent.

Definition at line 327 of file source_exporter.py.

Here is the caller graph for this function:

◆ clean_pycache_dirs()

Tuple[int, List[Path]] source_exporter.clean_pycache_dirs ( Path root,
bool dry_run = False )
Remove all ``__pycache__`` directories under *root*; see :func:`clean_matching_dirs`.

Definition at line 369 of file source_exporter.py.

Here is the call graph for this function:

◆ clean_source_dirs()

Tuple[int, List[Path]] source_exporter.clean_source_dirs ( Path root,
bool dry_run = False )
Remove all ``_source_code-*`` directories under *root*; see :func:`clean_matching_dirs`.

Definition at line 362 of file source_exporter.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ collect_recursive_files()

List[Path] source_exporter.collect_recursive_files ( Path folder,
dict cfg )

Definition at line 286 of file source_exporter.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_file_stats()

Tuple[int, int, int] source_exporter.get_file_stats ( Path path)

Definition at line 302 of file source_exporter.py.

Here is the caller graph for this function:

◆ load_exporter_config()

dict source_exporter.load_exporter_config ( Path root)
Load optional per-project config, merging with module-level defaults.

Definition at line 177 of file source_exporter.py.

Here is the caller graph for this function:

◆ run_exporter()

None source_exporter.run_exporter ( Path root,
list[str] args )
Execute the source exporter with the given root directory and arguments.

Definition at line 470 of file source_exporter.py.

Here is the call graph for this function:

◆ should_skip_dirname()

bool source_exporter.should_skip_dirname ( str dirname,
dict cfg )

Definition at line 270 of file source_exporter.py.

Here is the caller graph for this function:

◆ walk_included_dirs()

Iterator[Path] source_exporter.walk_included_dirs ( Path start,
dict cfg )

Definition at line 317 of file source_exporter.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_source_file_for_dir()

Tuple[int, int, int, int, list] source_exporter.write_source_file_for_dir ( Path folder,
Path output_path,
Path root,
dict cfg,
bool warn_secrets = False,
bool block_secrets = False,
set[Path] | None diff_filter = None )

Definition at line 397 of file source_exporter.py.

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ _CONFIG_FILENAME

str source_exporter._CONFIG_FILENAME = "_oct_exporter_config.json"
protected

Definition at line 170 of file source_exporter.py.

◆ _EXTENSION_PROFILES

dict source_exporter._EXTENSION_PROFILES
protected
Initial value:
1= {
2 "python": [".py"],
3 "web": [".js", ".ts", ".tsx", ".css", ".html"],
4 "jvm": [".java", ".kt"],
5 "systems": [".rs", ".go", ".cpp", ".c", ".h", ".hpp"],
6 "config": [".json", ".yaml", ".yml", ".toml", ".ini", ".xml"],
7 "docs": [".md"],
8 "scripts": [".sh", ".bat", ".ps1", ".ahk"],
9 "misc": [".npmignore", ".gitignore", ".sql", ".rb", ".swift"],
10}

Definition at line 131 of file source_exporter.py.

◆ _MAX_SAFE_PATH_LEN

int source_exporter._MAX_SAFE_PATH_LEN = 240
protected

Definition at line 168 of file source_exporter.py.

◆ _scanned_secret_paths

set source_exporter._scanned_secret_paths = set()
protected

Definition at line 117 of file source_exporter.py.

◆ _SECRET_ASSIGN_RE

source_exporter._SECRET_ASSIGN_RE
protected
Initial value:
1= re.compile(
2 # OCT-LINT: disable=no_hardcoded_secrets reason="identifier-and-quoted-value regex pattern, not a credential (operator-ruled 2026-09-07)"
3 r'(?P<name>[A-Za-z_][A-Za-z0-9_]*)\s*[:=]\s*'
4 r'(?:"(?P<dq>[^"\n]{4,})"|\'(?P<sq>[^\'\n]{4,})\')'
5)

Definition at line 79 of file source_exporter.py.

◆ _secret_scan_cache

dict source_exporter._secret_scan_cache = {}
protected

Definition at line 115 of file source_exporter.py.

◆ HEADER_TEXT

tuple source_exporter.HEADER_TEXT
Initial value:
1= (
2 # OCT-LINT: disable=no_hardcoded_secrets reason="prose header template with a format placeholder, not a credential (operator-ruled 2026-09-07)"
3 "This file contains all source-code files in the directory {directory} "
4 "(and its subdirectories) of this project.\n"
5 "Sections are separated as follows:\n"
6 "- '##### File name XX: <path>' marks individual files.\n"
7 "- '####### Subdirectory name XX: <dirname>' marks combined subdirectory sources.\n"
8 "- Root-level files use './<filename>' for clarity.\n\n"
9)

Definition at line 153 of file source_exporter.py.

◆ INCLUDE_EXTENSIONS

list source_exporter.INCLUDE_EXTENSIONS = [ext for exts in _EXTENSION_PROFILES.values() for ext in exts]

Definition at line 142 of file source_exporter.py.

◆ ROOT_HEADER

str source_exporter.ROOT_HEADER = "####### Root directory: .\n\n"

Definition at line 165 of file source_exporter.py.

◆ SEPARATOR_FILE

str source_exporter.SEPARATOR_FILE = "##### File name {num:02d}: {path}\n"

Definition at line 163 of file source_exporter.py.

◆ SEPARATOR_SUBDIR

str source_exporter.SEPARATOR_SUBDIR = "####### Subdirectory name {num:02d}: {dirname}\n"

Definition at line 164 of file source_exporter.py.