From 9c30ff82769ac688f962760650a501f0d92200f8 Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Sat, 17 Oct 2026 13:57:55 +0200 Subject: [PATCH] docs: publish docs/ to the GitHub wiki and reorganise the user guide - scripts/publish-wiki.sh publishes every page listed in SECTIONS, copies images, writes a sectioned sidebar and footer, and removes stale pages. --check fails on links to missing files or headings and on docs pages that are neither published nor excluded. - New wiki.yml runs the check on pull requests and pushes to main, and publishes when release.yml calls it or when started by hand. - Split USER_GUIDE.md into topic pages (files, synced folders, photos, sharing, computers, launcher and tray); add Getting started and FAQ. - Make the COPR repository the main Fedora path, with update and uninstall steps for every package type. - Fix the stale CAPTCHA note in CLI.md, document pdfs unlock and lock, and drop the broken AGENTS.md link from CONTRIBUTING.md. --- .github/ISSUE_TEMPLATE/config.yml | 3 + .github/PULL_REQUEST_TEMPLATE.md | 1 + .github/workflows/release.yml | 8 + .github/workflows/wiki.yml | 77 ++++++ CONTRIBUTING.md | 14 +- README.md | 38 ++- docs/CHANGELOG.md | 9 + docs/CLI.md | 16 +- docs/COMPUTERS.md | 60 +++++ docs/CONFIGURATION.md | 6 +- docs/DEVELOPMENT.md | 26 +- docs/FAQ.md | 104 ++++++++ docs/FILES.md | 88 +++++++ docs/GETTING_STARTED.md | 72 ++++++ docs/INSTALL.md | 392 +++++++++++++++++------------- docs/LAUNCHER_AND_TRAY.md | 86 +++++++ docs/PHOTOS.md | 77 ++++++ docs/README.md | 47 +++- docs/RECOVERY.md | 10 +- docs/SHARING.md | 52 ++++ docs/SYNCED_FOLDERS.md | 163 +++++++++++++ docs/TROUBLESHOOTING.md | 212 +++++++++------- docs/USER_GUIDE.md | 387 +++-------------------------- scripts/publish-wiki.sh | 279 +++++++++++++++------ 24 files changed, 1503 insertions(+), 724 deletions(-) create mode 100644 .github/workflows/wiki.yml create mode 100644 docs/COMPUTERS.md create mode 100644 docs/FAQ.md create mode 100644 docs/FILES.md create mode 100644 docs/GETTING_STARTED.md create mode 100644 docs/LAUNCHER_AND_TRAY.md create mode 100644 docs/PHOTOS.md create mode 100644 docs/SHARING.md create mode 100644 docs/SYNCED_FOLDERS.md diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 6140d48..0d9cf21 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,6 +3,9 @@ contact_links: - name: Security vulnerability url: https://github.com/narrrl/proton-drive-linux/security/advisories/new about: Report privately — never in a public issue. + - name: Troubleshooting and FAQ + url: https://github.com/narrrl/proton-drive-linux/wiki/Troubleshooting + about: Fixes for common problems, and what to include in a bug report. - name: Known issues url: https://github.com/narrrl/proton-drive-linux/blob/main/docs/BUGS.md about: The authoritative ledger of tracked bugs and their status. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e5b6771..a2d39c1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -21,6 +21,7 @@ cargo test --workspace --locked - [ ] Touches recovery, staging, or anything that can be the only copy of user data - [ ] Changes packaging, the systemd unit, or desktop entries - [ ] Changes the control protocol (daemon and front ends updated together) +- [ ] Adds or renames a page in `docs/` (listed in `SECTIONS` in `scripts/publish-wiki.sh`, which publishes it to the wiki) - [ ] None of the above diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cb6e9b1..4942d99 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -332,3 +332,11 @@ jobs: version: ${{ github.ref_name }} secrets: COPR_CONFIG: ${{ secrets.COPR_CONFIG }} + + wiki: + name: Publish the wiki + needs: publish + if: startsWith(github.ref, 'refs/tags/') + uses: ./.github/workflows/wiki.yml + with: + ref: ${{ github.ref_name }} diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml new file mode 100644 index 0000000..ace5612 --- /dev/null +++ b/.github/workflows/wiki.yml @@ -0,0 +1,77 @@ +name: Wiki + +# docs/ is the source of the GitHub wiki (docs/DEVELOPMENT.md#common-changes). +# Every change to the documentation checks its links; release.yml calls this +# once the release is published, so the wiki documents the latest release. Run +# it from the Actions tab to publish main in between. +on: + push: + branches: [main] + paths: + - 'docs/**' + - 'images/**' + - 'README.md' + - 'CONTRIBUTING.md' + - 'SECURITY.md' + - 'scripts/publish-wiki.sh' + - '.github/workflows/wiki.yml' + pull_request: + paths: + - 'docs/**' + - 'images/**' + - 'README.md' + - 'CONTRIBUTING.md' + - 'SECURITY.md' + - 'scripts/publish-wiki.sh' + - '.github/workflows/wiki.yml' + workflow_call: + inputs: + ref: + description: 'Tag or branch to publish' + required: true + type: string + workflow_dispatch: + inputs: + ref: + description: 'Tag or branch to publish' + required: false + default: 'main' + type: string + +permissions: + contents: read + +jobs: + check: + name: Check documentation links + if: inputs.ref == '' + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + + - name: Check links + run: scripts/publish-wiki.sh --check "$RUNNER_TEMP" + + publish: + name: Publish to the wiki + # Set only by release.yml and the Actions tab, so pushes and pull requests + # never publish. + if: inputs.ref != '' + runs-on: ubuntu-24.04 + concurrency: + group: wiki-publish + cancel-in-progress: false + permissions: + contents: write + steps: + - uses: actions/checkout@v7 + with: + ref: ${{ inputs.ref }} + + - name: Publish + env: + WIKI_REMOTE: https://x-access-token:${{ github.token }}@github.com/${{ github.repository }}.wiki.git + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com' + scripts/publish-wiki.sh --push "$RUNNER_TEMP" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b578671..0fac1e5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,10 +6,10 @@ deliberately high — everything else is ordinary Rust review. ## Before you start -- Read [`AGENTS.md`](AGENTS.md) for repository conventions, - [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) for building, running and debugging from source, - and [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for how the daemon, front ends, and SDK fit - together. [`docs/README.md`](docs/README.md) indexes the rest. +- Read [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) for building, running and debugging from + source, and [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for how the daemon, front ends, and + SDK fit together. [`docs/README.md`](docs/README.md) indexes the rest. The same pages are on + the [wiki](https://github.com/narrrl/proton-drive-linux/wiki). - Check [`docs/BUGS.md`](docs/BUGS.md) — it is the authoritative issue ledger, and your problem may already be tracked there with context. - For anything larger than a fix, open an issue first so the design can be discussed before you @@ -58,8 +58,10 @@ runs are destructive: use a dedicated test account, never one holding data you c catalog in `po/LINGUAS` in the same change. See [`docs/TRANSLATING.md`](docs/TRANSLATING.md). The CLI and daemon messages stay in English. - **Document what users see.** A new command, setting or behaviour belongs in the matching page - under `docs/` (user guide, CLI reference or configuration) and in the `[Unreleased]` section of - [`docs/CHANGELOG.md`](docs/CHANGELOG.md). + under `docs/` (a user guide topic, the CLI reference or configuration) and in the `[Unreleased]` + section of [`docs/CHANGELOG.md`](docs/CHANGELOG.md). Each release publishes `docs/` to the + wiki. A new page goes into `SECTIONS` in `scripts/publish-wiki.sh`, and + `scripts/publish-wiki.sh --check` must pass. CI runs it on every change to `docs/`. ## Commits and pull requests diff --git a/README.md b/README.md index 0308d0b..eecceac 100644 --- a/README.md +++ b/README.md @@ -73,17 +73,30 @@ scriptable CLI. | Distribution | Package | |---|---| -| Debian, Ubuntu 24.04 or newer | `.deb` from the [latest release](https://github.com/narrrl/proton-drive-linux/releases/latest) | -| Fedora 44 or newer | [`narl-rs/proton-drive-linux`](https://copr.fedorainfracloud.org/coprs/narl-rs/proton-drive-linux/) in COPR, or the `.rpm` from the [latest release](https://github.com/narrrl/proton-drive-linux/releases/latest) | +| Fedora 44 or newer | [`narl-rs/proton-drive-linux`](https://copr.fedorainfracloud.org/coprs/narl-rs/proton-drive-linux/) in COPR, updated with `dnf upgrade` | | Arch Linux | [`proton-drive-for-linux`](https://aur.archlinux.org/packages/proton-drive-for-linux) (also `-bin` and `-git`) in the AUR | -| NixOS | The flake in this repository: see [Install → NixOS](docs/INSTALL.md#nixos-flake) | +| Debian, Ubuntu 24.04 or newer | `.deb` from the [latest release](https://github.com/narrrl/proton-drive-linux/releases/latest) | +| NixOS | The flake in this repository: see [Installation → NixOS](docs/INSTALL.md#nixos-flake) | | Anything else | [Build from source](docs/INSTALL.md#build-from-source) | +**Fedora** + ```bash -sudo apt install ./proton-drive-linux_*.deb # Debian, Ubuntu -sudo dnf copr enable narl-rs/proton-drive-linux # Fedora +sudo dnf copr enable narl-rs/proton-drive-linux sudo dnf install proton-drive-linux -paru -S proton-drive-for-linux # Arch +``` + +**Arch Linux** + +```bash +paru -S proton-drive-for-linux +``` + +**Debian and Ubuntu:** download the `.deb` from the +[latest release](https://github.com/narrrl/proton-drive-linux/releases/latest), then: + +```bash +sudo apt install ./proton-drive-linux_*_amd64.deb ``` Then open **Proton Drive** from your applications menu and sign in. The app starts the background @@ -98,14 +111,20 @@ systemctl --user enable --now proton-drive.service pdfs status ``` -[docs/INSTALL.md](docs/INSTALL.md) has the requirements, optional extras (tray on GNOME, RAW and -video thumbnails), headless use and uninstalling. +New to the client? [Getting started](docs/GETTING_STARTED.md) walks through the first steps. +[Installation](docs/INSTALL.md) has the optional extras (tray on GNOME, RAW and video +thumbnails), updating, headless use and uninstalling. ## Documentation +The documentation is in [`docs/`](docs/README.md) and on the +[wiki](https://github.com/narrrl/proton-drive-linux/wiki). + | | | |---|---| +| [Getting started](docs/GETTING_STARTED.md) | From installing to your first synced folder | | [User guide](docs/USER_GUIDE.md) | Everything the app, tray and launcher do | +| [FAQ](docs/FAQ.md) | Short answers to common questions | | [Command-line reference](docs/CLI.md) | Every `pdfs` command and scripting with `--json` | | [Configuration](docs/CONFIGURATION.md) | `config.json`, file locations, environment variables, the service | | [Troubleshooting](docs/TROUBLESHOOTING.md) | Diagnosing problems and fixing common ones | @@ -152,7 +171,8 @@ keys before it leaves the machine, through a Rust implementation of Proton's Dri Files you open are decrypted into a local cache so programs can read them. What that means for the security of the machine is spelled out in the -[threat model](docs/ARCHITECTURE.md#10-threat-model-what-this-client-writes-to-disk-in-plaintext). +[security model](docs/SECURITY_MODEL.md#what-is-kept-on-this-computer), and in full detail in +the [threat model](docs/ARCHITECTURE.md#10-threat-model-what-this-client-writes-to-disk-in-plaintext). ## Contributing diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8aa852d..7393bed 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -20,6 +20,15 @@ scratch (user data in `staging/` and `recovery/` is never touched by this). version is out. It is off by default, and not offered for packages that a package manager updates (COPR, the AUR, Nix) (#42). +### Changed +- **Reorganised documentation, now also on the + [wiki](https://github.com/narrrl/proton-drive-linux/wiki).** A new + [Getting started](https://github.com/narrrl/proton-drive-linux/wiki/Getting-Started) page and + an [FAQ](https://github.com/narrrl/proton-drive-linux/wiki/FAQ). The user guide is split into + pages for files, synced folders, Photos, sharing, computers, and the launcher and tray. + Installation puts the COPR repository first for Fedora and explains updating and uninstalling + for each kind of package. Each release publishes `docs/` to the wiki. + ## [3.5.0] — 2026-10-16 Schema: **44**. Queued changes get an index by kind and name, and each synced file remembers the diff --git a/docs/CLI.md b/docs/CLI.md index a0e2045..0aa6b15 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -4,7 +4,8 @@ talks to the running service (`proton-drive.service`); `login`, `logout`, `mount`, `daemon` and `diagnose` work without it. -`pdfs --help` prints the full help of any command. This page groups them by task. +`pdfs --help` prints the full help of any command. This page groups them by task. For +what the commands do in the app, see the [user guide](USER_GUIDE.md). - [Conventions](#conventions) - [Account and service](#account-and-service) @@ -35,7 +36,9 @@ talks to the running service (`proton-drive.service`); `login`, `logout`, `mount | Command | Description | |---|---| -| `pdfs login [-u EMAIL]` | Sign in (password, then a 2FA code if the account has one) and store the session in the system keyring. Restarts the service if it is running. | +| `pdfs login [-u EMAIL] [--remember]` | Sign in (password, then a 2FA code if the account has one) and store the session in the system keyring. Restarts the service if it is running. `--remember` keeps a two-password account unlocked across logins. | +| `pdfs unlock [--remember]` | Enter the mailbox password of a two-password account, so the service can open your files. Needed once per login session, or once with `--remember`. | +| `pdfs lock` | Forget the unlock held in memory; the account is locked again. | | `pdfs logout` | End the session on Proton and remove the stored session. | | `pdfs status` | Account, mount, queue and cache state. | | `pdfs quota` | Storage used across all Proton products. | @@ -43,7 +46,8 @@ talks to the running service (`proton-drive.service`); `login`, `logout`, `mount | `pdfs daemon [MOUNTPOINT]` | Run the service in the foreground: wait for a session, mount, stay mounted. `proton-drive.service` runs this. | | `pdfs mount [MOUNTPOINT]` | Mount once and block until unmounted. Defaults to `~/ProtonDrive`. | -`pdfs login` cannot show a CAPTCHA. If Proton asks for one, sign in with `pdfs-app` instead. +If Proton asks for a CAPTCHA, `pdfs login` prints the address of the page. Open it in your +browser, complete it, then press Enter. ## Files @@ -86,7 +90,7 @@ commands are for scripts and for cases where the mount is not available. | `pdfs sync export ID DEST` | Save a copy of a queued upload's content. `DEST` may be a folder; an existing file is never overwritten. The upload stays queued. | | `pdfs sync discard ID [--yes]` | Drop a queued change and undo it here: a new file or folder goes, anything else goes back to what Proton Drive has. Content not exported first is lost. | | `pdfs sync retry [ID]` | Retry one queued operation, or every failed one. | -| `pdfs sync restore [--device UID] [--yes]` | Re-attach this computer's backed-up folders to local folders and download them. `--device` restores another computer's folders. See [RECOVERY.md](RECOVERY.md). | +| `pdfs sync restore [--device UID] [--yes]` | Re-attach this computer's backed-up folders to local folders and download them. `--device` restores another computer's folders. See [Recovery](RECOVERY.md). | ## Conflicts @@ -104,7 +108,7 @@ commands are for scripts and for cases where the mount is not available. | `pdfs devices rm UID` | Remove a computer and its backup from the account. | | `pdfs devices join UID [--yes]` | Sync the same folders as another computer. This machine syncs into that computer's backup alongside it, then offers its folders like `pdfs sync restore`. Both computers keep them in step. `--yes` skips the confirmation and accepts every proposed path. | | `pdfs devices adopt UID` | Make this machine continue another computer's backup, for example after a reinstall. `--clear` returns to matching by hostname. | -| `pdfs devices migrate UID [--yes]` | Move another computer's folders into this computer's backup, then restore them here like `pdfs sync restore`. The other computer stays registered, without those folders. `--yes` skips the confirmation and accepts every proposed path. See [RECOVERY.md](RECOVERY.md). | +| `pdfs devices migrate UID [--yes]` | Move another computer's folders into this computer's backup, then restore them here like `pdfs sync restore`. The other computer stays registered, without those folders. `--yes` skips the confirmation and accepts every proposed path. See [Recovery](RECOVERY.md). | ## Trash @@ -177,7 +181,7 @@ commands are for scripts and for cases where the mount is not available. | `pdfs cache vacuum` | Compact the database. Needs free space for a second copy of it while it runs. | | `pdfs cache clear` | Delete cached file content. Files kept available offline stay. | -[TROUBLESHOOTING.md](TROUBLESHOOTING.md) explains when to use each of these. +[Troubleshooting](TROUBLESHOOTING.md) explains when to use each of these. ## Scripting with `--json` diff --git a/docs/COMPUTERS.md b/docs/COMPUTERS.md new file mode 100644 index 0000000..4f4a8f2 --- /dev/null +++ b/docs/COMPUTERS.md @@ -0,0 +1,60 @@ +# Computers + +Every computer that backs up folders to your account has its own entry in Proton Drive. The +**Computers** page lists this computer and every other one, including computers that run the +official Windows or macOS app. + +- [What you can do](#what-you-can-do) +- [Syncing several computers](#syncing-several-computers) +- [Replacing or reinstalling a computer](#replacing-or-reinstalling-a-computer) + +![The Computers page](../images/computers.png) + +## What you can do + +**On this computer:** + +- See its synced folders and their state, and add more with **Add Folder to Sync**. See + [Synced folders](SYNCED_FOLDERS.md). +- **Restore Folders…** brings back folders that are backed up under this computer but not synced + here yet, for example after a reinstall. + +**On another computer**, from its menu: + +| Choose | When | What happens | +|---|---|---| +| **Browse Files** | You need a file from it | Its backup opens read-only, like My files | +| **Restore to This Computer…** | You want a copy of its folders here | Its folders download here and stay part of its backup | +| **Sync With This Computer…** | Both computers should share the same folders, such as a desktop and a laptop | Both keep the folders in step. See [below](#syncing-several-computers) | +| **Continue This Backup Here…** | This computer replaces it, after a reinstall or with new hardware | This computer takes over its backup. See [Recovery](RECOVERY.md) | +| **Move to This Computer…** | You switch for good, for example from Windows to Linux | Its folders move into this computer's backup and are offered for syncing here. The other computer stays in the list, without those folders | + +`pdfs devices list` shows the same computers with their IDs, for the commands in the +[command-line reference](CLI.md#computers). + +## Syncing several computers + +Two or more computers can sync the same folders through one backup in Proton Drive. + +1. Sync the folders on the first computer as usual. +2. On the second computer, open **Computers**, open the menu of the first computer and choose + **Sync With This Computer…**. From a terminal: `pdfs devices join UID`, with the ID from + `pdfs devices list`. +3. Choose which of its folders to sync here, and where. + +From then on, both computers sync into that backup: + +- A folder you add later on either computer lands there too. A folder with the same name joins + the one already there. +- A change on one computer reaches the other within about two minutes. +- When both computers change the same file within that time, each keeps the other's version under + the original name, and its own as a conflict copy named after it. See + [Conflicts](SYNCED_FOLDERS.md#conflicts). + +Folders that were synced on this computer before it joined stay in its own backup. + +## Replacing or reinstalling a computer + +Your synced folders are on Proton Drive, so a new or reinstalled computer can pick up where the +old one stopped. [Recovering on a new computer](RECOVERY.md) walks through it step by step, and +explains what is lost with a machine and what is not. diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 558ccf0..f3acf22 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -39,7 +39,7 @@ Inside `content/`: > not reached Proton Drive and exists nowhere else. Everything in these directories except the keyring is **decrypted**. See -[ARCHITECTURE.md §10](ARCHITECTURE.md#10-threat-model-what-this-client-writes-to-disk-in-plaintext). +the [security model](SECURITY_MODEL.md#what-is-kept-on-this-computer). ## `config.json` @@ -113,7 +113,7 @@ Gitignore-style rules applied to every synced folder, in addition to each folder ``` Set it to `[]` to turn the defaults off. See -[USER_GUIDE.md](USER_GUIDE.md#excluding-files-with-pdfsignore) for how ignoring behaves. +[Synced folders](SYNCED_FOLDERS.md#excluding-files-with-pdfsignore) for how excluding behaves. ### `conflict_sweep` @@ -202,7 +202,7 @@ Command-line flags win over the file: `--gtk`, `--dmenu`, `--fzf` and `--menu`. | `PDFS_STAND_IN_WIDGETS` | app | `1` uses the libadwaita 1.5 fallback widgets on newer systems (development) | The tests have their own variables (`PDFS_ACCEPTANCE_*`, `PDFS_SIM_*`, `PDFS_MIGRATE_DB`), -listed in [TESTING.md](TESTING.md). +listed in [Testing](TESTING.md). ## The systemd service diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 9c4396f..7a62fbc 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -141,10 +141,25 @@ file to `po/POTFILES.in`, run `po/update.sh`, and translate the new entries in e unit test, a simulation scenario or a `regression B` acceptance case, and cite the entry in the code as `docs/BUGS.md B`. Do not cite planning notes that are not in the repository. -**A user-visible change.** Update the matching page (user guide, CLI reference, configuration) -and the `[Unreleased]` section of [CHANGELOG.md](CHANGELOG.md). `scripts/publish-wiki.sh` copies -the six user pages (`INSTALL`, `USER_GUIDE`, `CLI`, `CONFIGURATION`, `TROUBLESHOOTING`, `RECOVERY`) -to the GitHub wiki, so keep their file names. +**A user-visible change.** Update the matching page (a user guide topic, the CLI reference, +configuration) and the `[Unreleased]` section of [CHANGELOG.md](CHANGELOG.md). Link between pages +with relative links such as `[Conflicts](SYNCED_FOLDERS.md#conflicts)`, and show screenshots from +`images/` with `../images/.png`. + +**The wiki.** `docs/` is the source of the [GitHub wiki](https://github.com/narrrl/proton-drive-linux/wiki). +`scripts/publish-wiki.sh` turns each page listed in its `SECTIONS` into a wiki page, rewrites the +links, copies the images and writes the sidebar. `docs/README.md` becomes the wiki's Home. +`BUGS.md` and `CHANGELOG.md` stay out of it; the wiki links to them on GitHub. + +- `scripts/publish-wiki.sh --check` checks every link and heading anchor in `docs/`, `README.md`, + `CONTRIBUTING.md` and `SECURITY.md`. It fails on a page in `docs/` that is not in `SECTIONS` + or `EXCLUDED`. `.github/workflows/wiki.yml` runs it for every change to the documentation. +- Each release publishes the wiki from the tag. Run the **Wiki** workflow from the Actions tab to + publish `main` in between, for example after fixing a mistake. +- `scripts/publish-wiki.sh [WORKDIR]` builds and commits the wiki in a local clone without + pushing, so you can look at the result first. `--push` pushes it. + +Never edit the wiki in the browser: the next publish replaces every page. ## Releasing @@ -162,7 +177,8 @@ Releases are cut from `main` by pushing a `v*` tag. `.github/workflows/release.y 5. calls `.github/workflows/aur.yml`, which updates and pushes the AUR recipes and commits them back to `main`; 6. calls `.github/workflows/copr.yml`, which builds the release in the - [COPR repository](../packaging/copr/README.md) (secret `COPR_CONFIG`). + [COPR repository](../packaging/copr/README.md) (secret `COPR_CONFIG`); +7. calls `.github/workflows/wiki.yml`, which publishes `docs/` at the tag to the wiki. To prepare a release: diff --git a/docs/FAQ.md b/docs/FAQ.md new file mode 100644 index 0000000..5824354 --- /dev/null +++ b/docs/FAQ.md @@ -0,0 +1,104 @@ +# FAQ + +Short answers to common questions, with links to the details. + +- [Is this an official Proton app?](#is-this-an-official-proton-app) +- [If I delete a file in `~/ProtonDrive`, is it deleted on Proton Drive?](#if-i-delete-a-file-in-protondrive-is-it-deleted-on-proton-drive) +- [Online only, available offline or synced folder: which do I want?](#online-only-available-offline-or-synced-folder-which-do-i-want) +- [Does it work offline?](#does-it-work-offline) +- [How do I get updates?](#how-do-i-get-updates) +- [Why is there no tray icon?](#why-is-there-no-tray-icon) +- [What is stored unencrypted on my computer?](#what-is-stored-unencrypted-on-my-computer) +- [Does it send telemetry?](#does-it-send-telemetry) +- [Can I use it on several computers?](#can-i-use-it-on-several-computers) +- [Can I continue a backup from Windows or macOS?](#can-i-continue-a-backup-from-windows-or-macos) +- [Can I run it on a server without a desktop?](#can-i-run-it-on-a-server-without-a-desktop) +- [Which architectures and languages are supported?](#which-architectures-and-languages-are-supported) +- [How do I report a bug?](#how-do-i-report-a-bug) + +## Is this an official Proton app? + +No. It is an independent, open-source client, not affiliated with or endorsed by Proton AG. It +uses a Rust port of Proton's own Drive SDK, and everything stays end-to-end encrypted. It has had +no independent security audit. See the [security model](SECURITY_MODEL.md). + +## If I delete a file in `~/ProtonDrive`, is it deleted on Proton Drive? + +Yes. `~/ProtonDrive` is your Proton Drive, not a copy. A deleted file moves to the Proton Drive +Trash, and you can restore it from **Trash** in the app or the web. See [Trash](FILES.md#trash). + +Stopping the service is not the same: once the service stops, `~/ProtonDrive` is just an empty +folder, and your files stay on Proton Drive. + +## Online only, available offline or synced folder: which do I want? + +- **Online only** for most of your Drive. Files take no space until you open them. +- **Available offline** for files in `~/ProtonDrive` you need without a connection. +- **Synced folder** for a folder that lives on this computer, such as `~/Documents`, and should be + backed up. + +[Getting started](GETTING_STARTED.md#3-choose-how-files-are-kept) compares them side by side. + +## Does it work offline? + +Yes, for files that are on this computer: available-offline files, synced folders, and recently +opened files still in the cache. You can also create, rename, move and delete files offline. The +changes are queued and sent when the connection is back. See +[Changes waiting for Proton Drive](SYNCED_FOLDERS.md#changes-waiting-for-proton-drive). + +## How do I get updates? + +Through your package manager. The Fedora COPR repository, the AUR and the Nix flake get every +release, so `dnf upgrade`, your AUR helper or a flake update brings it. The `.deb` has to be +downloaded again for each release. To be told about new releases, turn on **Check for updates** +in **Preferences**. The app never updates itself. See [Installation → Updating](INSTALL.md#updating). + +## Why is there no tray icon? + +GNOME needs the +[AppIndicator extension](https://extensions.gnome.org/extension/615/appindicator-support/) to show +tray icons. If you hid the icon from its own menu, turn it back on under +**Preferences → General → Appearance**. + +## What is stored unencrypted on my computer? + +To show your files, the client decrypts them on this computer. Recently opened files, files kept +offline, changes waiting to upload, and the names of your files and folders are stored without +extra encryption. Use full-disk or home-folder encryption. The +[security model](SECURITY_MODEL.md#what-is-kept-on-this-computer) has the full list. + +## Does it send telemetry? + +No. The client connects only to Proton, and, if you turn them on, to OpenFreeMap for the street map +in Photos and to GitHub to check for updates. See +[Network connections](SECURITY_MODEL.md#network-connections). + +## Can I use it on several computers? + +Yes. Each computer has its own backup in Proton Drive, and two or more computers can also sync the +same folders. See [Syncing several computers](COMPUTERS.md#syncing-several-computers). + +## Can I continue a backup from Windows or macOS? + +Yes. On the **Computers** page, choose **Move to This Computer…** on the old computer. Its folders +move into this computer's backup on Proton Drive, without uploading anything again. See +[Moving another computer's backup here](RECOVERY.md#moving-another-computers-backup-here). + +## Can I run it on a server without a desktop? + +Yes, with `pdfs daemon` or `pdfs mount`. It still needs a Secret Service provider such as GNOME +Keyring or KeePassXC to hold the session. See +[Headless and server use](INSTALL.md#headless-and-server-use). + +## Which architectures and languages are supported? + +Release packages are for x86_64. Other architectures can [build from source](INSTALL.md#build-from-source). + +The app, tray and launcher are available in English, German, Spanish, French, Italian, Dutch, +Polish and Brazilian Portuguese. [Translating](TRANSLATING.md) explains how to add a language. + +## How do I report a bug? + +Run `pdfs diagnose`, then [open an issue](https://github.com/narrrl/proton-drive-linux/issues/new/choose) +with what [Reporting a problem](TROUBLESHOOTING.md#reporting-a-problem) lists. Report security +problems privately, as described in [SECURITY.md](../SECURITY.md). diff --git a/docs/FILES.md b/docs/FILES.md new file mode 100644 index 0000000..87b3976 --- /dev/null +++ b/docs/FILES.md @@ -0,0 +1,88 @@ +# Files and offline access + +Your Proton Drive appears on this computer as a folder, `~/ProtonDrive`. Every file and folder in +it is listed straight away, but a file only downloads when a program opens it. This page covers +working in that folder, keeping files on this computer, the Trash, and earlier versions of a +file. + +- [Your Drive as a folder](#your-drive-as-a-folder) +- [Keep files available offline](#keep-files-available-offline) +- [Browse in the app](#browse-in-the-app) +- [Trash](#trash) +- [Earlier versions of a file](#earlier-versions-of-a-file) +- [Choose which program opens a file](#choose-which-program-opens-a-file) + +## Your Drive as a folder + +`~/ProtonDrive` is your Proton Drive, called **My files** in the app. It is not a copy. A file you +change there changes on Proton Drive, and a file you delete there goes to the Proton Drive +Trash. Every program can use it, from your file manager to a terminal. + +- **Only what you read is downloaded.** A video player that seeks, or a tool that reads only the + start of a file, downloads only those parts. Videos and music start playing before the whole + file is down. +- **Changes are instant, online or offline.** Creating, renaming, moving and deleting return at + once. When a program saves and closes a file, the new content is stored on this computer and + sent to Proton Drive in the background. Changes survive a lost connection, a crash or a reboot. + See [Changes waiting for Proton Drive](SYNCED_FOLDERS.md#changes-waiting-for-proton-drive). +- **Recently opened files are cached** up to a size limit (5 GiB by default, set in + **Preferences → Storage**). The oldest are removed first to make room. +- **Shared with me** is a folder inside `~/ProtonDrive` that holds what other people share with + you. Shares where you are a viewer are read-only. + +Proton Drive cannot store symbolic links, hard links, device files or FIFOs. A program that tries +to create one gets an error at once. For a project that needs them, use a +[synced folder](SYNCED_FOLDERS.md) and exclude those paths. + +To move the folder somewhere else, change **Preferences → General → Location**. + +## Keep files available offline + +Files you mark **Available offline** are downloaded completely and stay on this computer, so +they open without a connection. + +- **In the app:** select a file or folder in **My files** and turn on **Available offline**. +- **From a terminal:** `pdfs pin ~/ProtonDrive/Documents/Taxes` + +For a folder, every file in it and in its subfolders downloads in the background. The tray and +the app show the progress. **Preferences → Storage → Available offline** and `pdfs pins` list +what is kept. + +Turn it off again with the same switch, or `pdfs unpin PATH`. This frees the space. The files stay +on Proton Drive. A file inside a folder that is kept offline stays with its folder: turn the +folder off instead. + +## Browse in the app + +![My files in the app](../images/files.png) + +The **My files** page shows the same files without going through the folder. It has a grid and +a list view, sorting, thumbnails (including camera RAW previews), multi-select, and drag and drop +to upload. **Details** (Alt+Enter) shows the size, dates, sharing and version history of the +selected item. + +## Trash + +Deleted files go to the Trash, both from `~/ProtonDrive` and from the app. The **Trash** page +lists them with the date they were deleted. + +- **Restore** puts an item back where it was, together with any trashed folders above it. +- **Delete Forever** and **Empty Trash** are permanent. + +From a terminal: `pdfs trash` lists the Trash with an ID for each item, and `pdfs restore`, +`pdfs delete-forever` and `pdfs empty-trash` take those IDs. + +## Earlier versions of a file + +Proton Drive keeps earlier versions of every file. Open them with **Details → Versions…** in the +app, or `pdfs versions list PATH`. You can: + +- **Restore** a version. This happens on Proton Drive, so nothing is uploaded again. +- **Save** a version to a separate file, without touching the current one. +- **Delete** an old version permanently. The current version cannot be deleted. + +## Choose which program opens a file + +The app and the search launcher open files with your desktop's default program (`xdg-open`). To +open some file types differently, for example text files in Neovim inside a terminal, add +`open_with` rules to `config.json`. See [Configuration → `open_with`](CONFIGURATION.md#open_with). diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md new file mode 100644 index 0000000..3d0e002 --- /dev/null +++ b/docs/GETTING_STARTED.md @@ -0,0 +1,72 @@ +# Getting started + +From installing to your first synced folder in a few minutes. + +> [!IMPORTANT] +> Proton Drive for Linux is an unofficial client, built by the community and not by Proton. Try it +> first with files you also have somewhere else. + +## 1. Install + +| Distribution | Command | +|---|---| +| Fedora 44 or newer | `sudo dnf copr enable narl-rs/proton-drive-linux`
`sudo dnf install proton-drive-linux` | +| Arch Linux | `paru -S proton-drive-for-linux` (or any other AUR helper) | +| Debian, Ubuntu 24.04 or newer | Download the `.deb` from the [latest release](https://github.com/narrrl/proton-drive-linux/releases/latest), then `sudo apt install ./proton-drive-linux_*_amd64.deb` | +| NixOS | See [Installation → NixOS](INSTALL.md#nixos-flake) | + +On GNOME, also install the +[AppIndicator extension](https://extensions.gnome.org/extension/615/appindicator-support/) to see +the tray icon. [Installation](INSTALL.md) has every option, building from source, and the optional +extras. + +## 2. Sign in + +![The sign-in window](../images/login.png) + +1. Open **Proton Drive** from your applications menu. +2. Sign in with your Proton email and password, and the two-factor code if your account has one. + If Proton asks you to prove you are human (common on a VPN), solve the challenge in the window + that opens. +3. Wait a moment. Your Proton Drive appears as the folder `~/ProtonDrive`. + +The app starts the Proton Drive service for you, and the service starts by itself whenever you +log in. Your session is kept in the system keyring (GNOME Keyring, KWallet or KeePassXC), so you +sign in only once. + +## 3. Choose how files are kept + +There are three ways to have your files on this computer. You can mix them freely. + +| | Takes disk space | Works offline | Use it for | +|---|---|---|---| +| **Online only** (the default in `~/ProtonDrive`) | Only for files you opened recently | Only files still in the cache | Most of your Drive: archives, media, anything large | +| **Available offline** | Yes | Yes | Files and folders you need on the road | +| **Synced folder** | Yes, a full copy | Yes | Folders that live on this computer, such as `~/Documents`, backed up to Proton Drive | + +- **Online only:** open `~/ProtonDrive` in your file manager. Files download when you open them. +- **Available offline:** select a file or folder in the app and turn on **Available offline**. + [More about offline files](FILES.md#keep-files-available-offline). +- **Synced folder:** in the app, open **Computers** and choose **Add Folder to Sync**. + [More about synced folders](SYNCED_FOLDERS.md). + +## 4. Know where to look + +- **Tray icon:** shows whether everything is up to date, and pauses or resumes sync. +- **Sync → Overview** in the app: what is uploading, what is waiting, and anything that needs you. +- **Search launcher:** bind `pdfs-prompt` to a keyboard shortcut to find any file in Proton Drive + or your home folder. See [Search launcher and tray](LAUNCHER_AND_TRAY.md). + +> [!WARNING] +> `~/ProtonDrive` is your Proton Drive, not a copy. Deleting a file there moves it to the Proton +> Drive Trash on every device. You can restore it from **Trash** in the app. + +## Next steps + +- [User guide](USER_GUIDE.md): everything the app, tray and launcher do. +- [FAQ](FAQ.md): short answers to common questions. +- [Troubleshooting](TROUBLESHOOTING.md): when something does not work. +- [Recovering on a new computer](RECOVERY.md): read this before you rely on the client for + backups. +- Prefer a terminal? `pdfs status` shows the state of everything, and the + [command-line reference](CLI.md) lists every command. diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 8033650..6a6f63a 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -1,81 +1,53 @@ # Installation -This page covers installing Proton Drive for Linux from a package or from source, the first -sign-in, running without a desktop, and removing the client again. +Install Proton Drive for Linux from your distribution's package, sign in, and keep it up to date. +This page also covers building from source, running without a desktop, and removing the client +again. -- [Requirements](#requirements) - [Install a package](#install-a-package) -- [Build from source](#build-from-source) +- [Optional extras](#optional-extras) - [First run](#first-run) -- [Headless and server use](#headless-and-server-use) - [Updating](#updating) - [Uninstalling](#uninstalling) - -## Requirements - -| | Minimum | -|---|---| -| Architecture | x86_64 (release packages); other architectures build from source | -| Kernel | FUSE 3 (`fuse3` package, `/dev/fuse` available to your user) | -| GTK / libadwaita | GTK 4.12, libadwaita 1.5 (1.8 or newer gets the newest widgets) | -| WebKitGTK | 6.0 — used only for the CAPTCHA page during sign-in | -| Secret Service | GNOME Keyring, KWallet, KeePassXC, or another provider of `org.freedesktop.secrets` | -| Rust (source builds) | 1.96 | - -The session is stored only in the Secret Service. Without a running provider, sign-in succeeds but -cannot be saved, and the service cannot start unattended. - -Optional runtime extras: - -| Package | Adds | -|---|---| -| `exiftool` (`perl-image-exiftool`, `libimage-exiftool-perl`) | Thumbnails for camera RAW files | -| `ffmpeg` | Video thumbnails | -| `iso-codes` | Country names in your language on the Places map | -| `xdg-utils` | "Open Folder" in the tray, and the default file opener | -| `fzf` plus a terminal (foot, kitty, alacritty, …) | `pdfs-prompt --fzf`, the search-as-you-type launcher | -| AppIndicator extension (GNOME only) | The tray icon. KDE Plasma and most other desktops show it natively | +- [Headless and server use](#headless-and-server-use) +- [Build from source](#build-from-source) +- [What the packages install](#what-the-packages-install) ## Install a package -Every [release](https://github.com/narrrl/proton-drive-linux/releases/latest) ships a `.deb`, a -signed `.rpm` and a `.tar.gz` of the raw binaries. All packages install the same files: +| Distribution | Package | Updates | +|---|---|---| +| [Fedora 44 or newer](#fedora-44-or-newer) | COPR repository `narl-rs/proton-drive-linux` | With `dnf upgrade` | +| [Arch Linux](#arch-linux-aur) | `proton-drive-for-linux` in the AUR | With your AUR helper | +| [Debian, Ubuntu 24.04 or newer](#debian-and-ubuntu-2404-or-newer) | `.deb` from the release page | Download each release | +| [NixOS](#nixos-flake) | The flake in this repository | With `nix flake update` | +| [Anything else](#other-distributions) | `.tar.gz` from the release page, or [build from source](#build-from-source) | By hand | -| Path | Purpose | -|---|---| -| `/usr/bin/pdfs` | Command-line client and background service | -| `/usr/bin/pdfs-app` | Desktop app | -| `/usr/bin/pdfs-tray` | Tray icon | -| `/usr/bin/pdfs-prompt` | Search launcher | -| `/usr/lib/systemd/user/proton-drive.service` | User service that keeps the drive mounted | -| `/etc/xdg/autostart/io.narl.proton-drive-linux-tray.desktop` | Starts the tray at login | -| `/usr/share/locale/*/LC_MESSAGES/pdfs.mo` | Translations | - -### Debian and Ubuntu (24.04 or newer) - -```bash -sudo apt install ./proton-drive-linux_*_amd64.deb -``` +Release packages are for x86_64. You also need a Secret Service provider, such as GNOME +Keyring, KWallet or KeePassXC, to keep your session. Most desktops have one already. ### Fedora (44 or newer) -The [COPR repository](https://copr.fedorainfracloud.org/coprs/narl-rs/proton-drive-linux/) builds -every release, so `dnf upgrade` keeps the client up to date: +Enable the [COPR repository](https://copr.fedorainfracloud.org/coprs/narl-rs/proton-drive-linux/) +and install the package: ```bash sudo dnf copr enable narl-rs/proton-drive-linux sudo dnf install proton-drive-linux ``` -The `.rpm` from the release page installs the same files, but you have to download each new -version yourself: +COPR builds every release for Fedora 44, 45 and Rawhide, so `sudo dnf upgrade` keeps the client +up to date along with the rest of your system. + +You can also download the signed `.rpm` from the +[latest release](https://github.com/narrrl/proton-drive-linux/releases/latest). It installs the +same files, but you have to download each new version yourself: ```bash sudo dnf install ./proton-drive-linux-*.x86_64.rpm ``` -For a Fedora package built from your own checkout, see -[Build an RPM locally](#build-an-rpm-locally). +To build an RPM from your own checkout, see [Build an RPM locally](#build-an-rpm-locally). ### Arch Linux (AUR) @@ -83,21 +55,33 @@ Three packages cover the usual choices. They conflict with each other, so instal | Package | Contents | |---|---| -| [`proton-drive-for-linux`](https://aur.archlinux.org/packages/proton-drive-for-linux) | Latest tagged release, built from source | -| [`proton-drive-for-linux-bin`](https://aur.archlinux.org/packages/proton-drive-for-linux-bin) | Latest tagged release, prebuilt binaries | -| [`proton-drive-for-linux-git`](https://aur.archlinux.org/packages/proton-drive-for-linux-git) | `main`, built from git | +| [`proton-drive-for-linux`](https://aur.archlinux.org/packages/proton-drive-for-linux) | Latest release, built from source | +| [`proton-drive-for-linux-bin`](https://aur.archlinux.org/packages/proton-drive-for-linux-bin) | Latest release, prebuilt binaries | +| [`proton-drive-for-linux-git`](https://aur.archlinux.org/packages/proton-drive-for-linux-git) | The newest code on `main`, built from git | ```bash paru -S proton-drive-for-linux # or yay, or any other AUR helper ``` -The recipes live in [`packaging/aur/`](../packaging/aur/README.md). +The recipes are in [`packaging/aur/`](../packaging/aur/README.md). + +### Debian and Ubuntu (24.04 or newer) + +Download the `.deb` from the [latest release](https://github.com/narrrl/proton-drive-linux/releases/latest) +and install it: + +```bash +sudo apt install ./proton-drive-linux_*_amd64.deb +``` + +There is no APT repository yet, so repeat this for each new release. Turn on **Check for +updates** in **Preferences** to be told when one is out. ### NixOS (flake) -The repository is a flake. Add it as an input and enable the module, which installs the package, -links the user service into every graphical session and turns on the `fusermount3` wrapper and -GNOME Keyring for you: +The repository is a flake. Add it as an input and enable the module. The module installs the +package, starts the user service in every graphical session, and turns on the `fusermount3` +wrapper and GNOME Keyring for you: ```nix { @@ -118,7 +102,7 @@ That URL follows `main`. To stay on releases, pin the input to a release tag ins the tag to update: ```nix -inputs.proton-drive-linux.url = "github:narrrl/proton-drive-linux/v3.3.0"; +inputs.proton-drive-linux.url = "github:narrrl/proton-drive-linux/v3.5.0"; ``` Each release tag is built with Nix before the release is published. @@ -139,29 +123,176 @@ nix.settings = { ``` The cache holds the build against the `nixpkgs` this flake locks. Setting -`inputs.proton-drive-linux.inputs.nixpkgs.follows = "nixpkgs"` builds against yours instead, which -the cache does not have, so Nix compiles it. `nix run` and `nix shell` ask whether to use the -cache the first time; answer yes, or run `cachix use proton-drive-linux`. +`inputs.proton-drive-linux.inputs.nixpkgs.follows = "nixpkgs"` builds against yours instead, +which the cache does not have, so Nix compiles it. `nix run` and `nix shell` ask whether to use +the cache the first time; answer yes, or run `cachix use proton-drive-linux`. -To try it without changing your system, run the app straight from the flake: +To try it without changing your system, run it straight from the flake: ```bash nix run github:narrrl/proton-drive-linux#proton-drive-linux -- --help # the CLI nix shell github:narrrl/proton-drive-linux -c pdfs-app # the desktop app ``` -The mount itself needs the setuid `fusermount3` from NixOS (`programs.fuse.enable`, on by default -with the module) and a Secret Service such as GNOME Keyring or KWallet. To leave out ffmpeg and -with it video thumbnails, override the package with `withFfmpeg = false`. The recipe lives in +The mount needs the setuid `fusermount3` from NixOS (`programs.fuse.enable`, on by default with +the module) and a Secret Service such as GNOME Keyring or KWallet. To leave out ffmpeg, and with +it video thumbnails, override the package with `withFfmpeg = false`. The recipe is in [`packaging/nix/`](../packaging/nix/). ### Other distributions -Unpack the `.tar.gz` into a directory on your `PATH`, then install the service unit as shown in -[Using a binary outside `/usr/bin`](#using-a-binary-outside-usrbin). +Unpack the `.tar.gz` from the [latest release](https://github.com/narrrl/proton-drive-linux/releases/latest) +into a directory on your `PATH`, then install the service as shown in +[Using a binary outside `/usr/bin`](#using-a-binary-outside-usrbin). The binaries need GTK 4.12, +libadwaita 1.5, WebKitGTK 6.0 and FUSE 3; see [Requirements](#requirements). + +## Optional extras + +The packages pull in what the client needs. These add features if you install them: + +| Package | Adds | +|---|---| +| `exiftool` (`perl-image-exiftool`, `libimage-exiftool-perl`) | Thumbnails for camera RAW files | +| `ffmpeg` | Video thumbnails | +| `iso-codes` | Country names in your language on the Places map | +| `xdg-utils` | "Open Folder" in the tray, and the default file opener | +| `fzf` and a terminal (foot, kitty, alacritty, …) | `pdfs-prompt --fzf`, the search-as-you-type launcher | +| [AppIndicator extension](https://extensions.gnome.org/extension/615/appindicator-support/) (GNOME only) | The tray icon. KDE Plasma and most other desktops show it without help | + +## First run + +### With the desktop app + +1. Open **Proton Drive** from your applications menu, or run `pdfs-app`. +2. Sign in with your Proton email and password, and your two-factor code if the account has one. + If Proton asks for a CAPTCHA (common on a VPN or a new network), the app shows the challenge in + a window and continues after you solve it. +3. The app enables and starts `proton-drive.service`. Your Drive appears at `~/ProtonDrive`. + +The service belongs to your desktop session. It starts after you log in and stops when you log +out. To put the folder somewhere else, change **Preferences → General → Location**. + +[Getting started](GETTING_STARTED.md) explains what to do next. + +### With the command line + +`pdfs login` stores the session but does not enable the service, so a setup that runs the service +another way stays untouched. Enable it yourself: + +```bash +pdfs login # email, password, 2FA code +systemctl --user enable --now proton-drive.service +pdfs status # account, mount and queue state +``` + +`pdfs login` prints the address of the CAPTCHA page if Proton asks for one: open it in your +browser, solve it, then press Enter. + +## Updating + +| Installed from | Update with | +|---|---| +| COPR (Fedora) | `sudo dnf upgrade` | +| AUR | `paru -Syu`, or your AUR helper's equivalent | +| Nix flake | `nix flake update proton-drive-linux`, or change the pinned tag, then rebuild | +| `.deb`, release `.rpm`, `.tar.gz` | Download the new release and install it over the old one | + +The service switches to the new version the next time it starts. To switch at once: + +```bash +systemctl --user restart proton-drive.service +``` + +With the `.deb`, the release `.rpm` or the `.tar.gz`, nothing tells you about a new release. +Turn on **Preferences → General → Check for updates**: the app asks GitHub once a day and shows a +banner over the sidebar when a newer version is out. The app never installs updates itself. +Packages that a package manager updates do not offer the setting. A package marks itself that way +by installing the empty file `share/proton-drive-linux/managed-updates` under the prefix of its +`bin/` directory, for example `/usr/share/proton-drive-linux/managed-updates`. + +Coming from 2.8.0 or older, re-enable the service once. Those releases started it before the +desktop session was ready, and on KDE that crashes `ksecretd` at every login. Signing in again or +toggling **Start on login** does this as well: + +```bash +systemctl --user reenable proton-drive.service +``` + +Database upgrades run by themselves and only move forward. A newer release's database does not +open in an older release, so going back to an older version means clearing the local database +(see [Troubleshooting](TROUBLESHOOTING.md#start-over-with-a-clean-local-state)). + +## Uninstalling + +> [!WARNING] +> Check that nothing is waiting to upload before you remove anything. `pdfs sync queue` must be +> empty. Changes that have not reached Proton Drive exist only on this computer. + +1. Stop the service and sign out: + + ```bash + pdfs sync queue # must list nothing + systemctl --user disable --now proton-drive.service + pdfs logout # removes the session from the keyring + ``` + +2. Remove the package: + + | Installed from | Remove with | + |---|---| + | COPR (Fedora) | `sudo dnf remove proton-drive-linux`, then `sudo dnf copr remove narl-rs/proton-drive-linux` | + | Release `.rpm` | `sudo dnf remove proton-drive-linux` | + | `.deb` | `sudo apt remove proton-drive-linux` | + | AUR | `sudo pacman -R proton-drive-for-linux` (or the `-bin` or `-git` package) | + | NixOS | Remove the module and the flake input, then rebuild | + + Removing the package also stops the service of every logged-in user, in case step 1 was + skipped. + +3. If you want no trace left, remove the local data: + + ```bash + rm -rf ~/.config/proton-drive-linux ~/.local/state/proton-drive-linux ~/.cache/proton-drive-linux + ``` + +4. Sign the device out in your Proton account settings. If you no longer want this computer's + backups, remove it from **Computers** in the Proton Drive web app. + +> [!CAUTION] +> Do not delete `~/ProtonDrive` while it is mounted. It is your Proton Drive, not a copy: every +> file deleted there is moved to the Proton Drive trash. Once the service is stopped, the folder +> is empty, and removing it is safe. + +## Headless and server use + +The packaged service starts with a desktop session. On a machine without one, run the service +directly or from your own systemd unit: + +```bash +pdfs daemon # waits for a stored session, mounts, stays mounted +pdfs mount /srv/proton # mounts once at a given path, blocks until unmounted +``` + +Both still need a Secret Service provider for the session. On a server, run +`gnome-keyring-daemon --unlock` or KeePassXC's Secret Service integration inside the user's D-Bus +session. ## Build from source +### Requirements + +| | Minimum | +|---|---| +| Architecture | Any that Rust and GTK support. Release packages are x86_64 only | +| Kernel | FUSE 3 (`fuse3` package, `/dev/fuse` available to your user) | +| GTK / libadwaita | GTK 4.12, libadwaita 1.5 (1.8 or newer gets the newest widgets) | +| WebKitGTK | 6.0, used only for the CAPTCHA page during sign-in | +| Secret Service | GNOME Keyring, KWallet, KeePassXC, or another provider of `org.freedesktop.secrets` | +| Rust | 1.96 | + +The session is stored only in the Secret Service. Without a running provider, sign-in succeeds +but cannot be saved, and the service cannot start unattended. + ### Build dependencies **Debian / Ubuntu 24.04+** @@ -184,8 +315,8 @@ sudo dnf install -y cargo rust gettext pkgconf-pkg-config fuse3-devel gtk4-devel sudo pacman -S --needed rust gettext pkgconf fuse3 gtk4 libadwaita webkitgtk-6.0 libsecret dbus ``` -Install Rust 1.96 or newer with [rustup](https://rustup.rs) if your distribution ships an older -toolchain. +If your distribution ships a Rust older than 1.96, install a newer one with +[rustup](https://rustup.rs). ### Compile @@ -196,7 +327,7 @@ cargo build --release --locked po/build.sh target/locale # optional: compile the translations ``` -The four binaries are in `target/release/`: `pdfs`, `pdfs-app`, `pdfs-tray` and `pdfs-prompt`. +The four programs are in `target/release/`: `pdfs`, `pdfs-app`, `pdfs-tray` and `pdfs-prompt`. ### Build a package from the working tree @@ -222,7 +353,7 @@ sudo dnf install packaging/out/x86_64/proton-drive-linux-*.rpm ### Using a binary outside `/usr/bin` -The service unit starts `/usr/bin/pdfs daemon`. If you installed the binaries somewhere else, for +The service unit starts `/usr/bin/pdfs daemon`. If you installed the programs somewhere else, for example `~/.local/bin`, install the unit for your user and point it at your binary: ```bash @@ -234,105 +365,20 @@ systemctl --user daemon-reload ``` To start the tray at login, copy `packaging/io.narl.proton-drive-linux-tray.desktop` to -`~/.config/autostart/`. For the app launcher entry, copy `packaging/io.narl.proton-drive-linux.desktop` -to `~/.local/share/applications/` and the icon `packaging/io.narl.proton-drive-linux.svg` to -`~/.local/share/icons/hicolor/scalable/apps/`. +`~/.config/autostart/`. For the entry in your applications menu, copy +`packaging/io.narl.proton-drive-linux.desktop` to `~/.local/share/applications/` and the icon +`packaging/io.narl.proton-drive-linux.svg` to `~/.local/share/icons/hicolor/scalable/apps/`. -## First run +## What the packages install -### With the desktop app +Every package installs the same files: -1. Open **Proton Drive** from your application menu, or run `pdfs-app`. -2. Sign in with your Proton email and password, and your two-factor code if the account has one. - If Proton asks for a CAPTCHA (common on a VPN or a new network), the app shows the challenge in - a window and continues after you solve it. -3. The app enables and starts `proton-drive.service`. Your Drive appears at `~/ProtonDrive`. - -The service is tied to your graphical session. It starts after you log in and stops when you log -out. Change the folder location under **Preferences → General → Location**. - -### With the command line - -`pdfs login` stores the session but does not enable the service, so a setup that runs the daemon -another way stays untouched. Enable the service yourself: - -```bash -pdfs login # email, password, 2FA code -systemctl --user enable --now proton-drive.service -pdfs status # account, mount and queue state -``` - -The CLI cannot show a CAPTCHA. If sign-in reports one, sign in once with `pdfs-app` instead; the -session it stores is used by the CLI and the service as well. - -## Headless and server use - -The service unit is bound to `graphical-session.target`. On a machine without a desktop session, -run the daemon directly or from your own unit: - -```bash -pdfs daemon # waits for a stored session, mounts, stays mounted -pdfs mount /srv/proton # mounts once at a given path, blocks until unmounted -``` - -Both still need a Secret Service provider. On a server, run -`gnome-keyring-daemon --unlock` or KeePassXC's Secret Service integration inside the user's D-Bus -session. - -## Updating - -Install the new package over the old one. The service picks up the new binary the next time it -starts; to switch at once: - -```bash -systemctl --user restart proton-drive.service -``` - -With the `.deb`, the release `.rpm` or the `.tar.gz`, nothing tells you about a new release. -Turn on **Preferences → General → Check for updates** and the app asks GitHub once a day and -shows a banner over the sidebar when a newer version is out. Packages that a package manager -updates do not offer the setting. A package shows this by installing the empty file -`share/proton-drive-linux/managed-updates` under the prefix of its `bin/` directory, for example -`/usr/share/proton-drive-linux/managed-updates`. - -Coming from 2.8.0 or older, re-enable the service once. Those releases hooked it into -`default.target`, which starts it before the desktop session is ready; on KDE that crashes -`ksecretd` at every login. Signing in again or toggling "Start on login" does this as well: - -```bash -systemctl --user reenable proton-drive.service -``` - -Database migrations run automatically and only move forward. A database written by a newer -release refuses to open in an older one, so downgrading means clearing the local database (see -[Troubleshooting](TROUBLESHOOTING.md#start-over-with-a-clean-local-state)). - -## Uninstalling - -> [!WARNING] -> Check that nothing is waiting to upload before you remove local state. `pdfs sync queue` must be -> empty. Queued writes exist only on this computer until they reach Proton Drive. - -```bash -pdfs sync queue # must list nothing -systemctl --user disable --now proton-drive.service -pdfs logout # removes the session from the keyring -``` - -Then remove the package (`sudo apt remove proton-drive-linux`, `sudo dnf remove -proton-drive-linux`, or `sudo pacman -R proton-drive-for-linux`). Removing the package also stops -the service of every logged-in user, in case a step above was skipped. - -> [!CAUTION] -> Do not delete `~/ProtonDrive` while it is mounted. It is your Proton Drive, not a copy: every -> file deleted there is moved to the Proton Drive trash. Once the service is stopped the folder is -> an empty mount point, and removing it is safe. - -If you want no trace left, remove the local data as well: - -```bash -rm -rf ~/.config/proton-drive-linux ~/.local/state/proton-drive-linux ~/.cache/proton-drive-linux -``` - -Sign out of the device in your Proton account settings as well, and remove the computer from -**Computers** in the Proton Drive web app if you no longer want its backups. +| Path | Purpose | +|---|---| +| `/usr/bin/pdfs` | Command-line client and background service | +| `/usr/bin/pdfs-app` | Desktop app | +| `/usr/bin/pdfs-tray` | Tray icon | +| `/usr/bin/pdfs-prompt` | Search launcher | +| `/usr/lib/systemd/user/proton-drive.service` | User service that keeps the drive mounted | +| `/etc/xdg/autostart/io.narl.proton-drive-linux-tray.desktop` | Starts the tray at login | +| `/usr/share/locale/*/LC_MESSAGES/pdfs.mo` | Translations | diff --git a/docs/LAUNCHER_AND_TRAY.md b/docs/LAUNCHER_AND_TRAY.md new file mode 100644 index 0000000..4022f34 --- /dev/null +++ b/docs/LAUNCHER_AND_TRAY.md @@ -0,0 +1,86 @@ +# Search launcher and tray + +The search launcher finds files in Proton Drive and in your home folder from a keyboard shortcut. +The tray icon shows whether everything is up to date and gives quick access to the app. + +- [Search launcher](#search-launcher) +- [Using your own launcher](#using-your-own-launcher) +- [Search as you type with fzf](#search-as-you-type-with-fzf) +- [Tray](#tray) + +## Search launcher + +![The search launcher](../images/prompt_gtk.png) + +`pdfs-prompt` searches Proton Drive and your home folder together, in one list with the best +matches first. It copes with prefixes, abbreviations, typos and swapped letters, and also matches +the names of parent folders. + +To set it up, bind `pdfs-prompt` to a keyboard shortcut in your desktop's settings. + +The window stays loaded after the first use, so later shortcuts open it instantly. Folders, music +and videos open straight from `~/ProtonDrive`, so players can start before the whole file is down. +Other files from Proton Drive download first, then open. + +To make even the first shortcut instant, start the launcher hidden when you log in. +`pdfs-prompt --preload` loads the window without showing it, and does nothing if the launcher is +already running. For example, in Hyprland: + +```ini +exec-once = pdfs-prompt --preload +bind = SUPER, space, exec, pdfs-prompt +``` + +Which program opens a file can be changed per file type. See +[Choose which program opens a file](FILES.md#choose-which-program-opens-a-file). + +## Using your own launcher + +`pdfs-prompt --dmenu` shows the results in fuzzel, rofi, wofi, tofi, bemenu or dmenu, whichever is +installed: + +```bash +pdfs-prompt --dmenu +pdfs-prompt --dmenu --menu 'fuzzel --dmenu --width 60' +pdfs-prompt --dmenu --query invoice +``` + +These launchers filter a fixed list and cannot ask for new results while you type, so the search +takes two steps: + +1. The first list, `Search Drive ›`, shows your available-offline files. Type a search and press + Enter. +2. The second list, `Drive: invoice ›`, shows the results. Enter opens one. Typing something else + searches again. + +## Search as you type with fzf + +![The search launcher in fzf](../images/prompt_fzf.png) + +`pdfs-prompt --fzf` searches again on every key press, like the built-in window. It needs `fzf`. +Started from a keyboard shortcut, it opens a terminal by itself (foot, ghostty, kitty, alacritty, +wezterm or xterm) with the app ID `pdfs-prompt`, so one window rule covers all of them. For +example, in Hyprland: + +```ini +windowrulev2 = float, class:^(pdfs-prompt)$ +windowrulev2 = size 900 500, class:^(pdfs-prompt)$ +windowrulev2 = center, class:^(pdfs-prompt)$ +bind = SUPER, space, exec, pdfs-prompt --fzf +``` + +To make `--dmenu` or `--fzf` the default without changing your shortcut, set `prompt.mode` in +`config.json` (see [Configuration → `prompt`](CONFIGURATION.md#prompt)). `--gtk` always opens the +built-in window. + +## Tray + +`pdfs-tray` starts when you log in and shows whether your files are up to date, syncing, paused or +offline. Its menu opens the app or `~/ProtonDrive`, pauses or resumes sync, and stops or connects +the service. + +- **GNOME** shows tray icons only with the + [AppIndicator extension](https://extensions.gnome.org/extension/615/appindicator-support/). + KDE Plasma and most other desktops show it without help. +- **Hide Tray Icon** in its menu removes it until you turn it back on under + **Preferences → General → Appearance → Show tray icon**. diff --git a/docs/PHOTOS.md b/docs/PHOTOS.md new file mode 100644 index 0000000..80ee746 --- /dev/null +++ b/docs/PHOTOS.md @@ -0,0 +1,77 @@ +# Photos + +The **Photos** page of the app shows your Proton Photos library. Photos are stored apart from +My files, so they do not appear in `~/ProtonDrive`. + +- [Timeline](#timeline) +- [Albums](#albums) +- [Places](#places) +- [Viewer and duplicates](#viewer-and-duplicates) +- [Importing from Google Photos](#importing-from-google-photos) +- [Fixing photos filed under the wrong date](#fixing-photos-filed-under-the-wrong-date) + +![The Photos timeline](../images/photos.png) + +## Timeline + +- The timeline groups photos by day, month or year as you zoom. Drag the scrubber on the right + edge to jump through the years. +- **On this day** shows photos taken on the same date in earlier years. +- **Filters** narrow the timeline to images, videos or RAW files, to favorites, or to photos that + are in no album. +- **RAW + JPEG pairs** of the same shot show as one tile. The viewer switches between the two, and + moving the tile to the Trash removes both. +- **Upload** adds photos from this computer. + +## Albums + +**Albums** lists your own albums and the albums others share with you. Create, rename and delete +albums, and add or remove photos. Deleting an album keeps its photos in the timeline. + +## Places + +![Places on the map](../images/photos_map.png) + +**Places** groups photos by the town they were taken in, as cards or on a map. Town names come +from [GeoNames](https://www.geonames.org/) data (CC BY 4.0) and the map from +[Natural Earth](https://www.naturalearthdata.com/) (public domain). Both ship with the app, so +nothing is fetched online. + +A street map from [OpenFreeMap](https://openfreemap.org/) (© OpenStreetMap contributors) can be +turned on under **Preferences → General → Appearance**. It is off by default, because the map +server learns which areas you look at. + +## Viewer and duplicates + +- The viewer marks favorites, shows EXIF details, shows a photo on the map, and runs a slideshow + (F5). +- **Find Duplicates…** in the page menu lists byte-identical copies. Turn on **Similar** to also + find resized or re-encoded copies and burst shots. + +## Importing from Google Photos + +1. Request a [Google Takeout](https://takeout.google.com/) export of Google Photos and download + every `.zip` of it. +2. In the app, open the **Upload** menu on the Photos page and choose **Import from Google + Photos…**. Select all the `.zip` files at once, because a photo and its details are often in + different parts of the export. + +From a terminal: + +```bash +pdfs import-google-photos --dry-run ~/Downloads/takeout-*.zip # show what would happen +pdfs import-google-photos --wait ~/Downloads/takeout-*.zip +``` + +The import recreates your albums and takes capture dates and locations from the export. Photos +already in your library are skipped, so an interrupted import can simply be run again. +`pdfs import-status` shows how far an import is, and `pdfs cancel-import` stops it. + +## Fixing photos filed under the wrong date + +Photos from an earlier import sometimes sit under the day they were uploaded instead of the day +they were taken. `pdfs redate-photos --dry-run` finds those whose file name carries a different +date, and `pdfs redate-photos` fixes them. + +Proton cannot change a capture date in place. So each fix uploads the photo again with the right +date and moves the original to the Trash. Favorites and albums are kept. diff --git a/docs/README.md b/docs/README.md index afe77f7..8a474a6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,19 +1,48 @@ -# Documentation +# Proton Drive for Linux documentation -## For users +Proton Drive for Linux is an unofficial Proton Drive client for the Linux desktop. Your Drive +appears as a folder that downloads files when you open them, local folders are backed up and kept +in sync, and a GTK app with a tray icon and a search launcher covers Photos, sharing and more. A +command-line client does all of it from a terminal. + +These pages are also published as the +[wiki](https://github.com/narrrl/proton-drive-linux/wiki), generated from the +[`docs/`](https://github.com/narrrl/proton-drive-linux/tree/main/docs) folder of the repository. + +## Where to start + +- **New here?** [Getting started](GETTING_STARTED.md) takes you from installing to your first + synced folder. +- **Installing or updating?** [Installation](INSTALL.md) covers Fedora (COPR), Arch (AUR), + Debian and Ubuntu, NixOS, and building from source. +- **Something not working?** [Troubleshooting](TROUBLESHOOTING.md) starts with `pdfs diagnose` + and goes through common problems. +- **New computer, or the old one is gone?** [Recovering on a new computer](RECOVERY.md) gets your + synced folders back. +- **Quick question?** Try the [FAQ](FAQ.md). + +## Using it + +| Page | What it covers | +|---|---| +| [User guide](USER_GUIDE.md) | How the pieces fit together, the words the app uses, preferences | +| [Files and offline access](FILES.md) | The `~/ProtonDrive` folder, keeping files available offline, the Trash, earlier versions | +| [Synced folders](SYNCED_FOLDERS.md) | Backing up local folders, excluding files, changes waiting to upload, conflicts, pausing | +| [Photos](PHOTOS.md) | Timeline, albums, places, duplicates, importing from Google Photos | +| [Sharing](SHARING.md) | Invitations, public links, items shared with you | +| [Computers](COMPUTERS.md) | Other computers in your account, syncing several computers | +| [Search launcher and tray](LAUNCHER_AND_TRAY.md) | Finding files from a keyboard shortcut, the tray icon | + +## Reference | Page | What it covers | |---|---| -| [Installation](INSTALL.md) | Packages, building from source, first sign-in, updating and uninstalling | -| [User guide](USER_GUIDE.md) | My files, available offline, synced folders, sync issues and conflicts, Photos, sharing, Trash and versions, Computers, the search launcher, the tray | | [Command-line reference](CLI.md) | Every `pdfs` command, grouped by task, and scripting with `--json` | | [Configuration](CONFIGURATION.md) | `config.json`, environment variables, file locations, the systemd service | -| [Troubleshooting](TROUBLESHOOTING.md) | Diagnosing problems, common symptoms, starting over, reporting a bug | -| [Recovering on a new computer](RECOVERY.md) | What survives a lost machine and how to restore your synced folders | | [Security model](SECURITY_MODEL.md) | What protects your files, what is kept on this computer, what the client connects to | | [Changelog](CHANGELOG.md) | What changed in each release | -## For contributors +## Contributing | Page | What it covers | |---|---| @@ -24,5 +53,5 @@ | [Roadmap](ROADMAP.md) | Planned work and verification still owed | | [Bug ledger](BUGS.md) | Every tracked defect with its analysis and status | -Also see [CONTRIBUTING.md](../CONTRIBUTING.md) and [SECURITY.md](../SECURITY.md) in the repository -root. +Also see [CONTRIBUTING.md](../CONTRIBUTING.md), and [SECURITY.md](../SECURITY.md) to report a +vulnerability privately. diff --git a/docs/RECOVERY.md b/docs/RECOVERY.md index b6a58f4..3fc7c24 100644 --- a/docs/RECOVERY.md +++ b/docs/RECOVERY.md @@ -3,6 +3,10 @@ Your laptop is lost, stolen or reinstalled. This page explains what survives, and how to get your synced folders back on the replacement machine. +**In short:** sign the old machine out of your Proton account. Then, on the new one, install the +client and sign in. On the **Computers** page, choose **Continue This Backup Here…** on the old +computer, then **Restore Folders…** on this one. + - [1. What survives](#1-what-survives) - [2. Restore your synced folders](#2-restore-your-synced-folders) - [3. How the restore works](#3-how-the-restore-works) @@ -52,7 +56,7 @@ be decrypted. ### Step 1: Install and sign in -Install the client as described in [INSTALL.md](INSTALL.md) and sign in with `pdfs-app`. Signing +Install the client as described in [Installation](INSTALL.md) and sign in with `pdfs-app`. Signing in from the app also starts the service. ### Step 2: Continue the old computer's backup @@ -100,7 +104,7 @@ progress on **Sync → Overview** or with `pdfs sync list`. > Restore into empty or missing directories. If a directory already holds files, for example > from another backup, the client cannot tell which side is newer. It keeps both: your local file > is renamed to a `(sync-conflict …)` copy and the version from Proton Drive is downloaded. See -> [Conflicts](USER_GUIDE.md#conflicts). +> [Conflicts](SYNCED_FOLDERS.md#conflicts). ### Step 4: Restore the rest by hand @@ -191,4 +195,4 @@ This section is for the curious and for anyone debugging a restore. | No warning at shutdown or sign-out while changes are queued | Check `pdfs sync queue` before you retire a machine | | The full disaster drill (delete all local state, restore, compare byte for byte) has not been run against a live account | The individual steps are tested; the whole sequence is not | -Planned work is tracked in [ROADMAP.md](ROADMAP.md). +Planned work is tracked in the [roadmap](ROADMAP.md). diff --git a/docs/SHARING.md b/docs/SHARING.md new file mode 100644 index 0000000..a1e5d65 --- /dev/null +++ b/docs/SHARING.md @@ -0,0 +1,52 @@ +# Sharing + +Share files and folders with other people, by invitation or with a public link, and use what +others share with you. + +- [Invite people](#invite-people) +- [Create a public link](#create-a-public-link) +- [See what you share](#see-what-you-share) +- [Shared with you](#shared-with-you) + +## Invite people + +1. Select a file or folder and choose **Share…**. +2. Enter one or more email addresses and choose **Can view** or **Can edit**. +3. Send the invitation. People appear as members once they accept. + +The admin role, which may also manage the share, is available from the command line +(`--role admin`). + +From a terminal: + +```bash +pdfs share Documents/Plans alex@example.com --role editor +pdfs members Documents/Plans # members, pending invitations and the public link +``` + +`pdfs share-role` changes someone's role, and `pdfs unshare` removes one person or stops sharing +altogether. See the [command-line reference](CLI.md#sharing). + +## Create a public link + +In **Share…**, create a public link. Anyone with the link can open the item. You can protect the +link with a password and let it expire on a date. From a terminal, use `pdfs public-link create` +and `pdfs public-link remove`. + +## See what you share + +**Shared by me** lists everything you share. Filter it by links, by people, or by expired links. +Copy a link that is still valid, or stop several shares at once. `pdfs shared` prints the same +list. + +## Shared with you + +**Shared with me** lists what other people share with you, who shared it, and what you may do with +it. The same items are in the `Shared with me` folder inside `~/ProtonDrive`. Items where you are +a viewer are read-only. + +- **Invitations** wait in a banner at the top of the page until you accept or reject them. From a + terminal: `pdfs invitations list`, then `accept ID` or `reject ID`. +- **Saved public links** have their own view. `pdfs bookmarks` manages them. +- **Leave…** a share you no longer need, or run `pdfs leave UID` with the ID from + `pdfs shared-with-me`. diff --git a/docs/SYNCED_FOLDERS.md b/docs/SYNCED_FOLDERS.md new file mode 100644 index 0000000..aed940b --- /dev/null +++ b/docs/SYNCED_FOLDERS.md @@ -0,0 +1,163 @@ +# Synced folders + +A synced folder is an ordinary folder on this computer, for example `~/Documents`, that is backed +up to Proton Drive and kept in step with it. This page covers adding one, what to do with files +that should not be backed up, changes that are still waiting to upload, conflicts, and pausing. + +- [Add a folder](#add-a-folder) +- [Synced or online only](#synced-or-online-only) +- [Move files between synced folders and My files](#move-files-between-synced-folders-and-my-files) +- [Stop syncing a folder](#stop-syncing-a-folder) +- [Excluding files with `.pdfsignore`](#excluding-files-with-pdfsignore) +- [Changes waiting for Proton Drive](#changes-waiting-for-proton-drive) +- [Conflicts](#conflicts) +- [Pausing and limiting sync](#pausing-and-limiting-sync) + +![Synced folders in the app](../images/sync.png) + +## Add a folder + +- **In the app:** open **Computers** and choose **Add Folder to Sync**. +- **From a terminal:** `pdfs sync add ~/Documents` + +The folder is backed up under this computer's name. It shows on the **Computers** page of the app +and in the Proton Drive web app. + +From then on, changes go both ways: + +- A file you change here uploads a few seconds after the program closes it. A file that a + program still holds open for writing waits until it is closed. +- A file changed somewhere else downloads on the next sync pass. + +**Sync → Folders** in the app, and `pdfs sync list`, show every synced folder and its state. + +To sync the same folders on two computers, see [Syncing several computers](COMPUTERS.md#syncing-several-computers). + +## Synced or online only + +A synced folder normally keeps a full copy on this computer. You can switch it to **Online +only**: the files stay visible in the same place, but take no disk space until you open them, the +same as in `~/ProtonDrive`. + +- **In the app:** use the **Synced / Online only** switch on the folder's card. +- **From a terminal:** `pdfs sync mode ID ondemand`, and `pdfs sync mode ID mirror` to switch + back. `pdfs sync list` shows the ID. + +The switch waits until everything in the folder is on Proton Drive. It refuses while the folder +holds something that never goes there, such as an excluded `.git/` folder, a symbolic link, or a +folder you may not read. The message names what is in the way. + +`pdfs locations` lists every place on this computer the Proton Drive service uses. + +## Move files between synced folders and My files + +`~/ProtonDrive`, each online-only folder and each synced folder are separate places for your +system. Moving a file between them with `mv` or a file manager copies and then deletes: every file +is downloaded, uploaded again, and the original goes to the Trash. + +Use **Move to…** in the app or `pdfs move` instead. The move happens on Proton Drive and takes +seconds, whatever the size: + +```sh +pdfs move ~/Documents/Scans ~/ProtonDrive/Archive +pdfs move ~/Documents/a.pdf ~/Documents/b.pdf ~/ProtonDrive/Archive +``` + +The last path is the destination folder. Everything before it moves there. + +A move out of a synced folder waits until its files are on Proton Drive. A file that is still +uploading, has changes that are not uploaded yet, or is excluded by `.pdfsignore` stops the move, +and the message names it. Files you already opened in an online-only folder are not downloaded +again when they move into a synced one. + +## Stop syncing a folder + +**Stop Syncing** in the app, or `pdfs sync rm ID`, keeps both the local files and the copy on +Proton Drive. To delete the copy on Proton Drive as well, tick **Also delete from Proton Drive**, +or add `--delete-remote`. + +## Excluding files with `.pdfsignore` + +Synced folders skip build output, dependency folders and editor leftovers. Two sets of rules +apply together: + +1. A `.pdfsignore` file at the top of the synced folder (`.protonignore` works too). It uses the + same syntax as `.gitignore`, including `!` to include something again: + + ```gitignore + build/ + *.log + !important.log + ``` + +2. The `ignore_patterns` list in `config.json`, for every synced folder (see + [Configuration](CONFIGURATION.md#ignore_patterns)). When you have not set it, it skips + `.git/`, `.hg/`, `.svn/`, `node_modules/`, `target/`, `.venv/`, `__pycache__/`, `*~`, + `*.swp`, `*.tmp`, `.DS_Store` and `Thumbs.db`. + +Rules are read again on every sync pass. Excluding never deletes anything: a file that becomes +excluded is no longer synced, and its copy on Proton Drive stays. + +A folder you may not read, such as a cache that a container created as root, is skipped the same +way, and the activity feed mentions it once. Add it to `.pdfsignore` to stop the message. + +## Changes waiting for Proton Drive + +A change you make exists only on this computer until it reaches Proton Drive. `pdfs status`, the +tray and **Sync → Overview** count what is still waiting, and `pdfs sync queue` lists it. + +Sometimes Proton Drive refuses a change: the storage is full, a share was taken away, the folder +is gone, the folder holds too many items, or Proton Drive does not accept the name. The change +then needs you. It shows at once in **Sync → Overview**, in the tray and in `pdfs sync issues`, +with what it means and what you can do. The file or folder also gets a warning badge in +**Files**. Hover over it to see why. + +Nothing is deleted. The change stays queued and is tried again. You can: + +- **Retry** it now, for example after freeing space: the same list, or `pdfs sync retry`. +- **Export** a file's content to keep your version: `pdfs sync export ID FILE`. +- **Discard** the change: `pdfs sync discard ID`. It is undone here and never sent. A new file or + folder goes away, and anything else goes back to what Proton Drive has. Export first if you want + to keep the content. + +Two cases are not refused, and the activity log records both: + +- A new file or folder whose name is already taken on Proton Drive, by something this computer + had not seen yet, lands under a `(sync-conflict …)` name. See [Conflicts](#conflicts). +- A new file whose folder was deleted on another device in the meantime lands at the top of My + files, so its content is not lost. + +> [!IMPORTANT] +> Before you switch off or wipe a computer for good, check that nothing is waiting. Changes that +> have not reached Proton Drive are lost with the machine. See +> [Recovery](RECOVERY.md#lost-with-the-machine). + +## Conflicts + +![Sync history with resolved conflicts](../images/conflicts.png) + +When the same file changed on this computer and somewhere else since the last sync, neither +version is thrown away: + +- The other version keeps the original name. +- Your local version is kept as a copy named like + `report (sync-conflict laptop 1759068180).odt`. `laptop` is the computer that made the copy, + and the number is the time of the conflict. Copies made before 3.5.0 have no computer name. + +Conflicts show under **Sync → Overview → Needs attention** and in `pdfs conflicts`. For each one, +keep the original, keep the copy, or keep both under a new name: + +```bash +pdfs conflicts +pdfs conflicts resolve "Documents/report (sync-conflict laptop 1759068180).odt" --keep copy +``` + +The version you do not keep goes to the Trash, so a wrong choice can be undone. + +## Pausing and limiting sync + +- **Pause** from the tray, the **Sync** page, or `pdfs sync pause`. Uploads and synced folders + wait, and opening files keeps working. `pdfs sync pause --for 1h` resumes by itself, and + `pdfs sync resume` continues at once. +- **Limit bandwidth** under **Preferences → General → Network**, or with + `pdfs sync limit --up 2M --down 10M`. `0` removes a limit. diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index b0211aa..539a13b 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -57,7 +57,7 @@ journalctl --user -u proton-drive.service -b -p warning # warnings since boot ``` For more detail, raise the log level with a drop-in (see -[CONFIGURATION.md](CONFIGURATION.md#the-systemd-service)) and restart the service. +[Configuration](CONFIGURATION.md#the-systemd-service)) and restart the service. ### Service state @@ -68,96 +68,123 @@ pdfs status ## Signing in -**"Proton is asking for a CAPTCHA"** — Proton wants human verification, usually on a VPN or an -unfamiliar network. `pdfs login` prints the verification page's address: open it in your browser, -complete it, then press Enter. The app shows the page in its own window. +### Proton is asking for a CAPTCHA -**"Verify in Your Browser"** — WebKit, which shows the CAPTCHA page in the app, could not start -its sandbox. Hardened systems such as secureblue keep its bubblewrap from the journal socket, and -the log then shows `bwrap: Can't get type of source /run/systemd/journal/socket: Permission -denied` and `Failed to fully launch dbus-proxy`. Choose **Open Verification Page**, complete the -page in your browser, then choose **Continue**. If that sign-in is refused too, check that `bwrap` -and `xdg-dbus-proxy` are installed. As a last resort, sign in once with the sandbox switched off -for this one run: +Proton wants to check that you are human, usually on a VPN or an unfamiliar network. The app +shows the page in its own window. `pdfs login` prints the page's address instead: open it in your +browser, complete it, then press Enter. + +### "Verify in Your Browser" + +WebKit, which shows the CAPTCHA page in the app, could not start its sandbox. Hardened systems +such as secureblue keep its bubblewrap away from the journal socket. The log then shows +`bwrap: Can't get type of source /run/systemd/journal/socket: Permission denied` and +`Failed to fully launch dbus-proxy`. + +1. Choose **Open Verification Page** and complete the page in your browser. +2. Choose **Continue**. + +If that sign-in is refused too, check that `bwrap` and `xdg-dbus-proxy` are installed. As a last +resort, quit the app and sign in once with the sandbox switched off for this one run: ```bash WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1 pdfs-app ``` -Quit the app first, so this starts a new instance. The page then runs without WebKit's isolation, -so use this only for the sign-in. The stored session keeps working without it. Signing in from -your usual network, without a VPN, often avoids the CAPTCHA in the first place. +The page then runs without WebKit's isolation, so use this only for the sign-in. The stored +session keeps working without it. Signing in from your usual network, without a VPN, often avoids +the CAPTCHA in the first place. -**"This version of the app is no longer supported"** or **"Proton is temporarily refusing -sign-in from this device"** — Proton blocks sign-in for a while after too many attempts or from a -network it distrusts, and sends the first message even when the release is current. Do not retry -for several hours, up to a day, then sign in once. If it still fails, run -`RUST_LOG=debug pdfs login` and look for `code=` in the `proton api request failed` line: 2028 is -this block, 5003 is a release Proton no longer accepts. +### "This version of the app is no longer supported" or "Proton is temporarily refusing sign-in from this device" -**Sign-in works but is forgotten after a restart** — no Secret Service provider is running, or its -keyring is locked. Install and unlock GNOME Keyring, KWallet or KeePassXC (with Secret Service -enabled). `pdfs diagnose` shows `keyring session` as failing in that case. When the app finds -a saved sign-in it cannot read, it says so above the sign-in form and opens on its own once the -keyring is unlocked. You don't have to sign in again. +Proton blocks sign-in for a while after too many attempts, or from a network it distrusts. It sends +the first message even when your version is current. Do not retry for several hours, up to a day, +then sign in once. -**Asked for the mailbox password after every reboot** — the account has a separate mailbox -password (two-password mode). Such accounts are locked by default: the unlock lasts until you log -out or restart. To stay unlocked, turn on **Keep unlocked on this computer** in the unlock dialog, -or run `pdfs unlock --remember`. Either one stores the unlock in the system keyring. -[SECURITY_MODEL.md](SECURITY_MODEL.md) explains what that trades away. +If it still fails, run `RUST_LOG=debug pdfs login` and look for `code=` in the +`proton api request failed` line. 2028 is this block; 5003 is a release Proton no longer accepts. + +### Sign-in works but is forgotten after a restart + +No Secret Service provider is running, or its keyring is locked. Install and unlock GNOME +Keyring, KWallet or KeePassXC (with Secret Service turned on). `pdfs diagnose` then shows +`keyring session` as failing. + +When the app finds a saved sign-in it cannot read, it says so above the sign-in form, and opens +by itself once the keyring is unlocked. You do not have to sign in again. + +### Asked for the mailbox password after every reboot + +The account has a separate mailbox password (two-password mode). Such accounts are locked by +default: the unlock lasts until you log out or restart. To stay unlocked, turn on **Keep unlocked +on this computer** in the unlock dialog, or run `pdfs unlock --remember`. Either one stores the +unlock in the system keyring. The [security model](SECURITY_MODEL.md) explains what that trades +away. ## The Proton Drive folder > [!TIP] > When the service hangs, any program that touches the Proton Drive folder can hang with it, -> including `ls` and your shell's prompt. Prefix exploratory commands with `timeout 5`. +> including `ls` and your shell's prompt. Put `timeout 5` in front of commands you try. -**`Transport endpoint is not connected`** — the service stopped without unmounting. Unmount and -restart: +### `Transport endpoint is not connected` + +The service stopped without unmounting. Unmount and restart: ```bash fusermount3 -uz ~/ProtonDrive systemctl --user restart proton-drive.service ``` -**`fetch My Files root: … failed to decrypt: missing key`** in the service log — the account -keys cannot open your Drive volume, which happens after a password reset. Proton locks the volume -that was encrypted to the old keys. From 3.4.1 the client starts a new, empty My Files volume -in that case. Your old files stay in the locked volume: open [drive.proton.me](https://drive.proton.me) -and restore them there with your previous password. +### The folder is empty or missing -**The folder is empty or missing** — check that the service runs and is signed in -(`pdfs status`). The service waits for a stored session before it mounts. +Check that the service runs and is signed in, with `pdfs status`. The service waits for a stored +session before it shows your files. -**Everything in the folder hangs** — find out what the service is doing, then restart it: +### `fetch My Files root: … failed to decrypt: missing key` in the log + +Your account keys cannot open your Drive, which happens after a password reset: Proton locks the +files that were encrypted with the old keys. Since 3.4.1 the client then starts a new, empty My +files. Your old files are still there, locked: open [drive.proton.me](https://drive.proton.me) and +restore them with your previous password. + +### Everything in the folder hangs + +Find out what the service is doing, then restart it: ```bash timeout 10 pdfs diagnostics systemctl --user restart proton-drive.service ``` -The service watchdog restarts a service that stops answering for two minutes by itself. Attach the -`pdfs diagnostics` output to a bug report; it shows which worker is stuck. +The service restarts by itself when it stops answering for two minutes. Attach the +`pdfs diagnostics` output to a bug report; it shows which part is stuck. -**A change made on another device does not show up** — changes arrive through Proton's event -stream, normally within seconds. To fetch a folder again at once: +### A change made on another device does not show up + +Changes from other devices normally arrive within seconds. To fetch a folder again at once: ```bash pdfs refresh Documents ``` -**"Permission denied" when writing** — the item is in a share where you are a viewer, or under -`Shared with me/`, which is read-only as a folder. Check your role with `pdfs shared-with-me`. +### "Permission denied" when writing -**`ln` or another program fails with "Operation not permitted"** — Proton Drive cannot store -symbolic links, hard links, device files or FIFOs, so creating one fails at once. The error is -intentional. Use a synced folder for projects that need them, or exclude those paths. +The item is in a share where you are a viewer, or directly under `Shared with me/`, which is +read-only. Check your role with `pdfs shared-with-me`. + +### `ln` or another program fails with "Operation not permitted" + +Proton Drive cannot store symbolic links, hard links, device files or FIFOs, so creating one fails +at once. This is on purpose. For projects that need them, use a +[synced folder](SYNCED_FOLDERS.md) and exclude those paths. ## Uploads and sync -**A change shows here but not on other devices** — changes are recorded on this computer first -and sent from a queue. List what is still waiting, and what needs attention: +### A change shows here but not on other devices + +Changes are recorded on this computer first and sent from a queue. List what is still waiting, +and what needs you: ```bash pdfs sync queue @@ -165,72 +192,89 @@ pdfs sync issues ``` The app shows the same on **Sync → Overview**. A change waits while the service is offline or -sync is paused (`pdfs status`), and backs off after a failure. To retry at once: +sync is paused (`pdfs status`), and waits longer after each failure. To retry at once: ```bash -pdfs sync retry # every failed operation -pdfs sync retry 42 # one operation +pdfs sync retry # every failed change +pdfs sync retry 42 # one change ``` A change Proton Drive refuses (storage full, access taken away, folder gone) is listed by `pdfs sync issues` with what to do. It stays queued until you fix the cause or drop it. Dropping -it undoes it here; save a file's content first if you want to keep it: +it undoes it here, so save a file's content first if you want to keep it: ```bash pdfs sync export 42 ~/Desktop/ pdfs sync discard 42 ``` -If you suspect the local-first behaviour of 3.0.0 itself, `"local_first": false` in `config.json` -makes the Proton Drive folder wait for Proton Drive again while online (see -[CONFIGURATION.md](CONFIGURATION.md#local_first)), and please report the problem. +[Changes waiting for Proton Drive](SYNCED_FOLDERS.md#changes-waiting-for-proton-drive) explains +the choices. -**A file in a synced folder does not upload** — check that: +If you suspect that the instant, queued changes introduced in 3.0.0 are the problem, +`"local_first": false` in `config.json` makes the Proton Drive folder wait for Proton Drive again +while online (see [Configuration](CONFIGURATION.md#local_first)). Please report the problem too. -- it is not matched by `.pdfsignore` or `ignore_patterns`; +### A file in a synced folder does not upload + +Check that: + +- it is not excluded by `.pdfsignore` or `ignore_patterns`; - no program still holds it open for writing (such files wait until closed); -- sync is not paused (`pdfs status`, tray); -- the folder has no error on **Sync → Folders**. +- sync is not paused (`pdfs status`, or the tray); +- the folder shows no error on **Sync → Folders**. -`pdfs sync now` starts a pass immediately. +`pdfs sync now` starts a sync pass at once. -**Files named `(sync-conflict …)` appeared** — the file changed in two places at once. Nothing was -lost; see [Conflicts](USER_GUIDE.md#conflicts) to pick a version. +### Files named `(sync-conflict …)` appeared -**Photos show the wrong date after a Google Takeout import** — run -`pdfs redate-photos --dry-run`, see [USER_GUIDE.md](USER_GUIDE.md#importing-from-google-photos). +The file changed in two places at once. Nothing was lost. See +[Conflicts](SYNCED_FOLDERS.md#conflicts) to pick a version. + +### Photos show the wrong date after a Google Takeout import + +Run `pdfs redate-photos --dry-run`. See +[Fixing photos filed under the wrong date](PHOTOS.md#fixing-photos-filed-under-the-wrong-date). ## Disk space | What | Check | Reduce | |---|---|---| -| Content cache | `pdfs cache inspect` | Lower **Preferences → Storage → Cache size limit**, or `pdfs cache clear` | +| Cache of opened files | `pdfs cache inspect` | Lower **Preferences → Storage → Cache size limit**, or `pdfs cache clear` | | Available-offline files | `pdfs pins` | `pdfs unpin PATH` | | Metadata database | `pdfs cache inspect` (reclaimable) | `pdfs cache vacuum` | | Synced folders | `pdfs sync list` | Switch large folders to online only: `pdfs sync mode ID ondemand` | -`pdfs cache vacuum` locks the database while it runs and needs free space for a second copy of it. +`pdfs cache vacuum` locks the database while it runs, and needs free space for a second copy of +it. ## Desktop integration -**No tray icon on GNOME** — install and enable the AppIndicator and KStatusNotifierItem Support -extension. Other desktops show the icon natively. If you hid it from its own menu, turn it back on -under **Preferences → General → Appearance**. +### No tray icon on GNOME -**The search launcher does nothing** — `pdfs-prompt` needs the service. Run it from a terminal to -see its error. For `--fzf`, install `fzf` and a supported terminal. +Install and turn on the +[AppIndicator and KStatusNotifierItem Support](https://extensions.gnome.org/extension/615/appindicator-support/) +extension. Other desktops show the icon without help. If you hid it from its own menu, turn it +back on under **Preferences → General → Appearance**. -**The app shows "Not responding"** — the service runs but does not answer within five seconds. -See [Everything in the folder hangs](#the-proton-drive-folder). +### The search launcher does nothing + +`pdfs-prompt` needs the service. Run it from a terminal to see its error. For `--fzf`, install +`fzf` and a supported terminal. + +### The app shows "Not responding" + +The service runs but does not answer within five seconds. See +[Everything in the folder hangs](#everything-in-the-folder-hangs). ## Start over with a clean local state -This removes the local database and cache so they are rebuilt from Proton Drive. It is the fix for -a damaged database and the only way to downgrade to an older release. +This removes the local database and cache, so they are built again from Proton Drive. It fixes a +damaged database, and it is the only way to go back to an older release. > [!WARNING] > Content in `staging/` and `recovery/` has not reached Proton Drive yet. Deleting it loses those -> changes permanently. Wait until `pdfs sync queue` is empty. +> changes for good. Wait until `pdfs sync queue` is empty. ```bash pdfs sync queue # must list nothing @@ -241,8 +285,8 @@ systemctl --user start proton-drive.service ``` Your session is in the keyring and your settings in `~/.config`, so you stay signed in. Synced -folders are not re-attached automatically; restore them with `pdfs sync restore` as described in -[RECOVERY.md](RECOVERY.md#2-restore-your-synced-folders). Delete the `.bak` directories once +folders are not attached again by themselves. Restore them with `pdfs sync restore`, as described +in [Recovery](RECOVERY.md#2-restore-your-synced-folders). Delete the `.bak` directories once everything is back. ## Reporting a problem @@ -253,7 +297,7 @@ Include: - the output of `pdfs diagnose`; - relevant log lines from `journalctl --user -u proton-drive.service`; - for a hang, the output of `timeout 10 pdfs diagnostics`; -- the steps that reproduce it. +- the steps that make it happen. Logs contain file names. Remove anything private before posting. Report security problems -privately as described in [SECURITY.md](../SECURITY.md). +privately, as described in [SECURITY.md](../SECURITY.md). diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index c8292d8..dad46f7 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -1,29 +1,27 @@ # User guide -How Proton Drive for Linux works and how to use it day to day. For installation see -[INSTALL.md](INSTALL.md); every command mentioned here is described in [CLI.md](CLI.md). +How Proton Drive for Linux works and how to use it day to day. To install it, see +[Installation](INSTALL.md). If you are new, [Getting started](GETTING_STARTED.md) is the quicker +read. -- [How it works](#how-it-works) -- [My files](#my-files) -- [Keeping files on this computer](#keeping-files-on-this-computer) -- [Syncing local folders](#syncing-local-folders) -- [Changes waiting for Proton Drive](#changes-waiting-for-proton-drive) -- [Conflicts](#conflicts) -- [Pausing and limiting sync](#pausing-and-limiting-sync) -- [Photos](#photos) -- [Sharing](#sharing) -- [Trash and version history](#trash-and-version-history) -- [Computers](#computers) -- [Search launcher](#search-launcher) -- [Choosing how files open](#choosing-how-files-open) -- [Tray](#tray) -- [Preferences](#preferences) +## Topics + +| Page | What it covers | +|---|---| +| [Files and offline access](FILES.md) | The `~/ProtonDrive` folder, keeping files available offline, the Trash, earlier versions | +| [Synced folders](SYNCED_FOLDERS.md) | Backing up local folders, excluding files, changes waiting to upload, conflicts, pausing | +| [Photos](PHOTOS.md) | Timeline, albums, places, duplicates, importing from Google Photos | +| [Sharing](SHARING.md) | Invitations, public links, items shared with you | +| [Computers](COMPUTERS.md) | Other computers in your account, syncing several computers | +| [Search launcher and tray](LAUNCHER_AND_TRAY.md) | Finding files from a keyboard shortcut, the tray icon | + +Every command mentioned in these pages is listed in the +[command-line reference](CLI.md). ## How it works A background service, `proton-drive.service`, runs `pdfs daemon`. It holds your session, talks to -Proton Drive, and keeps your Drive mounted as a folder. Everything else is a front end that asks -the service to do things over a local socket: +Proton Drive, and shows your Drive as a folder. Everything else asks the service to do things: | Program | What it is | |---|---| @@ -32,357 +30,30 @@ the service to do things over a local socket: | `pdfs-prompt` | A search launcher for a keyboard shortcut | | `pdfs` | The command-line client, for everything above and for scripts | -Your Drive, your file names and your photos are end-to-end encrypted by Proton. On this computer, -the service must decrypt what it shows you, and it keeps a decrypted cache and index on disk. Use -full-disk or home-directory encryption. [ARCHITECTURE.md §10](ARCHITECTURE.md#10-threat-model-what-this-client-writes-to-disk-in-plaintext) +Your files, file names and photos are end-to-end encrypted by Proton. To show them to you, the +service decrypts them on this computer and keeps a cache, which is not encrypted. Use full-disk or +home-folder encryption. The [security model](SECURITY_MODEL.md#what-is-kept-on-this-computer) lists exactly what is stored. -The app uses these words consistently, and so does this guide: +## Words used in the app + +The app uses these words, and so do these pages: | Term | Meaning | |---|---| -| **My files** | The root of your Drive | -| **Proton Drive folder** | Where My files appears on disk, `~/ProtonDrive` by default | -| **Online only** | A file or folder whose content downloads when opened | +| **My files** | Everything in your Proton Drive, apart from Photos and computer backups | +| **Proton Drive folder** | Where My files appears on this computer, `~/ProtonDrive` by default | +| **Online only** | A file or folder that downloads when you open it | | **Available offline** | A file, or a folder with everything in it, kept on this computer | | **Synced folder** | A local folder with a full copy on this computer, backed up to Proton Drive | | **Proton Drive service** | The background service (`proton-drive.service`) | -## My files - -My files is mounted at `~/ProtonDrive`. Every file and folder appears immediately, but content -downloads only when a program reads it: - -- **Reads fetch only what is needed.** A video player that seeks, or a tool that reads a file - header, downloads only those parts. Media streams while it plays. -- **Changes work at local speed.** Creating, renaming, moving and deleting files and folders - returns at once, online or offline. When a program closes a file it wrote, the new content is - stored on disk. Every change is queued and sent to Proton Drive in the background; the changes - to one file are sent in the order you made them. The queue survives network loss, restarts and - crashes. See [Changes waiting for Proton Drive](#changes-waiting-for-proton-drive). -- **Recently read content is cached** on disk up to the cache size limit (5 GiB by default) and - evicted oldest first. -- **Items shared with you** appear under `Shared with me/` inside the Proton Drive folder. Shares - where you are a viewer are read-only. - -The **My files** page of the app browses the same tree without going through the mount. It has a -grid and a list view, sorting, thumbnails (including camera RAW previews), multi-select and drag -and drop upload. **Details** (Alt+Enter) shows size, dates, sharing and version history for the -selected item. - -Symbolic links, hard links, device files and FIFOs cannot be stored on Proton Drive. Programs that -try to create them get a clean error, not a hang or `EIO`. - -## Keeping files on this computer - -Turn on **Available offline** for a file or folder in My files, or run `pdfs pin `. A file -is downloaded completely and never evicted from the cache. For a folder, every file in it and in -its subfolders downloads in the background, and the tray and the app show the progress. -`pdfs pins` lists what is kept, and **Preferences → Storage → Available offline** shows it in the -app. - -Turning it off (`pdfs unpin `) frees the space. The files stay on Proton Drive. A file inside -a folder kept offline stays with its folder: turn the folder off instead. - -## Syncing local folders - -A synced folder is an ordinary folder on this computer, for example `~/Documents`, that is -backed up to Proton Drive under this computer's name. It appears on the **Computers** page of the -app and in the web app. - -- Add one with **Add Folder to Sync** on the **Computers** page, or `pdfs sync add ~/Documents`. -- Changes flow both ways. Local edits upload a few seconds after the file is closed; remote edits - download on the next pass. -- A file that another program still holds open for writing is not uploaded until it is closed. -- **Sync → Folders** in the app, and `pdfs sync list`, show every folder and its state. - -Each synced folder can also be switched to **Online only**. The local copy is replaced by a mount -of the folder, so the files stay visible but take no disk space until opened. Switch with the -**Synced / Online only** switch on the folder's card, or `pdfs sync mode ondemand` and back -with `pdfs sync mode mirror`. The switch waits until everything in the folder is on Proton -Drive, and refuses while the folder holds something that never goes there: an ignored path such -as `.git/`, a symlink, or a folder you may not read. The message names it. `pdfs locations` lists every local place the service occupies. - -### Moving between synced folders and My files - -`~/ProtonDrive` and each online-only folder are separate mounts, and a mirrored folder is a plain -folder on disk. `mv`, and dragging in a file manager, cannot rename across them, so they copy -and then delete: every file is downloaded, uploaded again, and the original goes to the Trash. - -Use `pdfs move ` or **Move to…** in the app instead. The move happens on Proton -Drive, so it takes seconds whatever the size. For example: - -```sh -pdfs move ~/Documents/Scans ~/ProtonDrive/Archive -pdfs move ~/Documents/a.pdf ~/Documents/b.pdf ~/ProtonDrive/Archive -``` - -The last path is the destination folder; everything before it moves there. -Files already opened in an online-only folder are not downloaded again when -they move into a mirrored one. - -A move out of a synced folder waits until its files are on Proton Drive. A file that is still -uploading, has changes that are not uploaded, or is excluded by `.pdfsignore` stops the move, -and the message names it. - -Removing a synced folder (**Stop Syncing** or `pdfs sync rm `) keeps the local files and the -copy on Proton Drive. Add `--delete-remote` (or tick **Also delete from Proton Drive**) to delete -the copy on Proton Drive as well. - -### Excluding files with `.pdfsignore` - -Synced folders skip build output, dependency folders and editor leftovers. Rules come from two -places, and both apply: - -1. A `.pdfsignore` file at the root of the synced folder (`.protonignore` also works), using - gitignore syntax, including `!` to re-include: - - ```gitignore - build/ - *.log - !important.log - ``` - -2. The global `ignore_patterns` list in `config.json` (see - [CONFIGURATION.md](CONFIGURATION.md#ignore_patterns)). When unset, it defaults to `.git/`, - `.hg/`, `.svn/`, `node_modules/`, `target/`, `.venv/`, `__pycache__/`, `*~`, `*.swp`, `*.tmp`, - `.DS_Store` and `Thumbs.db`. - -Rules are re-read on every pass. Ignoring never deletes anything: a file that becomes ignored is -simply no longer tracked, and its copy on Proton Drive stays. - -A folder you may not read, such as a cache a container created as root, is skipped the same way, -and the activity feed names it once. Add it to `.pdfsignore` to stop that message. - -## Changes waiting for Proton Drive - -A change you made in the Proton Drive folder exists only on this computer until it reaches -Proton Drive. `pdfs status`, the tray and **Sync → Overview** count what is still waiting, and -`pdfs sync queue` lists it. - -Sometimes Proton Drive refuses a change: the storage is full, a share was taken away, the folder -is gone, the folder holds too many items, or Drive does not accept a name. The change then needs -your attention. It shows at once in **Sync → Overview**, in the tray, and in `pdfs sync issues`, -with what it means and what you can do. A file or folder with such a change carries a warning -badge in **Files**; hover it to see why. - -Nothing is deleted. The change stays queued and is retried. You can: - -- **Retry** it now, from the same list or with `pdfs sync retry`, for example after freeing space. -- **Export** a file's content to keep your version (`pdfs sync export `). -- **Discard** the change (`pdfs sync discard `). It is undone here and never sent: a new file - or folder goes away, anything else goes back to what Proton Drive has. Export first if you want - to keep the content. - -Two cases are not refused, and the activity log records both: - -- A new file or folder whose name is already taken on Proton Drive by something this computer had - not seen yet lands under a `(sync-conflict …)` name, as described below. -- A new file whose folder was deleted on another device meanwhile lands at the top of My files, - so its content is not lost. - -Before you shut down a computer for good, check that nothing is waiting: see -[RECOVERY.md](RECOVERY.md#lost-with-the-machine). - -## Conflicts - -When the same file changed on this computer and somewhere else since the last sync, neither side -is thrown away. The local version is kept as a copy named like -`report (sync-conflict laptop 1759068180).odt`, where `laptop` is the name of the computer that -made the copy and the number is the time of the conflict in seconds since 1970. The remote -version takes the original name. Copies made before 3.5.0 have no computer name. - -Conflicts appear under **Sync → Overview → Needs attention** and in `pdfs conflicts`. For each -one, keep the original, keep the copy, or keep both under a new name: - -```bash -pdfs conflicts -pdfs conflicts resolve "Documents/report (sync-conflict laptop 1759068180).odt" --keep copy -``` - -The version you do not keep goes to the Trash, so a wrong choice can be undone. - -## Pausing and limiting sync - -- **Pause** from the tray, the Sync page, or `pdfs sync pause`. Uploads and synced folders wait; - reading files keeps working. `pdfs sync resume` continues. -- **Limit bandwidth** under **Preferences → General → Network**, or with - `pdfs sync limit --up 2M --down 10M`. `0` removes a limit. - -## Photos - -The **Photos** page shows your Proton Photos library. Photos are stored separately from My files -and do not appear in the Proton Drive folder. - -- **Timeline** groups photos by day, month or year as you zoom. Drag the scrubber on the right edge - to jump through the years. **On this day** shows photos from the same date in earlier years. -- **Filters** narrow the timeline to images, videos or RAW files, to favorites, or to photos that - are in no album. -- **RAW + JPEG pairs** of the same shot show as one tile. The viewer switches between them, and - moving the tile to the Trash removes both. -- **Albums** lists your albums and albums shared with you. Create, rename and delete albums, and - add or remove photos. -- **Places** groups photos by the town they were taken in, as cards or on a map. Towns come from - bundled [GeoNames](https://www.geonames.org/) data (CC BY 4.0) and the map from - [Natural Earth](https://www.naturalearthdata.com/) (public domain), so nothing is fetched online. - An optional street map from [OpenFreeMap](https://openfreemap.org/) (© OpenStreetMap - contributors) can be enabled under **Preferences → General → Appearance**. It is off by default - because the tile server learns which areas you look at. -- **Viewer**: favorites, EXIF details, show on map, slideshow (F5). -- **Find Duplicates…** in the page menu lists byte-identical copies. The **Similar** switch also - finds resized or re-encoded copies and burst shots by comparing thumbnails. -- **Upload** adds photos. Its menu holds **Import from Google Photos…**. - -### Importing from Google Photos - -Request a Google Takeout export of Google Photos, then pass every `.zip` of it at once. A photo's -metadata often sits in a different part of the export than the photo itself. - -```bash -pdfs import-google-photos --dry-run ~/Downloads/takeout-*.zip # see what would happen -pdfs import-google-photos --wait ~/Downloads/takeout-*.zip -``` - -Albums are recreated, capture dates and locations are taken from the metadata, and photos already -on the account are skipped, so an interrupted import can be run again. `pdfs import-status` and -`pdfs cancel-import` follow or stop an import that runs in the background. - -If photos from an earlier import are filed under the day they were uploaded, -`pdfs redate-photos --dry-run` finds those whose file name carries a different date, and -`pdfs redate-photos` fixes them. Proton cannot change a capture date in place, so each fix -re-uploads the photo and moves the original to the Trash, keeping favorites and albums. - -## Sharing - -- **Share…** on a file or folder invites people by email as viewer or editor, or creates a public - link with an optional password and expiry. `pdfs share`, `pdfs members`, `pdfs share-role`, - `pdfs unshare` and `pdfs public-link` do the same from a terminal. -- **Shared by me** lists everything you share, filtered by links, people or expired links. Copy a - live link or stop several shares at once. -- **Shared with me** lists what others share with you, with who shared it and your access. - Pending invitations wait in a banner; `pdfs invitations` accepts or rejects them. Saved public - links (`pdfs bookmarks`) have their own view. - -## Trash and version history - -The **Trash** page lists trashed items with the date they were deleted. Restore puts an item back -where it was, together with trashed folders above it. **Delete Forever** and **Empty Trash** are -permanent. The CLI equivalents are `pdfs trash`, `pdfs restore`, `pdfs delete-forever` and -`pdfs empty-trash`. - -Proton Drive keeps earlier versions of every file. **Details → Versions…** in the app, or -`pdfs versions list `, shows them. You can: - -- **Restore** a version. This happens on the server; nothing is re-uploaded. -- **Save** a version to a separate local file without touching the current one. -- **Delete** an old version permanently. The current version cannot be deleted. - -## Computers - -**Computers** lists this computer and every other computer that backs up to your account. - -- **This computer** shows its synced folders with their state, and **Restore Folders…** brings - back folders that are backed up under it but not synced here yet. -- **Another computer** can be browsed read-only in the same list or grid as My files, and - **Restore to This Computer…** downloads its folders here. -- **Sync With This Computer…** makes this computer sync the same folders as another one, for - example a desktop and a laptop. Both keep the folders in step: a change or a deletion on one - reaches the other. See [Syncing several computers](#syncing-several-computers). -- **Continue This Backup Here…** makes this computer take over another computer's backup, for - example after reinstalling or replacing a machine. See [RECOVERY.md](RECOVERY.md). -- **Move to This Computer…** moves another computer's folders into this computer's backup, for - example when you switch from Windows to Linux, and then offers them for syncing here. The other - computer stays in the list, without those folders. - -### Syncing several computers - -Two or more computers can sync the same folders through one backup in Proton Drive. - -1. Sync the folders on the first computer as usual. -2. On the second computer, open **Computers**, open the menu of the first computer and choose - **Sync With This Computer…**. From a terminal: `pdfs devices join UID`, with the UID from - `pdfs devices list`. -3. Choose which of its folders to sync here and where, as in a restore. - -From then on, both computers sync into that backup. A folder you add later on either computer -lands there too, and a folder with the same name joins the one already there. An edit on one -computer reaches the other within about two minutes. When both computers change the same file in -that time, each keeps the other's version under the original name and its own as a conflict copy -named after it. Folders that were synced here before joining stay in this computer's own backup. - -## Search launcher - -`pdfs-prompt` searches Proton Drive and your home folder together, in one ranked list. It -tolerates prefixes, abbreviations, typos and swapped letters, and matches on parent folder names -as well. Bind it to a keyboard shortcut in your desktop settings. - -The window stays loaded after the first use, so later shortcuts open it instantly. Folders, audio -and video open straight from the Proton Drive folder, so players can start before the whole file -downloads. Other Drive files download first, then open. - -To make the first shortcut instant as well, start the launcher hidden with your session. -`pdfs-prompt --preload` loads the window without showing it and does nothing if the launcher is -already running. For Hyprland: - -```ini -exec-once = pdfs-prompt --preload -bind = SUPER, space, exec, pdfs-prompt -``` - -### Using your own launcher - -`pdfs-prompt --dmenu` shows the results in fuzzel, rofi, wofi, tofi, bemenu or dmenu, whichever is -installed: - -```bash -pdfs-prompt --dmenu -pdfs-prompt --dmenu --menu 'fuzzel --dmenu --width 60' -pdfs-prompt --dmenu --query invoice -``` - -A dmenu-style launcher filters a fixed list and cannot ask for new results per keystroke, so the -search takes two steps. The first list, `Search Drive ›`, shows your available-offline files; type -a query and press Enter to search. The second, `Drive: invoice ›`, shows the results; Enter opens -one, and typing something else searches again. - -### Search as you type with fzf - -`pdfs-prompt --fzf` re-queries the service on every keystroke, like the built-in window. When -started from a keybinding without a terminal, it opens one itself (foot, ghostty, kitty, -alacritty, wezterm or xterm) with the app ID `pdfs-prompt`, so one window rule covers all of them. -For Hyprland: - -```ini -windowrulev2 = float, class:^(pdfs-prompt)$ -windowrulev2 = size 900 500, class:^(pdfs-prompt)$ -windowrulev2 = center, class:^(pdfs-prompt)$ -bind = SUPER, space, exec, pdfs-prompt --fzf -``` - -To make `--dmenu` or `--fzf` the default without changing your keybinding, set `prompt.mode` in -`config.json` ([CONFIGURATION.md](CONFIGURATION.md#prompt)). `--gtk` forces the built-in window. - -## Choosing how files open - -Files open with `xdg-open` by default. The `open_with` section of `config.json` overrides that per -file type, for example text in Neovim inside a terminal. The rules apply to the search launcher -and to the app. See [CONFIGURATION.md](CONFIGURATION.md#open_with). - -## Tray - -`pdfs-tray` starts at login and shows whether files are up to date, syncing, paused or offline. -Its menu opens the app or the Proton Drive folder, pauses or resumes sync, and stops or connects -the service. **Hide Tray Icon** removes it until you turn it back on under -**Preferences → General → Appearance → Show tray icon**. - -GNOME needs the AppIndicator extension to show tray icons. - ## Preferences | Page | Settings | |---|---| -| **General** | Start on login · Proton Drive folder location · upload and download limits · Proton theme, street map for Places, tray icon · language | +| **General** | Start on login · Proton Drive folder location · upload and download limits · Proton theme, street map for Places, tray icon · language · check for updates | | **Storage** | Cache size limit · clear the cache · files kept available offline | -The account menu shows storage used and holds **Sign Out…**. Settings not exposed in the app are -listed in [CONFIGURATION.md](CONFIGURATION.md). +The account menu shows the storage you use and holds **Sign Out…**. Settings that are not in the +app are described in [Configuration](CONFIGURATION.md). diff --git a/scripts/publish-wiki.sh b/scripts/publish-wiki.sh index 12933ba..2a5cefa 100755 --- a/scripts/publish-wiki.sh +++ b/scripts/publish-wiki.sh @@ -1,32 +1,40 @@ #!/usr/bin/env bash -# Publish the user documentation in docs/ to the GitHub wiki. +# Publish the documentation in docs/ to the GitHub wiki. # # The pages in docs/ are the source of truth; the wiki is a generated copy for -# people who look there first. Each run clones the wiki, replaces the pages -# listed below, rewrites links between them to wiki page names and every other -# repository link to an absolute GitHub URL, regenerates Home and _Sidebar, and -# commits. Nothing is pushed without --push. +# people who look there first. Each run checks every link in docs/, clones the +# wiki, replaces all of its pages with the ones listed in SECTIONS below, +# rewrites links between them to wiki page names and every other repository +# link to an absolute GitHub URL, copies the images they show, writes the +# sidebar and footer, and commits. Nothing is pushed without --push. +# +# --check only checks the links and that every page in docs/ is listed or +# excluded, without touching the wiki. CI runs it for every change to docs/. # # GitHub creates the wiki repository only when the first page is saved, so -# create any page once in the web UI before the first run. +# create any page once in the web UI before the first run. WIKI_REMOTE +# overrides the remote, which is how the workflow pushes with its token. # -# usage: scripts/publish-wiki.sh [--push] [WORKDIR] +# usage: scripts/publish-wiki.sh [--check | --push] [WORKDIR] set -euo pipefail repo_url="https://github.com/narrrl/proton-drive-linux" -wiki_remote="git@github.com:narrrl/proton-drive-linux.wiki.git" +wiki_remote="${WIKI_REMOTE:-git@github.com:narrrl/proton-drive-linux.wiki.git}" -push=0 -if [ "${1:-}" = "--push" ]; then - push=1 - shift -fi +mode=commit +case "${1:-}" in + --check) mode=check; shift ;; + --push) mode=push; shift ;; +esac root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" workdir="${1:-$(mktemp -d)}" wiki="$workdir/wiki" -if [ -d "$wiki/.git" ]; then +if [ "$mode" = check ]; then + wiki="$workdir/check" + mkdir -p "$wiki" +elif [ -d "$wiki/.git" ]; then git -C "$wiki" pull --ff-only --quiet else git clone --quiet "$wiki_remote" "$wiki" @@ -35,88 +43,223 @@ fi rev="$(git -C "$root" rev-parse --short HEAD)" version="$(grep -m1 '^version' "$root/Cargo.toml" | cut -d'"' -f2)" -python3 - "$root" "$wiki" "$repo_url" "$version" <<'EOF' +python3 - "$root" "$wiki" "$repo_url" "$version" "$rev" <<'EOF' import pathlib import re +import shutil import sys -root, wiki, repo_url, version = sys.argv[1:] +root, wiki, repo_url, version, rev = sys.argv[1:] root = pathlib.Path(root) wiki = pathlib.Path(wiki) +docs = root / "docs" -# docs/ file -> wiki page name, in sidebar order. -PAGES = { - "INSTALL.md": "Installation", - "USER_GUIDE.md": "User-Guide", - "CLI.md": "Command-Line-Reference", - "CONFIGURATION.md": "Configuration", - "TROUBLESHOOTING.md": "Troubleshooting", - "RECOVERY.md": "Recovery", -} +HOME = ("README.md", "Home") -LINK = re.compile(r"(\]\()([^)\s]+)(\))") +# Sidebar sections: docs/ file -> wiki page name, in order. +SECTIONS = [ + ("Start here", [ + ("GETTING_STARTED.md", "Getting-Started"), + ("INSTALL.md", "Installation"), + ("FAQ.md", "FAQ"), + ]), + ("Using it", [ + ("USER_GUIDE.md", "User-Guide"), + ("FILES.md", "Files-and-Offline"), + ("SYNCED_FOLDERS.md", "Synced-Folders"), + ("PHOTOS.md", "Photos"), + ("SHARING.md", "Sharing"), + ("COMPUTERS.md", "Computers"), + ("LAUNCHER_AND_TRAY.md", "Launcher-and-Tray"), + ]), + ("Reference", [ + ("CLI.md", "Command-Line-Reference"), + ("CONFIGURATION.md", "Configuration"), + ("SECURITY_MODEL.md", "Security-Model"), + ]), + ("When something goes wrong", [ + ("TROUBLESHOOTING.md", "Troubleshooting"), + ("RECOVERY.md", "Recovery"), + ]), + ("Contributing", [ + ("DEVELOPMENT.md", "Development"), + ("ARCHITECTURE.md", "Architecture"), + ("TESTING.md", "Testing"), + ("TRANSLATING.md", "Translating"), + ("ROADMAP.md", "Roadmap"), + ]), +] + +# Too long or too internal for the wiki; links to them go to GitHub. +EXCLUDED = {"BUGS.md", "CHANGELOG.md"} + +# Files outside docs/ whose links are checked but not published. +CHECKED = ["README.md", "CONTRIBUTING.md", "SECURITY.md"] + +PAGES = dict([HOME] + [page for _, pages in SECTIONS for page in pages]) +images_url = f"https://raw.githubusercontent.com/wiki/{repo_url.removeprefix('https://github.com/')}" + +LINK = re.compile(r"(\]\(|src=\")([^)\"\s]+)([)\"])") +FENCE = re.compile(r"^\s*(```|~~~)") +INLINE_CODE = re.compile(r"(`[^`\n]*`)") +HEADING = re.compile(r"^(#{1,6})\s+(.*?)\s*#*\s*$") +EXPLICIT_ID = re.compile(r" str: - if re.match(r"^[a-z]+:|^#", target): +def outside_fences(text): + """Yield (is_prose, chunk) so links in code blocks are left alone.""" + chunk, fenced = [], False + for line in text.splitlines(keepends=True): + if FENCE.match(line): + if chunk: + yield not fenced, "".join(chunk) + chunk, fenced = [], not fenced + yield False, line + continue + chunk.append(line) + if chunk: + yield not fenced, "".join(chunk) + + +def slug(heading): + """GitHub's anchor for a heading.""" + text = re.sub(r"\[([^\]]*)\]\([^)]*\)", r"\1", heading) + return re.sub(r"[^\w\- ]", "", text.lower()).replace(" ", "-") + + +anchor_cache = {} + + +def anchors(path): + if path not in anchor_cache: + found, seen = set(), {} + for prose, chunk in outside_fences(path.read_text()): + if not prose: + continue + for line in chunk.splitlines(): + found.update(EXPLICIT_ID.findall(line)) + m = HEADING.match(line) + if not m: + continue + base = slug(m.group(2)) + n = seen.get(base, 0) + seen[base] = n + 1 + found.add(base if n == 0 else f"{base}-{n}") + anchor_cache[path] = found + return anchor_cache[path] + + +def rewrite(source, target): + """The wiki form of one link in source, recording broken links.""" + if re.match(r"^[a-z]+:", target): return target path, _, anchor = target.partition("#") + resolved = (source.parent / path).resolve() if path else source + where = f"{source.relative_to(root)}: {target}" + if not resolved.is_relative_to(root) or not resolved.exists(): + errors.append(f"{where}: no such file") + return target + if anchor and resolved.suffix == ".md" and anchor not in anchors(resolved): + errors.append(f"{where}: no heading #{anchor}") + relative = resolved.relative_to(root) anchor = f"#{anchor}" if anchor else "" - if path in PAGES: - return PAGES[path] + anchor - # Anything else is a file in the repository: link to it on GitHub. - resolved = (root / "docs" / path).resolve().relative_to(root) - kind = "tree" if (root / resolved).is_dir() else "blob" - return f"{repo_url}/{kind}/main/{resolved}{anchor}" + if not path: + return anchor + if relative.parent == pathlib.Path("docs") and relative.name in PAGES: + return PAGES[relative.name] + anchor + if relative.parts[0] == "images": + images.add(relative) + return f"{images_url}/{relative}" + kind = "tree" if resolved.is_dir() else "blob" + return f"{repo_url}/{kind}/main/{relative}{anchor}" -def convert(text: str) -> str: - return LINK.sub(lambda m: m.group(1) + rewrite(m.group(2)) + m.group(3), text) +def convert(source): + out = [] + for prose, chunk in outside_fences(source.read_text()): + if prose: + # Odd pieces are `inline code`, which is left alone too. + pieces = INLINE_CODE.split(chunk) + pieces[::2] = [ + LINK.sub(lambda m: m.group(1) + rewrite(source, m.group(2)) + m.group(3), p) + for p in pieces[::2] + ] + chunk = "".join(pieces) + out.append(chunk) + return "".join(out) +def title(source): + return (docs / source).read_text().splitlines()[0].lstrip("# ").strip() + + +def without_title(text): + lines = text.splitlines(keepends=True) + if lines and lines[0].startswith("# "): + lines = lines[1:] + while lines and not lines[0].strip(): + lines = lines[1:] + return "".join(lines) + + +for name in sorted(p.name for p in docs.glob("*.md")): + if name not in PAGES and name not in EXCLUDED: + errors.append(f"docs/{name}: add it to SECTIONS or EXCLUDED in scripts/publish-wiki.sh") + +converted = {source: convert(docs / source) for source in PAGES} +published_images = set(images) +for name in CHECKED: + convert(root / name) + +if errors: + print("Broken documentation links:", file=sys.stderr) + for error in errors: + print(f" {error}", file=sys.stderr) + sys.exit(1) + +# The wiki is generated: anything not written below is stale. +for old in wiki.glob("*.md"): + old.unlink() +shutil.rmtree(wiki / "images", ignore_errors=True) + note = ( "\n\n" ) - for source, page in PAGES.items(): - text = (root / "docs" / source).read_text() - (wiki / f"{page}.md").write_text(note + convert(text)) + (wiki / f"{page}.md").write_text(note + without_title(converted[source])) +for image in published_images: + (wiki / image).parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(root / image, wiki / image) -def title(source: str) -> str: - return (root / "docs" / source).read_text().splitlines()[0].lstrip("# ").strip() - - -home = [ - note, - "# Proton Drive for Linux\n\n", - "An unofficial Proton Drive client for the Linux desktop: your files as a folder that ", - "downloads on demand, synced local folders, Photos, sharing, a GTK4 app with tray and search ", - "launcher, and a scriptable CLI.\n\n", - f"This wiki mirrors the documentation of version {version}. The source, releases and issue ", - f"tracker are in the [repository]({repo_url}).\n\n", - "## Pages\n\n", -] -home += [f"- [{title(source)}]({page})\n" for source, page in PAGES.items()] -home += [ - "\n## More\n\n", - f"- [Changelog]({repo_url}/blob/main/docs/CHANGELOG.md)\n", - f"- [Architecture]({repo_url}/blob/main/docs/ARCHITECTURE.md)\n", - f"- [Contributing]({repo_url}/blob/main/CONTRIBUTING.md)\n", - f"- [Report a problem]({repo_url}/issues/new/choose)\n", -] -(wiki / "Home.md").write_text("".join(home)) - -sidebar = ["**[Home](Home)**\n\n"] -sidebar += [f"- [{title(source)}]({page})\n" for source, page in PAGES.items()] +sidebar = ["**[Home](Home)**\n"] +for section, pages in SECTIONS: + sidebar.append(f"\n**{section}**\n\n") + sidebar += [f"- [{title(source)}]({page})\n" for source, page in pages] sidebar += [ "\n---\n\n", + f"[Changelog]({repo_url}/blob/main/docs/CHANGELOG.md) · ", f"[Releases]({repo_url}/releases) · [Issues]({repo_url}/issues)\n", ] -(wiki / "_Sidebar.md").write_text("".join(sidebar)) +(wiki / "_Sidebar.md").write_text(note + "".join(sidebar)) + +(wiki / "_Footer.md").write_text( + note + + f"Documentation of Proton Drive for Linux {version}, generated from " + + f"[`docs/`]({repo_url}/tree/{rev}/docs) at `{rev}`. " + + f"To change a page, edit it in the [repository]({repo_url}).\n" +) EOF +if [ "$mode" = check ]; then + echo "Documentation links are fine." + exit 0 +fi + cd "$wiki" git add -A if git diff --cached --quiet; then @@ -126,9 +269,9 @@ fi git commit --quiet -m "Update from docs at $rev" git show --stat --format='%s' HEAD -if [ "$push" = 1 ]; then +if [ "$mode" = push ]; then git push --quiet - echo "Pushed to $wiki_remote." + echo "Pushed to the wiki." else echo "Committed in $wiki. Review it, then push from there or re-run with --push." fi