mirror of
https://github.com/kevinveenbirkenbach/create-linux-swapfile.git
synced 2026-08-16 20:02:47 +00:00
feat: package as pip-installable distribution
Turns the loose main.py into the 'swap-forge' distribution with a src layout, shipping both the swap-forge and the older swafo command. A failing swap command no longer produces a traceback: CalledProcessError is caught and reported as "'mkswap' failed with exit code 1" at exit 1, a missing binary as exit 127. Required binaries are declared per filesystem path so an ext4 host is never asked for btrfs tooling. The fstab entry is still written last, after swapon, so a failed activation leaves /etc/fstab untouched. The e2e suite proves that byte for byte across a create, a same-size rerun and a resize cycle, with real fallocate, chmod and file sizes. Adds unit, integration and container-based e2e tests, ruff and markdown/mermaid linting, CodeQL and Dependabot, and pins the core metadata to 2.4 so twine accepts the artifacts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
107
README.md
107
README.md
@@ -1,50 +1,129 @@
|
||||
# SwapForge (swafo) 🔄
|
||||
[](https://github.com/sponsors/kevinveenbirkenbach) [](https://www.patreon.com/c/kevinveenbirkenbach) [](https://buymeacoffee.com/kevinveenbirkenbach) [](https://s.veen.world/paypaldonate)
|
||||
# SwapForge (swap-forge) 🔄
|
||||
|
||||
[](https://github.com/sponsors/kevinveenbirkenbach) [](https://www.patreon.com/c/kevinveenbirkenbach) [](https://buymeacoffee.com/kevinveenbirkenbach) [](https://s.veen.world/paypaldonate)
|
||||
|
||||
[](LICENSE) [](https://github.com/kevinveenbirkenbach/swap-forge/stargazers)
|
||||
|
||||
SwapForge is a simple yet powerful bash script for creating and managing Linux swapfiles. Whether you need to boost system performance or add swap space to your setup, SwapForge automates the process quickly and reliably.
|
||||
SwapForge is a small Python CLI for creating and managing Linux swapfiles. Whether you need to boost system performance or add swap space to your setup, SwapForge automates the process quickly and reliably — and it knows the difference between btrfs and everything else.
|
||||
|
||||
---
|
||||
|
||||
## 🧭 How it works
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["swap-forge SIZE"] --> B["parse SIZE into MiB"]
|
||||
B --> B2{"parsable?"}
|
||||
B2 -- no --> X["Invalid size format - exit 1"]
|
||||
B2 -- yes --> C["findmnt -no FSTYPE /"]
|
||||
C --> D{"root filesystem is btrfs?"}
|
||||
D -- yes --> E["target: /var/swap/swapfile"]
|
||||
D -- no --> F["target: /swapfile"]
|
||||
E --> G["read the size of the existing swapfile"]
|
||||
F --> G
|
||||
G --> H{"same size already?"}
|
||||
H -- yes --> Y["Skipping - exit 0"]
|
||||
H -- no --> I{"a swapfile is already there?"}
|
||||
I -- yes --> J["swapoff, delete it, drop its fstab line"]
|
||||
I -- no --> K
|
||||
J --> K{"root filesystem is btrfs?"}
|
||||
K -- yes --> L["chattr +C, turn compression off, allocate with dd"]
|
||||
K -- no --> M["allocate with fallocate"]
|
||||
L --> N["chmod 600"]
|
||||
M --> N
|
||||
N --> O["mkswap"]
|
||||
O --> P["swapon"]
|
||||
P --> Q["append the entry to /etc/fstab"]
|
||||
```
|
||||
|
||||
The fstab entry is written **after** activation succeeds, so a failed run never leaves a half-written fstab behind.
|
||||
|
||||
---
|
||||
|
||||
## 🛠 Features
|
||||
|
||||
- **Automated Swapfile Creation:** Easily create a swapfile with a specified size.
|
||||
- **Btrfs Aware:** Disables copy-on-write and compression on the swap directory and allocates with `dd`; other filesystems use `fallocate`.
|
||||
- **FSTAB Integration:** Automatically updates `/etc/fstab` to ensure the swapfile is mounted at boot.
|
||||
- **Safety Checks:** Skips swapfile creation if an entry already exists.
|
||||
- **Simple CLI Interface:** Run the script with a single command.
|
||||
- **Safety Checks:** Skips creation when a swapfile of the correct size already exists, and recreates it when the size differs.
|
||||
- **Simple CLI Interface:** Run the command with a single argument.
|
||||
|
||||
---
|
||||
|
||||
## 📥 Installation
|
||||
|
||||
Install SwapForge using [Kevin's Package Manager](https://github.com/kevinveenbirkenbach/package-manager) under the alias `swafo`:
|
||||
|
||||
```bash
|
||||
package-manager install swafo
|
||||
pip install swap-forge
|
||||
```
|
||||
|
||||
This command installs SwapForge globally, making it available as `swafo` in your terminal. 🚀
|
||||
pip is the single supported installation path.
|
||||
|
||||
The package installs **two** identical commands: `swap-forge` (primary) and `swafo` (kept for older documentation and scripts).
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Requirements
|
||||
|
||||
- **Python 3.10+** 🐍
|
||||
- **root privileges** — the tool writes `/etc/fstab` and activates swap
|
||||
- Always required on `PATH`: `findmnt`, `swapoff`, `chmod`, `mkswap`, `swapon`
|
||||
- On a **btrfs** root additionally: `chattr`, `btrfs`, `dd`
|
||||
- On any **other** root filesystem additionally: `fallocate`
|
||||
|
||||
If a required command is missing, the tool exits with code `127` and a one‑line error instead of a traceback.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Usage
|
||||
|
||||
Run SwapForge from the command line by specifying the desired swapfile size. For example, to create a 2G swapfile:
|
||||
Run SwapForge by specifying the desired swapfile size. For example, to create a 2G swapfile:
|
||||
|
||||
```bash
|
||||
swafo 2G
|
||||
sudo swap-forge 2G
|
||||
```
|
||||
|
||||
The script will check if a swapfile entry already exists in `/etc/fstab`. If not, it will create the swapfile, set the correct permissions, format it as swap, activate it, and append the necessary entry to `/etc/fstab`.
|
||||
Accepted sizes are whole numbers with an optional unit: `2048`, `2048M`, `2048MB`, `64G`, `64GB`. Without a unit the value is read as MiB.
|
||||
|
||||
The swapfile location follows the root filesystem:
|
||||
|
||||
| Root filesystem | Swapfile |
|
||||
| --- | --- |
|
||||
| `btrfs` | `/var/swap/swapfile` |
|
||||
| anything else | `/swapfile` |
|
||||
|
||||
SwapForge compares the existing swapfile against the requested size, skips when they match, and otherwise removes the old one — including its `/etc/fstab` line — before creating the new one.
|
||||
|
||||
### Exit codes
|
||||
|
||||
| Code | Meaning |
|
||||
| --- | --- |
|
||||
| `0` | Swapfile is in place, either created or already correct. |
|
||||
| `1` | Invalid size argument, or one of the swap commands failed. |
|
||||
| `2` | Invalid command line arguments. |
|
||||
| `127` | A required command is not installed. |
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Development
|
||||
|
||||
```bash
|
||||
make lint # ruff check + ruff format --check
|
||||
make format # apply ruff format
|
||||
make test # unit + integration tests
|
||||
make test-unit
|
||||
make test-integration
|
||||
make test-e2e # install the package in a container and exercise the CLI
|
||||
```
|
||||
|
||||
Tests run against the working tree — the `Makefile` puts `src/` on `PYTHONPATH`, so no install is needed. Every command execution is mocked and `fstab` handling is exercised against a temporary file, so the suite never touches real swap.
|
||||
|
||||
---
|
||||
|
||||
## 🧑💻 Author
|
||||
|
||||
Developed by **Kevin Veen-Birkenbach**
|
||||
- 📧 [kevin@veen.world](mailto:kevin@veen.world)
|
||||
Developed by **Kevin Veen-Birkenbach**
|
||||
|
||||
- 📧 [kevin@veen.world](mailto:kevin@veen.world)
|
||||
- 🌐 [https://www.veen.world](https://www.veen.world)
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user