forked from ni/labview-icon-editor
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathModifyVIPBDisplayInfo.ps1
More file actions
412 lines (360 loc) · 14.2 KB
/
Copy pathModifyVIPBDisplayInfo.ps1
File metadata and controls
412 lines (360 loc) · 14.2 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
402
403
404
405
406
407
408
409
410
411
412
<#
.SYNOPSIS
Updates display information in a VIPB file without launching LabVIEW.
.DESCRIPTION
Resolves paths, merges version data into the DisplayInformation JSON, loads
the VIPB XML, and updates the metadata fields in-place. This replaces the
previous LabVIEW VI + g-cli approach so the metadata update can run entirely
from PowerShell.
.PARAMETER SupportedBitness
LabVIEW bitness for the build ("32" or "64").
.PARAMETER RepoRoot
Path to the repository root.
.PARAMETER VIPBPath
Relative path to the VIPB file to modify.
.PARAMETER LabVIEWVersion
LabVIEW major version year (e.g., 2021).
Alias: MinimumSupportedLVVersion.
.PARAMETER LabVIEWMinorRevision
Minor revision number of LabVIEW (e.g., 0 for 21.0).
.PARAMETER Major
Major version component for the package.
.PARAMETER Minor
Minor version component for the package.
.PARAMETER Patch
Patch version component for the package.
.PARAMETER Build
Build number component for the package.
.PARAMETER Commit
Commit identifier embedded in the package metadata.
.PARAMETER ReleaseNotesFile
Path to a release notes file injected into the build.
.PARAMETER DisplayInformationJSON
JSON string representing the VIPB display information to update.
.EXAMPLE
.\ModifyVIPBDisplayInfo.ps1 -SupportedBitness "64" -RepoRoot "C:\repo" -VIPBPath "Tooling\deployment\NI Icon editor.vipb" -LabVIEWVersion 2021 -LabVIEWMinorRevision 0 -Major 1 -Minor 0 -Patch 0 -Build 2 -Commit "abcd123" -ReleaseNotesFile "Tooling\deployment\release_notes.md" -DisplayInformationJSON '{"Package Version":{"major":1,"minor":0,"patch":0,"build":2}}'
#>
param (
[string]$SupportedBitness,
[string]$RepoRoot,
[string]$VIPBPath,
[string]$WorktreeRoot,
[switch]$SkipWorktreeRootCheck,
[Alias('MinimumSupportedLVVersion')]
[ValidateRange(2000, 2100)]
[int]$LabVIEWVersion,
[ValidateRange(0, 99)]
[int]$LabVIEWMinorRevision = 0,
[int]$Major,
[int]$Minor,
[int]$Patch,
[int]$Build,
[string]$Commit,
[string]$ReleaseNotesFile,
[Parameter(Mandatory=$true)]
[string]$DisplayInformationJSON
)
# 1) Resolve paths
try {
$ResolvedRepoRoot = (Resolve-Path -Path $RepoRoot -ErrorAction Stop).Path
$ResolvedVIPBPath = Join-Path -Path $ResolvedRepoRoot -ChildPath $VIPBPath -ErrorAction Stop
}
catch {
$errorObject = [PSCustomObject]@{
error = "Error resolving paths. Ensure RepoRoot and VIPBPath are valid."
exception = $_.Exception.Message
stackTrace = $_.Exception.StackTrace
}
$errorObject | ConvertTo-Json -Depth 10
exit 1
}
# 1a) Worktree preflight (optional for local runs)
$preflightScript = Join-Path -Path $ResolvedRepoRoot -ChildPath 'Tooling\Invoke-Preflight.ps1'
if (Test-Path -Path $preflightScript) {
. $preflightScript
$scriptArgs = Convert-BoundParametersToArgumentList -BoundParameters $PSBoundParameters
$relativeScript = if ($PSCommandPath) { Get-RepoRelativePath -RepoRoot $ResolvedRepoRoot -Path $PSCommandPath } else { $null }
$preflight = Invoke-Preflight `
-RepoRoot $ResolvedRepoRoot `
-WorktreeRoot $WorktreeRoot `
-LabVIEWVersion $LabVIEWVersion `
-LabVIEWBitness $SupportedBitness `
-SkipWorktreeRootCheck:$SkipWorktreeRootCheck `
-AutoWorktree:$false `
-ScriptPath $relativeScript `
-ScriptArguments $scriptArgs
if ($preflight.Reinvoked) {
return
}
$ResolvedRepoRoot = $preflight.RepoRoot
}
# 2) Create release notes if needed
if (-not (Test-Path $ReleaseNotesFile)) {
Write-Host "Release notes file '$ReleaseNotesFile' does not exist. Creating it..."
New-Item -ItemType File -Path $ReleaseNotesFile -Force | Out-Null
}
try {
$ResolvedReleaseNotesFile = Resolve-Path -Path $ReleaseNotesFile -ErrorAction Stop
}
catch {
$errorObject = [PSCustomObject]@{
error = "Error resolving ReleaseNotesFile. Ensure the path exists and is accessible."
exception = $_.Exception.Message
stackTrace = $_.Exception.StackTrace
}
$errorObject | ConvertTo-Json -Depth 10
exit 1
}
# 3) Calculate the LabVIEW version string
$lvNumericMajor = $LabVIEWVersion - 2000
$lvNumericVersion = "$($lvNumericMajor).$LabVIEWMinorRevision"
if ($SupportedBitness -eq "64") {
$VIP_LVVersion_A = "$lvNumericVersion (64-bit)"
}
else {
$VIP_LVVersion_A = $lvNumericVersion
}
Write-Output "Modifying VI Package Information metadata (no LabVIEW dependency)..."
# 4) Parse and update the DisplayInformationJSON
try {
$jsonObj = $DisplayInformationJSON | ConvertFrom-Json
}
catch {
$errorObject = [PSCustomObject]@{
error = "Failed to parse DisplayInformationJSON into valid JSON."
exception = $_.Exception.Message
stackTrace = $_.Exception.StackTrace
}
$errorObject | ConvertTo-Json -Depth 10
exit 1
}
# If "Package Version" doesn't exist, create it as a subobject
if (-not $jsonObj.'Package Version') {
$jsonObj | Add-Member -MemberType NoteProperty -Name 'Package Version' -Value ([PSCustomObject]@{
major = $Major
minor = $Minor
patch = $Patch
build = $Build
})
}
else {
# "Package Version" exists, so just overwrite its fields
$jsonObj.'Package Version'.major = $Major
$jsonObj.'Package Version'.minor = $Minor
$jsonObj.'Package Version'.patch = $Patch
$jsonObj.'Package Version'.build = $Build
}
# Ensure required fields exist before modifying the VIPB
$requiredFields = @(
'Company Name',
'Product Name',
'Product Description Summary',
'Product Description'
)
$missingFields = $requiredFields | Where-Object { [string]::IsNullOrWhiteSpace($jsonObj.PSObject.Properties[$_].Value) }
if ($missingFields.Count -gt 0) {
$errorObject = [PSCustomObject]@{
error = "DisplayInformationJSON is missing required field(s)."
missing_fields = $missingFields
provided_payload = $jsonObj
}
$errorObject | ConvertTo-Json -Depth 10
exit 1
}
# Helper to set or create XML child nodes safely
function Set-VipbElementValue {
param(
[System.Xml.XmlNode]$ParentNode,
[string]$ElementName,
[string]$Value
)
if (-not $ParentNode) { return }
$element = $ParentNode.SelectSingleNode($ElementName)
if (-not $element) {
$element = $ParentNode.OwnerDocument.CreateElement($ElementName)
[void]$ParentNode.AppendChild($element)
}
$element.InnerText = $Value
}
# 5) Load and update the VIPB XML directly
try {
[xml]$vipbXml = Get-Content -Raw -Path $ResolvedVIPBPath
}
catch {
$errorObject = [PSCustomObject]@{
error = "Failed to load VIPB file."
exception = $_.Exception.Message
stackTrace = $_.Exception.StackTrace
}
$errorObject | ConvertTo-Json -Depth 10
exit 1
}
$generalSettings = $vipbXml.VI_Package_Builder_Settings.Library_General_Settings
$advancedSettings = $vipbXml.VI_Package_Builder_Settings.Advanced_Settings
$descriptionSettings = $advancedSettings.Description
if (-not $generalSettings -or -not $descriptionSettings) {
$errorObject = [PSCustomObject]@{
error = "VIPB file is missing expected sections (Library_General_Settings or Description)."
vipb_path = $ResolvedVIPBPath
}
$errorObject | ConvertTo-Json -Depth 10
exit 1
}
# Update high-level metadata
Set-VipbElementValue -ParentNode $generalSettings -ElementName "Library_Version" -Value "$Major.$Minor.$Patch.$Build"
Set-VipbElementValue -ParentNode $generalSettings -ElementName "Package_LabVIEW_Version" -Value $VIP_LVVersion_A
# Update metadata based on known DisplayInformation keys
$metadataMap = @(
@{ Key = 'Company Name'; Parent = $generalSettings; Element = 'Company_Name' },
@{ Key = 'Product Name'; Parent = $generalSettings; Element = 'Product_Name' },
@{ Key = 'Product Description Summary'; Parent = $descriptionSettings; Element = 'One_Line_Description_Summary' },
@{ Key = 'Author Name (Person or Company)'; Parent = $descriptionSettings; Element = 'Packager' },
@{ Key = 'Product Homepage (URL)'; Parent = $descriptionSettings; Element = 'URL' },
@{ Key = 'Legal Copyright'; Parent = $descriptionSettings; Element = 'Copyright' }
)
foreach ($mapping in $metadataMap) {
$value = $jsonObj.PSObject.Properties[$mapping.Key].Value
if ($null -ne $value) {
Set-VipbElementValue -ParentNode $mapping.Parent -ElementName $mapping.Element -Value $value
}
}
# Handle release notes: ReleaseNotesFile is the source of truth
$releaseNotesFromFile = $null
try {
if (Test-Path $ResolvedReleaseNotesFile) {
$releaseNotesFromFile = Get-Content -Raw -Path $ResolvedReleaseNotesFile -ErrorAction Stop
}
}
catch {
$errorObject = [PSCustomObject]@{
error = "Failed to read release notes file."
path = $ResolvedReleaseNotesFile
exception = $_.Exception.Message
}
$errorObject | ConvertTo-Json -Depth 10
exit 1
}
if ([string]::IsNullOrWhiteSpace($releaseNotesFromFile)) {
$errorObject = [PSCustomObject]@{
error = "Release notes file is empty. Populate it or provide valid content before running this action."
path = $ResolvedReleaseNotesFile
}
$errorObject | ConvertTo-Json -Depth 10
exit 1
}
$releaseNotesJsonValue = $jsonObj.'Release Notes - Change Log'
if (-not [string]::IsNullOrWhiteSpace($releaseNotesJsonValue) -and ($releaseNotesJsonValue -ne $releaseNotesFromFile)) {
Write-Warning "Release notes JSON differs from the contents of '$ResolvedReleaseNotesFile'. The file content will be used."
}
Set-VipbElementValue -ParentNode $descriptionSettings -ElementName "Release_Notes" -Value $releaseNotesFromFile
# Update long description and embed commit fingerprint
$descriptionValue = $jsonObj.'Product Description'
if (-not [string]::IsNullOrWhiteSpace($Commit)) {
$descriptionValue = "{0}`n`nCommit: {1}" -f $descriptionValue, $Commit
}
Set-VipbElementValue -ParentNode $descriptionSettings -ElementName "Description" -Value $descriptionValue
# Update optional license reference (resolve to an actual file path when possible)
$licenseAgreementInput = $jsonObj.'License Agreement Name'
$resolvedLicensePath = $null
if (-not [string]::IsNullOrWhiteSpace($licenseAgreementInput)) {
$candidatePath = $licenseAgreementInput
if (-not [System.IO.Path]::IsPathRooted($candidatePath)) {
$candidatePath = Join-Path -Path $ResolvedRepoRoot -ChildPath $licenseAgreementInput
}
if (Test-Path $candidatePath) {
try {
$resolvedLicensePath = (Resolve-Path -Path $candidatePath -ErrorAction Stop).Path
}
catch {
Write-Warning "Unable to resolve license file path '$candidatePath'."
}
}
else {
Write-Warning "License agreement path '$licenseAgreementInput' does not exist relative to the repository."
}
}
if ($resolvedLicensePath) {
$relativePath = $resolvedLicensePath
try {
$vipbDirectory = Split-Path -Parent $ResolvedVIPBPath
$relativePath = [System.IO.Path]::GetRelativePath($vipbDirectory, $resolvedLicensePath)
}
catch {
Write-Warning "Unable to compute a relative license path from '$ResolvedVIPBPath'. Using absolute path instead."
}
Set-VipbElementValue -ParentNode $advancedSettings -ElementName "License_Agreement_Filepath" -Value $relativePath
}
else {
# Ensure VIP builds don't depend on any local license file by default.
Set-VipbElementValue -ParentNode $advancedSettings -ElementName "License_Agreement_Filepath" -Value ''
}
# Ensure we don't accidentally ship local build artifacts (logs, diagnostics) in the VI package.
# The VIPB already excludes many non-shipping folders, but TestResults is intentionally used by
# CI/local tooling and should never be included in the built VIP.
try {
$sourceFiles = $advancedSettings.SelectSingleNode('Source_Files')
if ($null -ne $sourceFiles) {
$existing = $sourceFiles.SelectNodes('Exclusions/Path') | Where-Object { $_.InnerText -eq 'TestResults' }
if (-not $existing -or $existing.Count -eq 0) {
$exclusion = $vipbXml.CreateElement('Exclusions')
$pathNode = $vipbXml.CreateElement('Path')
$pathNode.InnerText = 'TestResults'
[void]$exclusion.AppendChild($pathNode)
[void]$sourceFiles.AppendChild($exclusion)
}
} else {
Write-Warning "VIPB does not contain an Advanced_Settings/Source_Files section; cannot enforce TestResults exclusion."
}
}
catch {
Write-Warning ("Failed to enforce TestResults exclusion in VIPB. {0}" -f $_.Exception.Message)
}
# Warn about any DisplayInformation JSON keys we don't yet handle
$recognizedKeys = @(
'Company Name',
'Product Name',
'Product Description Summary',
'Product Description',
'License Agreement Name',
'Author Name (Person or Company)',
'Product Homepage (URL)',
'Legal Copyright',
'Release Notes - Change Log',
'Package Version'
)
$unhandledKeys = $jsonObj.PSObject.Properties | Where-Object { $_.Name -notin $recognizedKeys }
if ($unhandledKeys.Count -gt 0) {
$details = $unhandledKeys | ForEach-Object {
[PSCustomObject]@{
key = $_.Name
value = $_.Value
}
}
$errorObject = [PSCustomObject]@{
error = "DisplayInformationJSON contains unhandled field(s). Update the mapping to keep metadata in sync."
unhandled_fields = $details
recognized_fields = $recognizedKeys
}
$errorObject | ConvertTo-Json -Depth 10
exit 1
}
try {
$writerSettings = New-Object System.Xml.XmlWriterSettings
$writerSettings.Indent = $true
$writerSettings.IndentChars = " "
$writerSettings.NewLineHandling = [System.Xml.NewLineHandling]::Replace
$writerSettings.NewLineChars = "`n"
$xmlWriter = [System.Xml.XmlWriter]::Create($ResolvedVIPBPath, $writerSettings)
$vipbXml.Save($xmlWriter)
$xmlWriter.Close()
Write-Host "Successfully updated VIPB metadata: $ResolvedVIPBPath"
}
catch {
$errorObject = [PSCustomObject]@{
error = "Failed to save updated VIPB metadata."
exception = $_.Exception.Message
stackTrace = $_.Exception.StackTrace
}
$errorObject | ConvertTo-Json -Depth 10
exit 1
}