Skip to content

Commit 37ba4da

Browse files
authored
Add upgrade rules to be implemented to zap file open and implement user-selected package persistence for .zap file imports when the paths in it a wrong relatively (#1643)
* Add getUpgradePackageMatch function to util.js for package matching logic * Modify httpPostFileOpen to extract and use selectedZclPackages/selectedTemplatePackages from request * Update ZapConfig.vue submitForm to include selected packages in file open requests * Enhance importDataFromFile to respect user-selected packages over embedded packages * Add upgrade package matching and rule execution during import process This ensures that user package selections from the UI are respected when opening .zap files, rather than defaulting to packages embedded in the .zap file itself. The changes maintain backward compatibility while adding support for package upgrade rules and multi-protocol configurations. - Resolves issue where package selections were not persisted during file operations. - Adding unit tests for the upgrade rule on file open/import - eliminate redundant upgrade rules code in startup.js and fix unit test failures - Github: ZAP #1638
1 parent d6ee831 commit 37ba4da

File tree

11 files changed

+2748
-88
lines changed

11 files changed

+2748
-88
lines changed

docs/api.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19161,6 +19161,7 @@ back into a JS integer.
1916119161
* [~collectJsonData(jsonFile)](#module_JS API_ random utilities..collectJsonData)
1916219162
* [~patternFormat(pattern, data)](#module_JS API_ random utilities..patternFormat)
1916319163
* [~toErrorObject(err, message)](#module_JS API_ random utilities..toErrorObject) ⇒ <code>Error</code>
19164+
* [~getUpgradePackageMatch(db, upgradePackages, zapFilePackages, packageType)](#module_JS API_ random utilities..getUpgradePackageMatch) ⇒
1916419165

1916519166
<a name="module_JS API_ random utilities..checksum"></a>
1916619167

@@ -19459,6 +19460,22 @@ If message is provided, it will be used as the error message.
1945919460
| err | <code>\*</code> | |
1946019461
| message | <code>\*</code> | <code></code> |
1946119462

19463+
<a name="module_JS API_ random utilities..getUpgradePackageMatch"></a>
19464+
19465+
### JS API: random utilities~getUpgradePackageMatch(db, upgradePackages, zapFilePackages, packageType) ⇒
19466+
Go over the zap file's top level packages and see if they can be upgraded
19467+
based on the upgrade packages given.
19468+
19469+
**Kind**: inner method of [<code>JS API: random utilities</code>](#module_JS API_ random utilities)
19470+
**Returns**: list of packages
19471+
19472+
| Param | Type |
19473+
| --- | --- |
19474+
| db | <code>\*</code> |
19475+
| upgradePackages | <code>\*</code> |
19476+
| zapFilePackages | <code>\*</code> |
19477+
| packageType | <code>\*</code> |
19478+
1946219479
<a name="module_REST API_ various zcl utilities"></a>
1946319480

1946419481
## REST API: various zcl utilities

src-electron/importexport/import.js

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,58 @@ function mergeZapExtension(baseState, extensionState) {
143143
}
144144
}
145145

146+
/**
147+
* Extract upgrade rules from ZCL packages
148+
* @param {Array} upgradeZclPackages - Array of ZCL packages
149+
* @returns {Array} Array of upgrade rule objects
150+
*/
151+
function extractUpgradeRules(upgradeZclPackages) {
152+
let upgradeRules = []
153+
// If more than one upgrade package is present then it is a multiprotocol
154+
// application so upgrade rules should be added to the corresponding endpoints.
155+
let isMultiProtocol = upgradeZclPackages.length > 1
156+
157+
for (const pkg of upgradeZclPackages) {
158+
if (pkg.path) {
159+
try {
160+
const jsonData = JSON.parse(fs.readFileSync(pkg.path, 'utf-8'))
161+
if (jsonData.upgradeRules !== undefined) {
162+
const upgradeRulesJsonPath = path.resolve(
163+
path.dirname(pkg.path),
164+
jsonData.upgradeRules
165+
)
166+
try {
167+
const upgradeRulesData = JSON.parse(
168+
fs.readFileSync(upgradeRulesJsonPath, 'utf-8')
169+
)
170+
// Sorting upgrade rules by priority and then run them
171+
upgradeRulesData.upgradeRuleScripts
172+
.sort((a, b) => a.priority - b.priority)
173+
.forEach((ur) => {
174+
upgradeRules.push({
175+
path: path.resolve(path.dirname(pkg.path), ur.path),
176+
category: isMultiProtocol ? upgradeRulesData.category : null
177+
})
178+
})
179+
} catch (error) {
180+
env.logError(
181+
`Error reading or parsing upgrade rules from path ${upgradeRulesJsonPath}:`,
182+
error
183+
)
184+
}
185+
}
186+
} catch (error) {
187+
env.logError(
188+
`Error reading or parsing JSON from path ${pkg.path}:`,
189+
error
190+
)
191+
}
192+
}
193+
}
194+
195+
return upgradeRules
196+
}
197+
146198
/**
147199
* Writes the data from the file into a new session.
148200
* NOTE: This function does NOT initialize session packages.
@@ -179,6 +231,92 @@ async function importDataFromFile(
179231
}
180232

181233
state = ff.convertFromFile(state)
234+
235+
// If upgrade rules are not known then figure them out.
236+
if (!options.upgradeRuleScripts) {
237+
// If defaultZclMetafile doesn't exist, figure it out based on filePath
238+
if (
239+
!options.defaultZclMetafile &&
240+
state.package &&
241+
Array.isArray(state.package)
242+
) {
243+
// Find all ZCL properties packages from the state
244+
const zclPackages = state.package.filter(
245+
(pkg) => pkg.type === dbEnum.packageType.zclProperties
246+
)
247+
if (zclPackages.length > 0) {
248+
options.defaultZclMetafile = zclPackages
249+
.map((pkg) => {
250+
if (pkg.path) {
251+
// If the path is relative, resolve it relative to the filePath directory
252+
if (!path.isAbsolute(pkg.path)) {
253+
return path.resolve(path.dirname(filePath), pkg.path)
254+
} else {
255+
return pkg.path
256+
}
257+
}
258+
return null
259+
})
260+
.filter((path) => path !== null)
261+
} else {
262+
// Fallback to builtin if no ZCL package found in state
263+
options.defaultZclMetafile = [env.builtinSilabsZclMetafile()]
264+
}
265+
}
266+
267+
// If defaultTemplateFile doesn't exist, figure it out based on filePath
268+
if (
269+
!options.defaultTemplateFile &&
270+
state.package &&
271+
Array.isArray(state.package)
272+
) {
273+
// Find all template packages from the state
274+
const templatePackages = state.package.filter(
275+
(pkg) => pkg.type === dbEnum.packageType.genTemplatesJson
276+
)
277+
if (templatePackages.length > 0) {
278+
options.defaultTemplateFile = templatePackages
279+
.map((pkg) => {
280+
if (pkg.path) {
281+
// If the path is relative, resolve it relative to the filePath directory
282+
if (!path.isAbsolute(pkg.path)) {
283+
return path.resolve(path.dirname(filePath), pkg.path)
284+
} else {
285+
return pkg.path
286+
}
287+
}
288+
return null
289+
})
290+
.filter((path) => path !== null)
291+
} else {
292+
// Fallback to builtin if no template package found in state
293+
options.defaultTemplateFile = [env.builtinTemplateMetafile()]
294+
}
295+
}
296+
297+
// Add upgrade package matching logic
298+
let upgradeZclPackages = await util.getUpgradePackageMatch(
299+
db,
300+
options.zclProperties || options.defaultZclMetafile,
301+
state.package,
302+
dbEnum.packageType.zclProperties
303+
)
304+
let upgradeTemplatePackages = await util.getUpgradePackageMatch(
305+
db,
306+
options.generationTemplate || options.defaultTemplateFile,
307+
state.package,
308+
dbEnum.packageType.genTemplatesJson
309+
)
310+
311+
let upgradeRules = extractUpgradeRules(upgradeZclPackages)
312+
313+
// Set upgrade rules in options if they exist
314+
if (upgradeRules.length > 0) {
315+
options.upgradeRuleScripts = upgradeRules
316+
}
317+
options.upgradeZclPackages = upgradeZclPackages
318+
options.upgradeTemplatePackages = upgradeTemplatePackages
319+
}
182320
try {
183321
await dbApi.dbBeginTransaction(db)
184322
let sid
@@ -269,3 +407,4 @@ async function importDataFromFile(
269407
exports.readDataFromFile = readDataFromFile
270408
exports.importDataFromFile = importDataFromFile
271409
exports.executePostImportScript = executePostImportScript
410+
exports.extractUpgradeRules = extractUpgradeRules

src-electron/main-process/startup.js

Lines changed: 5 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -222,45 +222,6 @@ function findZapFiles(dir) {
222222
return zapFiles
223223
}
224224

225-
/**
226-
* Go over the zap file's top level packages and see if they can be upgraded
227-
* based on the upgrade packages given.
228-
*
229-
* @param {*} db
230-
* @param {*} upgradePackages
231-
* @param {*} zapFilePackages
232-
* @param {*} packageType
233-
* @returns list of packages
234-
*/
235-
async function getUpgradePackageMatch(
236-
db,
237-
upgradePackages,
238-
zapFilePackages,
239-
packageType
240-
) {
241-
let matchedUpgradePackages = []
242-
if (Array.isArray(upgradePackages) && Array.isArray(zapFilePackages)) {
243-
for (let i = 0; i < upgradePackages.length; i++) {
244-
let upgradePackage = await queryPackage.getPackageByPathAndType(
245-
db,
246-
upgradePackages[i],
247-
packageType
248-
)
249-
if (upgradePackage) {
250-
for (let j = 0; j < zapFilePackages.length; j++) {
251-
if (
252-
zapFilePackages[j].category == upgradePackage.category &&
253-
zapFilePackages[j].type == upgradePackage.type
254-
) {
255-
matchedUpgradePackages.push(upgradePackage)
256-
}
257-
}
258-
}
259-
}
260-
}
261-
return matchedUpgradePackages
262-
}
263-
264225
/**
265226
* Upgrade the top level packages(.json files) of a .zap file when a gsdk is
266227
* updated.
@@ -299,60 +260,20 @@ async function upgradeZapFile(argv, options) {
299260
options.logger(` 🐝 New templates loaded: ${argv.generationTemplate}`)
300261
}
301262
let state = await importJs.readDataFromFile(zapFile)
302-
let upgradeZclPackages = await getUpgradePackageMatch(
263+
let upgradeZclPackages = await util.getUpgradePackageMatch(
303264
db,
304265
argv.zclProperties,
305266
state.package,
306267
dbEnum.packageType.zclProperties
307268
)
308-
let upgradeTemplatePackages = await getUpgradePackageMatch(
269+
let upgradeTemplatePackages = await util.getUpgradePackageMatch(
309270
db,
310271
argv.generationTemplate,
311272
state.package,
312273
dbEnum.packageType.genTemplatesJson
313274
)
314275

315-
let upgradeRules = []
316-
// If more than one upgrade package is present then it is a multiprotocol
317-
// application so upgrade rules should be added to the corresponding endpoints.
318-
let isMultiProtocol = upgradeZclPackages.length > 1
319-
for (const pkg of upgradeZclPackages) {
320-
if (pkg.path) {
321-
try {
322-
const jsonData = JSON.parse(fs.readFileSync(pkg.path, 'utf-8'))
323-
if (jsonData.upgradeRules !== undefined) {
324-
const upgradeRulesJsonPath = path.resolve(
325-
path.dirname(pkg.path),
326-
jsonData.upgradeRules
327-
)
328-
try {
329-
const upgradeRulesData = JSON.parse(
330-
fs.readFileSync(upgradeRulesJsonPath, 'utf-8')
331-
)
332-
// Sorting upgrade rules by priority and then run them
333-
upgradeRulesData.upgradeRuleScripts
334-
.sort((a, b) => a.priority - b.priority)
335-
.forEach((ur) => {
336-
upgradeRules.push({
337-
path: path.resolve(path.dirname(pkg.path), ur.path),
338-
category: isMultiProtocol ? upgradeRulesData.category : null
339-
})
340-
})
341-
} catch (error) {
342-
console.error(
343-
`Error reading or parsing upgrade rules from path ${upgradeRulesJsonPath}:`,
344-
error
345-
)
346-
}
347-
}
348-
} catch (error) {
349-
console.error(
350-
`Error reading or parsing JSON from path ${pkg.path}:`,
351-
error
352-
)
353-
}
354-
}
355-
}
276+
let upgradeRules = importJs.extractUpgradeRules(upgradeZclPackages)
356277

357278
let importResult = await importJs.importDataFromFile(db, zapFile, {
358279
defaultZclMetafile: argv.zclProperties,
@@ -837,13 +758,13 @@ async function generateSingleFile(
837758
}
838759

839760
if (!isZapPackagePathPresent) {
840-
upgradeZclPackages = await getUpgradePackageMatch(
761+
upgradeZclPackages = await util.getUpgradePackageMatch(
841762
db,
842763
options.zcl,
843764
state.package,
844765
dbEnum.packageType.zclProperties
845766
)
846-
upgradeTemplatePackages = await getUpgradePackageMatch(
767+
upgradeTemplatePackages = await util.getUpgradePackageMatch(
847768
db,
848769
options.template,
849770
state.package,

src-electron/rest/file-ops.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ function httpPostFileOpen(db) {
4545
let search = req.body.search
4646
const query = new URLSearchParams(search)
4747
let file = query.get('filePath')
48+
49+
// Extract selected packages from request body or query
50+
let selectedZclPackages = req.body.selectedZclPackages
51+
let selectedTemplatePackages = req.body.selectedTemplatePackages
52+
4853
// Gather .zapExtension files
4954
let zapFileExtensions = query.get('zapFileExtensions')
5055
if (file) {
@@ -82,6 +87,31 @@ function httpPostFileOpen(db) {
8287
if (zapFileExtensions) {
8388
options.extensionFiles = [zapFileExtensions]
8489
}
90+
// Update options if selectedZclPackages exists and has size > 0
91+
if (
92+
selectedZclPackages &&
93+
Array.isArray(selectedZclPackages) &&
94+
selectedZclPackages.length > 0
95+
) {
96+
options.zclProperties = selectedZclPackages.map((pkg) => pkg.path)
97+
env.logInfo(
98+
`Using ${selectedZclPackages.length} selected ZCL packages`
99+
)
100+
}
101+
102+
// Update options if selectedTemplatePackages exists and has size > 0
103+
if (
104+
selectedTemplatePackages &&
105+
Array.isArray(selectedTemplatePackages) &&
106+
selectedTemplatePackages.length > 0
107+
) {
108+
options.generationTemplate = selectedTemplatePackages.map(
109+
(pkg) => pkg.path
110+
)
111+
env.logInfo(
112+
`Using ${selectedTemplatePackages.length} selected template packages`
113+
)
114+
}
85115
let importResult = await importJs.importDataFromFile(
86116
db,
87117
zapFilePath,

0 commit comments

Comments
 (0)