Skip to main content

A cross-platform Python deployment framework for automated remote server deployments via SSH

Project description

🌼 PyDaffodil

Cross-Platform Python Deployment Framework

Automate remote server deployments with ease. Transfer files, execute commands, and manage deployments across Windows, macOS, and Linux.

PyPI Version Python Versions Downloads Stars Badge Forks Badge Issues Badge License Badge


📋 Table of Contents

🎯 Overview

PyDaffodil is a powerful, cross-platform Python deployment framework designed to simplify and automate the process of deploying applications to remote servers via SSH. Whether you're deploying to a VPS, cloud instance, or dedicated server, PyDaffodil provides a clean, intuitive API for managing your deployment workflows.

Key Benefits

  • Cross-Platform: Works seamlessly on Windows, macOS, and Linux
  • No Admin Required: Runs without administrator privileges
  • Efficient Transfers: Automatically archives files before transfer for faster deployments
  • Secure: Supports SSH key and password authentication
  • Progress Tracking: Visual progress bars for file transfers and operations
  • Modular: Build reusable deployment steps with a simple, declarative API

✨ Features

Core Capabilities

  • 🔐 Secure SSH Connections: Connect using SSH keys (RSA, DSA, ECDSA, Ed25519) or password authentication
  • 📦 Smart File Transfer: Automatically creates archives before transfer and extracts them on the remote server
  • ⚡ Remote Command Execution: Execute shell commands and SSH commands on remote servers
  • 📁 Directory Management: Create directories and manage file structures on remote servers
  • 🎨 Colored Output: Beautiful, color-coded terminal output for better visibility
  • 📊 Progress Tracking: Real-time progress bars for file operations
  • 🔄 Deployment Workflows: Chain multiple deployment steps together for complex workflows

Technical Features

  • Cross-platform archive creation and extraction (ZIP format)
  • Automatic cleanup of temporary files
  • Comprehensive error handling and reporting
  • Support for hidden files and directories
  • Configurable remote paths and SSH ports
  • Ignore file support (.scpignore)

🚀 Installation

Prerequisites

  • Python 3.6 or higher
  • SSH access to your remote server
  • SCP installed on your local machine (usually comes with SSH)

Install from PyPI

pip install pydaffodil

Verify Installation

from pydaffodil import Daffodil
print("PyDaffodil installed successfully!")

🏃 Quick Start

Here's a simple example to get you started:

from pydaffodil import Daffodil

# Initialize the deployment client
cli = Daffodil(
    remote_user="root",
    remote_host="your-server.com",
    remote_path="/var/www/myapp"
)

# Define deployment steps
steps = [
    {"step": "Build the project", "command": lambda: cli.run_command("npm run build")},
    {"step": "Transfer files", "command": lambda: cli.transfer_files("dist")},
    {"step": "Restart service", "command": lambda: cli.ssh_command("sudo systemctl restart myapp")}
]

# Execute deployment
cli.deploy(steps)

📚 Usage Examples

Basic File Transfer

from pydaffodil import Daffodil

cli = Daffodil(
    remote_user="deploy",
    remote_host="192.168.1.100",
    remote_path="/home/deploy/app"
)

# Transfer files (automatically archived and extracted)
cli.transfer_files("build", destination_path="/home/deploy/app/production")

Using SSH Keys

cli = Daffodil(
    remote_user="deploy",
    remote_host="example.com",
    ssh_key_path="~/.ssh/id_rsa",
    ssh_key_pass="your-passphrase"  # Optional, only if key is encrypted
)

Custom Port and Path

cli = Daffodil(
    remote_user="admin",
    remote_host="server.example.com",
    port=2222,  # Custom SSH port
    remote_path="/opt/myapplication"
)

Complex Deployment Workflow

from pydaffodil import Daffodil

cli = Daffodil(
    remote_user="root",
    remote_host="production.example.com",
    remote_path="/var/www/production"
)

steps = [
    {
        "step": "Build frontend",
        "command": lambda: cli.run_command("cd frontend && npm run build")
    },
    {
        "step": "Build backend",
        "command": lambda: cli.run_command("cd backend && npm run build")
    },
    {
        "step": "Stop services",
        "command": lambda: cli.ssh_command("sudo systemctl stop myapp")
    },
    {
        "step": "Backup current deployment",
        "command": lambda: cli.ssh_command("cp -r /var/www/production /var/www/backup/$(date +%Y%m%d_%H%M%S)")
    },
    {
        "step": "Transfer frontend",
        "command": lambda: cli.transfer_files("frontend/dist", "/var/www/production/frontend")
    },
    {
        "step": "Transfer backend",
        "command": lambda: cli.transfer_files("backend/dist", "/var/www/production/backend")
    },
    {
        "step": "Install dependencies",
        "command": lambda: cli.ssh_command("cd /var/www/production/backend && npm install --production")
    },
    {
        "step": "Start services",
        "command": lambda: cli.ssh_command("sudo systemctl start myapp")
    }
]

