windows: Publish nightly (#24800)
The installer, uninstaller, and the Zed binary files are all signed using Microsoft’s newly launched Trusted Signing service. For demonstration purposes, I have used my own account for the signing process. For more information about Trusted Signing, you can refer to the following links: - [Microsoft Security Blog: Trusted Signing is in Public Preview](https://techcommunity.microsoft.com/blog/microsoft-security-blog/trusted-signing-is-in-public-preview/4103457) - [Overview of Azure Trusted Signing](https://learn.microsoft.com/en-us/azure/trusted-signing/overview) **TODO:** - [x] `InnoSetup` script to setup an installer - [x] Signing process - [x] `Open with Zed` in right click context menu (by using sparse package) - [x] Integrate with `cli` - [x] Implement `cli` (#25412) - [x] Pack `cli.exe` into installer - [x] Implement auto updating (#25734) - [x] Pack autoupdater helper into installer - [x] Implement dock menus - [x] Add `Recent Documents` entries (#26369) - [x] Make `zed.exe` aware of sigle instance (#25412) - [x] Properly handle dock menu events (#26010) - [x] Handle `zed://***` uri **Materials needed:** - [ ] Icons - [ ] App icon for all channels (#9571) - [ ] Associated file icons, at minimum a default icon ([example](https://github.com/microsoft/vscode/tree/main/resources/win32)) - [ ] Logos for installer wizard - [ ] Icons for appx - [x] Code signing - [x] Secrets: AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, ACCOUNT_NAME, CERT_PROFILE_NAME - [x] Other constants: ENDPOINT, Identity Signature (i.e. `CN=Junkui Zhang, O=Junkui Zhang, L=Wuhan, S=Hubei, C=CN`)  https://github.com/user-attachments/assets/4f1092b4-90fc-4a47-a868-8f2f1a5d8ad8 Release Notes: - N/A --------- Co-authored-by: Kate <kate@zed.dev> Co-authored-by: localcc <work@localcc.cc> Co-authored-by: Peter Tripp <peter@zed.dev> Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
3a247ee947
commit
df57754baf
33 changed files with 3040 additions and 19 deletions
|
@ -19,6 +19,8 @@ rustflags = [
|
||||||
"windows_slim_errors", # This cfg will reduce the size of `windows::core::Error` from 16 bytes to 4 bytes
|
"windows_slim_errors", # This cfg will reduce the size of `windows::core::Error` from 16 bytes to 4 bytes
|
||||||
"-C",
|
"-C",
|
||||||
"target-feature=+crt-static", # This fixes the linking issue when compiling livekit on Windows
|
"target-feature=+crt-static", # This fixes the linking issue when compiling livekit on Windows
|
||||||
|
"-C",
|
||||||
|
"link-arg=-fuse-ld=lld",
|
||||||
]
|
]
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
|
|
64
.github/actions/install_trusted_signing/action.yml
vendored
Normal file
64
.github/actions/install_trusted_signing/action.yml
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
name: "Trusted Signing on Windows"
|
||||||
|
description: "Install trusted signing on Windows."
|
||||||
|
|
||||||
|
# Modified from https://github.com/Azure/trusted-signing-action
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Set variables
|
||||||
|
id: set-variables
|
||||||
|
shell: "pwsh"
|
||||||
|
run: |
|
||||||
|
$defaultPath = $env:PSModulePath -split ';' | Select-Object -First 1
|
||||||
|
"PSMODULEPATH=$defaultPath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
|
||||||
|
|
||||||
|
"TRUSTED_SIGNING_MODULE_VERSION=0.5.3" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
|
||||||
|
"BUILD_TOOLS_NUGET_VERSION=10.0.22621.3233" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
|
||||||
|
"TRUSTED_SIGNING_NUGET_VERSION=1.0.53" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
|
||||||
|
"DOTNET_SIGNCLI_NUGET_VERSION=0.9.1-beta.24469.1" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
|
||||||
|
|
||||||
|
- name: Cache TrustedSigning PowerShell module
|
||||||
|
id: cache-module
|
||||||
|
uses: actions/cache@v4
|
||||||
|
env:
|
||||||
|
cache-name: cache-module
|
||||||
|
with:
|
||||||
|
path: ${{ steps.set-variables.outputs.PSMODULEPATH }}\TrustedSigning\${{ steps.set-variables.outputs.TRUSTED_SIGNING_MODULE_VERSION }}
|
||||||
|
key: TrustedSigning-${{ steps.set-variables.outputs.TRUSTED_SIGNING_MODULE_VERSION }}
|
||||||
|
if: ${{ inputs.cache-dependencies == 'true' }}
|
||||||
|
|
||||||
|
- name: Cache Microsoft.Windows.SDK.BuildTools NuGet package
|
||||||
|
id: cache-buildtools
|
||||||
|
uses: actions/cache@v4
|
||||||
|
env:
|
||||||
|
cache-name: cache-buildtools
|
||||||
|
with:
|
||||||
|
path: ~\AppData\Local\TrustedSigning\Microsoft.Windows.SDK.BuildTools\Microsoft.Windows.SDK.BuildTools.${{ steps.set-variables.outputs.BUILD_TOOLS_NUGET_VERSION }}
|
||||||
|
key: Microsoft.Windows.SDK.BuildTools-${{ steps.set-variables.outputs.BUILD_TOOLS_NUGET_VERSION }}
|
||||||
|
if: ${{ inputs.cache-dependencies == 'true' }}
|
||||||
|
|
||||||
|
- name: Cache Microsoft.Trusted.Signing.Client NuGet package
|
||||||
|
id: cache-tsclient
|
||||||
|
uses: actions/cache@v4
|
||||||
|
env:
|
||||||
|
cache-name: cache-tsclient
|
||||||
|
with:
|
||||||
|
path: ~\AppData\Local\TrustedSigning\Microsoft.Trusted.Signing.Client\Microsoft.Trusted.Signing.Client.${{ steps.set-variables.outputs.TRUSTED_SIGNING_NUGET_VERSION }}
|
||||||
|
key: Microsoft.Trusted.Signing.Client-${{ steps.set-variables.outputs.TRUSTED_SIGNING_NUGET_VERSION }}
|
||||||
|
if: ${{ inputs.cache-dependencies == 'true' }}
|
||||||
|
|
||||||
|
- name: Cache SignCli NuGet package
|
||||||
|
id: cache-signcli
|
||||||
|
uses: actions/cache@v4
|
||||||
|
env:
|
||||||
|
cache-name: cache-signcli
|
||||||
|
with:
|
||||||
|
path: ~\AppData\Local\TrustedSigning\sign\sign.${{ steps.set-variables.outputs.DOTNET_SIGNCLI_NUGET_VERSION }}
|
||||||
|
key: SignCli-${{ steps.set-variables.outputs.DOTNET_SIGNCLI_NUGET_VERSION }}
|
||||||
|
if: ${{ inputs.cache-dependencies == 'true' }}
|
||||||
|
|
||||||
|
- name: Install Trusted Signing module
|
||||||
|
shell: "pwsh"
|
||||||
|
run: |
|
||||||
|
Install-Module -Name TrustedSigning -RequiredVersion ${{ steps.set-variables.outputs.TRUSTED_SIGNING_MODULE_VERSION }} -Force -Repository PSGallery
|
||||||
|
if: ${{ inputs.cache-dependencies != 'true' || steps.cache-module.outputs.cache-hit != 'true' }}
|
75
.github/workflows/ci.yml
vendored
75
.github/workflows/ci.yml
vendored
|
@ -411,11 +411,10 @@ jobs:
|
||||||
with:
|
with:
|
||||||
clean: false
|
clean: false
|
||||||
|
|
||||||
- name: Setup Cargo and Rustup
|
- name: Configure CI
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ${{ env.CARGO_HOME }} -ErrorAction Ignore
|
New-Item -ItemType Directory -Path "./../.cargo" -Force
|
||||||
cp ./.cargo/ci-config.toml ${{ env.CARGO_HOME }}/config.toml
|
Copy-Item -Path "./.cargo/ci-config.toml" -Destination "./../.cargo/config.toml"
|
||||||
.\script\install-rustup.ps1
|
|
||||||
|
|
||||||
- name: cargo clippy
|
- name: cargo clippy
|
||||||
run: |
|
run: |
|
||||||
|
@ -430,18 +429,9 @@ jobs:
|
||||||
- name: Limit target directory size
|
- name: Limit target directory size
|
||||||
run: ./script/clear-target-dir-if-larger-than.ps1 250
|
run: ./script/clear-target-dir-if-larger-than.ps1 250
|
||||||
|
|
||||||
# - name: Check dev drive space
|
|
||||||
# working-directory: ${{ env.ZED_WORKSPACE }}
|
|
||||||
# # `setup-dev-driver.ps1` creates a 100GB drive, with CI taking up ~45GB of the drive.
|
|
||||||
# run: ./script/exit-ci-if-dev-drive-is-full.ps1 95
|
|
||||||
|
|
||||||
# Since the Windows runners are stateful, so we need to remove the config file to prevent potential bug.
|
|
||||||
- name: Clean CI config file
|
- name: Clean CI config file
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: Remove-Item -Recurse -Path "./../.cargo" -Force -ErrorAction SilentlyContinue
|
||||||
if (Test-Path "${{ env.CARGO_HOME }}/config.toml") {
|
|
||||||
Remove-Item -Path "${{ env.CARGO_HOME }}/config.toml" -Force
|
|
||||||
}
|
|
||||||
|
|
||||||
tests_pass:
|
tests_pass:
|
||||||
name: Tests Pass
|
name: Tests Pass
|
||||||
|
@ -763,12 +753,67 @@ jobs:
|
||||||
# excludes the final package to only cache dependencies
|
# excludes the final package to only cache dependencies
|
||||||
cachix-filter: "-zed-editor-[0-9.]*-nightly"
|
cachix-filter: "-zed-editor-[0-9.]*-nightly"
|
||||||
|
|
||||||
|
bundle-windows-x64:
|
||||||
|
timeout-minutes: 120
|
||||||
|
name: Create a Windows installer
|
||||||
|
runs-on: [self-hosted, Windows, X64]
|
||||||
|
if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
|
||||||
|
needs: [windows_tests]
|
||||||
|
env:
|
||||||
|
AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
|
||||||
|
AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
|
||||||
|
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
|
||||||
|
ACCOUNT_NAME: ${{ vars.AZURE_SIGNING_ACCOUNT_NAME }}
|
||||||
|
CERT_PROFILE_NAME: ${{ vars.AZURE_SIGNING_CERT_PROFILE_NAME }}
|
||||||
|
ENDPOINT: ${{ vars.AZURE_SIGNING_ENDPOINT }}
|
||||||
|
DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
|
||||||
|
DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
|
||||||
|
FILE_DIGEST: SHA256
|
||||||
|
TIMESTAMP_DIGEST: SHA256
|
||||||
|
TIMESTAMP_SERVER: "http://timestamp.acs.microsoft.com"
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
with:
|
||||||
|
clean: false
|
||||||
|
|
||||||
|
- name: Determine version and release channel
|
||||||
|
working-directory: ${{ env.ZED_WORKSPACE }}
|
||||||
|
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||||
|
run: |
|
||||||
|
# This exports RELEASE_CHANNEL into env (GITHUB_ENV)
|
||||||
|
script/determine-release-channel.ps1
|
||||||
|
|
||||||
|
- name: Install trusted signing
|
||||||
|
uses: ./.github/actions/install_trusted_signing
|
||||||
|
|
||||||
|
- name: Build Zed installer
|
||||||
|
working-directory: ${{ env.ZED_WORKSPACE }}
|
||||||
|
run: script/bundle-windows.ps1
|
||||||
|
|
||||||
|
- name: Upload installer (x86_64) to Workflow - zed (run-bundling)
|
||||||
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||||
|
if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
|
||||||
|
with:
|
||||||
|
name: ZedEditorUserSetup-x64-${{ github.event.pull_request.head.sha || github.sha }}.exe
|
||||||
|
path: ${{ env.SETUP_PATH }}
|
||||||
|
|
||||||
|
- name: Upload Artifacts to release
|
||||||
|
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||||
|
if: ${{ !(contains(github.event.pull_request.labels.*.name, 'run-bundling')) && env.RELEASE_CHANNEL == 'preview' }} # upload only preview
|
||||||
|
with:
|
||||||
|
draft: true
|
||||||
|
prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
|
||||||
|
files: ${{ env.SETUP_PATH }}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
auto-release-preview:
|
auto-release-preview:
|
||||||
name: Auto release preview
|
name: Auto release preview
|
||||||
if: |
|
if: |
|
||||||
startsWith(github.ref, 'refs/tags/v')
|
startsWith(github.ref, 'refs/tags/v')
|
||||||
&& endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre')
|
&& endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre')
|
||||||
needs: [bundle-mac, bundle-linux-x86_x64, bundle-linux-aarch64, freebsd]
|
needs: [bundle-mac, bundle-linux-x86_x64, bundle-linux-aarch64, bundle-windows-x64, freebsd]
|
||||||
runs-on:
|
runs-on:
|
||||||
- self-hosted
|
- self-hosted
|
||||||
- bundle
|
- bundle
|
||||||
|
|
71
.github/workflows/release_nightly.yml
vendored
71
.github/workflows/release_nightly.yml
vendored
|
@ -51,6 +51,32 @@ jobs:
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
uses: ./.github/actions/run_tests
|
uses: ./.github/actions/run_tests
|
||||||
|
|
||||||
|
windows-tests:
|
||||||
|
timeout-minutes: 60
|
||||||
|
name: Run tests on Windows
|
||||||
|
if: github.repository_owner == 'zed-industries'
|
||||||
|
runs-on: [self-hosted, Windows, X64]
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
with:
|
||||||
|
clean: false
|
||||||
|
|
||||||
|
- name: Configure CI
|
||||||
|
run: |
|
||||||
|
New-Item -ItemType Directory -Path "./../.cargo" -Force
|
||||||
|
Copy-Item -Path "./.cargo/ci-config.toml" -Destination "./../.cargo/config.toml"
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
uses: ./.github/actions/run_tests_windows
|
||||||
|
|
||||||
|
- name: Limit target directory size
|
||||||
|
run: ./script/clear-target-dir-if-larger-than.ps1 1024
|
||||||
|
|
||||||
|
- name: Clean CI config file
|
||||||
|
if: always()
|
||||||
|
run: Remove-Item -Recurse -Path "./../.cargo" -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
bundle-mac:
|
bundle-mac:
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
name: Create a macOS bundle
|
name: Create a macOS bundle
|
||||||
|
@ -213,10 +239,54 @@ jobs:
|
||||||
|
|
||||||
bundle-nix:
|
bundle-nix:
|
||||||
name: Build and cache Nix package
|
name: Build and cache Nix package
|
||||||
|
if: false
|
||||||
needs: tests
|
needs: tests
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
uses: ./.github/workflows/nix.yml
|
uses: ./.github/workflows/nix.yml
|
||||||
|
|
||||||
|
bundle-windows-x64:
|
||||||
|
timeout-minutes: 60
|
||||||
|
name: Create a Windows installer
|
||||||
|
if: github.repository_owner == 'zed-industries'
|
||||||
|
runs-on: [self-hosted, Windows, X64]
|
||||||
|
needs: windows-tests
|
||||||
|
env:
|
||||||
|
AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
|
||||||
|
AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
|
||||||
|
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
|
||||||
|
ACCOUNT_NAME: ${{ vars.AZURE_SIGNING_ACCOUNT_NAME }}
|
||||||
|
CERT_PROFILE_NAME: ${{ vars.AZURE_SIGNING_CERT_PROFILE_NAME }}
|
||||||
|
ENDPOINT: ${{ vars.AZURE_SIGNING_ENDPOINT }}
|
||||||
|
DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
|
||||||
|
DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
|
||||||
|
FILE_DIGEST: SHA256
|
||||||
|
TIMESTAMP_DIGEST: SHA256
|
||||||
|
TIMESTAMP_SERVER: "http://timestamp.acs.microsoft.com"
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
with:
|
||||||
|
clean: false
|
||||||
|
|
||||||
|
- name: Set release channel to nightly
|
||||||
|
working-directory: ${{ env.ZED_WORKSPACE }}
|
||||||
|
run: |
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$version = git rev-parse --short HEAD
|
||||||
|
Write-Host "Publishing version: $version on release channel nightly"
|
||||||
|
"nightly" | Set-Content -Path "crates/zed/RELEASE_CHANNEL"
|
||||||
|
|
||||||
|
- name: Install trusted signing
|
||||||
|
uses: ./.github/actions/install_trusted_signing
|
||||||
|
|
||||||
|
- name: Build Zed installer
|
||||||
|
working-directory: ${{ env.ZED_WORKSPACE }}
|
||||||
|
run: script/bundle-windows.ps1
|
||||||
|
|
||||||
|
- name: Upload Zed Nightly
|
||||||
|
working-directory: ${{ env.ZED_WORKSPACE }}
|
||||||
|
run: script/upload-nightly.ps1 windows
|
||||||
|
|
||||||
update-nightly-tag:
|
update-nightly-tag:
|
||||||
name: Update nightly tag
|
name: Update nightly tag
|
||||||
if: github.repository_owner == 'zed-industries'
|
if: github.repository_owner == 'zed-industries'
|
||||||
|
@ -225,6 +295,7 @@ jobs:
|
||||||
- bundle-mac
|
- bundle-mac
|
||||||
- bundle-linux-x86
|
- bundle-linux-x86
|
||||||
- bundle-linux-arm
|
- bundle-linux-arm
|
||||||
|
- bundle-windows-x64
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
|
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -5191,6 +5191,16 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "explorer_command_injector"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"windows 0.61.1",
|
||||||
|
"windows-core 0.61.0",
|
||||||
|
"windows-registry 0.5.1",
|
||||||
|
"workspace-hack",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "exr"
|
name = "exr"
|
||||||
version = "1.73.0"
|
version = "1.73.0"
|
||||||
|
|
|
@ -45,6 +45,7 @@ members = [
|
||||||
"crates/diagnostics",
|
"crates/diagnostics",
|
||||||
"crates/docs_preprocessor",
|
"crates/docs_preprocessor",
|
||||||
"crates/editor",
|
"crates/editor",
|
||||||
|
"crates/explorer_command_injector",
|
||||||
"crates/eval",
|
"crates/eval",
|
||||||
"crates/extension",
|
"crates/extension",
|
||||||
"crates/extension_api",
|
"crates/extension_api",
|
||||||
|
@ -625,6 +626,8 @@ wasmtime = { version = "29", default-features = false, features = [
|
||||||
] }
|
] }
|
||||||
wasmtime-wasi = "29"
|
wasmtime-wasi = "29"
|
||||||
which = "6.0.0"
|
which = "6.0.0"
|
||||||
|
windows-core = "0.61"
|
||||||
|
wit-component = "0.221"
|
||||||
workspace-hack = "0.1.0"
|
workspace-hack = "0.1.0"
|
||||||
zed_llm_client = "= 0.8.6"
|
zed_llm_client = "= 0.8.6"
|
||||||
zstd = "0.11"
|
zstd = "0.11"
|
||||||
|
|
|
@ -638,7 +638,7 @@ impl AutoUpdater {
|
||||||
let filename = match OS {
|
let filename = match OS {
|
||||||
"macos" => anyhow::Ok("Zed.dmg"),
|
"macos" => anyhow::Ok("Zed.dmg"),
|
||||||
"linux" => Ok("zed.tar.gz"),
|
"linux" => Ok("zed.tar.gz"),
|
||||||
"windows" => Ok("ZedUpdateInstaller.exe"),
|
"windows" => Ok("zed_editor_installer.exe"),
|
||||||
unsupported_os => anyhow::bail!("not supported: {unsupported_os}"),
|
unsupported_os => anyhow::bail!("not supported: {unsupported_os}"),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 0 B After Width: | Height: | Size: 577 KiB |
|
@ -130,6 +130,13 @@ fn parse_path_with_position(argument_str: &str) -> anyhow::Result<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
#[cfg(all(not(debug_assertions), target_os = "windows"))]
|
||||||
|
unsafe {
|
||||||
|
use ::windows::Win32::System::Console::{ATTACH_PARENT_PROCESS, AttachConsole};
|
||||||
|
|
||||||
|
let _ = AttachConsole(ATTACH_PARENT_PROCESS);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
util::prevent_root_execution();
|
util::prevent_root_execution();
|
||||||
|
|
||||||
|
|
78
crates/explorer_command_injector/AppxManifest-Nightly.xml
Normal file
78
crates/explorer_command_injector/AppxManifest-Nightly.xml
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Package
|
||||||
|
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||||
|
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||||
|
xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
|
||||||
|
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||||
|
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||||
|
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||||
|
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||||
|
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||||
|
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||||
|
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
|
||||||
|
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||||
|
IgnorableNamespaces="uap uap2 uap3 rescap desktop desktop4 desktop5 desktop6 uap10 com">
|
||||||
|
<!-- TODO: Use Zed's signature here. -->
|
||||||
|
<Identity
|
||||||
|
Name="ZedIndustries.Zed.Nightly"
|
||||||
|
Publisher="CN=Zed Industries Inc, O=Zed Industries Inc, L=Denver, S=Colorado, C=US"
|
||||||
|
Version="1.0.0.0" />
|
||||||
|
<Properties>
|
||||||
|
<DisplayName>Zed Editor Nightly</DisplayName>
|
||||||
|
<PublisherDisplayName>Zed Industries</PublisherDisplayName>
|
||||||
|
<!-- TODO: Use actual icon here. -->
|
||||||
|
<Logo>resources\logo_150x150.png</Logo>
|
||||||
|
<uap10:AllowExternalContent>true</uap10:AllowExternalContent>
|
||||||
|
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
|
||||||
|
<desktop6:FileSystemWriteVirtualization>disabled</desktop6:FileSystemWriteVirtualization>
|
||||||
|
</Properties>
|
||||||
|
<Resources>
|
||||||
|
<Resource Language="en-us" />
|
||||||
|
<Resource Language="zh-cn" />
|
||||||
|
</Resources>
|
||||||
|
<Dependencies>
|
||||||
|
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19000.0" MaxVersionTested="10.0.22000.0" />
|
||||||
|
</Dependencies>
|
||||||
|
<Capabilities>
|
||||||
|
<rescap:Capability Name="runFullTrust" />
|
||||||
|
<rescap:Capability Name="unvirtualizedResources"/>
|
||||||
|
</Capabilities>
|
||||||
|
<Applications>
|
||||||
|
<Application Id="ZedNightly"
|
||||||
|
Executable="Zed.exe"
|
||||||
|
uap10:TrustLevel="mediumIL"
|
||||||
|
uap10:RuntimeBehavior="win32App">
|
||||||
|
<!-- TODO: Use actual icon here. -->
|
||||||
|
<uap:VisualElements
|
||||||
|
AppListEntry="none"
|
||||||
|
DisplayName="Zed Editor Nightly"
|
||||||
|
Description="Zed Editor Nightly explorer command injector"
|
||||||
|
BackgroundColor="transparent"
|
||||||
|
Square150x150Logo="resources\logo_150x150.png"
|
||||||
|
Square44x44Logo="resources\logo_70x70.png">
|
||||||
|
</uap:VisualElements>
|
||||||
|
<Extensions>
|
||||||
|
<desktop4:Extension Category="windows.fileExplorerContextMenus">
|
||||||
|
<desktop4:FileExplorerContextMenus>
|
||||||
|
<desktop5:ItemType Type="Directory">
|
||||||
|
<desktop5:Verb Id="OpenWithZedNightly" Clsid="266f2cfe-1653-42af-b55c-fe3590c83871" />
|
||||||
|
</desktop5:ItemType>
|
||||||
|
<desktop5:ItemType Type="Directory\Background">
|
||||||
|
<desktop5:Verb Id="OpenWithZedNightly" Clsid="266f2cfe-1653-42af-b55c-fe3590c83871" />
|
||||||
|
</desktop5:ItemType>
|
||||||
|
<desktop5:ItemType Type="*">
|
||||||
|
<desktop5:Verb Id="OpenWithZedNightly" Clsid="266f2cfe-1653-42af-b55c-fe3590c83871" />
|
||||||
|
</desktop5:ItemType>
|
||||||
|
</desktop4:FileExplorerContextMenus>
|
||||||
|
</desktop4:Extension>
|
||||||
|
<com:Extension Category="windows.comServer">
|
||||||
|
<com:ComServer>
|
||||||
|
<com:SurrogateServer DisplayName="Zed Editor Nightly">
|
||||||
|
<com:Class Id="266f2cfe-1653-42af-b55c-fe3590c83871" Path="zed_explorer_command_injector.dll" ThreadingModel="STA"/>
|
||||||
|
</com:SurrogateServer>
|
||||||
|
</com:ComServer>
|
||||||
|
</com:Extension>
|
||||||
|
</Extensions>
|
||||||
|
</Application>
|
||||||
|
</Applications>
|
||||||
|
</Package>
|
78
crates/explorer_command_injector/AppxManifest-Preview.xml
Normal file
78
crates/explorer_command_injector/AppxManifest-Preview.xml
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Package
|
||||||
|
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||||
|
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||||
|
xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
|
||||||
|
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||||
|
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||||
|
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||||
|
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||||
|
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||||
|
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||||
|
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
|
||||||
|
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||||
|
IgnorableNamespaces="uap uap2 uap3 rescap desktop desktop4 desktop5 desktop6 uap10 com">
|
||||||
|
<!-- TODO: Use Zed's signature here. -->
|
||||||
|
<Identity
|
||||||
|
Name="ZedIndustries.Zed.Preview"
|
||||||
|
Publisher="CN=Zed Industries Inc, O=Zed Industries Inc, L=Denver, S=Colorado, C=US"
|
||||||
|
Version="1.0.0.0" />
|
||||||
|
<Properties>
|
||||||
|
<DisplayName>Zed Editor Preview</DisplayName>
|
||||||
|
<PublisherDisplayName>Zed Industries</PublisherDisplayName>
|
||||||
|
<!-- TODO: Use actual icon here. -->
|
||||||
|
<Logo>resources\logo_150x150.png</Logo>
|
||||||
|
<uap10:AllowExternalContent>true</uap10:AllowExternalContent>
|
||||||
|
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
|
||||||
|
<desktop6:FileSystemWriteVirtualization>disabled</desktop6:FileSystemWriteVirtualization>
|
||||||
|
</Properties>
|
||||||
|
<Resources>
|
||||||
|
<Resource Language="en-us" />
|
||||||
|
<Resource Language="zh-cn" />
|
||||||
|
</Resources>
|
||||||
|
<Dependencies>
|
||||||
|
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19000.0" MaxVersionTested="10.0.22000.0" />
|
||||||
|
</Dependencies>
|
||||||
|
<Capabilities>
|
||||||
|
<rescap:Capability Name="runFullTrust" />
|
||||||
|
<rescap:Capability Name="unvirtualizedResources"/>
|
||||||
|
</Capabilities>
|
||||||
|
<Applications>
|
||||||
|
<Application Id="ZedPreview"
|
||||||
|
Executable="Zed.exe"
|
||||||
|
uap10:TrustLevel="mediumIL"
|
||||||
|
uap10:RuntimeBehavior="win32App">
|
||||||
|
<!-- TODO: Use actual icon here. -->
|
||||||
|
<uap:VisualElements
|
||||||
|
AppListEntry="none"
|
||||||
|
DisplayName="Zed Editor Preview"
|
||||||
|
Description="Zed Editor Preview explorer command injector"
|
||||||
|
BackgroundColor="transparent"
|
||||||
|
Square150x150Logo="resources\logo_150x150.png"
|
||||||
|
Square44x44Logo="resources\logo_70x70.png">
|
||||||
|
</uap:VisualElements>
|
||||||
|
<Extensions>
|
||||||
|
<desktop4:Extension Category="windows.fileExplorerContextMenus">
|
||||||
|
<desktop4:FileExplorerContextMenus>
|
||||||
|
<desktop5:ItemType Type="Directory">
|
||||||
|
<desktop5:Verb Id="OpenWithZedPreview" Clsid="af8e85ea-fb20-4db2-93cf-56513c1ec697" />
|
||||||
|
</desktop5:ItemType>
|
||||||
|
<desktop5:ItemType Type="Directory\Background">
|
||||||
|
<desktop5:Verb Id="OpenWithZedPreview" Clsid="af8e85ea-fb20-4db2-93cf-56513c1ec697" />
|
||||||
|
</desktop5:ItemType>
|
||||||
|
<desktop5:ItemType Type="*">
|
||||||
|
<desktop5:Verb Id="OpenWithZedPreview" Clsid="af8e85ea-fb20-4db2-93cf-56513c1ec697" />
|
||||||
|
</desktop5:ItemType>
|
||||||
|
</desktop4:FileExplorerContextMenus>
|
||||||
|
</desktop4:Extension>
|
||||||
|
<com:Extension Category="windows.comServer">
|
||||||
|
<com:ComServer>
|
||||||
|
<com:SurrogateServer DisplayName="Zed Editor Preview">
|
||||||
|
<com:Class Id="af8e85ea-fb20-4db2-93cf-56513c1ec697" Path="zed_explorer_command_injector.dll" ThreadingModel="STA"/>
|
||||||
|
</com:SurrogateServer>
|
||||||
|
</com:ComServer>
|
||||||
|
</com:Extension>
|
||||||
|
</Extensions>
|
||||||
|
</Application>
|
||||||
|
</Applications>
|
||||||
|
</Package>
|
79
crates/explorer_command_injector/AppxManifest.xml
Normal file
79
crates/explorer_command_injector/AppxManifest.xml
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Package
|
||||||
|
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||||
|
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||||
|
xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
|
||||||
|
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||||
|
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||||
|
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||||
|
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||||
|
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||||
|
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||||
|
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
|
||||||
|
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||||
|
IgnorableNamespaces="uap uap2 uap3 rescap desktop desktop4 desktop5 desktop6 uap10 com">
|
||||||
|
<!-- TODO: Use Zed's signature here. -->
|
||||||
|
<Identity
|
||||||
|
Name="ZedIndustries.Zed"
|
||||||
|
Publisher="CN=Zed Industries Inc, O=Zed Industries Inc, L=Denver, S=Colorado, C=US"
|
||||||
|
Version="1.0.0.0" />
|
||||||
|
<Properties>
|
||||||
|
<DisplayName>Zed Editor</DisplayName>
|
||||||
|
|
||||||
|
<PublisherDisplayName>Zed Industries</PublisherDisplayName>
|
||||||
|
<!-- TODO: Use actual icon here. -->
|
||||||
|
<Logo>resources\logo_150x150.png</Logo>
|
||||||
|
<uap10:AllowExternalContent>true</uap10:AllowExternalContent>
|
||||||
|
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
|
||||||
|
<desktop6:FileSystemWriteVirtualization>disabled</desktop6:FileSystemWriteVirtualization>
|
||||||
|
</Properties>
|
||||||
|
<Resources>
|
||||||
|
<Resource Language="en-us" />
|
||||||
|
<Resource Language="zh-cn" />
|
||||||
|
</Resources>
|
||||||
|
<Dependencies>
|
||||||
|
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19000.0" MaxVersionTested="10.0.22000.0" />
|
||||||
|
</Dependencies>
|
||||||
|
<Capabilities>
|
||||||
|
<rescap:Capability Name="runFullTrust" />
|
||||||
|
<rescap:Capability Name="unvirtualizedResources"/>
|
||||||
|
</Capabilities>
|
||||||
|
<Applications>
|
||||||
|
<Application Id="Zed"
|
||||||
|
Executable="Zed.exe"
|
||||||
|
uap10:TrustLevel="mediumIL"
|
||||||
|
uap10:RuntimeBehavior="win32App">
|
||||||
|
<!-- TODO: Use actual icon here. -->
|
||||||
|
<uap:VisualElements
|
||||||
|
AppListEntry="none"
|
||||||
|
DisplayName="Zed Editor"
|
||||||
|
Description="Zed Editor explorer command injector"
|
||||||
|
BackgroundColor="transparent"
|
||||||
|
Square150x150Logo="resources\logo_150x150.png"
|
||||||
|
Square44x44Logo="resources\logo_70x70.png">
|
||||||
|
</uap:VisualElements>
|
||||||
|
<Extensions>
|
||||||
|
<desktop4:Extension Category="windows.fileExplorerContextMenus">
|
||||||
|
<desktop4:FileExplorerContextMenus>
|
||||||
|
<desktop5:ItemType Type="Directory">
|
||||||
|
<desktop5:Verb Id="OpenWithZed" Clsid="6a1f6b13-3b82-48a1-9e06-7bb0a6d0bffd" />
|
||||||
|
</desktop5:ItemType>
|
||||||
|
<desktop5:ItemType Type="Directory\Background">
|
||||||
|
<desktop5:Verb Id="OpenWithZed" Clsid="6a1f6b13-3b82-48a1-9e06-7bb0a6d0bffd" />
|
||||||
|
</desktop5:ItemType>
|
||||||
|
<desktop5:ItemType Type="*">
|
||||||
|
<desktop5:Verb Id="OpenWithZed" Clsid="6a1f6b13-3b82-48a1-9e06-7bb0a6d0bffd" />
|
||||||
|
</desktop5:ItemType>
|
||||||
|
</desktop4:FileExplorerContextMenus>
|
||||||
|
</desktop4:Extension>
|
||||||
|
<com:Extension Category="windows.comServer">
|
||||||
|
<com:ComServer>
|
||||||
|
<com:SurrogateServer DisplayName="Zed Editor">
|
||||||
|
<com:Class Id="6a1f6b13-3b82-48a1-9e06-7bb0a6d0bffd" Path="zed_explorer_command_injector.dll" ThreadingModel="STA"/>
|
||||||
|
</com:SurrogateServer>
|
||||||
|
</com:ComServer>
|
||||||
|
</com:Extension>
|
||||||
|
</Extensions>
|
||||||
|
</Application>
|
||||||
|
</Applications>
|
||||||
|
</Package>
|
28
crates/explorer_command_injector/Cargo.toml
Normal file
28
crates/explorer_command_injector/Cargo.toml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
[package]
|
||||||
|
name = "explorer_command_injector"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition.workspace = true
|
||||||
|
publish.workspace = true
|
||||||
|
license = "GPL-3.0-or-later"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
path = "src/explorer_command_injector.rs"
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["nightly"]
|
||||||
|
stable = []
|
||||||
|
preview = []
|
||||||
|
nightly = []
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
|
windows.workspace = true
|
||||||
|
windows-core.workspace = true
|
||||||
|
windows-registry = "0.5"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
workspace-hack.workspace = true
|
1
crates/explorer_command_injector/LICENSE-GPL
Symbolic link
1
crates/explorer_command_injector/LICENSE-GPL
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../LICENSE-GPL
|
|
@ -0,0 +1,201 @@
|
||||||
|
#![cfg(target_os = "windows")]
|
||||||
|
|
||||||
|
use std::{os::windows::ffi::OsStringExt, path::PathBuf};
|
||||||
|
|
||||||
|
use windows::{
|
||||||
|
Win32::{
|
||||||
|
Foundation::{
|
||||||
|
CLASS_E_CLASSNOTAVAILABLE, E_FAIL, E_INVALIDARG, E_NOTIMPL, ERROR_INSUFFICIENT_BUFFER,
|
||||||
|
GetLastError, HINSTANCE, MAX_PATH,
|
||||||
|
},
|
||||||
|
Globalization::u_strlen,
|
||||||
|
System::{
|
||||||
|
Com::{IBindCtx, IClassFactory, IClassFactory_Impl},
|
||||||
|
LibraryLoader::GetModuleFileNameW,
|
||||||
|
SystemServices::DLL_PROCESS_ATTACH,
|
||||||
|
},
|
||||||
|
UI::Shell::{
|
||||||
|
ECF_DEFAULT, ECS_ENABLED, IEnumExplorerCommand, IExplorerCommand,
|
||||||
|
IExplorerCommand_Impl, IShellItemArray, SHStrDupW, SIGDN_FILESYSPATH,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
core::{BOOL, GUID, HRESULT, HSTRING, Interface, Ref, Result, implement},
|
||||||
|
};
|
||||||
|
|
||||||
|
static mut DLL_INSTANCE: HINSTANCE = HINSTANCE(std::ptr::null_mut());
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "system" fn DllMain(
|
||||||
|
hinstdll: HINSTANCE,
|
||||||
|
fdwreason: u32,
|
||||||
|
_lpvreserved: *mut core::ffi::c_void,
|
||||||
|
) -> bool {
|
||||||
|
if fdwreason == DLL_PROCESS_ATTACH {
|
||||||
|
unsafe { DLL_INSTANCE = hinstdll };
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[implement(IExplorerCommand)]
|
||||||
|
struct ExplorerCommandInjector;
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
impl IExplorerCommand_Impl for ExplorerCommandInjector_Impl {
|
||||||
|
fn GetTitle(&self, _: Ref<IShellItemArray>) -> Result<windows_core::PWSTR> {
|
||||||
|
let command_description =
|
||||||
|
retrieve_command_description().unwrap_or(HSTRING::from("Open with Zed"));
|
||||||
|
unsafe { SHStrDupW(&command_description) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetIcon(&self, _: Ref<IShellItemArray>) -> Result<windows_core::PWSTR> {
|
||||||
|
let Some(zed_exe) = get_zed_exe_path() else {
|
||||||
|
return Err(E_FAIL.into());
|
||||||
|
};
|
||||||
|
unsafe { SHStrDupW(&HSTRING::from(zed_exe)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetToolTip(&self, _: Ref<IShellItemArray>) -> Result<windows_core::PWSTR> {
|
||||||
|
Err(E_NOTIMPL.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetCanonicalName(&self) -> Result<windows_core::GUID> {
|
||||||
|
Ok(GUID::zeroed())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetState(&self, _: Ref<IShellItemArray>, _: BOOL) -> Result<u32> {
|
||||||
|
Ok(ECS_ENABLED.0 as _)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Invoke(&self, psiitemarray: Ref<IShellItemArray>, _: Ref<IBindCtx>) -> Result<()> {
|
||||||
|
let items = psiitemarray.ok()?;
|
||||||
|
let Some(zed_exe) = get_zed_exe_path() else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
let count = unsafe { items.GetCount()? };
|
||||||
|
for idx in 0..count {
|
||||||
|
let item = unsafe { items.GetItemAt(idx)? };
|
||||||
|
let item_path = unsafe { item.GetDisplayName(SIGDN_FILESYSPATH)?.to_string()? };
|
||||||
|
std::process::Command::new(&zed_exe)
|
||||||
|
.arg(&item_path)
|
||||||
|
.spawn()
|
||||||
|
.map_err(|_| E_INVALIDARG)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetFlags(&self) -> Result<u32> {
|
||||||
|
Ok(ECF_DEFAULT.0 as _)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn EnumSubCommands(&self) -> Result<IEnumExplorerCommand> {
|
||||||
|
Err(E_NOTIMPL.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[implement(IClassFactory)]
|
||||||
|
struct ExplorerCommandInjectorFactory;
|
||||||
|
|
||||||
|
impl IClassFactory_Impl for ExplorerCommandInjectorFactory_Impl {
|
||||||
|
fn CreateInstance(
|
||||||
|
&self,
|
||||||
|
punkouter: Ref<windows_core::IUnknown>,
|
||||||
|
riid: *const windows_core::GUID,
|
||||||
|
ppvobject: *mut *mut core::ffi::c_void,
|
||||||
|
) -> Result<()> {
|
||||||
|
unsafe {
|
||||||
|
*ppvobject = std::ptr::null_mut();
|
||||||
|
}
|
||||||
|
if punkouter.is_none() {
|
||||||
|
let factory: IExplorerCommand = ExplorerCommandInjector {}.into();
|
||||||
|
let ret = unsafe { factory.query(riid, ppvobject).ok() };
|
||||||
|
if ret.is_ok() {
|
||||||
|
unsafe {
|
||||||
|
*ppvobject = factory.into_raw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
} else {
|
||||||
|
Err(E_INVALIDARG.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn LockServer(&self, _: BOOL) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "stable", not(feature = "preview"), not(feature = "nightly")))]
|
||||||
|
const MODULE_ID: GUID = GUID::from_u128(0x6a1f6b13_3b82_48a1_9e06_7bb0a6d0bffd);
|
||||||
|
#[cfg(all(feature = "preview", not(feature = "stable"), not(feature = "nightly")))]
|
||||||
|
const MODULE_ID: GUID = GUID::from_u128(0xaf8e85ea_fb20_4db2_93cf_56513c1ec697);
|
||||||
|
#[cfg(all(feature = "nightly", not(feature = "stable"), not(feature = "preview")))]
|
||||||
|
const MODULE_ID: GUID = GUID::from_u128(0x266f2cfe_1653_42af_b55c_fe3590c83871);
|
||||||
|
|
||||||
|
// Make cargo clippy happy
|
||||||
|
#[cfg(all(feature = "nightly", feature = "stable", feature = "preview"))]
|
||||||
|
const MODULE_ID: GUID = GUID::from_u128(0x685f4d49_6718_4c55_b271_ebb5c6a48d6f);
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "system" fn DllGetClassObject(
|
||||||
|
class_id: *const GUID,
|
||||||
|
iid: *const GUID,
|
||||||
|
out: *mut *mut std::ffi::c_void,
|
||||||
|
) -> HRESULT {
|
||||||
|
unsafe {
|
||||||
|
*out = std::ptr::null_mut();
|
||||||
|
}
|
||||||
|
let class_id = unsafe { *class_id };
|
||||||
|
if class_id == MODULE_ID {
|
||||||
|
let instance: IClassFactory = ExplorerCommandInjectorFactory {}.into();
|
||||||
|
let ret = unsafe { instance.query(iid, out) };
|
||||||
|
if ret.is_ok() {
|
||||||
|
unsafe {
|
||||||
|
*out = instance.into_raw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
} else {
|
||||||
|
CLASS_E_CLASSNOTAVAILABLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_zed_install_folder() -> Option<PathBuf> {
|
||||||
|
let mut buf = vec![0u16; MAX_PATH as usize];
|
||||||
|
unsafe { GetModuleFileNameW(Some(DLL_INSTANCE.into()), &mut buf) };
|
||||||
|
|
||||||
|
while unsafe { GetLastError() } == ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
buf = vec![0u16; buf.len() * 2];
|
||||||
|
unsafe { GetModuleFileNameW(Some(DLL_INSTANCE.into()), &mut buf) };
|
||||||
|
}
|
||||||
|
let len = unsafe { u_strlen(buf.as_ptr()) };
|
||||||
|
let path: PathBuf = std::ffi::OsString::from_wide(&buf[..len as usize])
|
||||||
|
.into_string()
|
||||||
|
.ok()?
|
||||||
|
.into();
|
||||||
|
Some(path.parent()?.parent()?.to_path_buf())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zed_exe_path() -> Option<String> {
|
||||||
|
get_zed_install_folder().map(|path| path.join("Zed.exe").to_string_lossy().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn retrieve_command_description() -> Result<HSTRING> {
|
||||||
|
#[cfg(all(feature = "stable", not(feature = "preview"), not(feature = "nightly")))]
|
||||||
|
const REG_PATH: &str = "Software\\Classes\\ZedEditorContextMenu";
|
||||||
|
#[cfg(all(feature = "preview", not(feature = "stable"), not(feature = "nightly")))]
|
||||||
|
const REG_PATH: &str = "Software\\Classes\\ZedEditorPreviewContextMenu";
|
||||||
|
#[cfg(all(feature = "nightly", not(feature = "stable"), not(feature = "preview")))]
|
||||||
|
const REG_PATH: &str = "Software\\Classes\\ZedEditorNightlyContextMenu";
|
||||||
|
|
||||||
|
// Make cargo clippy happy
|
||||||
|
#[cfg(all(feature = "nightly", feature = "stable", feature = "preview"))]
|
||||||
|
const REG_PATH: &str = "Software\\Classes\\ZedEditorClippyContextMenu";
|
||||||
|
|
||||||
|
let key = windows_registry::CURRENT_USER.open(REG_PATH)?;
|
||||||
|
key.get_hstring("Title")
|
||||||
|
}
|
|
@ -220,7 +220,7 @@ blade-macros.workspace = true
|
||||||
flume = "0.11"
|
flume = "0.11"
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
windows.workspace = true
|
windows.workspace = true
|
||||||
windows-core = "0.61"
|
windows-core.workspace = true
|
||||||
windows-numerics = "0.2"
|
windows-numerics = "0.2"
|
||||||
windows-registry = "0.5"
|
windows-registry = "0.5"
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,17 @@ fn main() {
|
||||||
println!("cargo:rustc-link-arg=/stack:{}", 8 * 1024 * 1024);
|
println!("cargo:rustc-link-arg=/stack:{}", 8 * 1024 * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
let icon = std::path::Path::new("resources/windows/app-icon.ico");
|
let release_channel = option_env!("RELEASE_CHANNEL").unwrap_or("nightly");
|
||||||
|
|
||||||
|
let icon = match release_channel {
|
||||||
|
"stable" => "resources/windows/app-icon.ico",
|
||||||
|
"preview" => "resources/windows/app-icon-preview.ico",
|
||||||
|
"nightly" => "resources/windows/app-icon-nightly.ico",
|
||||||
|
_ => "resources/windows/app-icon-dev.ico",
|
||||||
|
};
|
||||||
|
let icon = std::path::Path::new(icon);
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-env-changed=RELEASE_CHANNEL");
|
||||||
println!("cargo:rerun-if-changed={}", icon.display());
|
println!("cargo:rerun-if-changed={}", icon.display());
|
||||||
|
|
||||||
let mut res = winresource::WindowsResource::new();
|
let mut res = winresource::WindowsResource::new();
|
||||||
|
|
BIN
crates/zed/resources/windows/app-icon-dev.ico
Normal file
BIN
crates/zed/resources/windows/app-icon-dev.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 153 KiB |
BIN
crates/zed/resources/windows/app-icon-nightly.ico
Normal file
BIN
crates/zed/resources/windows/app-icon-nightly.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 156 KiB |
BIN
crates/zed/resources/windows/app-icon-preview.ico
Normal file
BIN
crates/zed/resources/windows/app-icon-preview.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 152 KiB |
403
crates/zed/resources/windows/messages/Default.zh-cn.isl
Normal file
403
crates/zed/resources/windows/messages/Default.zh-cn.isl
Normal file
|
@ -0,0 +1,403 @@
|
||||||
|
; *** Inno Setup version 6.4.0+ Chinese Simplified messages ***
|
||||||
|
;
|
||||||
|
; To download user-contributed translations of this file, go to:
|
||||||
|
; https://jrsoftware.org/files/istrans/
|
||||||
|
;
|
||||||
|
; Note: When translating this text, do not add periods (.) to the end of
|
||||||
|
; messages that didn't have them already, because on those messages Inno
|
||||||
|
; Setup adds the periods automatically (appending a period would result in
|
||||||
|
; two periods being displayed).
|
||||||
|
;
|
||||||
|
; Maintained by Zhenghan Yang
|
||||||
|
; Email: 847320916@QQ.com
|
||||||
|
; Translation based on network resource
|
||||||
|
; The latest Translation is on https://github.com/kira-96/Inno-Setup-Chinese-Simplified-Translation
|
||||||
|
;
|
||||||
|
|
||||||
|
[LangOptions]
|
||||||
|
; The following three entries are very important. Be sure to read and
|
||||||
|
; understand the '[LangOptions] section' topic in the help file.
|
||||||
|
LanguageName=简体中文
|
||||||
|
; If Language Name display incorrect, uncomment next line
|
||||||
|
; LanguageName=<7B80><4F53><4E2D><6587>
|
||||||
|
; About LanguageID, to reference link:
|
||||||
|
; https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c
|
||||||
|
LanguageID=$0804
|
||||||
|
; About CodePage, to reference link:
|
||||||
|
; https://docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
|
||||||
|
LanguageCodePage=936
|
||||||
|
; If the language you are translating to requires special font faces or
|
||||||
|
; sizes, uncomment any of the following entries and change them accordingly.
|
||||||
|
;DialogFontName=
|
||||||
|
;DialogFontSize=8
|
||||||
|
;WelcomeFontName=Verdana
|
||||||
|
;WelcomeFontSize=12
|
||||||
|
;TitleFontName=Arial
|
||||||
|
;TitleFontSize=29
|
||||||
|
;CopyrightFontName=Arial
|
||||||
|
;CopyrightFontSize=8
|
||||||
|
|
||||||
|
[Messages]
|
||||||
|
|
||||||
|
; *** 应用程序标题
|
||||||
|
SetupAppTitle=安装
|
||||||
|
SetupWindowTitle=安装 - %1
|
||||||
|
UninstallAppTitle=卸载
|
||||||
|
UninstallAppFullTitle=%1 卸载
|
||||||
|
|
||||||
|
; *** Misc. common
|
||||||
|
InformationTitle=信息
|
||||||
|
ConfirmTitle=确认
|
||||||
|
ErrorTitle=错误
|
||||||
|
|
||||||
|
; *** SetupLdr messages
|
||||||
|
SetupLdrStartupMessage=现在将安装 %1。您想要继续吗?
|
||||||
|
LdrCannotCreateTemp=无法创建临时文件。安装程序已中止
|
||||||
|
LdrCannotExecTemp=无法执行临时目录中的文件。安装程序已中止
|
||||||
|
HelpTextNote=
|
||||||
|
|
||||||
|
; *** 启动错误消息
|
||||||
|
LastErrorMessage=%1。%n%n错误 %2: %3
|
||||||
|
SetupFileMissing=安装目录中缺少文件 %1。请修正这个问题或者获取程序的新副本。
|
||||||
|
SetupFileCorrupt=安装文件已损坏。请获取程序的新副本。
|
||||||
|
SetupFileCorruptOrWrongVer=安装文件已损坏,或是与这个安装程序的版本不兼容。请修正这个问题或获取新的程序副本。
|
||||||
|
InvalidParameter=无效的命令行参数:%n%n%1
|
||||||
|
SetupAlreadyRunning=安装程序正在运行。
|
||||||
|
WindowsVersionNotSupported=此程序不支持当前计算机运行的 Windows 版本。
|
||||||
|
WindowsServicePackRequired=此程序需要 %1 服务包 %2 或更高版本。
|
||||||
|
NotOnThisPlatform=此程序不能在 %1 上运行。
|
||||||
|
OnlyOnThisPlatform=此程序只能在 %1 上运行。
|
||||||
|
OnlyOnTheseArchitectures=此程序只能安装到为下列处理器架构设计的 Windows 版本中:%n%n%1
|
||||||
|
WinVersionTooLowError=此程序需要 %1 版本 %2 或更高。
|
||||||
|
WinVersionTooHighError=此程序不能安装于 %1 版本 %2 或更高。
|
||||||
|
AdminPrivilegesRequired=在安装此程序时您必须以管理员身份登录。
|
||||||
|
PowerUserPrivilegesRequired=在安装此程序时您必须以管理员身份或有权限的用户组身份登录。
|
||||||
|
SetupAppRunningError=安装程序发现 %1 当前正在运行。%n%n请先关闭正在运行的程序,然后点击“确定”继续,或点击“取消”退出。
|
||||||
|
UninstallAppRunningError=卸载程序发现 %1 当前正在运行。%n%n请先关闭正在运行的程序,然后点击“确定”继续,或点击“取消”退出。
|
||||||
|
|
||||||
|
; *** 启动问题
|
||||||
|
PrivilegesRequiredOverrideTitle=选择安装程序模式
|
||||||
|
PrivilegesRequiredOverrideInstruction=选择安装模式
|
||||||
|
PrivilegesRequiredOverrideText1=%1 可以为所有用户安装(需要管理员权限),或仅为您安装。
|
||||||
|
PrivilegesRequiredOverrideText2=%1 只能为您安装,或为所有用户安装(需要管理员权限)。
|
||||||
|
PrivilegesRequiredOverrideAllUsers=为所有用户安装(&A)
|
||||||
|
PrivilegesRequiredOverrideAllUsersRecommended=为所有用户安装(&A) (建议选项)
|
||||||
|
PrivilegesRequiredOverrideCurrentUser=只为我安装(&M)
|
||||||
|
PrivilegesRequiredOverrideCurrentUserRecommended=只为我安装(&M) (建议选项)
|
||||||
|
|
||||||
|
; *** 其他错误
|
||||||
|
ErrorCreatingDir=安装程序无法创建目录“%1”
|
||||||
|
ErrorTooManyFilesInDir=无法在目录“%1”中创建文件,因为里面包含太多文件
|
||||||
|
|
||||||
|
; *** 安装程序公共消息
|
||||||
|
ExitSetupTitle=退出安装程序
|
||||||
|
ExitSetupMessage=安装程序尚未完成。如果现在退出,将不会安装该程序。%n%n您之后可以再次运行安装程序完成安装。%n%n现在退出安装程序吗?
|
||||||
|
AboutSetupMenuItem=关于安装程序(&A)...
|
||||||
|
AboutSetupTitle=关于安装程序
|
||||||
|
AboutSetupMessage=%1 版本 %2%n%3%n%n%1 主页:%n%4
|
||||||
|
AboutSetupNote=
|
||||||
|
TranslatorNote=简体中文翻译由Kira(847320916@qq.com)维护。项目地址:https://github.com/kira-96/Inno-Setup-Chinese-Simplified-Translation
|
||||||
|
|
||||||
|
; *** 按钮
|
||||||
|
ButtonBack=< 上一步(&B)
|
||||||
|
ButtonNext=下一步(&N) >
|
||||||
|
ButtonInstall=安装(&I)
|
||||||
|
ButtonOK=确定
|
||||||
|
ButtonCancel=取消
|
||||||
|
ButtonYes=是(&Y)
|
||||||
|
ButtonYesToAll=全是(&A)
|
||||||
|
ButtonNo=否(&N)
|
||||||
|
ButtonNoToAll=全否(&O)
|
||||||
|
ButtonFinish=完成(&F)
|
||||||
|
ButtonBrowse=浏览(&B)...
|
||||||
|
ButtonWizardBrowse=浏览(&R)...
|
||||||
|
ButtonNewFolder=新建文件夹(&M)
|
||||||
|
|
||||||
|
; *** “选择语言”对话框消息
|
||||||
|
SelectLanguageTitle=选择安装语言
|
||||||
|
SelectLanguageLabel=选择安装时使用的语言。
|
||||||
|
|
||||||
|
; *** 公共向导文字
|
||||||
|
ClickNext=点击“下一步”继续,或点击“取消”退出安装程序。
|
||||||
|
BeveledLabel=
|
||||||
|
BrowseDialogTitle=浏览文件夹
|
||||||
|
BrowseDialogLabel=在下面的列表中选择一个文件夹,然后点击“确定”。
|
||||||
|
NewFolderName=新建文件夹
|
||||||
|
|
||||||
|
; *** “欢迎”向导页
|
||||||
|
WelcomeLabel1=欢迎使用 [name] 安装向导
|
||||||
|
WelcomeLabel2=现在将安装 [name/ver] 到您的电脑中。%n%n建议您在继续安装前关闭所有其他应用程序。
|
||||||
|
|
||||||
|
; *** “密码”向导页
|
||||||
|
WizardPassword=密码
|
||||||
|
PasswordLabel1=这个安装程序有密码保护。
|
||||||
|
PasswordLabel3=请输入密码,然后点击“下一步”继续。密码区分大小写。
|
||||||
|
PasswordEditLabel=密码(&P):
|
||||||
|
IncorrectPassword=您输入的密码不正确,请重新输入。
|
||||||
|
|
||||||
|
; *** “许可协议”向导页
|
||||||
|
WizardLicense=许可协议
|
||||||
|
LicenseLabel=请在继续安装前阅读以下重要信息。
|
||||||
|
LicenseLabel3=请仔细阅读下列许可协议。在继续安装前您必须同意这些协议条款。
|
||||||
|
LicenseAccepted=我同意此协议(&A)
|
||||||
|
LicenseNotAccepted=我不同意此协议(&D)
|
||||||
|
|
||||||
|
; *** “信息”向导页
|
||||||
|
WizardInfoBefore=信息
|
||||||
|
InfoBeforeLabel=请在继续安装前阅读以下重要信息。
|
||||||
|
InfoBeforeClickLabel=准备好继续安装后,点击“下一步”。
|
||||||
|
WizardInfoAfter=信息
|
||||||
|
InfoAfterLabel=请在继续安装前阅读以下重要信息。
|
||||||
|
InfoAfterClickLabel=准备好继续安装后,点击“下一步”。
|
||||||
|
|
||||||
|
; *** “用户信息”向导页
|
||||||
|
WizardUserInfo=用户信息
|
||||||
|
UserInfoDesc=请输入您的信息。
|
||||||
|
UserInfoName=用户名(&U):
|
||||||
|
UserInfoOrg=组织(&O):
|
||||||
|
UserInfoSerial=序列号(&S):
|
||||||
|
UserInfoNameRequired=您必须输入用户名。
|
||||||
|
|
||||||
|
; *** “选择目标目录”向导页
|
||||||
|
WizardSelectDir=选择目标位置
|
||||||
|
SelectDirDesc=您想将 [name] 安装在哪里?
|
||||||
|
SelectDirLabel3=安装程序将安装 [name] 到下面的文件夹中。
|
||||||
|
SelectDirBrowseLabel=点击“下一步”继续。如果您想选择其他文件夹,点击“浏览”。
|
||||||
|
DiskSpaceGBLabel=至少需要有 [gb] GB 的可用磁盘空间。
|
||||||
|
DiskSpaceMBLabel=至少需要有 [mb] MB 的可用磁盘空间。
|
||||||
|
CannotInstallToNetworkDrive=安装程序无法安装到一个网络驱动器。
|
||||||
|
CannotInstallToUNCPath=安装程序无法安装到一个 UNC 路径。
|
||||||
|
InvalidPath=您必须输入一个带驱动器卷标的完整路径,例如:%n%nC:\APP%n%n或UNC路径:%n%n\\server\share
|
||||||
|
InvalidDrive=您选定的驱动器或 UNC 共享不存在或不能访问。请选择其他位置。
|
||||||
|
DiskSpaceWarningTitle=磁盘空间不足
|
||||||
|
DiskSpaceWarning=安装程序至少需要 %1 KB 的可用空间才能安装,但选定驱动器只有 %2 KB 的可用空间。%n%n您一定要继续吗?
|
||||||
|
DirNameTooLong=文件夹名称或路径太长。
|
||||||
|
InvalidDirName=文件夹名称无效。
|
||||||
|
BadDirName32=文件夹名称不能包含下列任何字符:%n%n%1
|
||||||
|
DirExistsTitle=文件夹已存在
|
||||||
|
DirExists=文件夹:%n%n%1%n%n已经存在。您一定要安装到这个文件夹中吗?
|
||||||
|
DirDoesntExistTitle=文件夹不存在
|
||||||
|
DirDoesntExist=文件夹:%n%n%1%n%n不存在。您想要创建此文件夹吗?
|
||||||
|
|
||||||
|
; *** “选择组件”向导页
|
||||||
|
WizardSelectComponents=选择组件
|
||||||
|
SelectComponentsDesc=您想安装哪些程序组件?
|
||||||
|
SelectComponentsLabel2=选中您想安装的组件;取消您不想安装的组件。然后点击“下一步”继续。
|
||||||
|
FullInstallation=完全安装
|
||||||
|
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
|
||||||
|
CompactInstallation=简洁安装
|
||||||
|
CustomInstallation=自定义安装
|
||||||
|
NoUninstallWarningTitle=组件已存在
|
||||||
|
NoUninstallWarning=安装程序检测到下列组件已安装在您的电脑中:%n%n%1%n%n取消选中这些组件不会卸载它们。%n%n确定要继续吗?
|
||||||
|
ComponentSize1=%1 KB
|
||||||
|
ComponentSize2=%1 MB
|
||||||
|
ComponentsDiskSpaceGBLabel=当前选择的组件需要至少 [gb] GB 的磁盘空间。
|
||||||
|
ComponentsDiskSpaceMBLabel=当前选择的组件需要至少 [mb] MB 的磁盘空间。
|
||||||
|
|
||||||
|
; *** “选择附加任务”向导页
|
||||||
|
WizardSelectTasks=选择附加任务
|
||||||
|
SelectTasksDesc=您想要安装程序执行哪些附加任务?
|
||||||
|
SelectTasksLabel2=选择您想要安装程序在安装 [name] 时执行的附加任务,然后点击“下一步”。
|
||||||
|
|
||||||
|
; *** “选择开始菜单文件夹”向导页
|
||||||
|
WizardSelectProgramGroup=选择开始菜单文件夹
|
||||||
|
SelectStartMenuFolderDesc=安装程序应该在哪里放置程序的快捷方式?
|
||||||
|
SelectStartMenuFolderLabel3=安装程序将在下列“开始”菜单文件夹中创建程序的快捷方式。
|
||||||
|
SelectStartMenuFolderBrowseLabel=点击“下一步”继续。如果您想选择其他文件夹,点击“浏览”。
|
||||||
|
MustEnterGroupName=您必须输入一个文件夹名。
|
||||||
|
GroupNameTooLong=文件夹名或路径太长。
|
||||||
|
InvalidGroupName=无效的文件夹名字。
|
||||||
|
BadGroupName=文件夹名不能包含下列任何字符:%n%n%1
|
||||||
|
NoProgramGroupCheck2=不创建开始菜单文件夹(&D)
|
||||||
|
|
||||||
|
; *** “准备安装”向导页
|
||||||
|
WizardReady=准备安装
|
||||||
|
ReadyLabel1=安装程序准备就绪,现在可以开始安装 [name] 到您的电脑。
|
||||||
|
ReadyLabel2a=点击“安装”继续此安装程序。如果您想重新考虑或修改任何设置,点击“上一步”。
|
||||||
|
ReadyLabel2b=点击“安装”继续此安装程序。
|
||||||
|
ReadyMemoUserInfo=用户信息:
|
||||||
|
ReadyMemoDir=目标位置:
|
||||||
|
ReadyMemoType=安装类型:
|
||||||
|
ReadyMemoComponents=已选择组件:
|
||||||
|
ReadyMemoGroup=开始菜单文件夹:
|
||||||
|
ReadyMemoTasks=附加任务:
|
||||||
|
|
||||||
|
; *** TExtractionWizardPage wizard page and Extract7ZipArchive
|
||||||
|
ExtractionLabel=正在提取附加文件...
|
||||||
|
ButtonStopExtraction=停止提取(&S)
|
||||||
|
StopExtraction=您确定要停止提取吗?
|
||||||
|
ErrorExtractionAborted=提取已中止
|
||||||
|
ErrorExtractionFailed=提取失败:%1
|
||||||
|
|
||||||
|
; *** TDownloadWizardPage wizard page and DownloadTemporaryFile
|
||||||
|
DownloadingLabel=正在下载附加文件...
|
||||||
|
ButtonStopDownload=停止下载(&S)
|
||||||
|
StopDownload=您确定要停止下载吗?
|
||||||
|
ErrorDownloadAborted=下载已中止
|
||||||
|
ErrorDownloadFailed=下载失败:%1 %2
|
||||||
|
ErrorDownloadSizeFailed=获取下载大小失败:%1 %2
|
||||||
|
ErrorFileHash1=校验文件哈希失败:%1
|
||||||
|
ErrorFileHash2=无效的文件哈希:预期 %1,实际 %2
|
||||||
|
ErrorProgress=无效的进度:%1 / %2
|
||||||
|
ErrorFileSize=文件大小错误:预期 %1,实际 %2
|
||||||
|
|
||||||
|
; *** “正在准备安装”向导页
|
||||||
|
WizardPreparing=正在准备安装
|
||||||
|
PreparingDesc=安装程序正在准备安装 [name] 到您的电脑。
|
||||||
|
PreviousInstallNotCompleted=先前的程序安装或卸载未完成,您需要重启您的电脑以完成。%n%n在重启电脑后,再次运行安装程序以完成 [name] 的安装。
|
||||||
|
CannotContinue=安装程序不能继续。请点击“取消”退出。
|
||||||
|
ApplicationsFound=以下应用程序正在使用将由安装程序更新的文件。建议您允许安装程序自动关闭这些应用程序。
|
||||||
|
ApplicationsFound2=以下应用程序正在使用将由安装程序更新的文件。建议您允许安装程序自动关闭这些应用程序。安装完成后,安装程序将尝试重新启动这些应用程序。
|
||||||
|
CloseApplications=自动关闭应用程序(&A)
|
||||||
|
DontCloseApplications=不要关闭应用程序(&D)
|
||||||
|
ErrorCloseApplications=安装程序无法自动关闭所有应用程序。建议您在继续之前,关闭所有在使用需要由安装程序更新的文件的应用程序。
|
||||||
|
PrepareToInstallNeedsRestart=安装程序必须重启您的计算机。计算机重启后,请再次运行安装程序以完成 [name] 的安装。%n%n是否立即重新启动?
|
||||||
|
|
||||||
|
; *** “正在安装”向导页
|
||||||
|
WizardInstalling=正在安装
|
||||||
|
InstallingLabel=安装程序正在安装 [name] 到您的电脑,请稍候。
|
||||||
|
|
||||||
|
; *** “安装完成”向导页
|
||||||
|
FinishedHeadingLabel=[name] 安装完成
|
||||||
|
FinishedLabelNoIcons=安装程序已在您的电脑中安装了 [name]。
|
||||||
|
FinishedLabel=安装程序已在您的电脑中安装了 [name]。您可以通过已安装的快捷方式运行此应用程序。
|
||||||
|
ClickFinish=点击“完成”退出安装程序。
|
||||||
|
FinishedRestartLabel=为完成 [name] 的安装,安装程序必须重新启动您的电脑。要立即重启吗?
|
||||||
|
FinishedRestartMessage=为完成 [name] 的安装,安装程序必须重新启动您的电脑。%n%n要立即重启吗?
|
||||||
|
ShowReadmeCheck=是,我想查阅自述文件
|
||||||
|
YesRadio=是,立即重启电脑(&Y)
|
||||||
|
NoRadio=否,稍后重启电脑(&N)
|
||||||
|
; used for example as 'Run MyProg.exe'
|
||||||
|
RunEntryExec=运行 %1
|
||||||
|
; used for example as 'View Readme.txt'
|
||||||
|
RunEntryShellExec=查阅 %1
|
||||||
|
|
||||||
|
; *** “安装程序需要下一张磁盘”提示
|
||||||
|
ChangeDiskTitle=安装程序需要下一张磁盘
|
||||||
|
SelectDiskLabel2=请插入磁盘 %1 并点击“确定”。%n%n如果这个磁盘中的文件可以在下列文件夹之外的文件夹中找到,请输入正确的路径或点击“浏览”。
|
||||||
|
PathLabel=路径(&P):
|
||||||
|
FileNotInDir2=“%2”中找不到文件“%1”。请插入正确的磁盘或选择其他文件夹。
|
||||||
|
SelectDirectoryLabel=请指定下一张磁盘的位置。
|
||||||
|
|
||||||
|
; *** 安装状态消息
|
||||||
|
SetupAborted=安装程序未完成安装。%n%n请修正这个问题并重新运行安装程序。
|
||||||
|
AbortRetryIgnoreSelectAction=选择操作
|
||||||
|
AbortRetryIgnoreRetry=重试(&T)
|
||||||
|
AbortRetryIgnoreIgnore=忽略错误并继续(&I)
|
||||||
|
AbortRetryIgnoreCancel=关闭安装程序
|
||||||
|
|
||||||
|
; *** 安装状态消息
|
||||||
|
StatusClosingApplications=正在关闭应用程序...
|
||||||
|
StatusCreateDirs=正在创建目录...
|
||||||
|
StatusExtractFiles=正在解压缩文件...
|
||||||
|
StatusCreateIcons=正在创建快捷方式...
|
||||||
|
StatusCreateIniEntries=正在创建 INI 条目...
|
||||||
|
StatusCreateRegistryEntries=正在创建注册表条目...
|
||||||
|
StatusRegisterFiles=正在注册文件...
|
||||||
|
StatusSavingUninstall=正在保存卸载信息...
|
||||||
|
StatusRunProgram=正在完成安装...
|
||||||
|
StatusRestartingApplications=正在重启应用程序...
|
||||||
|
StatusRollback=正在撤销更改...
|
||||||
|
|
||||||
|
; *** 其他错误
|
||||||
|
ErrorInternal2=内部错误:%1
|
||||||
|
ErrorFunctionFailedNoCode=%1 失败
|
||||||
|
ErrorFunctionFailed=%1 失败;错误代码 %2
|
||||||
|
ErrorFunctionFailedWithMessage=%1 失败;错误代码 %2.%n%3
|
||||||
|
ErrorExecutingProgram=无法执行文件:%n%1
|
||||||
|
|
||||||
|
; *** 注册表错误
|
||||||
|
ErrorRegOpenKey=打开注册表项时出错:%n%1\%2
|
||||||
|
ErrorRegCreateKey=创建注册表项时出错:%n%1\%2
|
||||||
|
ErrorRegWriteKey=写入注册表项时出错:%n%1\%2
|
||||||
|
|
||||||
|
; *** INI 错误
|
||||||
|
ErrorIniEntry=在文件“%1”中创建 INI 条目时出错。
|
||||||
|
|
||||||
|
; *** 文件复制错误
|
||||||
|
FileAbortRetryIgnoreSkipNotRecommended=跳过此文件(&S) (不推荐)
|
||||||
|
FileAbortRetryIgnoreIgnoreNotRecommended=忽略错误并继续(&I) (不推荐)
|
||||||
|
SourceIsCorrupted=源文件已损坏
|
||||||
|
SourceDoesntExist=源文件“%1”不存在
|
||||||
|
ExistingFileReadOnly2=无法替换现有文件,它是只读的。
|
||||||
|
ExistingFileReadOnlyRetry=移除只读属性并重试(&R)
|
||||||
|
ExistingFileReadOnlyKeepExisting=保留现有文件(&K)
|
||||||
|
ErrorReadingExistingDest=尝试读取现有文件时出错:
|
||||||
|
FileExistsSelectAction=选择操作
|
||||||
|
FileExists2=文件已经存在。
|
||||||
|
FileExistsOverwriteExisting=覆盖已存在的文件(&O)
|
||||||
|
FileExistsKeepExisting=保留现有的文件(&K)
|
||||||
|
FileExistsOverwriteOrKeepAll=为所有冲突文件执行此操作(&D)
|
||||||
|
ExistingFileNewerSelectAction=选择操作
|
||||||
|
ExistingFileNewer2=现有的文件比安装程序将要安装的文件还要新。
|
||||||
|
ExistingFileNewerOverwriteExisting=覆盖已存在的文件(&O)
|
||||||
|
ExistingFileNewerKeepExisting=保留现有的文件(&K) (推荐)
|
||||||
|
ExistingFileNewerOverwriteOrKeepAll=为所有冲突文件执行此操作(&D)
|
||||||
|
ErrorChangingAttr=尝试更改下列现有文件的属性时出错:
|
||||||
|
ErrorCreatingTemp=尝试在目标目录创建文件时出错:
|
||||||
|
ErrorReadingSource=尝试读取下列源文件时出错:
|
||||||
|
ErrorCopying=尝试复制下列文件时出错:
|
||||||
|
ErrorReplacingExistingFile=尝试替换现有文件时出错:
|
||||||
|
ErrorRestartReplace=重启并替换失败:
|
||||||
|
ErrorRenamingTemp=尝试重命名下列目标目录中的一个文件时出错:
|
||||||
|
ErrorRegisterServer=无法注册 DLL/OCX:%1
|
||||||
|
ErrorRegSvr32Failed=RegSvr32 失败;退出代码 %1
|
||||||
|
ErrorRegisterTypeLib=无法注册类库:%1
|
||||||
|
|
||||||
|
; *** 卸载显示名字标记
|
||||||
|
; used for example as 'My Program (32-bit)'
|
||||||
|
UninstallDisplayNameMark=%1 (%2)
|
||||||
|
; used for example as 'My Program (32-bit, All users)'
|
||||||
|
UninstallDisplayNameMarks=%1 (%2, %3)
|
||||||
|
UninstallDisplayNameMark32Bit=32 位
|
||||||
|
UninstallDisplayNameMark64Bit=64 位
|
||||||
|
UninstallDisplayNameMarkAllUsers=所有用户
|
||||||
|
UninstallDisplayNameMarkCurrentUser=当前用户
|
||||||
|
|
||||||
|
; *** 安装后错误
|
||||||
|
ErrorOpeningReadme=尝试打开自述文件时出错。
|
||||||
|
ErrorRestartingComputer=安装程序无法重启电脑,请手动重启。
|
||||||
|
|
||||||
|
; *** 卸载消息
|
||||||
|
UninstallNotFound=文件“%1”不存在。无法卸载。
|
||||||
|
UninstallOpenError=文件“%1”不能被打开。无法卸载。
|
||||||
|
UninstallUnsupportedVer=此版本的卸载程序无法识别卸载日志文件“%1”的格式。无法卸载
|
||||||
|
UninstallUnknownEntry=卸载日志中遇到一个未知条目 (%1)
|
||||||
|
ConfirmUninstall=您确认要完全移除 %1 及其所有组件吗?
|
||||||
|
UninstallOnlyOnWin64=仅允许在 64 位 Windows 中卸载此程序。
|
||||||
|
OnlyAdminCanUninstall=仅使用管理员权限的用户能完成此卸载。
|
||||||
|
UninstallStatusLabel=正在从您的电脑中移除 %1,请稍候。
|
||||||
|
UninstalledAll=已顺利从您的电脑中移除 %1。
|
||||||
|
UninstalledMost=%1 卸载完成。%n%n有部分内容未能被删除,但您可以手动删除它们。
|
||||||
|
UninstalledAndNeedsRestart=为完成 %1 的卸载,需要重启您的电脑。%n%n立即重启电脑吗?
|
||||||
|
UninstallDataCorrupted=文件“%1”已损坏。无法卸载
|
||||||
|
|
||||||
|
; *** 卸载状态消息
|
||||||
|
ConfirmDeleteSharedFileTitle=删除共享的文件吗?
|
||||||
|
ConfirmDeleteSharedFile2=系统表示下列共享的文件已不有其他程序使用。您希望卸载程序删除这些共享的文件吗?%n%n如果删除这些文件,但仍有程序在使用这些文件,则这些程序可能出现异常。如果您不能确定,请选择“否”,在系统中保留这些文件以免引发问题。
|
||||||
|
SharedFileNameLabel=文件名:
|
||||||
|
SharedFileLocationLabel=位置:
|
||||||
|
WizardUninstalling=卸载状态
|
||||||
|
StatusUninstalling=正在卸载 %1...
|
||||||
|
|
||||||
|
; *** Shutdown block reasons
|
||||||
|
ShutdownBlockReasonInstallingApp=正在安装 %1。
|
||||||
|
ShutdownBlockReasonUninstallingApp=正在卸载 %1。
|
||||||
|
|
||||||
|
; The custom messages below aren't used by Setup itself, but if you make
|
||||||
|
; use of them in your scripts, you'll want to translate them.
|
||||||
|
|
||||||
|
[CustomMessages]
|
||||||
|
|
||||||
|
NameAndVersion=%1 版本 %2
|
||||||
|
AdditionalIcons=附加快捷方式:
|
||||||
|
CreateDesktopIcon=创建桌面快捷方式(&D)
|
||||||
|
CreateQuickLaunchIcon=创建快速启动栏快捷方式(&Q)
|
||||||
|
ProgramOnTheWeb=%1 网站
|
||||||
|
UninstallProgram=卸载 %1
|
||||||
|
LaunchProgram=运行 %1
|
||||||
|
AssocFileExtension=将 %2 文件扩展名与 %1 建立关联(&A)
|
||||||
|
AssocingFileExtension=正在将 %2 文件扩展名与 %1 建立关联...
|
||||||
|
AutoStartProgramGroupDescription=启动:
|
||||||
|
AutoStartProgram=自动启动 %1
|
||||||
|
AddonHostProgramNotFound=您选择的文件夹中无法找到 %1。%n%n您要继续吗?
|
15
crates/zed/resources/windows/messages/en.isl
Normal file
15
crates/zed/resources/windows/messages/en.isl
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[Messages]
|
||||||
|
FinishedLabel=Setup has finished installing [name] on your computer. The application may be launched by selecting the installed shortcuts.
|
||||||
|
ConfirmUninstall=Are you sure you want to completely remove %1 and all of its components?
|
||||||
|
|
||||||
|
[CustomMessages]
|
||||||
|
AdditionalIcons=Additional icons:
|
||||||
|
CreateDesktopIcon=Create a &desktop icon
|
||||||
|
AddContextMenuFiles=Add "Open with %1" action to Windows Explorer file context menu
|
||||||
|
AddContextMenuFolders=Add "Open with %1" action to Windows Explorer directory context menu
|
||||||
|
AssociateWithFiles=Register %1 as an editor for supported file types
|
||||||
|
AddToPath=Add to PATH (requires shell restart)
|
||||||
|
RunAfter=Run %1 after installation
|
||||||
|
Other=Other:
|
||||||
|
SourceFile=%1 Source File
|
||||||
|
OpenWithContextMenu=Open w&ith %1
|
9
crates/zed/resources/windows/messages/zh-cn.isl
Normal file
9
crates/zed/resources/windows/messages/zh-cn.isl
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[CustomMessages]
|
||||||
|
AddContextMenuFiles=将“通过 %1 打开”操作添加到 Windows 资源管理器文件上下文菜单
|
||||||
|
AddContextMenuFolders=将“通过 %1 打开”操作添加到 Windows 资源管理器目录上下文菜单
|
||||||
|
AssociateWithFiles=将 %1 注册为受支持的文件类型的编辑器
|
||||||
|
AddToPath=添加到 PATH (重启后生效)
|
||||||
|
RunAfter=安装后运行 %1
|
||||||
|
Other=其他:
|
||||||
|
SourceFile=%1 源文件
|
||||||
|
OpenWithContextMenu=通过 %1 打开
|
53
crates/zed/resources/windows/sign.ps1
Normal file
53
crates/zed/resources/windows/sign.ps1
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$filePath
|
||||||
|
)
|
||||||
|
|
||||||
|
$params = @{}
|
||||||
|
|
||||||
|
$endpoint = $ENV:ENDPOINT
|
||||||
|
if ([string]::IsNullOrWhiteSpace($endpoint)) {
|
||||||
|
throw "The 'ENDPOINT' env is required."
|
||||||
|
}
|
||||||
|
$params["Endpoint"] = $endpoint
|
||||||
|
|
||||||
|
$trustedSigningAccountName = $ENV:ACCOUNT_NAME
|
||||||
|
if ([string]::IsNullOrWhiteSpace($trustedSigningAccountName)) {
|
||||||
|
throw "The 'ACCOUNT_NAME' env is required."
|
||||||
|
}
|
||||||
|
$params["CodeSigningAccountName"] = $trustedSigningAccountName
|
||||||
|
|
||||||
|
$certificateProfileName = $ENV:CERT_PROFILE_NAME
|
||||||
|
if ([string]::IsNullOrWhiteSpace($certificateProfileName)) {
|
||||||
|
throw "The 'CERT_PROFILE_NAME' env is required."
|
||||||
|
}
|
||||||
|
$params["CertificateProfileName"] = $certificateProfileName
|
||||||
|
|
||||||
|
$fileDigest = $ENV:FILE_DIGEST
|
||||||
|
if ([string]::IsNullOrWhiteSpace($fileDigest)) {
|
||||||
|
throw "The 'FILE_DIGEST' env is required."
|
||||||
|
}
|
||||||
|
$params["FileDigest"] = $fileDigest
|
||||||
|
|
||||||
|
$timeStampDigest = $ENV:TIMESTAMP_DIGEST
|
||||||
|
if ([string]::IsNullOrWhiteSpace($timeStampDigest)) {
|
||||||
|
throw "The 'TIMESTAMP_DIGEST' env is required."
|
||||||
|
}
|
||||||
|
$params["TimestampDigest"] = $timeStampDigest
|
||||||
|
|
||||||
|
$timeStampServer = $ENV:TIMESTAMP_SERVER
|
||||||
|
if ([string]::IsNullOrWhiteSpace($timeStampServer)) {
|
||||||
|
throw "The 'TIMESTAMP_SERVER' env is required."
|
||||||
|
}
|
||||||
|
$params["TimestampRfc3161"] = $timeStampServer
|
||||||
|
|
||||||
|
$params["Files"] = $filePath
|
||||||
|
|
||||||
|
$trace = $ENV:TRACE
|
||||||
|
if (-Not [string]::IsNullOrWhiteSpace($trace)) {
|
||||||
|
if ([System.Convert]::ToBoolean($trace)) {
|
||||||
|
Set-PSDebug -Trace 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-TrustedSigning @params
|
1412
crates/zed/resources/windows/zed.iss
Normal file
1412
crates/zed/resources/windows/zed.iss
Normal file
File diff suppressed because it is too large
Load diff
263
script/bundle-windows.ps1
Normal file
263
script/bundle-windows.ps1
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter()][Alias('i')][switch]$Install,
|
||||||
|
[Parameter()][Alias('h')][switch]$Help,
|
||||||
|
[Parameter()][string]$Name
|
||||||
|
)
|
||||||
|
|
||||||
|
. "$PSScriptRoot/lib/blob-store.ps1"
|
||||||
|
. "$PSScriptRoot/lib/workspace.ps1"
|
||||||
|
|
||||||
|
# https://stackoverflow.com/questions/57949031/powershell-script-stops-if-program-fails-like-bash-set-o-errexit
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$PSNativeCommandUseErrorActionPreference = $true
|
||||||
|
|
||||||
|
$buildSuccess = $false
|
||||||
|
|
||||||
|
if ($Help) {
|
||||||
|
Write-Output "Usage: test.ps1 [-Install] [-Help]"
|
||||||
|
Write-Output "Build the installer for Windows.\n"
|
||||||
|
Write-Output "Options:"
|
||||||
|
Write-Output " -Install, -i Run the installer after building."
|
||||||
|
Write-Output " -Help, -h Show this help message."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Push-Location -Path crates/zed
|
||||||
|
$channel = Get-Content "RELEASE_CHANNEL"
|
||||||
|
$env:ZED_RELEASE_CHANNEL = $channel
|
||||||
|
Pop-Location
|
||||||
|
|
||||||
|
function CheckEnvironmentVariables {
|
||||||
|
$requiredVars = @(
|
||||||
|
'ZED_WORKSPACE', 'RELEASE_VERSION', 'ZED_RELEASE_CHANNEL',
|
||||||
|
'AZURE_TENANT_ID', 'AZURE_CLIENT_ID', 'AZURE_CLIENT_SECRET',
|
||||||
|
'ACCOUNT_NAME', 'CERT_PROFILE_NAME', 'ENDPOINT',
|
||||||
|
'FILE_DIGEST', 'TIMESTAMP_DIGEST', 'TIMESTAMP_SERVER'
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach ($var in $requiredVars) {
|
||||||
|
if (-not (Test-Path "env:$var")) {
|
||||||
|
Write-Error "$var is not set"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$innoDir = "$env:ZED_WORKSPACE\inno"
|
||||||
|
|
||||||
|
function PrepareForBundle {
|
||||||
|
if (Test-Path "$innoDir") {
|
||||||
|
Remove-Item -Path "$innoDir" -Recurse -Force
|
||||||
|
}
|
||||||
|
New-Item -Path "$innoDir" -ItemType Directory -Force
|
||||||
|
Copy-Item -Path "$env:ZED_WORKSPACE\crates\zed\resources\windows\*" -Destination "$innoDir" -Recurse -Force
|
||||||
|
New-Item -Path "$innoDir\make_appx" -ItemType Directory -Force
|
||||||
|
New-Item -Path "$innoDir\appx" -ItemType Directory -Force
|
||||||
|
New-Item -Path "$innoDir\bin" -ItemType Directory -Force
|
||||||
|
New-Item -Path "$innoDir\tools" -ItemType Directory -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
function BuildZedAndItsFriends {
|
||||||
|
Write-Output "Building Zed and its friends, for channel: $channel"
|
||||||
|
# Build zed.exe, cli.exe and auto_update_helper.exe
|
||||||
|
cargo build --release --package zed --package cli --package auto_update_helper
|
||||||
|
Copy-Item -Path ".\target\release\zed.exe" -Destination "$innoDir\Zed.exe" -Force
|
||||||
|
Copy-Item -Path ".\target\release\cli.exe" -Destination "$innoDir\cli.exe" -Force
|
||||||
|
Copy-Item -Path ".\target\release\auto_update_helper.exe" -Destination "$innoDir\auto_update_helper.exe" -Force
|
||||||
|
# Build explorer_command_injector.dll
|
||||||
|
switch ($channel) {
|
||||||
|
"stable" {
|
||||||
|
cargo build --release --features stable --no-default-features --package explorer_command_injector
|
||||||
|
}
|
||||||
|
"preview" {
|
||||||
|
cargo build --release --features preview --no-default-features --package explorer_command_injector
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
cargo build --release --package explorer_command_injector
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Copy-Item -Path ".\target\release\explorer_command_injector.dll" -Destination "$innoDir\zed_explorer_command_injector.dll" -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
function ZipZedAndItsFriendsDebug {
|
||||||
|
$items = @(
|
||||||
|
".\target\release\zed.pdb",
|
||||||
|
".\target\release\cli.pdb",
|
||||||
|
".\target\release\auto_update_helper.pdb",
|
||||||
|
".\target\release\explorer_command_injector.pdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
Compress-Archive -Path $items -DestinationPath ".\target\release\zed-$env:RELEASE_VERSION-$env:ZED_RELEASE_CHANNEL.dbg.zip" -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
function MakeAppx {
|
||||||
|
switch ($channel) {
|
||||||
|
"stable" {
|
||||||
|
$manifestFile = "$env:ZED_WORKSPACE\crates\explorer_command_injector\AppxManifest.xml"
|
||||||
|
}
|
||||||
|
"preview" {
|
||||||
|
$manifestFile = "$env:ZED_WORKSPACE\crates\explorer_command_injector\AppxManifest-Preview.xml"
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
$manifestFile = "$env:ZED_WORKSPACE\crates\explorer_command_injector\AppxManifest-Nightly.xml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Copy-Item -Path "$manifestFile" -Destination "$innoDir\make_appx\AppxManifest.xml"
|
||||||
|
# Add makeAppx.exe to Path
|
||||||
|
$sdk = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64"
|
||||||
|
$env:Path += ';' + $sdk
|
||||||
|
makeAppx.exe pack /d "$innoDir\make_appx" /p "$innoDir\zed_explorer_command_injector.appx" /nv
|
||||||
|
}
|
||||||
|
|
||||||
|
function SignZedAndItsFriends {
|
||||||
|
$files = "$innoDir\Zed.exe,$innoDir\cli.exe,$innoDir\auto_update_helper.exe,$innoDir\zed_explorer_command_injector.dll,$innoDir\zed_explorer_command_injector.appx"
|
||||||
|
& "$innoDir\sign.ps1" $files
|
||||||
|
}
|
||||||
|
|
||||||
|
function CollectFiles {
|
||||||
|
Move-Item -Path "$innoDir\zed_explorer_command_injector.appx" -Destination "$innoDir\appx\zed_explorer_command_injector.appx" -Force
|
||||||
|
Move-Item -Path "$innoDir\zed_explorer_command_injector.dll" -Destination "$innoDir\appx\zed_explorer_command_injector.dll" -Force
|
||||||
|
Move-Item -Path "$innoDir\cli.exe" -Destination "$innoDir\bin\zed.exe" -Force
|
||||||
|
Move-Item -Path "$innoDir\auto_update_helper.exe" -Destination "$innoDir\tools\auto_update_helper.exe" -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
function BuildInstaller {
|
||||||
|
$issFilePath = "$innoDir\zed.iss"
|
||||||
|
switch ($channel) {
|
||||||
|
"stable" {
|
||||||
|
$appId = "{{2DB0DA96-CA55-49BB-AF4F-64AF36A86712}"
|
||||||
|
$appIconName = "app-icon"
|
||||||
|
$appName = "Zed Editor"
|
||||||
|
$appDisplayName = "Zed Editor"
|
||||||
|
$appSetupName = "ZedEditorUserSetup-x64-$env:RELEASE_VERSION"
|
||||||
|
# The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
|
||||||
|
$appMutex = "Zed-Editor-Stable-Instance-Mutex"
|
||||||
|
$appExeName = "Zed"
|
||||||
|
$regValueName = "ZedEditor"
|
||||||
|
$appUserId = "ZedIndustries.Zed"
|
||||||
|
$appShellNameShort = "Z&ed Editor"
|
||||||
|
$appAppxFullName = "ZedIndustries.Zed_1.0.0.0_neutral__japxn1gcva8rg"
|
||||||
|
}
|
||||||
|
"preview" {
|
||||||
|
$appId = "{{F70E4811-D0E2-4D88-AC99-D63752799F95}"
|
||||||
|
$appIconName = "app-icon-preview"
|
||||||
|
$appName = "Zed Editor Preview"
|
||||||
|
$appDisplayName = "Zed Editor Preview"
|
||||||
|
$appSetupName = "ZedEditorUserSetup-x64-$env:RELEASE_VERSION-preview"
|
||||||
|
# The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
|
||||||
|
$appMutex = "Zed-Editor-Preview-Instance-Mutex"
|
||||||
|
$appExeName = "Zed"
|
||||||
|
$regValueName = "ZedEditorPreview"
|
||||||
|
$appUserId = "ZedIndustries.Zed.Preview"
|
||||||
|
$appShellNameShort = "Z&ed Editor Preview"
|
||||||
|
$appAppxFullName = "ZedIndustries.Zed.Preview_1.0.0.0_neutral__japxn1gcva8rg"
|
||||||
|
}
|
||||||
|
"nightly" {
|
||||||
|
$appId = "{{1BDB21D3-14E7-433C-843C-9C97382B2FE0}"
|
||||||
|
$appIconName = "app-icon-nightly"
|
||||||
|
$appName = "Zed Editor Nightly"
|
||||||
|
$appDisplayName = "Zed Editor Nightly"
|
||||||
|
$appSetupName = "ZedEditorUserSetup-x64-$env:RELEASE_VERSION-nightly"
|
||||||
|
# The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
|
||||||
|
$appMutex = "Zed-Editor-Nightly-Instance-Mutex"
|
||||||
|
$appExeName = "Zed"
|
||||||
|
$regValueName = "ZedEditorNightly"
|
||||||
|
$appUserId = "ZedIndustries.Zed.Nightly"
|
||||||
|
$appShellNameShort = "Z&ed Editor Nightly"
|
||||||
|
$appAppxFullName = "ZedIndustries.Zed.Nightly_1.0.0.0_neutral__japxn1gcva8rg"
|
||||||
|
}
|
||||||
|
"dev" {
|
||||||
|
$appId = "{{8357632E-24A4-4F32-BA97-E575B4D1FE5D}"
|
||||||
|
$appIconName = "app-icon-nightly"
|
||||||
|
$appName = "Zed Editor Dev"
|
||||||
|
$appDisplayName = "Zed Editor Dev"
|
||||||
|
$appSetupName = "ZedEditorUserSetup-x64-$env:RELEASE_VERSION-dev"
|
||||||
|
# The mutex name here should match the mutex name in crates\zed\src\zed\windows_only_instance.rs
|
||||||
|
$appMutex = "Zed-Editor-Dev-Instance-Mutex"
|
||||||
|
$appExeName = "Zed"
|
||||||
|
$regValueName = "ZedEditorDev"
|
||||||
|
$appUserId = "ZedIndustries.Zed.Dev"
|
||||||
|
$appShellNameShort = "Z&ed Editor Dev"
|
||||||
|
$appAppxFullName = "ZedIndustries.Zed.Dev_1.0.0.0_neutral__japxn1gcva8rg"
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
Write-Error "can't bundle installer for $channel."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Windows runner 2022 default has iscc in PATH, https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md
|
||||||
|
# Currently, we are using Windows 2022 runner.
|
||||||
|
# Windows runner 2025 doesn't have iscc in PATH for now, https://github.com/actions/runner-images/issues/11228
|
||||||
|
# $innoSetupPath = "iscc.exe"
|
||||||
|
$innoSetupPath = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
|
||||||
|
|
||||||
|
$definitions = @{
|
||||||
|
"AppId" = $appId
|
||||||
|
"AppIconName" = $appIconName
|
||||||
|
"OutputDir" = "$env:ZED_WORKSPACE\target"
|
||||||
|
"AppSetupName" = $appSetupName
|
||||||
|
"AppName" = $appName
|
||||||
|
"AppDisplayName" = $appDisplayName
|
||||||
|
"RegValueName" = $regValueName
|
||||||
|
"AppMutex" = $appMutex
|
||||||
|
"AppExeName" = $appExeName
|
||||||
|
"ResourcesDir" = "$innoDir"
|
||||||
|
"ShellNameShort" = $appShellNameShort
|
||||||
|
"AppUserId" = $appUserId
|
||||||
|
"Version" = "$env:RELEASE_VERSION"
|
||||||
|
"SourceDir" = "$env:ZED_WORKSPACE"
|
||||||
|
"AppxFullName" = $appAppxFullName
|
||||||
|
}
|
||||||
|
|
||||||
|
$signTool = "powershell.exe -ExecutionPolicy Bypass -File $innoDir\sign.ps1 `$f"
|
||||||
|
|
||||||
|
$defs = @()
|
||||||
|
foreach ($key in $definitions.Keys) {
|
||||||
|
$defs += "/d$key=`"$($definitions[$key])`""
|
||||||
|
}
|
||||||
|
|
||||||
|
$innoArgs = @($issFilePath) + $defs + "/sDefaultsign=`"$signTool`""
|
||||||
|
|
||||||
|
# Execute Inno Setup
|
||||||
|
Write-Host "🚀 Running Inno Setup: $innoSetupPath $innoArgs"
|
||||||
|
$process = Start-Process -FilePath $innoSetupPath -ArgumentList $innoArgs -NoNewWindow -Wait -PassThru
|
||||||
|
|
||||||
|
if ($process.ExitCode -eq 0) {
|
||||||
|
Write-Host "✅ Inno Setup successfully compiled the installer"
|
||||||
|
Write-Output "SETUP_PATH=target/$appSetupName.exe" >> $env:GITHUB_ENV
|
||||||
|
$script:buildSuccess = $true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "❌ Inno Setup failed: $($process.ExitCode)"
|
||||||
|
$script:buildSuccess = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseZedWorkspace
|
||||||
|
CheckEnvironmentVariables
|
||||||
|
PrepareForBundle
|
||||||
|
BuildZedAndItsFriends
|
||||||
|
MakeAppx
|
||||||
|
SignZedAndItsFriends
|
||||||
|
ZipZedAndItsFriendsDebug
|
||||||
|
CollectFiles
|
||||||
|
BuildInstaller
|
||||||
|
|
||||||
|
$debugArchive = ".\target\release\zed-$env:RELEASE_VERSION-$env:ZED_RELEASE_CHANNEL.dbg.zip"
|
||||||
|
$debugStoreKey = "$env:ZED_RELEASE_CHANNEL/zed-$env:RELEASE_VERSION-$env:ZED_RELEASE_CHANNEL.dbg.zip"
|
||||||
|
UploadToBlobStorePublic -BucketName "zed-debug-symbols" -FileToUpload $debugArchive -BlobStoreKey $debugStoreKey
|
||||||
|
|
||||||
|
if ($buildSuccess) {
|
||||||
|
Write-Output "Build successful"
|
||||||
|
if ($Install) {
|
||||||
|
Write-Output "Installing Zed..."
|
||||||
|
Start-Process -FilePath "$env:ZED_WORKSPACE/target/ZedEditorUserSetup-x64-$env:RELEASE_VERSION.exe"
|
||||||
|
}
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Output "Build failed"
|
||||||
|
exit 1
|
||||||
|
}
|
|
@ -18,5 +18,5 @@ Write-Host "target directory size: ${current_size_gb}GB. max size: ${MAX_SIZE_IN
|
||||||
|
|
||||||
if ($current_size_gb -gt $MAX_SIZE_IN_GB) {
|
if ($current_size_gb -gt $MAX_SIZE_IN_GB) {
|
||||||
Write-Host "clearing target directory"
|
Write-Host "clearing target directory"
|
||||||
Remove-Item -Recurse -Force -Path "target\*"
|
Remove-Item -Recurse -Force -Path "target\*" -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
|
|
37
script/determine-release-channel.ps1
Normal file
37
script/determine-release-channel.ps1
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
if (-not $env:GITHUB_ACTIONS) {
|
||||||
|
Write-Error "Error: This script must be run in a GitHub Actions environment"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $env:GITHUB_REF) {
|
||||||
|
Write-Error "Error: GITHUB_REF is not set"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$version = & "script/get-crate-version.ps1" "zed"
|
||||||
|
$channel = Get-Content "crates/zed/RELEASE_CHANNEL"
|
||||||
|
|
||||||
|
Write-Host "Publishing version: $version on release channel $channel"
|
||||||
|
Write-Output "RELEASE_CHANNEL=$channel" >> $env:GITHUB_ENV
|
||||||
|
Write-Output "RELEASE_VERSION=$version" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
|
$expectedTagName = ""
|
||||||
|
switch ($channel) {
|
||||||
|
"stable" {
|
||||||
|
$expectedTagName = "v$version"
|
||||||
|
}
|
||||||
|
"preview" {
|
||||||
|
$expectedTagName = "v$version-pre"
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
Write-Error "can't publish a release on channel $channel"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($env:GITHUB_REF_NAME -ne $expectedTagName) {
|
||||||
|
Write-Error "invalid release tag $($env:GITHUB_REF_NAME). expected $expectedTagName"
|
||||||
|
exit 1
|
||||||
|
}
|
16
script/get-crate-version.ps1
Normal file
16
script/get-crate-version.ps1
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
if ($args.Length -ne 1) {
|
||||||
|
Write-Error "Usage: $($MyInvocation.MyCommand.Name) <crate_name>"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$crateName = $args[0]
|
||||||
|
|
||||||
|
$metadata = cargo metadata --no-deps --format-version=1 | ConvertFrom-Json
|
||||||
|
|
||||||
|
$package = $metadata.packages | Where-Object { $_.name -eq $crateName }
|
||||||
|
if ($package) {
|
||||||
|
$package.version
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Error "Crate '$crateName' not found."
|
||||||
|
}
|
68
script/lib/blob-store.ps1
Normal file
68
script/lib/blob-store.ps1
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
function UploadToBlobStoreWithACL {
|
||||||
|
param (
|
||||||
|
[string]$BucketName,
|
||||||
|
[string]$FileToUpload,
|
||||||
|
[string]$BlobStoreKey,
|
||||||
|
[string]$ACL
|
||||||
|
)
|
||||||
|
|
||||||
|
# Format date to match AWS requirements
|
||||||
|
$Date = (Get-Date).ToUniversalTime().ToString("r")
|
||||||
|
# Note: Original script had a bug where it overrode the ACL parameter
|
||||||
|
# I'm keeping the same behavior for compatibility
|
||||||
|
$ACL = "public-read"
|
||||||
|
$ContentType = "application/octet-stream"
|
||||||
|
$StorageClass = "STANDARD"
|
||||||
|
|
||||||
|
# Create string to sign (AWS S3 compatible format)
|
||||||
|
$StringToSign = "PUT`n`n${ContentType}`n${Date}`nx-amz-acl:${ACL}`nx-amz-storage-class:${StorageClass}`n/${BucketName}/${BlobStoreKey}"
|
||||||
|
|
||||||
|
# Generate HMAC-SHA1 signature
|
||||||
|
$HMACSHA1 = New-Object System.Security.Cryptography.HMACSHA1
|
||||||
|
$HMACSHA1.Key = [System.Text.Encoding]::UTF8.GetBytes($env:DIGITALOCEAN_SPACES_SECRET_KEY)
|
||||||
|
$Signature = [System.Convert]::ToBase64String($HMACSHA1.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($StringToSign)))
|
||||||
|
|
||||||
|
# Upload file using Invoke-WebRequest (equivalent to curl)
|
||||||
|
$Headers = @{
|
||||||
|
"Host" = "${BucketName}.nyc3.digitaloceanspaces.com"
|
||||||
|
"Date" = $Date
|
||||||
|
"Content-Type" = $ContentType
|
||||||
|
"x-amz-storage-class" = $StorageClass
|
||||||
|
"x-amz-acl" = $ACL
|
||||||
|
"Authorization" = "AWS ${env:DIGITALOCEAN_SPACES_ACCESS_KEY}:$Signature"
|
||||||
|
}
|
||||||
|
|
||||||
|
$Uri = "https://${BucketName}.nyc3.digitaloceanspaces.com/${BlobStoreKey}"
|
||||||
|
|
||||||
|
# Read file content
|
||||||
|
$FileContent = Get-Content $FileToUpload -Raw -AsByteStream
|
||||||
|
|
||||||
|
try {
|
||||||
|
Invoke-WebRequest -Uri $Uri -Method PUT -Headers $Headers -Body $FileContent -ContentType $ContentType -Verbose
|
||||||
|
Write-Host "Successfully uploaded $FileToUpload to $Uri" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "Failed to upload file: $_"
|
||||||
|
throw $_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function UploadToBlobStorePublic {
|
||||||
|
param (
|
||||||
|
[string]$BucketName,
|
||||||
|
[string]$FileToUpload,
|
||||||
|
[string]$BlobStoreKey
|
||||||
|
)
|
||||||
|
|
||||||
|
UploadToBlobStoreWithACL -BucketName $BucketName -FileToUpload $FileToUpload -BlobStoreKey $BlobStoreKey -ACL "public-read"
|
||||||
|
}
|
||||||
|
|
||||||
|
function UploadToBlobStore {
|
||||||
|
param (
|
||||||
|
[string]$BucketName,
|
||||||
|
[string]$FileToUpload,
|
||||||
|
[string]$BlobStoreKey
|
||||||
|
)
|
||||||
|
|
||||||
|
UploadToBlobStoreWithACL -BucketName $BucketName -FileToUpload $FileToUpload -BlobStoreKey $BlobStoreKey -ACL "private"
|
||||||
|
}
|
6
script/lib/workspace.ps1
Normal file
6
script/lib/workspace.ps1
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
function ParseZedWorkspace {
|
||||||
|
$metadata = cargo metadata --no-deps --offline | ConvertFrom-Json
|
||||||
|
$env:ZED_WORKSPACE = $metadata.workspace_root
|
||||||
|
$env:RELEASE_VERSION = $metadata.packages | Where-Object { $_.name -eq "zed" } | Select-Object -ExpandProperty version
|
||||||
|
}
|
60
script/upload-nightly.ps1
Normal file
60
script/upload-nightly.ps1
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
# Based on the template in: https://docs.digitalocean.com/reference/api/spaces-api/
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
. "$PSScriptRoot\lib\blob-store.ps1"
|
||||||
|
. "$PSScriptRoot\lib\workspace.ps1"
|
||||||
|
|
||||||
|
$allowedTargets = @("windows")
|
||||||
|
|
||||||
|
function Test-AllowedTarget {
|
||||||
|
param (
|
||||||
|
[string]$Target
|
||||||
|
)
|
||||||
|
|
||||||
|
return $allowedTargets -contains $Target
|
||||||
|
}
|
||||||
|
|
||||||
|
# Process arguments
|
||||||
|
if ($args.Count -gt 0) {
|
||||||
|
$target = $args[0]
|
||||||
|
if (Test-AllowedTarget $target) {
|
||||||
|
# Valid target
|
||||||
|
} else {
|
||||||
|
Write-Error "Error: Target '$target' is not allowed.`nUsage: $($MyInvocation.MyCommand.Name) [$($allowedTargets -join ', ')]"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Error "Error: Target is not specified.`nUsage: $($MyInvocation.MyCommand.Name) [$($allowedTargets -join ', ')]"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseZedWorkspace
|
||||||
|
Write-Host "Uploading nightly for target: $target"
|
||||||
|
|
||||||
|
$bucketName = "zed-nightly-host"
|
||||||
|
|
||||||
|
# Get current git SHA
|
||||||
|
$sha = git rev-parse HEAD
|
||||||
|
$sha | Out-File -FilePath "target/latest-sha" -NoNewline
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# Upload remote server files
|
||||||
|
# $remoteServerFiles = Get-ChildItem -Path "target" -Filter "zed-remote-server-*.gz" -Recurse -File
|
||||||
|
# foreach ($file in $remoteServerFiles) {
|
||||||
|
# Upload-ToBlobStore -BucketName $bucketName -FileToUpload $file.FullName -BlobStoreKey "nightly/$($file.Name)"
|
||||||
|
# Remove-Item -Path $file.FullName
|
||||||
|
# }
|
||||||
|
|
||||||
|
switch ($target) {
|
||||||
|
"windows" {
|
||||||
|
UploadToBlobStore -BucketName $bucketName -FileToUpload $env:SETUP_PATH -BlobStoreKey "nightly/zed_editor_installer_x86_64.exe"
|
||||||
|
UploadToBlobStore -BucketName $bucketName -FileToUpload "target/latest-sha" -BlobStoreKey "nightly/latest-sha-windows"
|
||||||
|
|
||||||
|
Remove-Item -Path $env:SETUP_PATH -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item -Path "target/latest-sha" -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
default {
|
||||||
|
Write-Error "Error: Unknown target '$target'"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,6 +46,8 @@ extend-exclude = [
|
||||||
"script/danger/dangerfile.ts",
|
"script/danger/dangerfile.ts",
|
||||||
# Eval examples for prompts and criteria
|
# Eval examples for prompts and criteria
|
||||||
"crates/eval/src/examples/",
|
"crates/eval/src/examples/",
|
||||||
|
# File type extensions are not typos
|
||||||
|
"crates/zed/resources/windows/zed.iss",
|
||||||
# typos-cli doesn't understand our `vˇariable` markup
|
# typos-cli doesn't understand our `vˇariable` markup
|
||||||
"crates/editor/src/hover_links.rs",
|
"crates/editor/src/hover_links.rs",
|
||||||
# typos-cli doesn't understand `setis` is intentional test case
|
# typos-cli doesn't understand `setis` is intentional test case
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue