-
Notifications
You must be signed in to change notification settings - Fork 289
Expand file tree
/
Copy pathbuild-windows-installer-gpu.yml
More file actions
401 lines (345 loc) · 18.8 KB
/
Copy pathbuild-windows-installer-gpu.yml
File metadata and controls
401 lines (345 loc) · 18.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
name: Build Windows Installer (GPU)
on:
release:
types: [published]
workflow_dispatch:
inputs:
manual_version:
description: 'Version to build (e.g., 1.0.0 or v1.0.0). Required for manual runs.'
required: false # Set to false to allow an empty string check, but script will enforce it for manual runs
jobs:
build_windows:
runs-on: Windows-2022
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
# No 'path' means checkout to the root
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install CUDA Toolkit
id: cuda-toolkit
shell: pwsh
run: |
$version = "12.8.1"
$short = "12.8"
$url = "https://developer.download.nvidia.com/compute/cuda/$version/network_installers/cuda_${version}_windows_network.exe"
Write-Host "Downloading CUDA $version network installer..."
Invoke-WebRequest -Uri $url -OutFile cuda_installer.exe -UseBasicParsing
Write-Host "Installing sub-packages..."
$proc = Start-Process -FilePath .\cuda_installer.exe -ArgumentList @(
"-s",
"nvcc_$short",
"cudart_$short",
"cublas_$short",
"cublas_dev_$short",
"curand_$short",
"curand_dev_$short",
"cuda_profiler_api_$short",
"visual_studio_integration_$short"
) -Wait -NoNewWindow -PassThru
if ($proc.ExitCode -ne 0) {
Write-Error "CUDA installer failed with exit code $($proc.ExitCode)"
exit $proc.ExitCode
}
$cudaPath = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$short"
Write-Host "CUDA installed at: $cudaPath"
Write-Host "Contents of CUDA path:"
Get-ChildItem $cudaPath -ErrorAction SilentlyContinue
Write-Host "Contents of include dir:"
Get-ChildItem "$cudaPath\include" -ErrorAction SilentlyContinue | Select-Object -First 10
if (Test-Path "$cudaPath\include\cuda.h") {
Write-Host "cuda.h found"
} else {
Write-Host "ERROR: cuda.h NOT found"
exit 1
}
# Replicate the outputs that Jimver/cuda-toolkit provides so downstream
# steps using steps.cuda-toolkit.outputs.CUDA_PATH require no changes.
"CUDA_PATH=$cudaPath" | Out-File -Append $env:GITHUB_OUTPUT
"CUDA_PATH=$cudaPath" | Out-File -Append $env:GITHUB_ENV
"CUDA_HOME=$cudaPath" | Out-File -Append $env:GITHUB_ENV
"INCLUDE=$cudaPath\include;$env:INCLUDE" | Out-File -Append $env:GITHUB_ENV
"LIB=$cudaPath\lib\x64;$env:LIB" | Out-File -Append $env:GITHUB_ENV
"$cudaPath\bin" | Out-File -Append $env:GITHUB_PATH
- name: Determine Version
id: determine_version
shell: bash
run: |
VERSION=""
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
if [ -n "${{ inputs.manual_version }}" ]; then
VERSION="${{ inputs.manual_version }}"
VERSION=${VERSION#v}
echo "Manual run detected. Using provided version: $VERSION"
else
echo "Error: For manual runs (workflow_dispatch), the 'manual_version' input is required."
exit 1
fi
elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then
VERSION=$(echo "${{ github.ref }}" | sed 's!refs/tags/v!!')
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
VERSION=$(echo "${{ github.ref }}" | sed 's!refs/tags/!!')
fi
if [ -z "$VERSION" ]; then
echo "Error: Could not determine installer version."
echo " github.event_name: ${{ github.event_name }}"
echo " github.ref: ${{ github.ref }}"
echo " inputs.manual_version: ${{ inputs.manual_version }}"
exit 1
fi
echo "installer_version_out=$VERSION" >> "$GITHUB_OUTPUT"
echo "Installer version set to: $VERSION"
- name: Install Inno Setup
shell: pwsh
run: |
$installerUrl = "https://jrsoftware.org/download.php/is.exe"
$installerPath = "${{ runner.temp }}\isetup.exe"
echo "Downloading Inno Setup from $installerUrl..."
Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath
if (-not $?) { Write-Error "Failed to download Inno Setup installer"; exit 1 }
echo "Installing Inno Setup..."
Start-Process -FilePath $installerPath -ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-" -Wait
if (-not $?) { Write-Error "Failed to install Inno Setup"; exit 1 }
$innoPath = "C:\Program Files (x86)\Inno Setup 6"
echo "Adding Inno Setup directory to PATH: $innoPath"
Add-Content -Path $env:GITHUB_PATH -Value $innoPath
# Verify ISCC.exe exists
if (-not (Test-Path (Join-Path $innoPath "ISCC.exe"))) {
Write-Error "ISCC.exe not found at $innoPath after installation."
exit 1
}
echo "Inno Setup installed and added to PATH."
- name: Install DigiCert Client tools
id: install_digicert_tools # Renamed for clarity
uses: digicert/ssm-code-signing@v1.2.1
- name: Set DigiCert certificate
shell: bash
run: |
if [ -z "${{ secrets.SM_CLIENT_CERT_FILE_B64 }}" ]; then
echo "Error: SM_CLIENT_CERT_FILE_B64 secret is not set."
exit 1
fi
# Ensure the D drive directory exists or create it if not
# This is usually available on Windows runners, but good to be safe.
# However, direct creation like this might be problematic if D: isn't guaranteed.
# The action creates /d/ which on Windows often means a temp drive.
# Let's stick to a path the DigiCert action might expect or a runner temp path.
# The DigiCert docs for GH Actions specify /d/Certificate_pkcs12.p12. On Windows, this might translate to a specific temp path.
# Let's try to use a known writable path like runner.temp
CERT_PATH="${{ runner.temp }}\\Certificate_pkcs12.p12"
echo "Decoding certificate to $CERT_PATH"
echo "${{ secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > "$CERT_PATH"
if [ ! -f "$CERT_PATH" ]; then
echo "Error: Failed to create certificate file at $CERT_PATH"
exit 1
fi
echo "SM_CLIENT_CERT_FILE_PATH=$CERT_PATH" >> $GITHUB_ENV
- name: Set DigiCert environment variables
id: set_digicert_config_vars # Renamed for clarity, id might not be strictly needed anymore unless other steps reference it
shell: bash
run: |
if [ -z "${{ secrets.SM_HOST }}" ] || \
[ -z "${{ secrets.SM_API_KEY }}" ] || \
[ -z "${{ secrets.SM_CLIENT_CERT_PASSWORD }}" ] || \
[ -z "${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}" ]; then
echo "Error: One or more DigiCert secrets (SM_HOST, SM_API_KEY, SM_CLIENT_CERT_PASSWORD, SM_CODE_SIGNING_CERT_SHA1_HASH) are not set."
exit 1
fi
echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV"
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=${{ env.SM_CLIENT_CERT_FILE_PATH }}" >> "$GITHUB_ENV" # This comes from 'Set up DigiCert certificate' step
echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV"
# VERSION logic is now removed from this step
- name: Test DigiCert Signing on Dummy File
shell: cmd
# This step runs even if previous steps failed if we want to test signing independently at some point
# but for now, it depends on secrets and tools setup, so it will fail if those did.
run: |
echo "Starting dummy file signing test..."
set SM_LOG_LEVEL=TRACE
echo "SM_LOG_LEVEL set to TRACE for dummy sign test"
REM Create a dummy file to sign
echo @echo Test script for signing > %TEMP%\dummy_sign_test.cmd
set DUMMY_FILE_TO_SIGN=%TEMP%\dummy_sign_test.cmd
echo "Dummy file created at: %DUMMY_FILE_TO_SIGN%"
set PKCS11_CONFIG_PATH_TEST=%USERPROFILE%\AppData\Local\Temp\smtools-windows-x64\pkcs11properties.cfg
echo "PKCS11 Config Path for test: %PKCS11_CONFIG_PATH_TEST%"
if not exist "%PKCS11_CONFIG_PATH_TEST%" (
echo "Error: PKCS11 config file not found for test signing at '%PKCS11_CONFIG_PATH_TEST%'. Ensure 'Install DigiCert Client tools' ran."
exit /b 1
)
echo "Attempting to sync certificates with local store (for dummy test)..."
smctl windows certsync
set CERTSYNC_EXIT_CODE_TEST=%ERRORLEVEL%
set SMCTL_LOG_FILE_PATH_TEST=%USERPROFILE%\.signingmanager\logs\smctl.log
echo "--- smctl.log content after certsync (dummy test from %SMCTL_LOG_FILE_PATH_TEST%) ---"
if exist "%SMCTL_LOG_FILE_PATH_TEST%" (
type "%SMCTL_LOG_FILE_PATH_TEST%"
) else (
echo "smctl.log not found at %SMCTL_LOG_FILE_PATH_TEST% after certsync attempt (dummy test)."
)
echo "--- end of smctl.log content after certsync (dummy test) ---"
if %CERTSYNC_EXIT_CODE_TEST% neq 0 (
echo "Error: (Dummy Test) smctl windows certsync command failed with exit code %CERTSYNC_EXIT_CODE_TEST%."
exit /b 1
)
echo "(Dummy Test) smctl windows certsync completed successfully (exit code %CERTSYNC_EXIT_CODE_TEST%)."
echo "Attempting to sign dummy file: %DUMMY_FILE_TO_SIGN%"
set SMCTL_CLI_OUTPUT_TEMP_FILE_TEST=%TEMP%\smctl_cli_output_test.txt
smctl sign --fingerprint ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }} --input "%DUMMY_FILE_TO_SIGN%" --config-file "%PKCS11_CONFIG_PATH_TEST%" > "%SMCTL_CLI_OUTPUT_TEMP_FILE_TEST%" 2>&1
set SMCTL_EXIT_CODE_TEST=%ERRORLEVEL%
echo "--- smctl CLI output (dummy test) ---"
type "%SMCTL_CLI_OUTPUT_TEMP_FILE_TEST%"
echo "--- end of smctl CLI output (dummy test) ---"
echo "smctl CLI exit code (dummy test): %SMCTL_EXIT_CODE_TEST%"
set TEMP_CLI_OUTPUT_FOR_FINDSTR_TEST=%SMCTL_CLI_OUTPUT_TEMP_FILE_TEST%
echo "--- smctl.log content after dummy sign attempt (from %SMCTL_LOG_FILE_PATH_TEST%) ---"
if exist "%SMCTL_LOG_FILE_PATH_TEST%" (
type "%SMCTL_LOG_FILE_PATH_TEST%"
) else (
echo "smctl.log not found at %SMCTL_LOG_FILE_PATH_TEST% after dummy sign attempt."
)
echo "--- end of smctl.log content after dummy sign attempt ---"
findstr /I /C:"FAILED" "%TEMP_CLI_OUTPUT_FOR_FINDSTR_TEST%"
set FINDSTR_EXIT_CODE_TEST=%ERRORLEVEL%
del "%TEMP_CLI_OUTPUT_FOR_FINDSTR_TEST%"
if %SMCTL_EXIT_CODE_TEST% neq 0 (
echo "Error: (Dummy Test) smctl sign command failed with exit code %SMCTL_EXIT_CODE_TEST%."
exit /b 1
)
if %FINDSTR_EXIT_CODE_TEST% equ 0 (
echo "Error: (Dummy Test) smctl CLI output indicates failure (found 'FAILED' in output)."
exit /b 1
)
echo "(Dummy Test) Dummy file signed successfully. DigiCert signing seems configured correctly."
REM Do not delete the dummy file itself, it's in %TEMP% and will be cleaned up by runner eventually.
- name: Build local inference wheels
shell: bash # Ensures 'make' and 'rm -rf' work as expected
run: make create_wheels
- name: Install inference_gpu and dependencies from local wheels
shell: bash # Using bash for wildcard expansion in pip install
run: |
pip install -U --index-url https://download.pytorch.org/whl/cu128 torch torchvision
WHEEL_FILE=$(ls dist/inference_gpu-*.whl)
echo "Found GPU wheel: $WHEEL_FILE"
pip install --find-links=./dist/ "$WHEEL_FILE[sam,transformers,clip,http,yolo-world,grounding-dino]"
echo "--- Installed inference_gpu details ---"
pip show inference-gpu
- name: Install PyInstaller and other build dependencies
working-directory: ./app_bundles/windows # Adjusted path
run: |
pip install --upgrade pip
pip install --upgrade pyinstaller pyinstaller-hooks-contrib
pip install -r requirements.txt # This now only installs pyinstaller
echo "DEBUG: PyInstaller version:"
pip show pyinstaller
echo "DEBUG: pyinstaller-hooks-contrib version:"
pip show pyinstaller-hooks-contrib
- name: Build Windows installer
working-directory: ./app_bundles/windows
env:
BUILD_VERSION: ${{ steps.determine_version.outputs.installer_version_out }} # Use output from new Determine Version step
run: python build.py
- name: Sign Windows Installer with DigiCert
shell: cmd
env:
INSTALLER_VERSION_FROM_STEP: ${{ steps.determine_version.outputs.installer_version_out }}
run: |
echo "Starting installer signing process..."
REM Set smctl log level to TRACE for detailed logging
set SM_LOG_LEVEL=TRACE
echo "SM_LOG_LEVEL set to TRACE"
set PKCS11_CONFIG_PATH=%USERPROFILE%\AppData\Local\Temp\smtools-windows-x64\pkcs11properties.cfg
echo "PKCS11 Config Path: %PKCS11_CONFIG_PATH%"
REM Sync KeyLocker certificates to the local Windows certificate store as per DigiCert docs
echo "Attempting to sync certificates with local store using 'smctl windows certsync'..."
smctl windows certsync
set CERTSYNC_EXIT_CODE=%ERRORLEVEL%
REM Always display smctl.log after certsync, as it might contain TRACE details for this operation
set SMCTL_LOG_FILE_PATH_AFTER_CERTSYNC=%USERPROFILE%\.signingmanager\logs\smctl.log
if %CERTSYNC_EXIT_CODE% neq 0 (
echo "Error: smctl windows certsync command failed with exit code %CERTSYNC_EXIT_CODE%."
exit /b 1
)
echo "smctl windows certsync completed successfully (exit code %CERTSYNC_EXIT_CODE%)."
set INSTALLER_BASE_PATH=app_bundles\windows\installer
set INSTALLER_VERSION=%INSTALLER_VERSION_FROM_STEP%
set INSTALLER_FILENAME=inference-%INSTALLER_VERSION%-installer.exe
set UNSIGNED_INSTALLER_PATH=%INSTALLER_BASE_PATH%\%INSTALLER_FILENAME%
echo "Debug: Listing contents of app_bundles\windows"
dir app_bundles\windows
echo "Debug: Listing contents of %INSTALLER_BASE_PATH%"
dir "%INSTALLER_BASE_PATH%"
echo "Looking for installer at: %UNSIGNED_INSTALLER_PATH%"
if not exist "%UNSIGNED_INSTALLER_PATH%" (
echo "Error: Unsigned installer not found at '%UNSIGNED_INSTALLER_PATH%'"
echo "Current directory for this step: "
cd
exit /b 1
)
echo "Looking for PKCS11 config at: %PKCS11_CONFIG_PATH%"
if not exist "%PKCS11_CONFIG_PATH%" (
echo "Error: DigiCert PKCS11 config file not found..."
exit /b 1
)
echo "Attempting to sign: %UNSIGNED_INSTALLER_PATH%"
set SMCTL_CLI_OUTPUT_TEMP_FILE=%TEMP%\smctl_cli_output.txt
smctl sign --fingerprint ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }} --input "%UNSIGNED_INSTALLER_PATH%" --config-file "%PKCS11_CONFIG_PATH%" > "%SMCTL_CLI_OUTPUT_TEMP_FILE%" 2>&1
set SMCTL_EXIT_CODE=%ERRORLEVEL%
echo "--- smctl CLI output ---"
type "%SMCTL_CLI_OUTPUT_TEMP_FILE%"
echo "--- end of smctl CLI output ---"
echo "smctl CLI exit code: %SMCTL_EXIT_CODE%"
REM Temporarily store CLI output for findstr before deleting the file
set TEMP_CLI_OUTPUT_FOR_FINDSTR=%SMCTL_CLI_OUTPUT_TEMP_FILE%
REM Display the detailed smctl.log file
set SMCTL_LOG_FILE_PATH=%USERPROFILE%\.signingmanager\logs\smctl.log
echo "--- smctl.log content (from %SMCTL_LOG_FILE_PATH%) ---"
if exist "%SMCTL_LOG_FILE_PATH%" (
type "%SMCTL_LOG_FILE_PATH%"
) else (
echo "smctl.log not found at %SMCTL_LOG_FILE_PATH%."
)
echo "--- end of smctl.log content ---"
REM We need to re-capture CLI output or pass it if we want to search it again here.
REM Let's assume for a moment that with TRACE logging, the exit code becomes more reliable,
REM OR that the TRACE log itself will contain an undeniable error message we could search for.
REM The original findstr logic was based on the brief "FAILED" message.
REM Check for "FAILED" in the originally captured CLI output
findstr /I /C:"FAILED" "%TEMP_CLI_OUTPUT_FOR_FINDSTR%"
set FINDSTR_EXIT_CODE=%ERRORLEVEL%
REM findstr returns 0 if string is found, 1 if not found (or error)
REM Now delete the temp CLI output file
del "%TEMP_CLI_OUTPUT_FOR_FINDSTR%"
if %SMCTL_EXIT_CODE% neq 0 (
echo "Error: smctl sign command failed with exit code %SMCTL_EXIT_CODE% (see smctl.log above for details)."
exit /b 1
)
if %FINDSTR_EXIT_CODE% equ 0 (
REM String "FAILED" was found in the CLI output
echo "Error: smctl CLI output indicates failure (found 'FAILED' in output). Review smctl.log for details."
exit /b 1
)
echo "Installer signed successfully (based on smctl exit code and absence of 'FAILED' in CLI output). Review logs carefully."
- name: Upload Windows Installer
uses: actions/upload-artifact@v7
with:
name: Roboflow-Inference-Windows-Installer
# The build.py script creates the installer in installer/inference-{version}-installer.exe
# We'll upload the whole installer directory, or use a wildcard if preferred.
path: app_bundles/windows/installer/ # Adjusted path
if-no-files-found: error # Fail the step if the installer directory is not found or empty
- name: Upload Installer to Release
if: github.event_name == 'release'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./app_bundles/windows/installer/inference-${{ steps.determine_version.outputs.installer_version_out }}-installer.exe
asset_name: inference-${{ steps.determine_version.outputs.installer_version_out }}-gpu-installer.exe
asset_content_type: application/vnd.microsoft.portable-executable