Files
ftsync/README.md
T
2026-03-25 15:20:16 +03:00

3.5 KiB

ftsync

A terminal-based FTP sync tool built with Ratatui. Local directory is always authoritative — new and modified files are uploaded to the server.


Requirements

  • Rust 1.80+ (install via rustup)
  • OpenSSL development headers (for FTPS/TLS support)
# Debian / Ubuntu
sudo apt install libssl-dev pkg-config

# Arch
sudo pacman -S openssl

# Fedora
sudo dnf install openssl-devel

Build

cargo build --release
# Binary: ./target/release/ftsync

Optionally install system-wide:

cargo install --path .

Running

Option A — environment variables (credentials never written to disk)

FTP_HOST=ftp.example.com \
FTP_USER=ian \
FTP_PASS=secret \
FTP_LOCAL=/home/ian/dist \
FTP_REMOTE=/public_html \
./target/release/ftsync

Full list of env vars:

Variable Description Default
FTP_HOST FTP server hostname or IP —
FTP_PORT FTP port 21
FTP_USER FTP username —
FTP_PASS FTP password —
FTP_LOCAL Local directory to sync from —
FTP_REMOTE Remote directory to sync to —
FTP_TLS Enable FTPS/TLS (1/true/yes) false

Option B — interactive config screen

Run ftsync with no env vars. A config form will appear. Fill in your credentials and press Enter — they are saved to ~/.ftpsync.conf.


Keybindings

Config screen

Key Action
Tab / ↓ Next field
Shift+Tab / ↑ Previous field
Enter Save and go to sync
q / Esc Quit

Sync screen

Key Action
s Start sync
d Dry run (preview only)
c Back to config
q Quit (or abort active sync)

Summary screen

Key Action
s Sync again
c Back to config
q Quit

Config file

Stored at ~/.ftpsync.conf (TOML). Environment variables always override values in this file.

host = "ftp.example.com"
port = 21
user = "ian"
password = "secret"
local_dir = "/home/ian/dist"
remote_dir = "/public_html"
tls = false
excludes = [".git", "node_modules", "__pycache__", ".DS_Store", "Thumbs.db"]

How sync works

  1. Connects to the FTP server (plain or FTPS).
  2. Recursively lists all files on the remote, recording their sizes.
  3. Walks the local directory tree, skipping excluded patterns.
  4. For each local file: if the remote file exists with the same byte size, it is skipped. Otherwise it is uploaded.
  5. Remote directories are created automatically as needed.
  6. The sync task runs on a Tokio async thread; the Ratatui UI stays responsive throughout via an mpsc channel.

Project structure

src/
├── main.rs     Terminal setup, Tokio event loop, keyboard handling
├── app.rs      App state machine (screens, fields, sync state)
├── ftp.rs      FTP/FTPS connection and sync engine (suppaftp)
├── ui.rs       All Ratatui widget rendering (3 screens)
└── config.rs   Config loading/saving, env var overlay