128 lines
3.7 KiB
Python
128 lines
3.7 KiB
Python
"""Data models for the disk reorganizer"""
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
|
|
@dataclass
|
|
class FileRecord:
|
|
"""Core file record with all metadata"""
|
|
path: Path
|
|
size: int
|
|
modified_time: float
|
|
created_time: float
|
|
disk_label: str
|
|
checksum: Optional[str] = None
|
|
status: str = 'indexed' # indexed, planned, moved, verified
|
|
category: Optional[str] = None
|
|
duplicate_of: Optional[str] = None
|
|
|
|
def to_dict(self) -> dict:
|
|
"""Convert to dictionary for serialization"""
|
|
return {
|
|
'path': str(self.path),
|
|
'size': self.size,
|
|
'modified_time': self.modified_time,
|
|
'created_time': self.created_time,
|
|
'disk_label': self.disk_label,
|
|
'checksum': self.checksum,
|
|
'status': self.status,
|
|
'category': self.category,
|
|
'duplicate_of': self.duplicate_of
|
|
}
|
|
|
|
|
|
@dataclass
|
|
class OperationRecord:
|
|
"""Record of a migration operation"""
|
|
source_path: Path
|
|
target_path: Path
|
|
operation_type: str # move, copy, hardlink, symlink
|
|
size: int = 0
|
|
status: str = 'pending' # pending, in_progress, completed, failed
|
|
error: Optional[str] = None
|
|
executed_at: Optional[datetime] = None
|
|
verified: bool = False
|
|
|
|
def to_dict(self) -> dict:
|
|
"""Convert to dictionary for serialization"""
|
|
return {
|
|
'source_path': str(self.source_path),
|
|
'target_path': str(self.target_path),
|
|
'operation_type': self.operation_type,
|
|
'size': self.size,
|
|
'status': self.status,
|
|
'error': self.error,
|
|
'executed_at': self.executed_at.isoformat() if self.executed_at else None,
|
|
'verified': self.verified
|
|
}
|
|
|
|
|
|
@dataclass
|
|
class DiskInfo:
|
|
"""Information about a disk/volume"""
|
|
name: str
|
|
device: str
|
|
mount_point: Path
|
|
total_size: int
|
|
used_size: int
|
|
free_size: int
|
|
fs_type: str
|
|
|
|
@property
|
|
def usage_percent(self) -> float:
|
|
"""Calculate usage percentage"""
|
|
if self.total_size == 0:
|
|
return 0.0
|
|
return (self.used_size / self.total_size) * 100
|
|
|
|
|
|
@dataclass
|
|
class MigrationPlan:
|
|
"""Complete migration plan"""
|
|
target_disk: str
|
|
destination_disks: list[str]
|
|
operations: list[OperationRecord]
|
|
total_size: int
|
|
file_count: int
|
|
created_at: datetime = field(default_factory=datetime.now)
|
|
|
|
def to_dict(self) -> dict:
|
|
"""Convert to dictionary for serialization"""
|
|
return {
|
|
'target_disk': self.target_disk,
|
|
'destination_disks': self.destination_disks,
|
|
'operations': [op.to_dict() for op in self.operations],
|
|
'total_size': self.total_size,
|
|
'file_count': self.file_count,
|
|
'created_at': self.created_at.isoformat()
|
|
}
|
|
|
|
|
|
@dataclass
|
|
class ProcessingStats:
|
|
"""Statistics for processing operations"""
|
|
files_processed: int = 0
|
|
bytes_processed: int = 0
|
|
files_succeeded: int = 0
|
|
files_failed: int = 0
|
|
start_time: datetime = field(default_factory=datetime.now)
|
|
|
|
@property
|
|
def elapsed_seconds(self) -> float:
|
|
"""Calculate elapsed time in seconds"""
|
|
return (datetime.now() - self.start_time).total_seconds()
|
|
|
|
@property
|
|
def files_per_second(self) -> float:
|
|
"""Calculate processing rate"""
|
|
elapsed = self.elapsed_seconds
|
|
return self.files_processed / elapsed if elapsed > 0 else 0.0
|
|
|
|
@property
|
|
def bytes_per_second(self) -> float:
|
|
"""Calculate throughput"""
|
|
elapsed = self.elapsed_seconds
|
|
return self.bytes_processed / elapsed if elapsed > 0 else 0.0
|