feat(packaging): open files from argv, ship Windows MSI installer (#36)
Cross-platform prerequisite for OS-level file associations: the boot task now consumes `std::env::args_os().nth(1)` as a path and dispatches `Message::OpenRecent` for it. Flag-style args (starting with `-`) are ignored, and `OpenRecent` already does the file-existence check, so a bogus path lands as a clean command-line error instead of a panic. Linux: the AppImage's desktop entry adds `image/vnd.dwg` alongside the existing `image/vnd.dxf` MIME type and grows a `%f` placeholder in `Exec=` so the launcher forwards the picked file path. Once the AppImage is integrated with the system (xdg-mime / AppImageLauncher), double-clicking a .dwg / .dxf opens it in Open CAD Studio. Windows: new `packaging/windows/main.wxs` defines an MSI installer — per-machine install to `Program Files\Open CAD Studio`, Start Menu shortcut, `MajorUpgrade` so newer MSIs replace older ones, and a single ProgID `OpenCADStudio.Drawing` that owns both `.dwg` and `.dxf` and launches the exe with the file as `argv[1]`. The icon is pulled from the SVG logo, converted to multi-resolution ICO at build time with the runner's pre-installed ImageMagick. CI now also runs `candle` / `light` (WiX Toolset 3, pre-installed on `windows-latest`) and uploads both the bare `.exe` (portable) and `.msi` (installer) to the release. macOS Info.plist already declares the DWG / DXF UTIs; combined with the argv-handling change above, double-clicking a drawing in Finder will open it in Open CAD Studio without further packaging changes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
92f368f275
commit
a0800d95c9
4 changed files with 180 additions and 7 deletions
46
.github/workflows/release.yml
vendored
46
.github/workflows/release.yml
vendored
|
|
@ -78,13 +78,53 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --release
|
run: cargo build --release
|
||||||
|
|
||||||
- name: Upload exe to release
|
- name: Convert SVG icon to ICO
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
# ImageMagick is pre-installed on windows-latest. The
|
||||||
|
# auto-resize generates every size Explorer / Add-Remove
|
||||||
|
# Programs / the Start Menu shortcut may request from a
|
||||||
|
# single source SVG.
|
||||||
|
magick assets/logo.svg `
|
||||||
|
-define icon:auto-resize=16,24,32,48,64,128,256 `
|
||||||
|
packaging/windows/AppIcon.ico
|
||||||
|
|
||||||
|
- name: Build MSI installer
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$version = "${{ github.ref_name }}" -replace '^v', ''
|
||||||
|
if (-not $version) { $version = "0.0.0" }
|
||||||
|
# WiX Toolset 3.x is pre-installed on windows-latest; $env:WIX
|
||||||
|
# points to the install root. candle compiles .wxs → .wixobj
|
||||||
|
# and light links it into the final .msi.
|
||||||
|
$candle = Join-Path $env:WIX "bin\candle.exe"
|
||||||
|
$light = Join-Path $env:WIX "bin\light.exe"
|
||||||
|
& $candle -arch x64 `
|
||||||
|
-dVersion=$version `
|
||||||
|
-dSource=target\release\OpenCADStudio.exe `
|
||||||
|
-dIcon=packaging\windows\AppIcon.ico `
|
||||||
|
packaging\windows\main.wxs `
|
||||||
|
-out packaging\windows\main.wixobj
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "candle failed" }
|
||||||
|
& $light packaging\windows\main.wixobj -out OpenCADStudio.msi
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "light failed" }
|
||||||
|
|
||||||
|
- name: Upload artifacts to release
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
|
shell: pwsh
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
mv target/release/OpenCADStudio.exe OpenCADStudio-${{ github.ref_name }}-windows-x86_64.exe
|
$tag = "${{ github.ref_name }}"
|
||||||
gh release upload ${{ github.ref_name }} OpenCADStudio-${{ github.ref_name }}-windows-x86_64.exe --clobber --repo ${{ github.repository }}
|
# Ship both the bare .exe (portable, no install) and the
|
||||||
|
# .msi (installer with Start Menu shortcut + .dwg / .dxf
|
||||||
|
# file association). Users pick the form they want.
|
||||||
|
Move-Item target\release\OpenCADStudio.exe "OpenCADStudio-$tag-windows-x86_64.exe"
|
||||||
|
Move-Item OpenCADStudio.msi "OpenCADStudio-$tag-windows-x86_64.msi"
|
||||||
|
gh release upload $tag `
|
||||||
|
"OpenCADStudio-$tag-windows-x86_64.exe" `
|
||||||
|
"OpenCADStudio-$tag-windows-x86_64.msi" `
|
||||||
|
--clobber --repo ${{ github.repository }}
|
||||||
|
|
||||||
build-macos:
|
build-macos:
|
||||||
runs-on: macos-14 # Apple Silicon (arm64) only
|
runs-on: macos-14 # Apple Silicon (arm64) only
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=Open CAD Studio
|
Name=Open CAD Studio
|
||||||
Comment=A CAD application for 2D/3D drawing and design
|
Comment=A CAD application for 2D/3D drawing and design
|
||||||
Exec=OpenCADStudio
|
Exec=OpenCADStudio %f
|
||||||
Icon=io.github.HakanSeven12.OpenCadStudio
|
Icon=io.github.HakanSeven12.OpenCadStudio
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Categories=Graphics;Engineering;
|
Categories=Graphics;Engineering;
|
||||||
MimeType=image/vnd.dxf;
|
MimeType=image/vnd.dwg;image/vnd.dxf;
|
||||||
Keywords=CAD;DXF;drawing;design;engineering;2D;3D;
|
Keywords=CAD;DWG;DXF;drawing;design;engineering;2D;3D;
|
||||||
StartupWMClass=OpenCADStudio
|
StartupWMClass=OpenCADStudio
|
||||||
|
|
|
||||||
118
packaging/windows/main.wxs
Normal file
118
packaging/windows/main.wxs
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
<?xml version='1.0' encoding='windows-1252'?>
|
||||||
|
<!--
|
||||||
|
WiX source for the Windows MSI installer.
|
||||||
|
|
||||||
|
Build (CI / locally with WiX Toolset 3.x in PATH):
|
||||||
|
candle.exe -arch x64 -dVersion=<x.y.z> -dSource=target\release\OpenCADStudio.exe \
|
||||||
|
-dIcon=packaging\windows\AppIcon.ico packaging\windows\main.wxs \
|
||||||
|
-out packaging\windows\main.wixobj
|
||||||
|
light.exe packaging\windows\main.wixobj -out OpenCADStudio.msi
|
||||||
|
|
||||||
|
Provides:
|
||||||
|
* Per-machine install under Program Files\Open CAD Studio.
|
||||||
|
* Start Menu shortcut under Programs\Open CAD Studio.
|
||||||
|
* File associations for .dwg and .dxf via a single ProgID; both
|
||||||
|
route through `OpenCADStudio.exe "%1"` so the OS hands the file
|
||||||
|
path to the app as argv[1] (consumed in OpenCADStudio::boot).
|
||||||
|
* Standard Add/Remove Programs entry with icon.
|
||||||
|
* MajorUpgrade — installing a newer MSI replaces the old version.
|
||||||
|
-->
|
||||||
|
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
|
||||||
|
<Product
|
||||||
|
Id='*'
|
||||||
|
Name='Open CAD Studio'
|
||||||
|
UpgradeCode='bd6bceab-6c7a-4ce2-a62d-6ef06a92f8b1'
|
||||||
|
Manufacturer='Hakan Seven'
|
||||||
|
Language='1033'
|
||||||
|
Codepage='1252'
|
||||||
|
Version='$(var.Version)'>
|
||||||
|
|
||||||
|
<Package
|
||||||
|
Id='*'
|
||||||
|
Keywords='Installer'
|
||||||
|
Description='Open CAD Studio Installer'
|
||||||
|
Manufacturer='Hakan Seven'
|
||||||
|
InstallerVersion='450'
|
||||||
|
Languages='1033'
|
||||||
|
Compressed='yes'
|
||||||
|
InstallScope='perMachine'
|
||||||
|
SummaryCodepage='1252' />
|
||||||
|
|
||||||
|
<MajorUpgrade
|
||||||
|
Schedule='afterInstallInitialize'
|
||||||
|
DowngradeErrorMessage='A newer version of [ProductName] is already installed. Setup will now exit.' />
|
||||||
|
|
||||||
|
<Media Id='1' Cabinet='product.cab' EmbedCab='yes' />
|
||||||
|
|
||||||
|
<Icon Id='AppIcon.ico' SourceFile='$(var.Icon)' />
|
||||||
|
<Property Id='ARPPRODUCTICON' Value='AppIcon.ico' />
|
||||||
|
<Property Id='ARPHELPLINK' Value='https://github.com/HakanSeven12/OpenCADStudio' />
|
||||||
|
<Property Id='ARPURLINFOABOUT' Value='https://github.com/HakanSeven12/OpenCADStudio' />
|
||||||
|
|
||||||
|
<Directory Id='TARGETDIR' Name='SourceDir'>
|
||||||
|
<Directory Id='ProgramFiles64Folder'>
|
||||||
|
<Directory Id='APPLICATIONROOTDIRECTORY' Name='Open CAD Studio'>
|
||||||
|
|
||||||
|
<Component Id='MainExecutable' Guid='2900c116-e9a5-4650-8a4c-48c0987d1a33' Win64='yes'>
|
||||||
|
<File
|
||||||
|
Id='OpenCADStudioEXE'
|
||||||
|
Name='OpenCADStudio.exe'
|
||||||
|
DiskId='1'
|
||||||
|
Source='$(var.Source)'
|
||||||
|
KeyPath='yes'>
|
||||||
|
<Shortcut
|
||||||
|
Id='StartMenuShortcut'
|
||||||
|
Directory='ProgramMenuDir'
|
||||||
|
Name='Open CAD Studio'
|
||||||
|
Description='Launch Open CAD Studio'
|
||||||
|
WorkingDirectory='APPLICATIONROOTDIRECTORY'
|
||||||
|
Icon='AppIcon.ico'
|
||||||
|
IconIndex='0'
|
||||||
|
Advertise='yes' />
|
||||||
|
</File>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
File association: a single ProgID handles both .dwg and
|
||||||
|
.dxf. ContentType isn't strictly required on Windows but
|
||||||
|
improves "Open with…" suggestions.
|
||||||
|
-->
|
||||||
|
<ProgId
|
||||||
|
Id='OpenCADStudio.Drawing'
|
||||||
|
Description='Drawing'
|
||||||
|
Icon='OpenCADStudioEXE'
|
||||||
|
IconIndex='0'>
|
||||||
|
<Extension Id='dwg' ContentType='image/vnd.dwg'>
|
||||||
|
<Verb Id='open' Command='Open' TargetFile='OpenCADStudioEXE' Argument='"%1"' />
|
||||||
|
</Extension>
|
||||||
|
<Extension Id='dxf' ContentType='image/vnd.dxf'>
|
||||||
|
<Verb Id='open' Command='Open' TargetFile='OpenCADStudioEXE' Argument='"%1"' />
|
||||||
|
</Extension>
|
||||||
|
</ProgId>
|
||||||
|
</Component>
|
||||||
|
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Directory Id='ProgramMenuFolder'>
|
||||||
|
<Directory Id='ProgramMenuDir' Name='Open CAD Studio'>
|
||||||
|
<Component Id='ProgramMenuDirComp' Guid='34a788ba-f9d4-4e73-b1ff-9eb8749b369e'>
|
||||||
|
<RemoveFolder Id='ProgramMenuDir' On='uninstall' />
|
||||||
|
<RegistryValue
|
||||||
|
Root='HKCU'
|
||||||
|
Key='Software\Open CAD Studio'
|
||||||
|
Name='installed'
|
||||||
|
Type='integer'
|
||||||
|
Value='1'
|
||||||
|
KeyPath='yes' />
|
||||||
|
</Component>
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Feature Id='Complete' Title='Open CAD Studio' Level='1'>
|
||||||
|
<ComponentRef Id='MainExecutable' />
|
||||||
|
<ComponentRef Id='ProgramMenuDirComp' />
|
||||||
|
</Feature>
|
||||||
|
|
||||||
|
</Product>
|
||||||
|
</Wix>
|
||||||
|
|
@ -1036,7 +1036,22 @@ impl OpenCADStudio {
|
||||||
Message::UpdateCheckResult,
|
Message::UpdateCheckResult,
|
||||||
);
|
);
|
||||||
let focus_cmd = s.focus_cmd_input();
|
let focus_cmd = s.focus_cmd_input();
|
||||||
(s, Task::batch([open_main, check_update, focus_cmd]))
|
// Open a file path passed on the command line. Used by the
|
||||||
|
// OS file association: double-clicking a .dwg in the file
|
||||||
|
// explorer launches the binary with the file path as the
|
||||||
|
// first positional argument. Unknown / flag-style args are
|
||||||
|
// ignored. `Message::OpenRecent` does the existence check
|
||||||
|
// and reports a clean error if the path is bogus.
|
||||||
|
let cli_open: Task<Message> = std::env::args_os()
|
||||||
|
.nth(1)
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.filter(|p| !p.as_os_str().to_string_lossy().starts_with('-'))
|
||||||
|
.map(|p| Task::done(Message::OpenRecent(p)))
|
||||||
|
.unwrap_or_else(Task::none);
|
||||||
|
(
|
||||||
|
s,
|
||||||
|
Task::batch([open_main, check_update, focus_cmd, cli_open]),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue