Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pyo3 = { version = "0.26.0", features = ["generate-import-lib"] }
shellexpand = "3.1.0"
pyo3-async-runtimes = { version = "0.26.0", features = ["tokio-runtime"] }
tokio = { version = "1", features = ["full"] }
russh = { version = "0.56", default-features = false, features = ["flate2", "async-trait", "ring", "rsa"] }
russh = { version = "0.58", default-features = false, features = ["flate2", "async-trait", "ring", "rsa"] }
russh-sftp = "2.1"
async-trait = "0.1"

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ conn.sftp_write(local_path="/path/to/my/file", remote_path="/dest/path/file")

# Read a remote file
contents = conn.sftp_read(remote_path="/dest/path/file")

# Upload an entire local directory recursively
transferred, failed = conn.sftp_put_dir("/local/build/", "/remote/app/")

# Download an entire remote directory recursively
transferred, failed = conn.sftp_get_dir("/remote/logs/", "/local/logs/")
```

📚 **For complete documentation including SCP, file tailing, interactive shells, and more, see [Synchronous Usage](docs/synchronous.md).**
Expand Down
29 changes: 29 additions & 0 deletions docs/asynchronous.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,35 @@ async with AsyncConnection(host="my.test.server", password="pass") as conn:
print(file)
```

### Directory Transfers

Upload or download entire directory trees with a single awaitable call. Both methods return a tuple of `(transferred_files, failed_files)`, where each is a list of file paths.

```python
async with AsyncConnection(host="my.test.server", password="pass") as conn:
# Upload an entire local directory to the remote server
transferred, failed = await conn.sftp_put_dir(
local_path="/local/build/",
remote_path="/remote/app/",
)
if failed:
print(f"Failed to upload: {failed}")

# Download an entire remote directory to a local destination
transferred, failed = await conn.sftp_get_dir(
remote_path="/remote/logs/",
local_path="/local/logs/",
)
```

Optional keyword arguments control symlink, permission, and error-handling behaviour:

| Parameter | Default | Description |
|-----------|---------|-------------|
| `follow_symlinks` | `True` | Follow symlinks; set `False` to skip them |
| `preserve_permissions` | `True` | Mirror source permissions on the destination |
| `fail_fast` | `False` | Raise on the first error instead of collecting failures |

### Concurrent File Operations

```python
Expand Down
36 changes: 36 additions & 0 deletions docs/synchronous.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,42 @@ contents = conn.sftp_read(remote_path="/dest/path/file")
print(contents)
```

### Directory Transfers

Upload or download entire directory trees with a single call. Both methods return a tuple of `(transferred_files, failed_files)`, where each is a list of file paths.

```python
# Upload an entire local directory to the remote server
transferred, failed = conn.sftp_put_dir(
local_path="/local/build/",
remote_path="/remote/app/",
)
if failed:
print(f"Failed to upload: {failed}")

# Download an entire remote directory to a local destination
transferred, failed = conn.sftp_get_dir(
remote_path="/remote/logs/",
local_path="/local/logs/",
)
```

Optional keyword arguments control symlink, permission, and error-handling behaviour:

| Parameter | Default | Description |
|-----------|---------|-------------|
| `follow_symlinks` | `True` | Follow symlinks; set `False` to skip them |
| `preserve_permissions` | `True` | Mirror source permissions on the destination |
| `fail_fast` | `False` | Raise on the first error instead of collecting failures |

```python
# Raise immediately on the first error
conn.sftp_put_dir("/src/", "/dst/", fail_fast=True)

# Skip symlinks and don't mirror permissions
conn.sftp_put_dir("/src/", "/dst/", follow_symlinks=False, preserve_permissions=False)
```

### Copy Files Between Connections

Hussh provides a convenient way to copy files between two remote servers:
Expand Down
Loading
Loading