cli.deploy(steps)

📖 API Reference

Daffodil Class

Constructor Parameters

  • remote_user (str, required): Username for SSH connection
  • remote_host (str, required): Hostname or IP address of the remote server
  • remote_path (str, optional): Default remote directory path
  • port (int, optional): SSH port number (default: 22)
  • ssh_key_path (str, optional): Path to SSH private key file
  • ssh_key_pass (str, optional): Passphrase for encrypted SSH keys
  • scp_ignore (str, optional): Path to ignore file (default: ".scpignore")

Methods

transfer_files(local_path, destination_path=None)

Transfer files and directories to the remote server. Files are automatically archived before transfer and extracted on the remote server.

  • local_path (str): Local directory or file path to transfer
  • destination_path (str, optional): Remote destination path (defaults to remote_path)
run_command(command)

Execute a shell command on the local machine.

  • command (str): Shell command to execute
ssh_command(command)

Execute a command on the remote server via SSH.

  • command (str): Command to execute on remote server
make_directory(directory_name)

Create a directory on the remote server.

  • directory_name (str): Name of the directory to create
deploy(steps)

Execute a series of deployment steps.

  • steps (list): List of step dictionaries, each containing:
    • step (str): Description of the step
    • command (callable): Lambda function or callable to execute

🔧 Requirements

System Requirements

  • Python 3.6+
  • SCP (usually included with SSH/OpenSSH)

Python Dependencies

  • paramiko >= 2.0.0 - SSH client library
  • tqdm >= 4.60.0 - Progress bars
  • colorama >= 0.4.0 - Cross-platform colored terminal output

🌍 Cross-Platform Support

PyDaffodil is fully cross-platform and has been tested on:

  • Windows 10/11
  • macOS (all recent versions)
  • Linux (Ubuntu, Debian, CentOS, etc.)

The framework automatically handles platform-specific differences in:

  • Archive creation and extraction
  • File path handling
  • SSH key detection
  • Command execution

🔒 Security

PyDaffodil prioritizes security:

  • Supports all major SSH key types (RSA, DSA, ECDSA, Ed25519)
  • Encrypted key support with passphrase protection
  • Secure password authentication (when keys aren't available)
  • No storage of credentials in code
  • Automatic cleanup of temporary files

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

📝 Publishing to PyPI

Automated Publishing (Recommended)

This project uses GitHub Actions to automatically publish to PyPI when a new release is created.

Setup:

  1. Go to your PyPI account settings: https://pypi.org/manage/account/
  2. Create an API token: https://pypi.org/manage/account/token/
  3. Add the token as a GitHub secret:
    • Go to your repository → Settings → Secrets and variables → Actions
    • Click "New repository secret"
    • Name: PYPI_API_TOKEN
    • Value: Your PyPI API token (starts with pypi-)

Publishing:

  1. Update version in setup.py
  2. Commit and push your changes
  3. Create a new release on GitHub (the workflow will automatically publish to PyPI)

Alternatively, you can trigger the workflow manually:

  • Go to Actions → "Publish to PyPI" → Run workflow

Manual Publishing

To publish manually:

  1. Update version in setup.py
  2. Install build tools: pip install build twine
  3. Build package: python -m build
  4. Check package: twine check dist/*
  5. Upload: twine upload dist/*

For testing, use TestPyPI:

twine upload --repository-url https://test.pypi.org/legacy/ dist/*

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

👤 Author

Mark Wayne Menorca

🙏 Acknowledgments

  • Built with Paramiko for SSH functionality
  • Progress bars powered by tqdm
  • Cross-platform colors with Colorama

Made with ❤️ for developers who love automation

⭐ Star this repo if you find it useful!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pydaffodil-1.2.0.tar.gz (18.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pydaffodil-1.2.0-py3-none-any.whl (13.4 kB view details)

Uploaded Python 3

File details

Details for the file pydaffodil-1.2.0.tar.gz.

File metadata

  • Download URL: pydaffodil-1.2.0.tar.gz
  • Upload date:
  • Size: 18.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for pydaffodil-1.2.0.tar.gz
Algorithm Hash digest
SHA256 66bd7d09914850181a10e4a449ed97aba2a0ba383cf38be2c089d671c1ab1e5e
MD5 63e1c92b5e7a35beaa2280cfcb7a5787
BLAKE2b-256 b28979c57939f2f8269e336e50b2c0daff1b90bbd35bd79110ef216b5e02b9bc

See more details on using hashes here.

File details

Details for the file pydaffodil-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: pydaffodil-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 13.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for pydaffodil-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 106bada1a210e8750661baad1d670dfa27052c720bf29e436f95cd93a350c198
MD5 c45cfa03f269480cf3a246e321c5f8c7
BLAKE2b-256 c7761cd48a7e583a837a621e89f16c881e06eb0fc2de706c2044fdaf50b438d3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page