diff --git a/README.md b/README.md index 4d06d78..4a38db5 100644 --- a/README.md +++ b/README.md @@ -37,21 +37,20 @@ Positional arguments: Options: - `--target-root TARGET_ROOT` - subfolder on target to synchronize to + subfolder on target to synchronize to (default: "") - `--target-port TARGET_PORT` - SSH port on target + SSH port on target (default: 22) - `--on-change ON_CHANGE` - command to be executed on remote host after any file change + command to be executed on remote host after any file change (default: None) - `--mutex-interval MUTEX_INTERVAL` - interval in which mutex is updated + interval in which mutex is updated (default: 10 seconds) ### 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. -- By default `.git/` folders are not synchronized. -- All files and directories from the `.gitignore` of any source directory are also excluded from synchronization. - 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`. - If you pass a VSCode workspace file as `source`, LiveSync will synchronize each directory listed in the `folders` section. ## Installation diff --git a/livesync/folder.py b/livesync/folder.py index de8dc76..96b45f8 100644 --- a/livesync/folder.py +++ b/livesync/folder.py @@ -9,6 +9,7 @@ import watchfiles KWONLY_SLOTS = {'kw_only': True, 'slots': True} if sys.version_info >= (3, 10) else {} +DEFAULT_IGNORES = ['.git/', '__pycache__/', '.DS_Store', '*.tmp', '.env'] def run_subprocess(command: str, *, quiet: bool = False) -> None: @@ -36,7 +37,7 @@ def __init__(self, local_dir: Path, target: Target) -> None: # from https://stackoverflow.com/a/22090594/3419103 match_pattern = pathspec.patterns.gitwildmatch.GitWildMatchPattern - self._ignore_spec = pathspec.PathSpec.from_lines(match_pattern, self.get_excludes()) + self._ignore_spec = pathspec.PathSpec.from_lines(match_pattern, self.get_ignores()) self._stop_watching = asyncio.Event() @@ -48,17 +49,11 @@ def target_path(self) -> Path: def ssh_path(self) -> str: return f'{self.target.host}:{self.target_path}' - def get_excludes(self) -> List[str]: - return ['.git/', '__pycache__/', '.DS_Store', '*.tmp', '.env'] + \ - self._parse_ignore_file(self.local_path / '.syncignore') + \ - self._parse_ignore_file(self.local_path / '.gitignore') - - @staticmethod - def _parse_ignore_file(path: Path) -> List[str]: + def get_ignores(self) -> List[str]: + path = self.local_path / '.syncignore' if not path.is_file(): - return [] - with path.open() as f: - return [line.strip() for line in f.readlines() if not line.startswith('#')] + path.write_text('\n'.join(DEFAULT_IGNORES)) + return [line.strip() for line in path.read_text().splitlines() if not line.startswith('#')] def get_summary(self) -> str: summary = f'{self.local_path} --> {self.ssh_path}\n' @@ -90,7 +85,7 @@ def stop_watching(self) -> None: def sync(self, post_sync_command: Optional[str] = None) -> None: args = '--prune-empty-dirs --delete -avz --checksum --no-t' # args += ' --mkdirs' # INFO: this option is not available in rsync < 3.2.3 - args += ''.join(f' --exclude="{e}"' for e in self.get_excludes()) + args += ''.join(f' --exclude="{e}"' for e in self.get_ignores()) args += f' -e "ssh -p {self.target.port}"' run_subprocess(f'rsync {args} {self.local_path}/ {self.ssh_path}/', quiet=True) if post_sync_command: diff --git a/livesync/livesync.py b/livesync/livesync.py index 0c4ca65..2541c09 100755 --- a/livesync/livesync.py +++ b/livesync/livesync.py @@ -15,7 +15,9 @@ def git_summary(folders: List[Folder]) -> str: async def async_main() -> None: - parser = argparse.ArgumentParser(description='Repeatedly synchronize local directories with remote machine') + parser = argparse.ArgumentParser( + description='Repeatedly synchronize local directories with remote machine', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('source', type=str, help='local source folder or VSCode workspace file') parser.add_argument('--target-root', type=str, default='', help='subfolder on target to synchronize to') parser.add_argument('--target-port', type=int, default=22, help='SSH port on target') diff --git a/tests/test_syncing_with_git_summary.sh b/tests/test_syncing_with_git_summary.sh index 9e53ca4..c3cb7be 100755 --- a/tests/test_syncing_with_git_summary.sh +++ b/tests/test_syncing_with_git_summary.sh @@ -5,6 +5,7 @@ set -e # create source folder mkdir -p /root/my_project echo 'file content' > /root/my_project/file.txt +echo '.syncignore' > /root/my_project/.gitignore # create git repository cd /root/my_project @@ -13,6 +14,7 @@ git config --global user.email "livesync@zauberzeug.com" git config --global user.name "Zauberzeug" git init git add file.txt +git add .gitignore git commit -m 'initial commit' # livesync should create the target file