updated scan.py to help us error handle the weird searches and alos build an ignore list
This commit is contained in:
@@ -34,7 +34,12 @@ Extracts and organizes documents from FileCabinet CS (Thomson Reuters) using GUI
|
||||
python fccs_scan.py
|
||||
```
|
||||
|
||||
Reads the restored FCCS backup directory and writes all drawer IDs (subfolder names) to `drawer_ids.txt`.
|
||||
Reads the restored FCCS backup directory and writes all drawer IDs (subfolder names) to `drawer_ids.txt`. It also:
|
||||
|
||||
- **Flags prefix clashes** — if one drawer ID is a prefix of another (e.g. `02218` and `02218A`), searching the shorter ID in FCCS pops up a selection box that breaks automated navigation. These are reported so you can export them manually or ignore the shorter ID.
|
||||
- **Reports ignored drawers** — any IDs listed in `ignore.txt` that exist in this backup are shown as ones the export will skip.
|
||||
|
||||
**Ignoring drawers:** To exclude specific drawers from export (e.g. password-protected folders that would stall the automation), add their IDs to the file at `ignore_file` (default `C:\Migration\ignore.txt`), one per line. `drawer_ids.txt` stays a full inventory; the export skips anything in the ignore list. Lines starting with `#` are treated as comments.
|
||||
|
||||
### Step 2: Export Documents
|
||||
|
||||
@@ -88,6 +93,6 @@ Exported filenames follow the format `{drawer_id}_{client_name}_{folder_name}_{c
|
||||
|
||||
All scripts read from `config.ini` (or specify `--config path\to\config.ini`).
|
||||
|
||||
- **`[paths]`** -- backup_dir, export_dir, output_dir, drawer_id_file, completed_file, log_file, screenshot_dir, folder_list
|
||||
- **`[paths]`** -- backup_dir, export_dir, output_dir, drawer_id_file, completed_file, ignore_file, log_file, screenshot_dir, manifest_dir, folder_list
|
||||
- **`[timeouts]`** -- nav_timeout, dialog_timeout, progress_appear, progress_finish, settle, confirm_timeout
|
||||
- **`[controls]`** -- FCCS window class names and button titles (rarely need changing)
|
||||
|
||||
Binary file not shown.
@@ -5,6 +5,7 @@ export_dir = C:\Migration\Export
|
||||
output_dir = C:\Migration\Output
|
||||
drawer_id_file = C:\Migration\drawer_ids.txt
|
||||
completed_file = C:\Migration\completed.txt
|
||||
ignore_file = C:\Migration\ignore.txt
|
||||
log_file = C:\Migration\run_log.txt
|
||||
screenshot_dir = C:\Migration\screenshots
|
||||
manifest_dir = C:\Migration\manifests
|
||||
|
||||
@@ -137,3 +137,23 @@ def load_lines(path):
|
||||
return []
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return [line.strip() for line in f if line.strip() and not line.strip().startswith("#")]
|
||||
|
||||
|
||||
def check_for_clashes(drawer_ids):
|
||||
"""Find drawer IDs that are a prefix of another drawer ID.
|
||||
|
||||
FCCS searches by prefix, so searching the shorter ID (e.g. '02218')
|
||||
pops up a selection box when a longer ID exists (e.g. '02218A'),
|
||||
which breaks the automated navigation.
|
||||
|
||||
Returns a list of (short_id, [longer_ids...]) tuples, sorted by short_id.
|
||||
Empty list means no clashes.
|
||||
"""
|
||||
ids = sorted(set(drawer_ids))
|
||||
clashes = []
|
||||
for short in ids:
|
||||
matches = [other for other in ids
|
||||
if other != short and other.startswith(short)]
|
||||
if matches:
|
||||
clashes.append((short, matches))
|
||||
return clashes
|
||||
|
||||
@@ -354,6 +354,7 @@ def main():
|
||||
paths = {
|
||||
"drawer_id_file": cfg.get("paths", "drawer_id_file"),
|
||||
"completed_file": cfg.get("paths", "completed_file"),
|
||||
"ignore_file": cfg.get("paths", "ignore_file"),
|
||||
"screenshot_dir": cfg.get("paths", "screenshot_dir"),
|
||||
"manifest_dir": cfg.get("paths", "manifest_dir"),
|
||||
}
|
||||
@@ -391,10 +392,12 @@ def main():
|
||||
sys.exit(1)
|
||||
|
||||
completed = load_completed(paths["completed_file"])
|
||||
ignored = set(load_lines(paths["ignore_file"]))
|
||||
|
||||
pending = [d for d in all_ids if d not in completed]
|
||||
pending = [d for d in all_ids if d not in completed and d not in ignored]
|
||||
log(f"Total drawers in list : {len(all_ids)}")
|
||||
log(f"Already completed : {len(completed)}")
|
||||
log(f"Ignored (skipped) : {len(ignored & set(all_ids))}")
|
||||
log(f"Remaining to process : {len(pending)}")
|
||||
|
||||
if not pending:
|
||||
|
||||
29
fccs_scan.py
29
fccs_scan.py
@@ -8,7 +8,9 @@ Writes the sorted list of drawer IDs to the configured drawer_id_file.
|
||||
import os
|
||||
import sys
|
||||
|
||||
from fccs_config import parse_args, load_config, make_logger
|
||||
from fccs_config import (
|
||||
parse_args, load_config, make_logger, load_lines, check_for_clashes,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
@@ -18,6 +20,7 @@ def main():
|
||||
|
||||
backup_dir = cfg.get("paths", "backup_dir")
|
||||
output_file = cfg.get("paths", "drawer_id_file")
|
||||
ignore_file = cfg.get("paths", "ignore_file")
|
||||
|
||||
if not os.path.isdir(backup_dir):
|
||||
log(f"ERROR: backup directory not found: {backup_dir}")
|
||||
@@ -34,6 +37,30 @@ def main():
|
||||
|
||||
log(f"Found {len(drawer_ids)} drawers, written to {output_file}")
|
||||
|
||||
# Report which drawers are set to be ignored (skipped by the export).
|
||||
ignored = set(load_lines(ignore_file))
|
||||
if ignored:
|
||||
present = sorted(ignored & set(drawer_ids))
|
||||
log(f"Ignore list ({ignore_file}): {len(ignored)} IDs, "
|
||||
f"{len(present)} present in this backup — these will be SKIPPED "
|
||||
f"by fccs_export.py: {', '.join(present) if present else '(none present)'}")
|
||||
|
||||
# Flag prefix clashes: FCCS search on the shorter ID pops a selection box.
|
||||
clashes = check_for_clashes(drawer_ids)
|
||||
if clashes:
|
||||
log("-" * 60)
|
||||
log(f"WARNING: {len(clashes)} potential drawer ID clash(es) found.")
|
||||
log("Searching the shorter ID in FCCS may show a selection box "
|
||||
"instead of navigating directly, which breaks the export.")
|
||||
log("Consider exporting these manually, or add the shorter ID to "
|
||||
f"the ignore list ({ignore_file}).")
|
||||
for short, matches in clashes:
|
||||
flag = " [ignored]" if short in ignored else ""
|
||||
log(f" {short}{flag} -> also matches: {', '.join(matches)}")
|
||||
log("-" * 60)
|
||||
else:
|
||||
log("No drawer ID prefix clashes found.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user