Skip to content

Key Concepts

Understanding these core concepts will help you use fscm effectively.

Change Tracking

Every operation in fscm is tracked. When you call file(), run(), or any other function that modifies the system, a Change object is recorded.

import fscm
from fscm import file, run

file("/etc/myapp.conf", "setting=value\n")
run("systemctl restart myapp", sudo=True)

# View all changes
for change in fscm.CHANGELIST:
    print(change)

Output:

FileAdd(filename='/etc/myapp.conf')
CmdRun(cmd='systemctl restart myapp')

Change Types

Change Type Description
FileAdd New file created
FileModify Existing file modified
FileRm File removed
DirAdd Directory created
CmdRun Command executed
PkgAdd Package installed
ChmodModify Permissions changed
ChownModify Ownership changed
SymlinkAdd Symlink created

Why Track Changes?

  1. Audit trail — Know exactly what was modified
  2. Dry-run mode — Preview changes before applying
  3. Idempotency checking — Detect if changes are needed
  4. Debugging — Understand what your script did

Dry-Run Mode

Dry-run mode simulates all operations without making actual changes.

import fscm

# Enable dry-run
fscm.settings.dry_run = True

# These won't actually happen
fscm.s.pkgs_install("nginx")  # Won't install
fscm.file("/etc/config", "x")  # Won't write
fscm.run("rm -rf /")  # Definitely won't run!

# But changes are still tracked
print(fscm.CHANGELIST)  # Shows what WOULD have happened

Best Practice

Always run with --dry-run first, especially on production systems.

System Detection

fscm automatically detects your operating system and uses the appropriate package manager and system commands.

import fscm

# Detect the current system
system = fscm.detect_system()
print(type(system))  # Debian, Arch, or MacOS

# The global 's' object is pre-configured for your system
fscm.s.pkgs_install("nginx")  # Uses apt, pacman, or brew

Supported Systems

System Class Package Manager
Debian/Ubuntu Debian apt-get
Arch Linux Arch pacman
macOS MacOS Homebrew

Manual System Selection

import fscm

# Force a specific system type
fscm.settings.system = fscm.Debian()

The Settings Object

Global configuration is managed through fscm.settings:

import fscm

# Dry-run mode
fscm.settings.dry_run = True

# Sudo password (for automated sudo)
fscm.settings.sudo_password = "secret"

# Disable colored output
fscm.settings.stream_output = False

# Backup settings
fscm.settings.backup_dir = "/var/backups/fscm"
fscm.settings.backup_threshold = 1024 * 1024  # 1MB max

Key Settings

Setting Type Description
dry_run bool Simulate operations
sudo_password str Password for sudo
stream_output bool Show command output
backup_dir Path Where to store backups
backup_threshold int Max file size to backup
container_cmd str Docker or podman

Idempotency

fscm operations are designed to be idempotent — running them multiple times produces the same result.

import fscm

# Running twice has no additional effect
fscm.file("/etc/config", "content")
fscm.file("/etc/config", "content")  # No change, file already matches

# Package installation is idempotent
fscm.s.pkgs_install("nginx")  # Installs nginx
fscm.s.pkgs_install("nginx")  # No-op, already installed

How Idempotency Works

Operation Check Before Acting
file() Compares content hash
mkdir() Checks if dir exists
pkgs_install() Checks if installed
chmod() Compares current mode
chown() Compares current owner

File Backups

Before modifying files, fscm can create backups:

import fscm

# Configure backups
fscm.settings.backup_dir = "/var/backups/fscm"
fscm.settings.backup_threshold = 1024 * 1024  # Skip files > 1MB

# This will backup /etc/nginx/nginx.conf before modifying
fscm.file("/etc/nginx/nginx.conf", new_content)

Backups are stored with timestamps:

/var/backups/fscm/etc/nginx/nginx.conf.20240115_143022

The run() Function

The run() function executes shell commands with many options:

import fscm

# Basic command
result = fscm.run("ls -la")

# With sudo
fscm.run("systemctl restart nginx", sudo=True)

# Capture output
result = fscm.run("cat /etc/hostname")
print(result.stdout)

# Check success
result = fscm.run("some-command", check=False)
if result.ok:
    print("Success!")

# Quiet mode (no output)
fscm.run("apt-get update", quiet=True, sudo=True)

RunReturn Object

result = fscm.run("command")

result.ok          # True if returncode == 0
result.returncode  # Exit code
result.stdout      # Standard output
result.stderr      # Standard error
result.assert_ok() # Raise if failed

Next Steps