Skip to content

feat(engines): install engines from files and save them for another computer - #1363

Merged
KnifeLemon merged 2 commits into
mainfrom
feat/engine-import-export-447
Nov 10, 2026
Merged

KnifeLemon merged 2 commits into
mainfrom
feat/engine-import-export-447

Conversation

@KnifeLemon

Copy link
Copy Markdown
Owner

Closes #447

What users notice

Every optional engine card in Settings → Engines that Filee can download here gets an Offline button with three entries:

  • Install from downloaded files… – pick the engine's downloads that were brought from another computer (or downloaded there in a browser). Filee checks them against the SHA-256 pinned in engines.json, exactly as it checks its own download, and installs them. If a file is missing or wrong, the card names it and nothing is installed.
  • Save the files for another computer… – on a computer with internet, saves the package's downloads (checked the same way) in a folder, e.g. a USB stick. The message afterwards says to use Install from downloaded files on the other computer, which needs the same Filee version.
  • Copy download links – puts each file's name, URL and SHA-256 on the clipboard, for fetching them in a browser.

The CLI does the same:

filee engines download pandoc -o E:\Engines          # on a computer with internet
filee engines install pandoc --from E:\Engines        # on the one without

What changed

  • src/Filee.Engines/Infrastructure/EngineInstaller.cs
    • InstallFromFilesAsync(package, paths, …): takes files or folders (top level only). Each pending component is the file with its exact pinned size; its download's name breaks a tie. Every file is copied into .downloads through the same hash-checked copy as a download (FetchAsync, split out of DownloadAsync), and all of them are checked before the first is unpacked. A read stops once it passes the pinned size, so a file that grows after it was picked can't make Filee read on. Missing → error.engine_files_missing (detail: the file names), wrong hash → error.engine_file_mismatch (detail: the file). Unpacking, markers and the package lock are the existing path.
    • SaveFilesAsync(package, folder, …): downloads every component into the folder under its download's name, through .part + hash check; a file there that already matches is kept.
    • EngineInstallStage.Copying for the copy phase.
  • src/Filee.Engines/Infrastructure/EngineDownloads.cs: FileName(component), which is the URL's file name, decoded, and never a path (.., / and \ in an encoded name can't leave the folder), and DownloadList for the clipboard.
  • src/Filee.App/Services/EngineDownloadService.cs: install from files and save files run through the same one-at-a-time queue with progress on the card (RunQueuedAsync). The new Copying status reads "Copying N%". Saving leaves the card's status as it was and returns the error to show.
  • src/Filee.App/Views/Pages/EnginesPage.axaml(.cs), EnginesPageViewModel.cs: the Offline button, its MenuFlyout and the pickers/messages.
  • src/Filee.Cli/{CliOptions,EnginesCommand,Help}.cs: engines download <id> -o <folder>, engines install <id> --from <path> (repeatable), JSON files on download, a "Copying" progress line.
  • 13 new strings in all 22 src/Filee.App/Assets/i18n/*.json.
  • docs/ENGINES.md: how it works.

No settings schema change.

Not done, on purpose

Exporting an installed engine folder (a zip of %LOCALAPPDATA%\Filee\engines\<id>) is left out. After unpacking, Filee trims the folder (LibreOffice help, dictionaries, the Tesseract installer files) and copies runtime DLLs into it, so engines.json has nothing pinned to check such a folder against on the other computer. That would make it an unchecked program from another PC, which Use my copy… already covers. The download files are what can be verified, so "export" here means saving those. One consequence: saving needs internet on the computer that saves, because Filee doesn't keep the downloads after installing.

Tests

  • EngineInstallerTests (47 pass): install from a folder without the network, a renamed file found by size, a damaged file of the right size installs nothing of the package (the first, correct file isn't unpacked either), missing files named, save → install on a second engines folder with no network and no second download, a non-matching download not saved, FileName traversal cases.
  • EnginesCommandTests / HelpTests / CliTests: download then install --from with the server emptied, a folder without the file, new usage errors. CliTests.Zip_to_iso_converts_archive_contents_without_manual_extraction fails in the fresh worktree only because it has no fetched engines/7zip (main checkout has it). It's unrelated to this change.
  • EnginesPageTests (7 pass): the Offline button on each downloadable card with its three entries, save keeps the card's status (also on failure), install from files shows Copying and ends installed. LocalizationResourceTests/LocalizationTests pass with the new keys.
  • dotnet format --verify-no-changes clean on all six touched projects.

Not tested: a real LibreOffice/calibre MSI from a USB stick (the MSI path itself is unchanged), and macOS/Linux by hand. The .dmg/tar.xz components go through the same copy step.

🤖 Generated with Claude Code

…omputer

Some networks can't reach the engine downloads (#447). Each optional engine card gets an
Offline menu:

- Install from downloaded files: picks the downloads brought from another computer. Each
  component is matched by its pinned download size (name breaks a tie), copied into
  .downloads and checked against its engines.json SHA-256 before anything is unpacked, so a
  missing or wrong file leaves the package as it was. Then it unpacks like a download.
- Save the files for another computer: downloads the package's files (checked the same way)
  into a folder, under the names a browser gives them; files that already match are kept.
- Copy download links: name, URL and SHA-256 of each file, to fetch them in a browser.

The CLI gets the same: 'filee engines download <id> -o <folder>' and
'filee engines install <id> --from <file or folder>'.

Installed engine folders are never exported: unpacked and trimmed, they have nothing pinned
to check them against on the other computer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the feature New features label Nov 10, 2026
@KnifeLemon
KnifeLemon merged commit 47e24cd into main Nov 10, 2026
33 of 36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

引擎导入导出

1 participant