Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
files_copied, bytes_transferred = conn.sftp_put_dir("/local/build/", "/remote/app/")

# Download an entire remote directory recursively
files_copied, bytes_transferred = 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
26 changes: 26 additions & 0 deletions docs/asynchronous.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,32 @@ 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 `(files_copied, bytes_transferred)`.

```python
async with AsyncConnection(host="my.test.server", password="pass") as conn:
# Upload an entire local directory to the remote server
files_copied, bytes_transferred = await conn.sftp_put_dir(
local_path="/local/build/",
remote_path="/remote/app/",
)

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

Optional keyword arguments control symlink and permission behaviour:

| Parameter | Default | Description |
|-----------|---------|-------------|
| `follow_symlinks` | `True` | Follow symlinks; set `False` to skip them |
| `preserve_permissions` | `True` | Mirror source permissions on the destination |

### Concurrent File Operations

```python
Expand Down
29 changes: 29 additions & 0 deletions docs/synchronous.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,35 @@ 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 `(files_copied, bytes_transferred)`.

```python
# Upload an entire local directory to the remote server
files_copied, bytes_transferred = conn.sftp_put_dir(
local_path="/local/build/",
remote_path="/remote/app/",
)

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

Optional keyword arguments control symlink and permission behaviour:

| Parameter | Default | Description |
|-----------|---------|-------------|
| `follow_symlinks` | `True` | Follow symlinks; set `False` to skip them |
| `preserve_permissions` | `True` | Mirror source permissions on the destination |

```python
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