Merge pull request #76 from narrrl/chore/release-3.7.0

chore(release): 3.7.0
This commit is contained in:
nvrl authored and GitHub committed 2026-11-02 15:34:08 +01:00
commit 7ab14bb8f7
9 files changed
+59 -19

No files matched your search

Generated
+4 -4
View File
@@ -3520,7 +3520,7 @@ checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4"
[[package]] [[package]]
name = "pdfs-cli" name = "pdfs-cli"
version = "3.6.0" version = "3.7.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
@@ -3536,7 +3536,7 @@ dependencies = [
[[package]] [[package]]
name = "pdfs-core" name = "pdfs-core"
version = "3.6.0" version = "3.7.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base64 0.23.1", "base64 0.23.1",
@@ -3563,7 +3563,7 @@ dependencies = [
[[package]] [[package]]
name = "pdfs-fuse" name = "pdfs-fuse"
version = "3.6.0" version = "3.7.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base64 0.23.1", "base64 0.23.1",
@@ -3585,7 +3585,7 @@ dependencies = [
[[package]] [[package]]
name = "pdfs-gui" name = "pdfs-gui"
version = "3.6.0" version = "3.7.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-channel", "async-channel",
+1 -1
View File
@@ -3,7 +3,7 @@ resolver = "2"
members = ["crates/pdfs-core", "crates/pdfs-fuse", "crates/pdfs-cli", "crates/pdfs-gui"] members = ["crates/pdfs-core", "crates/pdfs-fuse", "crates/pdfs-cli", "crates/pdfs-gui"]
[workspace.package] [workspace.package]
version = "3.6.0" version = "3.7.0"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
authors = ["Nils Pukropp <contact@narl.io>"] authors = ["Nils Pukropp <contact@narl.io>"]
+19 -9
View File
@@ -1036,10 +1036,7 @@ fn cmd_devices(action: DeviceCmd) -> Result<()> {
CtlResponse::Devices { items } if items.is_empty() => println!("No devices."), CtlResponse::Devices { items } if items.is_empty() => println!("No devices."),
CtlResponse::Devices { items } => { CtlResponse::Devices { items } => {
for d in items { for d in items {
let sync = d let sync = last_synced(d.last_sync);
.last_sync
.map(|t| t.to_string())
.unwrap_or_else(|| "never".to_string());
let tag = match (d.adopted, d.this_device) { let tag = match (d.adopted, d.this_device) {
(true, _) => " *adopted*", (true, _) => " *adopted*",
(false, true) => " *this machine*", (false, true) => " *this machine*",
@@ -1130,11 +1127,7 @@ fn cmd_sync(action: SyncCmd) -> Result<()> {
} }
CtlResponse::SyncFolders { items } => { CtlResponse::SyncFolders { items } => {
for f in items { for f in items {
let sync = if f.last_sync == 0 { let sync = last_synced(Some(f.last_sync));
"never".to_string()
} else {
f.last_sync.to_string()
};
// A queued switch is reported as the mode the folder is moving // A queued switch is reported as the mode the folder is moving
// to, so `sync list` never reads as if the request was dropped. // to, so `sync list` never reads as if the request was dropped.
let mode = match &f.pending_mode { let mode = match &f.pending_mode {
@@ -1915,6 +1908,15 @@ fn format_epoch(secs: i64) -> String {
format!("{m:02}-{d:02} {h:02}:{mi:02}") format!("{m:02}-{d:02} {h:02}:{mi:02}")
} }
/// The `synced:` column of `sync list` and `devices list`: when the last pass
/// finished, or `never`. The daemon reports 0 for a folder that never synced.
fn last_synced(secs: Option<i64>) -> String {
match secs {
Some(secs) if secs > 0 => format_epoch(secs),
_ => "never".to_string(),
}
}
fn cmd_leave(uid: String) -> Result<()> { fn cmd_leave(uid: String) -> Result<()> {
ok_or_bail(control_request(CtlRequest::LeaveShared { uid })?) ok_or_bail(control_request(CtlRequest::LeaveShared { uid })?)
} }
@@ -4452,6 +4454,14 @@ mod login_wait_tests {
assert_eq!(format_epoch_utc(-86_400), "1969-12-31"); assert_eq!(format_epoch_utc(-86_400), "1969-12-31");
} }
#[test]
fn last_synced_shows_a_time_not_epoch_seconds() {
// B278: issue #46 showed `synced: 1793570850`.
assert_eq!(last_synced(Some(1_793_570_850)), "11-01 22:07");
assert_eq!(last_synced(Some(0)), "never");
assert_eq!(last_synced(None), "never");
}
#[test] #[test]
fn a_forged_looking_invitation_is_flagged_not_stated() { fn a_forged_looking_invitation_is_flagged_not_stated() {
let mut entry = pdfs_core::control::DirEntry { let mut entry = pdfs_core::control::DirEntry {
+24 -1
View File
@@ -109,6 +109,7 @@ a live account since.
| Entry | Title | | Entry | Title |
|---|---| |---|---|
| [B278](#b278--sync-list-and-devices-list-show-the-last-sync-as-epoch-seconds) | `sync list` and `devices list` show the last sync as epoch seconds |
| [B277](#b277--my-files-mounted-over-a-folder-with-files-in-it-and-hid-them) | My files mounted over a folder with files in it, and hid them | | [B277](#b277--my-files-mounted-over-a-folder-with-files-in-it-and-hid-them) | My files mounted over a folder with files in it, and hid them |
| [B274](#b274--opening-a-file-for-writing-fails-with-eio-while-its-queued-revision-lands) | Opening a file for writing fails with EIO while its queued revision lands | | [B274](#b274--opening-a-file-for-writing-fails-with-eio-while-its-queued-revision-lands) | Opening a file for writing fails with EIO while its queued revision lands |
| [B272](#b272--after-a-folder-is-removed-and-added-again-its-file-events-go-to-the-old-id) | After a folder is removed and added again, its file events go to the old id | | [B272](#b272--after-a-folder-is-removed-and-added-again-its-file-events-go-to-the-old-id) | After a folder is removed and added again, its file events go to the old id |
@@ -380,6 +381,26 @@ a live account since.
Newest first. Newest first.
### B278 — `sync list` and `devices list` show the last sync as epoch seconds
**Status:** Fixed, not verified live
**Found:** 2026-11-02, issue #46. The reporter's `pdfs sync list` on 3.6.0 read
`synced: 1793570850`, a pass that finished at 2026-11-01 22:07 UTC.
**Where:** `cmd_sync` and `cmd_devices` in `crates/pdfs-cli/src/main.rs`
**Repro:** Let a synced folder finish one pass and run `pdfs sync list`, or `pdfs devices list`
on an account with a device that synced.
**Cause.** Both commands printed `last_sync` with `to_string()`. The activity feed already
formats the same epoch seconds with `format_epoch`.
**Fix.** Both columns go through `last_synced`, which prints `MM-DD HH:MM` in UTC like
`pdfs activity`, and `never` for 0 or no value. `--json` output is unchanged.
**Test:** `last_synced_shows_a_time_not_epoch_seconds` in `crates/pdfs-cli/src/main.rs`.
---
### B277 — My files mounted over a folder with files in it, and hid them ### B277 — My files mounted over a folder with files in it, and hid them
**Status:** Fixed, not verified live **Status:** Fixed, not verified live
@@ -575,7 +596,9 @@ folder list has now.
**Status:** Fixed, not verified live **Status:** Fixed, not verified live
**Found:** 2026-10-31, code audit after issue #46: a folder of about 19,900 items restored on a **Found:** 2026-10-31, code audit after issue #46: a folder of about 19,900 items restored on a
second computer sat at `scanning…` with nothing downloaded, and the journal showed second computer sat at `scanning…` with nothing downloaded, and the journal showed
`RequestTimeout (http 408)`. `RequestTimeout (http 408)`. On 2026-11-01 the reporter's 3.6.0 journal showed the same pass
failing four times in four minutes with `reconcile failed id=1 error=enumerate …: HTTP transport
error`, after the laptop woke from sleep; a later pass finished.
**Where:** `walk_remote` in `crates/pdfs-fuse/src/sync.rs` **Where:** `walk_remote` in `crates/pdfs-fuse/src/sync.rs`
**Repro:** Restore or add a mirror folder with tens of thousands of items on Drive, on a link **Repro:** Restore or add a mirror folder with tens of thousands of items on Drive, on a link
+7
View File
@@ -11,6 +11,10 @@ scratch (user data in `staging/` and `recovery/` is never touched by this).
## [Unreleased] ## [Unreleased]
## [3.7.0] — 2026-11-02
Schema: **44**, unchanged.
### Added ### Added
- **The app and the tray say why your Drive does not open** (B263, #40). When the service runs - **The app and the tray say why your Drive does not open** (B263, #40). When the service runs
@@ -78,6 +82,9 @@ scratch (user data in `staging/` and `recovery/` is never touched by this).
- **A restore that skipped folders is reported as failed**, with the reason for each, instead of - **A restore that skipped folders is reported as failed**, with the reason for each, instead of
"restored 0 folder(s)" as a success (B269). "restored 0 folder(s)" as a success (B269).
- **`pdfs sync list` and `pdfs devices list` show when a folder last synced as a time**, such as
`synced: 11-01 22:07` in UTC like `pdfs activity`, instead of seconds since 1970 (B278, #46).
- **"You're offline" no longer appears for a cache or database error** when pinning, unpinning, - **"You're offline" no longer appears for a cache or database error** when pinning, unpinning,
searching or loading a folder (B266, #38). The app shows the actual error. searching or loading a folder (B266, #38). The app shows the actual error.
+1 -1
View File
@@ -102,7 +102,7 @@ That URL follows `main`. To stay on releases, pin the input to a release tag ins
the tag to update: the tag to update:
```nix ```nix
inputs.proton-drive-linux.url = "github:narrrl/proton-drive-linux/v3.6.0"; inputs.proton-drive-linux.url = "github:narrrl/proton-drive-linux/v3.7.0";
``` ```
Each release tag is built with Nix before the release is published. Each release tag is built with Nix before the release is published.
+1 -1
View File
@@ -9,7 +9,7 @@
# Build + install: cd packaging && makepkg -fi # Build + install: cd packaging && makepkg -fi
pkgname=proton-drive-linux pkgname=proton-drive-linux
pkgver=3.6.0 pkgver=3.7.0
pkgrel=1 pkgrel=1
pkgdesc="Unofficial Proton Drive client for Linux: files-on-demand FUSE mount, CLI, GTK4 app + tray" pkgdesc="Unofficial Proton Drive client for Linux: files-on-demand FUSE mount, CLI, GTK4 app + tray"
arch=('x86_64') arch=('x86_64')
+1 -1
View File
@@ -10,7 +10,7 @@
# Match Arch PKGBUILD `!lto` — LTO has broken some GTK/Rust links in practice. # Match Arch PKGBUILD `!lto` — LTO has broken some GTK/Rust links in practice.
%global _lto_cflags %{nil} %global _lto_cflags %{nil}
%{!?version: %global version 3.6.0} %{!?version: %global version 3.7.0}
%global forge https://github.com/narrrl/proton-drive-linux %global forge https://github.com/narrrl/proton-drive-linux
# Files come from the checkout, or from the unpacked tag archive. # Files come from the checkout, or from the unpacked tag archive.
%global src %{?git_dir}%{!?git_dir:.} %global src %{?git_dir}%{!?git_dir:.}
+1 -1
View File
@@ -6,7 +6,7 @@
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: proton-drive-linux 3.6.0\n" "Project-Id-Version: proton-drive-linux 3.7.0\n"
"Report-Msgid-Bugs-To: https://github.com/narrrl/proton-drive-linux/issues\n" "Report-Msgid-Bugs-To: https://github.com/narrrl/proton-drive-linux/issues\n"
"POT-Creation-Date: 2026-11-01 17:51+0100\n" "POT-Creation-Date: 2026-11-01 17:51+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"