Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
c30858b
Linux perf: ReadyToRun publish, indexed MIME glob lookup, cached MIME…
MemerGamer Oct 5, 2026
ee8166c
Merge remote-tracking branch 'origin/linux/main' into linux/perf1
MemerGamer Oct 5, 2026
bfea528
Linux: virtualize Grid/Cards layouts with a wrapping virtualizing pan…
MemerGamer Oct 5, 2026
c789ec7
Merge remote-tracking branch 'origin/linux/main' into linux/p4-b
MemerGamer Oct 5, 2026
b06c137
Merge remote-tracking branch 'origin/linux/main' into linux/p4-a
MemerGamer Oct 5, 2026
b75441a
Merge remote-tracking branch 'origin/linux/main' into linux/p4-c
MemerGamer Oct 5, 2026
a3546d4
Linux perf: cache SVG typefaces, MIME XML recheck, incremental list u…
MemerGamer Oct 5, 2026
d57e6f5
Merge remote-tracking branch 'origin/linux/main' into linux/perf1
MemerGamer Oct 5, 2026
3ba6189
Merge origin/linux/main into linux/perf1
MemerGamer Oct 5, 2026
d09d65a
Linux: platform file-operation factory and path-based history (P4-B)
MemerGamer Oct 5, 2026
41ca91a
Linux: read-only archive browsing via storable routes (P4-A)
MemerGamer Oct 5, 2026
a1da58b
Linux: resolver-based storage helpers; Windows enumeration/search iso…
MemerGamer Oct 5, 2026
d56a0f2
Merge remote-tracking branch 'origin/linux/main' into linux/p4-b
MemerGamer Oct 5, 2026
f674ad7
Merge remote-tracking branch 'origin/linux/main' into linux/p4-a
MemerGamer Oct 5, 2026
8353652
Merge origin/linux/main into linux/p4-c
MemerGamer Oct 5, 2026
f0e5609
Isolate Windows-only actions and shell UX (P4-H)
MemerGamer Oct 5, 2026
201f831
Merge pull request #66 from MemerGamer/linux/p4-b
MemerGamer Oct 5, 2026
f7b9f53
Merge remote-tracking branch 'origin/linux/main' into linux/p4-a
MemerGamer Oct 5, 2026
a6956f6
Gate dropped-item executable launch behind the Linux run confirmation
MemerGamer Oct 5, 2026
71537de
Merge remote-tracking branch 'origin/linux/main' into linux/p4-h
MemerGamer Oct 5, 2026
7c9fd59
WIP P4-G: previews and leaf storage users on storables
MemerGamer Oct 5, 2026
026fc5d
Merge remote-tracking branch 'origin/linux/main' into linux/p4-g
MemerGamer Oct 5, 2026
62c9c45
Fix P4-A review: duplicate project reference, browsing-only archive l…
MemerGamer Oct 5, 2026
bb3bfb8
Merge origin/linux/main into linux/p4-c
MemerGamer Oct 5, 2026
e64fff8
Keep build green with ShowWindowCommand enum and shared factory
MemerGamer Oct 5, 2026
9f32a25
Linux: Home, widgets and sidebar on portable storables (P4-J)
MemerGamer Oct 5, 2026
7bb4f0c
Bound archive header listing for every caller; truncated result inste…
MemerGamer Oct 5, 2026
7812d42
Linux: working legacy item on resolver success, SystemStorageFile/Fol…
MemerGamer Oct 5, 2026
0663563
Merge origin/linux/p4-a into linux/p4-c
MemerGamer Oct 5, 2026
d0a46da
Previews and leaf storage users on storables (P4-G)
MemerGamer Oct 5, 2026
b09be39
Refresh compat-off baseline after storage wrappers
MemerGamer Oct 5, 2026
823ee5b
Linux perf: grid panel review fixes (extent, resize anchoring, row/co…
MemerGamer Oct 5, 2026
d1d14d0
Merge remote-tracking branch 'origin/linux/main' into linux/perf1
MemerGamer Oct 5, 2026
007a5f0
Fix toolbar row missing on Linux: realize x:Load controls on Loaded
MemerGamer Oct 5, 2026
0d5e3e7
Merge pull request #71 from MemerGamer/linux/fix-toolbar
MemerGamer Oct 5, 2026
9cbc1e8
Merge pull request #56 from MemerGamer/linux/perf1
MemerGamer Oct 5, 2026
29c3b25
Isolate remaining Windows-only code (P4 orphans)
MemerGamer Oct 5, 2026
0c7488d
Merge pull request #72 from MemerGamer/linux/p4-orph
MemerGamer Oct 5, 2026
ec3f984
Merge pull request #69 from MemerGamer/linux/p4-j
MemerGamer Oct 5, 2026
8f61549
Merge remote-tracking branch 'origin/linux/main' into linux/p4-h
MemerGamer Oct 5, 2026
bcd99bc
Skip tar metadata entries; browsing needs only header caps
MemerGamer Oct 5, 2026
cc8de13
Merge remote-tracking branch 'origin/linux/p4-a' into linux/p4-c
MemerGamer Oct 5, 2026
1a985d5
Guard clipboard publish, keep Windows shelf path, tidy preprocessor b…
MemerGamer Oct 5, 2026
bf17c78
Show full argv before running an executable with dropped items; keep …
MemerGamer Oct 5, 2026
fcc3a6b
Merge pull request #68 from MemerGamer/linux/p4-h
MemerGamer Oct 5, 2026
56dfe5c
Merge origin/linux/main into linux/p4-g
MemerGamer Oct 5, 2026
1b1f7e2
Linux: safe SystemStorage members, existence-checked legacy items, dr…
MemerGamer Oct 5, 2026
4d83897
Ratchet compat-off baseline after merge
MemerGamer Oct 5, 2026
848efca
Merge origin/linux/main into linux/p4-a
MemerGamer Oct 5, 2026
a409f26
Merge pull request #70 from MemerGamer/linux/p4-g
MemerGamer Oct 5, 2026
3fbefae
Merge origin/linux/main into linux/p4-a
MemerGamer Oct 5, 2026
fb454ac
Merge pull request #65 from MemerGamer/linux/p4-a
MemerGamer Oct 5, 2026
8994ac7
Merge origin/linux/main into linux/p4-c
MemerGamer Oct 5, 2026
3533002
Refresh compat-off baseline after merge
MemerGamer Oct 5, 2026
ee71ff5
Merge pull request #67 from MemerGamer/linux/p4-c
MemerGamer Oct 5, 2026
d7db90d
Isolate ShellViewModel Windows code and list archives on Linux (P4-E)
MemerGamer Oct 5, 2026
889d848
Switch Win32 compat mode off on Linux (P4-Z)
MemerGamer Oct 5, 2026
6044a2b
Add nightly Linux builds published as a rolling pre-release
MemerGamer Oct 5, 2026
07c6283
Merge pull request #75 from MemerGamer/linux/ci-nightly
MemerGamer Oct 5, 2026
473e711
Merge pull request #73 from MemerGamer/linux/p4-e
MemerGamer Oct 5, 2026
df9f844
Merge pull request #74 from MemerGamer/linux/p4-z
MemerGamer Oct 5, 2026
692c385
Use main as the single integration branch; nightly builds from main
MemerGamer Oct 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ cd LinuxFiles
scripts/linux/install-local.sh
```

### Nightly builds

Every merge to `main` publishes a tarball and AppImage to the rolling [nightly pre-release](https://github.com/MemerGamer/LinuxFiles/releases/tag/nightly). Run it with:

```sh
curl -LO https://github.com/MemerGamer/LinuxFiles/releases/download/nightly/LinuxFiles-nightly-x86_64.AppImage && chmod +x LinuxFiles-nightly-x86_64.AppImage && ./LinuxFiles-nightly-x86_64.AppImage
```

See [docs/linux-port/packaging.md](../docs/linux-port/packaging.md) for packaging details and [docs/linux-port/PLAN.md](../docs/linux-port/PLAN.md) for the roadmap.

## Reporting bugs
Expand Down
2 changes: 1 addition & 1 deletion .github/SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Security Policy

LinuxFiles is an unofficial, community-maintained Linux port of [Files](https://github.com/files-community/Files). It is in alpha, and only the latest release and the `linux/main` branch receive fixes.
LinuxFiles is an unofficial, community-maintained Linux port of [Files](https://github.com/files-community/Files). It is in alpha, and only the latest release and the `main` branch receive fixes.

## Reporting a vulnerability in LinuxFiles

Expand Down
14 changes: 11 additions & 3 deletions .github/workflows/ci-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,17 @@ jobs:
- name: Build Files.App.Storage (Uno desktop)
run: dotnet build src/Files.App.Storage/Files.App.Storage.csproj -c Release -f net10.0-desktop

# Informational until the Phase 2 error inventory (docs/linux-port/phase2-errors.md) reaches zero.
- name: Build Files.App (Uno desktop)
run: dotnet build src/Files.App/Files.App.csproj -c Release -f net10.0-desktop
# Blocking: Win32 compat mode is off (the default since P4-Z), so no Win32/Shell code and no CsWin32 assembly may be needed.
- name: Build Files.App (Uno desktop, Win32 compat off)
run: dotnet build src/Files.App/Files.App.csproj -c Release -f net10.0-desktop -p:FilesWin32Compat=false

- name: Verify the desktop build did not build CsWin32
shell: bash
run: |
if [ -d src/Files.App.CsWin32/bin ] || [ -d src/Files.App.CsWin32/obj ]; then
echo "::error::Files.App.CsWin32 was built for the desktop target; something still depends on Win32 compat mode."
exit 1
fi

- name: Build and test platform test projects (if any)
shell: bash
Expand Down
119 changes: 119 additions & 0 deletions .github/workflows/nightly-linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Copyright (c) Files Community
# Licensed under the MIT License.

# Abstract:
# Builds the self-contained linux-x64 tarball and AppImage on every push to main and publishes them to
# one rolling "nightly" GitHub pre-release with stable asset names. Pull requests targeting main get the
# same build as workflow artifacts only (read-only token). The Flatpak is left to package-linux.yml.

name: Nightly Linux

on:
workflow_dispatch:
push:
branches:
- main
pull_request:
branches:
- main

concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || 'nightly' }}
cancel-in-progress: true

permissions:
contents: read

jobs:

build-linux-x64:

runs-on: ubuntu-latest

steps:

- name: Checkout the repository
uses: actions/checkout@v6

- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json

- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props') }}
restore-keys: |
${{ runner.os }}-nuget-

- name: Publish self-contained linux-x64
run: scripts/linux/publish.sh --rid linux-x64 --tarball

- name: Build AppImage
run: packaging/linux/appimage/build-appimage.sh

- name: Stage assets with stable names
run: |
mkdir -p dist
cp artifacts/files-linux-x64.tar.gz dist/LinuxFiles-nightly-linux-x64.tar.gz
cp artifacts/Files-x86_64.AppImage dist/LinuxFiles-nightly-x86_64.AppImage

- name: Upload packages
uses: actions/upload-artifact@v4
with:
name: linuxfiles-nightly-linux-x64
path: dist/*
if-no-files-found: error

publish-nightly:

if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
needs: build-linux-x64
runs-on: ubuntu-latest
permissions:
contents: write

steps:

- name: Checkout the repository
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Download packages
uses: actions/download-artifact@v4
with:
name: linuxfiles-nightly-linux-x64
path: dist

- name: Replace the nightly release
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
SHA: ${{ github.sha }}
run: |
short="${SHA:0:7}"

# Commit list since the previous nightly (falls back to the last 20 commits).
prev="$(gh api "repos/$REPO/git/ref/tags/nightly" --jq '.object.sha' 2>/dev/null || true)"
if [ -n "$prev" ] && git cat-file -e "$prev^{commit}" 2>/dev/null; then
range="$prev..$SHA"
else
range="-20 $SHA"
fi
{
echo "Rolling build of \`main\` at $SHA. Replaced on every push; not for production use."
echo
echo "Run the AppImage: \`chmod +x LinuxFiles-nightly-x86_64.AppImage && ./LinuxFiles-nightly-x86_64.AppImage\`"
echo
echo "### Changes since the previous nightly"
# shellcheck disable=SC2086
git log --no-merges --format='- %h %s' $range
} > notes.md

gh release delete nightly -R "$REPO" --cleanup-tag --yes 2>/dev/null || true
gh release create nightly -R "$REPO" --target "$SHA" --prerelease \
--title "Nightly (main @ $short)" --notes-file notes.md \
dist/LinuxFiles-nightly-linux-x64.tar.gz dist/LinuxFiles-nightly-x86_64.AppImage
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<WindowsSdkPackageVersion>10.0.26100.67-preview</WindowsSdkPackageVersion>
<WindowsTargetFramework>$(BaseTargetFramework)-windows$(TargetWindowsVersion)</WindowsTargetFramework>
<DesktopTargetFramework>$(BaseTargetFramework)-desktop</DesktopTargetFramework>
<!-- Linux bring-up: compile existing Win32 code against CsWin32 types until it is replaced by Files.Platform services. -->
<FilesWin32Compat Condition="'$(FilesWin32Compat)' == ''">true</FilesWin32Compat>
<!-- Opt-in (-p:FilesWin32Compat=true): compiles the leftover Win32 code on the desktop TFM against CsWin32 types, for inventory only. -->
<FilesWin32Compat Condition="'$(FilesWin32Compat)' == ''">false</FilesWin32Compat>
<LangVersion>preview</LangVersion>
<!-- Uno's nullability annotations differ from WinUI's; keep nullable diagnostics as warnings on the Linux desktop build for now. -->
<WarningsAsErrors Condition="!$(TargetFramework.EndsWith('-desktop'))">nullable</WarningsAsErrors>
Expand Down
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
<PackageVersion Include="Microsoft.WindowsAppSDK.Widgets" Version="2.0.5" />
<PackageVersion Include="Microsoft.Graphics.Win2D" Version="1.4.0" />
<PackageVersion Include="TagLibSharp" Version="2.3.0" />
<PackageVersion Include="Krafs.Publicizer" Version="2.3.0" />
<PackageVersion Include="Uno.WinUI" Version="6.7.135" />
<PackageVersion Include="Uno.WinUI.Runtime.Skia.X11" Version="6.7.135" />
<PackageVersion Include="Uno.Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.4.2" />
Expand Down
4 changes: 2 additions & 2 deletions docs/linux-port/AGENT-RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ Read this first, then `PLAN.md` §0, then `CLAUDE.md`.
- Never commit anything from the real home directory.

## Git / GitHub
- Branch from `origin/linux/main`: `git fetch origin && git switch -c linux/<wp> origin/linux/main`.
- Branch from `origin/main` (the single integration branch; releases are tags: `nightly` rolling, `linux-v*` stable): `git fetch origin && git switch -c linux/<wp> origin/main`.
- Commit trailer: `Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>`.
- Push: `git -c credential.helper='!gh auth git-credential' push -u origin linux/<wp>`.
- PR: `gh pr create -R MemerGamer/LinuxFiles --base linux/main --head linux/<wp> ...`. The body ends with `🤖 Generated with [Claude Code](https://claude.com/claude-code)`.
- PR: `gh pr create -R MemerGamer/LinuxFiles --base main --head linux/<wp> ...`. The body ends with `🤖 Generated with [Claude Code](https://claude.com/claude-code)`.
- Never target, push to, or comment on upstream `files-community/Files`.

## Code
Expand Down
15 changes: 10 additions & 5 deletions docs/linux-port/PLAN.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Files on Linux — Porting Plan

> **Branching (2026-10-05):** `main` is the single integration branch. `linux/main` is retired (frozen at the last merge). Releases are tags: the rolling `nightly` pre-release (every push to `main`) and stable `linux-v*` tags.

Status: draft v1 · 2026-10-04 · fork base `0e3c17ca4` (in sync with `files-community/Files` main)

## 0. Revision 2 (2026-10-04): Linux-first
Expand Down Expand Up @@ -43,7 +45,7 @@ The owner decided to focus on Linux first. Windows support is revisited only aft
| 1 | Abstraction skeleton (`Files.Platform.*`, tests, DI) | serial, small |
| 2 | **Linux bring-up: make `Files.App` compile and launch on Uno `net10.0-desktop`.** Retarget Controls + App to Uno. Exclude Windows-only folders (`Compile Remove`). Replace Win32/WinRT calls with interface calls, backed by stub or simple Linux implementations. Fix compile errors folder by folder. **✅ Done (2026-10-05):** the app compiles, launches and runs on Linux; the compat-off criterion moved to Phase 4. | parallel by folder ownership |
| 3 | Real Linux backends per interface (enumeration, watcher, file ops, trash, launcher, thumbnails, drives, clipboard…), with unit tests | parallel, one agent per interface |
| 4 | Replace the legacy WinRT storage layer (`BaseStorageFile`/`Folder`) with OwlCore storables, then switch Win32 compat mode off (moved from Phase 2) | parallel work packages (see Phase 4 plan, Revision 3) |
| 4 | Replace the legacy WinRT storage layer (`BaseStorageFile`/`Folder`) with OwlCore storables, then switch Win32 compat mode off (moved from Phase 2). **✅ Done (2026-10-05, P4-Z):** compat mode is off by default and the desktop build has 0 errors, which also meets Phase 2's criterion | parallel work packages (see Phase 4 plan, Revision 3) |
| 5 | UI blockers and UX parity: L-DND, SpeedGraph, StickyHeader, title bar, previews, single instance | parallel |
| 6 | Desktop integration and packaging (FileManager1 D-Bus, `.desktop`, Flatpak/AppImage/AUR) | parallel |
| 7 | Hardening (performance, HiDPI, themes, localisation) | parallel |
Expand All @@ -53,7 +55,7 @@ The Phase 2 workstreams in §7.3 still define folder ownership. Their goal is no
not "Windows code wrapped without behaviour change".

### Phase 2 build decisions (2026-10-04)
- **Win32 compat mode is the default** (`FilesWin32Compat=true` in `Directory.Build.props`). Existing Win32/Shell code compiles on Linux against the CsWin32 assembly, which is built automatically for Platform=x64. It cannot run on Linux, so any call that is reached at runtime must be replaced by a `Files.Platform` service. Switching compat mode off was Phase 2's exit criterion; since 2026-10-05 it is Phase 4's (P4-Z), because it depends on removing the legacy storage layer.
- **Win32 compat mode is off by default since P4-Z (2026-10-05)** (`FilesWin32Compat=false` in `Directory.Build.props`). The desktop build no longer compiles Win32/Shell code or builds the CsWin32 assembly. `-p:FilesWin32Compat=true` still works as an opt-in inventory lens: it compiles the Windows-only folders against CsWin32 and defines `FILES_WIN32_COMPAT`. Nothing compiled that way runs on Linux. Linux CI builds with compat off and fails on any error. (Until P4-Z compat mode was the default. Switching it off was Phase 2's exit criterion and became Phase 4's on 2026-10-05.)
- **Nullable diagnostics are warnings on `-desktop`**, because Uno's annotations differ from WinUI's. Re-enable once the build is clean.
- Stubbed behaviour is tagged `// LINUX-TODO(<area>)`. Use `rg -n LINUX-TODO src` to find the backlog.

Expand Down Expand Up @@ -247,7 +249,8 @@ Each workstream: define its interface methods from real call sites, implement th
(`Files.Core.Storage`) + the Phase 2 interfaces. `ShellViewModel` first, then properties, search, archives (`Zip*`),
FTP, virtual folders.
- Kept on a single owner (or a strictly serialized queue), because almost everything touches `ShellViewModel`.
- **Exit:** `Utils/Storage/StorageItems/*` is no longer referenced by the Linux build.
- **Exit:** `Utils/Storage/StorageItems/*` is no longer referenced by the Linux build. *Superseded by the Revision 3 exit below, which is met. The legacy items
(`FtpStorage*`, `SystemStorage*`, `ZipStorageFolder.IsZipPath`, `BaseStorage*`) still compile on Linux behind `LINUX-TODO(storage)` and remain follow-up work.*

#### Phase 4 plan, Revision 3 (2026-10-05): drop the legacy storage layer, then switch Win32 compat off
The two are one project: the legacy items (`Zip*`, `NativeStorageFile`, `VirtualStorageItem`, `Shell*`, `SystemStorageFolder`) call
Expand Down Expand Up @@ -287,6 +290,8 @@ Add first, delete last; default build stays green. Contracts (P4-0, then frozen)
| P4-Z | 1–2 | Flip `FilesWin32Compat=false`, fix leftovers, delete `#if WINDOWS` IStorageItem members, CI job blocking | all | strong |

Order: P4-0 → wave 1a (K, A, B, C, H, I) → wave 1b (F, D, G, J) → E → Z. Critical path ≈ 10 working days.
**Status (2026-10-05):** all 14 packages are merged or in review; P4-E (#73) and P4-Z close the phase. Compat off by default, 0 errors, headless smoke
test passed (browse, copy/move, trash/restore, browse into a zip, Properties, search, live updates), and the Linux CI compat-off build is blocking.
Gate after every merge: normal desktop build passes; `-p:FilesWin32Compat=false` error count ratchets down vs
`docs/linux-port/compat-off-baseline.txt`; `rg --no-ignore 'BaseStorage|StorageItems\.|Windows\.Win32|PInvoke\.|Win32Helper\.'` on the WP's
files (outside `*.Windows.cs`) → 0. Exit: compat off by default, 0 errors, headless smoke run passes, CI compat-off job blocking.
Expand Down Expand Up @@ -356,8 +361,8 @@ files (outside `*.Windows.cs`) → 0. Exit: compat off by default, 0 errors, hea
unit tests, and an `rg --no-ignore` coupling check against the WP's owned files. It reports pass/fail plus a
capped log.
4. **Opus** reviews the diff (correctness, CRLF, `.editorconfig`, AOT rules, no scope creep), then merges into
`linux/main` in dependency order.
5. **Haiku** merges `upstream/main` into `linux/main` weekly and reports conflicts. **Opus** resolves non-trivial ones.
`main` in dependency order.
5. **Haiku** merges `upstream/main` into `main` (via a sync PR) weekly and reports conflicts. **Opus** resolves non-trivial ones.

Windows builds can't run locally on Linux. Validate them through GitHub Actions on `windows-2025-vs2026`, with a
Haiku agent polling `gh run` results.
Expand Down
Loading
Loading