Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
name: Release

# Build the binaries + GUI installer and attach them to a GitHub Release.
# Triggered by pushing a version tag (v1.2.3). Can also be run manually
# (workflow_dispatch) to build the artifacts without publishing a release.

on:
push:
tags: ['v*']
workflow_dispatch:
inputs:
version:
description: 'Version for a manual build (e.g. 0.2.0-test); no release is published'
required: false
default: '0.0.0-dev'

permissions:
contents: write

jobs:
# -- Linux client (Direction B), built on a Linux runner and handed to the
# Windows job so the installer can embed it. --------------------------
linux:
name: Linux client
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y ninja-build libfuse3-dev
- name: Build
run: |
cmake --preset linux-release
cmake --build --preset linux-release --target wsldrive --parallel
- name: Upload Linux client
uses: actions/upload-artifact@v4
with:
name: wsldrive-linux
path: build/linux-release/src/tools/wsldrive
if-no-files-found: error

# -- Windows binaries + installer, then publish the release. -------------
windows:
name: Windows binaries + installer
runs-on: windows-latest
needs: linux
steps:
- uses: actions/checkout@v4

- name: Determine version
id: ver
shell: pwsh
run: |
$v = '${{ github.event.inputs.version }}'
if (-not $v) { $v = ('${{ github.ref_name }}' -replace '^v','') }
"version=$v" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
Write-Host "version = $v"

- name: Install WinFsp (SDK) and Inno Setup
shell: pwsh
run: |
choco install winfsp -y --no-progress
if ($LASTEXITCODE -eq 3010) { $global:LASTEXITCODE = 0 } # 3010 = success, reboot pending
if ($LASTEXITCODE -ne 0) { throw "winfsp install failed ($LASTEXITCODE)" }
choco install innosetup -y --no-progress
if ($LASTEXITCODE -eq 3010) { $global:LASTEXITCODE = 0 }
if ($LASTEXITCODE -ne 0) { throw "innosetup install failed ($LASTEXITCODE)" }
$inc = 'C:\Program Files (x86)\WinFsp\inc\fuse3\fuse.h'
$lib = 'C:\Program Files (x86)\WinFsp\lib\winfsp-x64.lib'
if (-not (Test-Path $inc) -or -not (Test-Path $lib)) {
throw "WinFsp SDK (inc/lib) not found after install — the built wsldrive.exe would lack mount support. Adjust the WinFsp install step."
}

- name: Set up MSVC
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64

- name: Build binaries
shell: pwsh
run: |
cmake --preset msvc-release
cmake --build --preset msvc-release --target wsldrive wsldrived --parallel

- name: Verify mount support was compiled in
shell: pwsh
run: |
$u = & '.\build\msvc-release\src\tools\wsldrive.exe' 2>&1 | Out-String # usage exits non-zero
if ($u -notmatch 'mount') { throw "wsldrive.exe has no 'mount' command — WinFsp was not linked." }
Write-Host "mount support present."
exit 0 # ignore wsldrive.exe's usage exit code

- name: Fetch Linux client
uses: actions/download-artifact@v4
with:
name: wsldrive-linux
path: build/linux-release/src/tools

- name: Build installer
shell: pwsh
run: .\scripts\build-installer.ps1 -Version ${{ steps.ver.outputs.version }}

- name: Stage release assets
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path staging | Out-Null
Copy-Item installer\dist\wsldrive-setup.exe staging\
# Zip of raw binaries + the script installer, for the no-build script path.
$z = 'staging\wsldrive-windows-x64.zip'
Copy-Item build\msvc-release\src\tools\wsldrive.exe,build\msvc-release\src\tools\wsldrived.exe .
Compress-Archive -Force -DestinationPath $z -Path `
wsldrive.exe,wsldrived.exe,scripts\install.ps1,scripts\register-hvsocket.ps1,README.md
Copy-Item build\linux-release\src\tools\wsldrive staging\wsldrive-linux-x64

- name: Upload build artifacts (always, for inspection)
uses: actions/upload-artifact@v4
with:
name: wsldrive-release-assets
path: staging/*

- name: Publish release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: staging/*
generate_release_notes: true
fail_on_unmatched_files: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
build/
out/
.cache/
installer/dist/

# IDE / editor
.vs/
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,45 @@ paths from the mount and from sync.
**Non-goals:** replacing `/mnt/c` (wsldrive mounts alongside it); general-purpose bidirectional sync;
kernel drivers or signing beyond WinFsp's.

## Install

However you install it, the outcome is the same: the installer confirms each choice with you first —
drive letter, distro, paths, and whether to restart WSL — then does *everything else itself* (installs
the binaries, checks for / chain-installs WinFsp, registers the Hyper-V socket services, restarts WSL
once with your OK, and registers an at-logon task that mounts on every boot and re-discovers the dynamic
WSL VM GUID each time). The one-time elevation steps and the single `wsl --shutdown` are the installer's
job — the only thing you supply is what to mount where. Pick whichever route below suits you.

### 1. Download the installer (easiest — no build)

Grab **`wsldrive-setup.exe`** from the [latest release](https://github.com/zcsizmadia/wsldrive/releases/latest)
and run it. It's a wizard: choose the direction(s), confirm the details, done. Each release also ships
`wsldrive-windows-x64.zip` (raw binaries + the install script, for the route below) and
`wsldrive-linux-x64` (the Direction B client).

### 2. Run the script (no packaging — for CI, locked-down machines, or preference)

Download `wsldrive-windows-x64.zip` (or clone the repo), then from an **elevated** PowerShell:

```powershell
powershell -ExecutionPolicy Bypass -File scripts\install.ps1 # interactive: asks + confirms
scripts\install.ps1 -DryRun # print the full plan, change nothing
scripts\install.ps1 -Unattended -DriveLetter W -Distro Ubuntu -WslRoot '~' -Yes
scripts\install.ps1 -Uninstall # remove tasks + registration + binaries
```

### 3. Build the installer from source

```powershell
.\scripts\build.ps1 # build wsldrive.exe / wsldrived.exe first
.\scripts\build-installer.ps1 # compile the wizard -> installer\dist\wsldrive-setup.exe
```

`build-installer.ps1` needs [Inno Setup](https://jrsoftware.org/isdl.php) (pass `-InstallInno` to fetch
it via winget). The GUI wizard is a thin front-end that drives `install.ps1`, so routes 1–3 all do
exactly the same thing. Releases (and their `wsldrive-setup.exe`) are produced automatically by the
`Release` workflow on each `v*` tag. To run wsldrive manually without installing, use the commands below.

## Usage

### Direction A — mount a WSL ext4 tree as a Windows drive
Expand Down
Loading
Loading