Skip to content

Filesystem

filesystem

FileSystem Adapter — atomic filesystem operations with rollback.

Provides safe file/directory creation with transaction support for atomic multi-file operations used during project scaffolding.

FileSystemAdapter

Adapter for atomic filesystem operations.

Supports both single operations and transactions for multi-file atomic operations with rollback on failure.

Source code in packages/axm-init/src/axm_init/adapters/filesystem.py
class FileSystemAdapter:
    """Adapter for atomic filesystem operations.

    Supports both single operations and transactions for multi-file
    atomic operations with rollback on failure.
    """

    def write_file(self, path: Path, content: str) -> bool:
        """Write content to a file, creating parent directories.

        Args:
            path: Target file path.
            content: File content to write.

        Returns:
            True if successful.
        """
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(content)
        return True

    def create_dir(self, path: Path) -> bool:
        """Create a directory (and parents).

        Args:
            path: Directory path to create.

        Returns:
            True if successful.
        """
        path.mkdir(parents=True, exist_ok=True)
        return True

    @contextmanager
    def transaction(self) -> Generator[Transaction, None, None]:
        """Context manager for atomic multi-file operations.

        On success: files are kept.
        On exception: all created files are rolled back.

        Yields:
            Transaction object for tracked operations.
        """
        tx = Transaction()
        try:
            yield tx
            tx.commit()
        except Exception:
            tx.rollback()
            raise
create_dir(path)

Create a directory (and parents).

Parameters:

Name Type Description Default
path Path

Directory path to create.

required

Returns:

Type Description
bool

True if successful.

Source code in packages/axm-init/src/axm_init/adapters/filesystem.py
def create_dir(self, path: Path) -> bool:
    """Create a directory (and parents).

    Args:
        path: Directory path to create.

    Returns:
        True if successful.
    """
    path.mkdir(parents=True, exist_ok=True)
    return True
transaction()

Context manager for atomic multi-file operations.

On success: files are kept. On exception: all created files are rolled back.

Yields:

Type Description
Transaction

Transaction object for tracked operations.

Source code in packages/axm-init/src/axm_init/adapters/filesystem.py
@contextmanager
def transaction(self) -> Generator[Transaction, None, None]:
    """Context manager for atomic multi-file operations.

    On success: files are kept.
    On exception: all created files are rolled back.

    Yields:
        Transaction object for tracked operations.
    """
    tx = Transaction()
    try:
        yield tx
        tx.commit()
    except Exception:
        tx.rollback()
        raise
write_file(path, content)

Write content to a file, creating parent directories.

Parameters:

Name Type Description Default
path Path

Target file path.

required
content str

File content to write.

required

Returns:

Type Description
bool

True if successful.

Source code in packages/axm-init/src/axm_init/adapters/filesystem.py
def write_file(self, path: Path, content: str) -> bool:
    """Write content to a file, creating parent directories.

    Args:
        path: Target file path.
        content: File content to write.

    Returns:
        True if successful.
    """
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(content)
    return True

Transaction dataclass

Transaction context for atomic filesystem operations.

Tracks created files/directories for rollback on failure.

Source code in packages/axm-init/src/axm_init/adapters/filesystem.py
@dataclass
class Transaction:
    """Transaction context for atomic filesystem operations.

    Tracks created files/directories for rollback on failure.
    """

    created_files: list[Path] = field(default_factory=list)
    created_dirs: list[Path] = field(default_factory=list)
    _committed: bool = False

    def write_file(self, path: Path, content: str) -> bool:
        """Write file and track for potential rollback."""
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(content)
        self.created_files.append(path)
        return True

    def create_dir(self, path: Path) -> bool:
        """Create directory and track for potential rollback."""
        path.mkdir(parents=True, exist_ok=True)
        self.created_dirs.append(path)
        return True

    def commit(self) -> None:
        """Mark transaction as committed (no rollback)."""
        self._committed = True

    def rollback(self) -> None:
        """Remove all created files and directories."""
        if self._committed:
            return

        # Remove files first
        for f in reversed(self.created_files):
            try:
                if f.exists():
                    f.unlink()
            except OSError as exc:
                logger.warning("Rollback: failed to remove file %s: %s", f, exc)

        # Remove directories (reverse order for nested)
        for d in reversed(self.created_dirs):
            try:
                if d.exists() and not any(d.iterdir()):
                    d.rmdir()
            except OSError as exc:
                logger.warning("Rollback: failed to remove dir %s: %s", d, exc)
commit()

Mark transaction as committed (no rollback).

Source code in packages/axm-init/src/axm_init/adapters/filesystem.py
def commit(self) -> None:
    """Mark transaction as committed (no rollback)."""
    self._committed = True
create_dir(path)

Create directory and track for potential rollback.

Source code in packages/axm-init/src/axm_init/adapters/filesystem.py
def create_dir(self, path: Path) -> bool:
    """Create directory and track for potential rollback."""
    path.mkdir(parents=True, exist_ok=True)
    self.created_dirs.append(path)
    return True
rollback()

Remove all created files and directories.

Source code in packages/axm-init/src/axm_init/adapters/filesystem.py
def rollback(self) -> None:
    """Remove all created files and directories."""
    if self._committed:
        return

    # Remove files first
    for f in reversed(self.created_files):
        try:
            if f.exists():
                f.unlink()
        except OSError as exc:
            logger.warning("Rollback: failed to remove file %s: %s", f, exc)

    # Remove directories (reverse order for nested)
    for d in reversed(self.created_dirs):
        try:
            if d.exists() and not any(d.iterdir()):
                d.rmdir()
        except OSError as exc:
            logger.warning("Rollback: failed to remove dir %s: %s", d, exc)
write_file(path, content)

Write file and track for potential rollback.

Source code in packages/axm-init/src/axm_init/adapters/filesystem.py
def write_file(self, path: Path, content: str) -> bool:
    """Write file and track for potential rollback."""
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(content)
    self.created_files.append(path)
    return True