Skip to content

Changes

Change tracking for audit trails and dry-run support.

CHANGELIST

The global list of all changes made during execution.

import fscm

fscm.file("/etc/config", "content")
fscm.run("systemctl restart myapp", sudo=True)

for change in fscm.CHANGELIST:
    print(change)

Change Types

All changes inherit from the Change base class.

File Changes

FileAdd

A new file was created.

@dataclass
class FileAdd(Change):
    filename: str

FileModify

An existing file was modified.

@dataclass
class FileModify(Change):
    filename: str
    diff: str

FileRm

A file was removed.

@dataclass
class FileRm(Change):
    filename: str

Directory Changes

DirAdd

A directory was created.

@dataclass
class DirAdd(Change):
    dirname: str

Permission Changes

ChmodModify

File permissions were changed.

@dataclass
class ChmodModify(Change):
    path: str
    mode: str
    old_mode: str

ChownModify

File ownership was changed.

@dataclass
class ChownModify(Change):
    path: str
    owner: str
    old_owner: str

SymlinkAdd

A symbolic link was created.

@dataclass
class SymlinkAdd(Change):
    link: str
    target: str

Command Changes

CmdRun

A command was executed.

@dataclass
class CmdRun(Change):
    cmd: str
    returncode: int
    stdout: str
    stderr: str

Package Changes

PkgAdd

A package was installed.

@dataclass
class PkgAdd(Change):
    name: str
    version: str
    manager: str  # "apt", "pacman", "brew"

Working with Changes

Iterate Changes

for change in fscm.CHANGELIST:
    print(f"{type(change).__name__}: {change}")

Filter by Type

# Get all file changes
file_changes = [c for c in fscm.CHANGELIST if isinstance(c, fscm.FileAdd)]

# Get all package installations
packages = [c for c in fscm.CHANGELIST if isinstance(c, fscm.PkgAdd)]

Check if Changes Were Made

if fscm.CHANGELIST:
    print(f"Made {len(fscm.CHANGELIST)} changes")
else:
    print("No changes needed")

Clear Changes

fscm.CHANGELIST.clear()

Change Properties

All Change objects have:

Property Type Description
timestamp datetime When the change occurred
msg str Human-readable description

Example: Audit Report

import fscm
from datetime import datetime

def generate_audit_report():
    """Generate a report of all changes."""
    report = []
    report.append(f"Audit Report - {datetime.now()}")
    report.append("=" * 50)

    for change in fscm.CHANGELIST:
        timestamp = change.timestamp.strftime("%H:%M:%S")
        report.append(f"[{timestamp}] {type(change).__name__}")
        report.append(f"  {change.msg}")

    report.append("=" * 50)
    report.append(f"Total changes: {len(fscm.CHANGELIST)}")

    return "\n".join(report)

# After running your configuration
print(generate_audit_report())

Example: Conditional Restart

import fscm

# Configure the application
fscm.file("/etc/myapp/config.yaml", new_config)
fscm.file("/etc/myapp/secrets.env", secrets)

# Only restart if config files changed
config_changed = any(
    isinstance(c, (fscm.FileAdd, fscm.FileModify))
    and "/etc/myapp/" in str(getattr(c, 'filename', ''))
    for c in fscm.CHANGELIST
)

if config_changed:
    fscm.run("systemctl restart myapp", sudo=True)