LiveSync


NameLiveSync JSON
Version 0.3.4 PyPI version JSON
download
home_pagehttps://github.com/zauberzeug/livesync
SummaryRepeatedly synchronize local workspace with a (slow) remote machine
upload_time2024-07-04 16:14:30
maintainerNone
docs_urlNone
authorZauberzeug GmbH
requires_python>=3.7
licenseMIT
keywords sync remote watch filesystem development deploy live hot reload
VCS
bugtrack_url
requirements pathspec watchfiles
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # LiveSync

Repeatedly synchronize local workspace with a (slow) remote machine.
It is available as [PyPI package](https://pypi.org/project/livesync/) and hosted on [GitHub](https://github.com/zauberzeug/livesync).

[![PyPI version](https://badge.fury.io/py/livesync.svg)](https://pypi.org/project/livesync/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/livesync)](https://pypi.org/project/livesync/)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/zauberzeug/livesync)](https://github.com/zauberzeug/livesync/graphs/commit-activity)
[![GitHub issues](https://img.shields.io/github/issues/zauberzeug/livesync)](https://github.com/zauberzeug/livesync/issues)
[![GitHub license](https://img.shields.io/github/license/zauberzeug/livesync)](https://github.com/zauberzeug/livesync/blob/main/LICENSE)

## Use Case

[VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview) and similar tools are great as long as your remote machine is powerful enough.
But if your target is a Raspberry Pi, Jetson Nano/Xavier/Orin, Beagle Board or similar, it feels like coding in jelly.
Especially if you run powerful extensions like Pylance, GitHub Copilot or Duet AI.
LiveSync solves this by watching your code for changes and just copying the modifications to the slow remote machine.
So you can develop on your own machine (and run tests there in the background) while all your changes appear also on the remote.
It works best if you have some kind of reload mechanism in place on the target ([NiceGUI](https://nicegui.io), [FastAPI](https://fastapi.tiangolo.com/) or [Flask](https://flask.palletsprojects.com/) for example).

## Usage

### BASH

```bash
livesync <source> <username>@<host>
```

LiveSync uses rsync (SSH) to copy the files, so the `<username>@<host>` must be accessible via SSH (ideally by key, not password or passphrase, because it will be called over and over).

Press `CTRL-C` to abort the synchronization.

Positional arguments:

- `<source>`
  local folder
- `<target>`
  target user, host and path (e.g. user@host:~/path; path defaults to source folder name in home directory)
- `<rsync_args>`
  arbitrary rsync parameters after "--"

Options:

- `--ssh-port SSH_PORT`
  SSH port on target (default: 22)
- `--on-change ON_CHANGE`
  command to be executed on remote host after any file change (default: None)
- `--mutex-interval MUTEX_INTERVAL`
  interval in which mutex is updated (default: 10 seconds)
- `--ignore-mutex`
  ignore mutex (use with caution) (default: False)
- `--no-watch`
  don't keep watching the copied folders for changes after the sync (default: False)

### Python

Simple example (where `robot` is the ssh hostname of the target system):

```py
from livesync import Folder, sync

sync(
    Folder('.', 'robot:~/navigation'),
    Folder('../rosys', 'robot:~/rosys'),
)
```

The `sync` call will block until the script is aborted.
Only if `watch=False` is used, the `sync` call will end after copying the folders to the target once.
The `Folder` class allows to set the `port` and an `on_change` bash command which is executed after a sync has been performed.
Via the `rsync_args` build method you can pass additional options to configure rsync.

Advanced example:

```py
import argparse
from livesync import Folder, sync

parser = argparse.ArgumentParser(description='Sync local code with robot.')
parser.add_argument('robot', help='Robot hostname')

args = parser.parse_args()

touch = 'touch ~/robot/main.py'
sync(
    Folder('.', f'{args.robot}:~/navigation', on_change='touch ~/navigation/main.py'),
    Folder('../rosys', f'{args.robot}:~/rosys').rsync_args(add='-L', remove='--checksum'),
    mutex_interval=30,
)
```

### Notes

- We suggest you have some auto-reloading in place on the (slow) target machine, like [NiceGUI](https://nicegui.io).
- Only one user per target host should run LiveSync at a time. Therefore LiveSync provides a mutex mechanism.
- You can create a `.syncignore` file in any source directory to skip additional files and directories from syncing.
- If a `.syncignore` file doesn't exist, it is automatically created containing `.git/`, `__pycache__/`, `.DS_Store`, `*.tmp`, and `.env`.

## Installation

```bash
python3 -m pip install livesync
```

## Development

For development we suggest to use the following instructions instead of the normal pip installation:

```bash
git clone git@github.com:zauberzeug/livesync.git
cd livesync
python3 -m pip uninstall livesync # remove previous installed version
python3 -m pip install -e .
```

Now you can change the code and call the `livesync` command from your `$PATH` variable with the modified code.

## Testing

We have build a small testing infrastructure with two docker containers.
See [tests/README.md](https://github.com/zauberzeug/livesync/blob/main/tests/README.md) for details.

## Releases

Just create and push a new tag with the new version name (v0.2.1 for example).
After a successful build a new release will be created.
This should be edited to describe the changes in the release notes.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/zauberzeug/livesync",
    "name": "LiveSync",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "sync remote watch filesystem development deploy live hot reload",
    "author": "Zauberzeug GmbH",
    "author_email": "info@zauberzeug.com",
    "download_url": "https://files.pythonhosted.org/packages/bf/d6/fed2ee6f4b1ec828c8c5c4775d3d4384599dc4bc349416a67d3ba2ef312d/LiveSync-0.3.4.tar.gz",
    "platform": null,
    "description": "# LiveSync\n\nRepeatedly synchronize local workspace with a (slow) remote machine.\nIt is available as [PyPI package](https://pypi.org/project/livesync/) and hosted on [GitHub](https://github.com/zauberzeug/livesync).\n\n[![PyPI version](https://badge.fury.io/py/livesync.svg)](https://pypi.org/project/livesync/)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/livesync)](https://pypi.org/project/livesync/)\n[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/zauberzeug/livesync)](https://github.com/zauberzeug/livesync/graphs/commit-activity)\n[![GitHub issues](https://img.shields.io/github/issues/zauberzeug/livesync)](https://github.com/zauberzeug/livesync/issues)\n[![GitHub license](https://img.shields.io/github/license/zauberzeug/livesync)](https://github.com/zauberzeug/livesync/blob/main/LICENSE)\n\n## Use Case\n\n[VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview) and similar tools are great as long as your remote machine is powerful enough.\nBut if your target is a Raspberry Pi, Jetson Nano/Xavier/Orin, Beagle Board or similar, it feels like coding in jelly.\nEspecially if you run powerful extensions like Pylance, GitHub Copilot or Duet AI.\nLiveSync solves this by watching your code for changes and just copying the modifications to the slow remote machine.\nSo you can develop on your own machine (and run tests there in the background) while all your changes appear also on the remote.\nIt works best if you have some kind of reload mechanism in place on the target ([NiceGUI](https://nicegui.io), [FastAPI](https://fastapi.tiangolo.com/) or [Flask](https://flask.palletsprojects.com/) for example).\n\n## Usage\n\n### BASH\n\n```bash\nlivesync <source> <username>@<host>\n```\n\nLiveSync uses rsync (SSH) to copy the files, so the `<username>@<host>` must be accessible via SSH (ideally by key, not password or passphrase, because it will be called over and over).\n\nPress `CTRL-C` to abort the synchronization.\n\nPositional arguments:\n\n- `<source>`\n  local folder\n- `<target>`\n  target user, host and path (e.g. user@host:~/path; path defaults to source folder name in home directory)\n- `<rsync_args>`\n  arbitrary rsync parameters after \"--\"\n\nOptions:\n\n- `--ssh-port SSH_PORT`\n  SSH port on target (default: 22)\n- `--on-change ON_CHANGE`\n  command to be executed on remote host after any file change (default: None)\n- `--mutex-interval MUTEX_INTERVAL`\n  interval in which mutex is updated (default: 10 seconds)\n- `--ignore-mutex`\n  ignore mutex (use with caution) (default: False)\n- `--no-watch`\n  don't keep watching the copied folders for changes after the sync (default: False)\n\n### Python\n\nSimple example (where `robot` is the ssh hostname of the target system):\n\n```py\nfrom livesync import Folder, sync\n\nsync(\n    Folder('.', 'robot:~/navigation'),\n    Folder('../rosys', 'robot:~/rosys'),\n)\n```\n\nThe `sync` call will block until the script is aborted.\nOnly if `watch=False` is used, the `sync` call will end after copying the folders to the target once.\nThe `Folder` class allows to set the `port` and an `on_change` bash command which is executed after a sync has been performed.\nVia the `rsync_args` build method you can pass additional options to configure rsync.\n\nAdvanced example:\n\n```py\nimport argparse\nfrom livesync import Folder, sync\n\nparser = argparse.ArgumentParser(description='Sync local code with robot.')\nparser.add_argument('robot', help='Robot hostname')\n\nargs = parser.parse_args()\n\ntouch = 'touch ~/robot/main.py'\nsync(\n    Folder('.', f'{args.robot}:~/navigation', on_change='touch ~/navigation/main.py'),\n    Folder('../rosys', f'{args.robot}:~/rosys').rsync_args(add='-L', remove='--checksum'),\n    mutex_interval=30,\n)\n```\n\n### Notes\n\n- We suggest you have some auto-reloading in place on the (slow) target machine, like [NiceGUI](https://nicegui.io).\n- Only one user per target host should run LiveSync at a time. Therefore LiveSync provides a mutex mechanism.\n- You can create a `.syncignore` file in any source directory to skip additional files and directories from syncing.\n- If a `.syncignore` file doesn't exist, it is automatically created containing `.git/`, `__pycache__/`, `.DS_Store`, `*.tmp`, and `.env`.\n\n## Installation\n\n```bash\npython3 -m pip install livesync\n```\n\n## Development\n\nFor development we suggest to use the following instructions instead of the normal pip installation:\n\n```bash\ngit clone git@github.com:zauberzeug/livesync.git\ncd livesync\npython3 -m pip uninstall livesync # remove previous installed version\npython3 -m pip install -e .\n```\n\nNow you can change the code and call the `livesync` command from your `$PATH` variable with the modified code.\n\n## Testing\n\nWe have build a small testing infrastructure with two docker containers.\nSee [tests/README.md](https://github.com/zauberzeug/livesync/blob/main/tests/README.md) for details.\n\n## Releases\n\nJust create and push a new tag with the new version name (v0.2.1 for example).\nAfter a successful build a new release will be created.\nThis should be edited to describe the changes in the release notes.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Repeatedly synchronize local workspace with a (slow) remote machine",
    "version": "0.3.4",
    "project_urls": {
        "Homepage": "https://github.com/zauberzeug/livesync"
    },
    "split_keywords": [
        "sync",
        "remote",
        "watch",
        "filesystem",
        "development",
        "deploy",
        "live",
        "hot",
        "reload"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f4fec5bfc498121735833ad21bb1b65ad52daf913c9a18b71d672c71c38074c0",
                "md5": "983dac245e33d647448ab964fa19f5fc",
                "sha256": "aa6d529fc281a82b6640171f566b6c20b3d29edc3fb51cf5e1bbd5f2b13b448b"
            },
            "downloads": -1,
            "filename": "LiveSync-0.3.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "983dac245e33d647448ab964fa19f5fc",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 9111,
            "upload_time": "2024-07-04T16:14:28",
            "upload_time_iso_8601": "2024-07-04T16:14:28.852662Z",
            "url": "https://files.pythonhosted.org/packages/f4/fe/c5bfc498121735833ad21bb1b65ad52daf913c9a18b71d672c71c38074c0/LiveSync-0.3.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "bfd6fed2ee6f4b1ec828c8c5c4775d3d4384599dc4bc349416a67d3ba2ef312d",
                "md5": "30b7d6e3be732fe38433e0cccacaadc8",
                "sha256": "1748c4b2ce7820a6307b0e984a2d7844d74fa8f4a0c4d8f0e6b9a05a3aea34bb"
            },
            "downloads": -1,
            "filename": "LiveSync-0.3.4.tar.gz",
            "has_sig": false,
            "md5_digest": "30b7d6e3be732fe38433e0cccacaadc8",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 7223,
            "upload_time": "2024-07-04T16:14:30",
            "upload_time_iso_8601": "2024-07-04T16:14:30.348690Z",
            "url": "https://files.pythonhosted.org/packages/bf/d6/fed2ee6f4b1ec828c8c5c4775d3d4384599dc4bc349416a67d3ba2ef312d/LiveSync-0.3.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-07-04 16:14:30",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "zauberzeug",
    "github_project": "livesync",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "pathspec",
            "specs": []
        },
        {
            "name": "watchfiles",
            "specs": []
        }
    ],
    "lcname": "livesync"
}
        
Elapsed time: 0.29341s