Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing the top level zcl file registration when the gsdk is updated from one branch to another #1347

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,250 changes: 2,180 additions & 2,070 deletions docs/zap-schema.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 59 additions & 23 deletions src-electron/db/query-package.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,11 @@ async function getZclPropertiesPackage(db, packages) {
*/
async function getPackageByPathAndType(db, path, type) {
return dbApi
.dbGet(db, `${querySelectFromPackage} WHERE PATH = ? AND TYPE = ?`, [
path,
type,
])
.dbGet(
db,
`${querySelectFromPackage} WHERE PATH = ? AND TYPE = ? AND IS_IN_SYNC = 1`,
[path, type]
)
.then(dbMapping.map.package)
}

Expand All @@ -119,8 +120,18 @@ async function getPackageByPathAndType(db, path, type) {
async function getPackageIdByPathAndTypeAndVersion(db, path, type, version) {
// Version can be null for custom xml
let packageQuery =
`SELECT PACKAGE_ID FROM PACKAGE WHERE PATH = '${path}' AND TYPE = '${type}' AND ` +
(version ? `VERSION = '${version}'` : `VERSION IS NULL`)
`
SELECT
PACKAGE_ID
FROM
PACKAGE
WHERE
IS_IN_SYNC = 1
AND
PATH = '${path}'
AND
TYPE = '${type}'
AND ` + (version ? `VERSION = '${version}'` : `VERSION IS NULL`)
return dbApi.dbGet(db, packageQuery).then((row) => {
if (row == null) return null
else return row.PACKAGE_ID
Expand All @@ -136,7 +147,9 @@ async function getPackageIdByPathAndTypeAndVersion(db, path, type, version) {
*/
async function getPackagesByType(db, type) {
return dbApi
.dbAll(db, `${querySelectFromPackage} WHERE TYPE = ?`, [type])
.dbAll(db, `${querySelectFromPackage} WHERE TYPE = ? AND IS_IN_SYNC = 1`, [
type,
])
.then((rows) => rows.map(dbMapping.map.package))
}
/**
Expand All @@ -150,7 +163,7 @@ async function getPackagesByCategoryAndType(db, type, category = '') {
return dbApi
.dbAll(
db,
`${querySelectFromPackage} WHERE TYPE = ? AND (CATEGORY IN (${category}) OR CATEGORY IS NULL)`,
`${querySelectFromPackage} WHERE IS_IN_SYNC = 1 AND TYPE = ? AND (CATEGORY IN (${category}) OR CATEGORY IS NULL)`,
[type]
)
.then((rows) => rows.map(dbMapping.map.package))
Expand Down Expand Up @@ -231,16 +244,20 @@ async function getPackageRefByAttributeId(db, attributeId) {
* @returns Promise resolving with a CRC or null.
*/
async function getPathCrc(db, path) {
return dbApi.dbGet(db, 'SELECT CRC FROM PACKAGE WHERE PATH = ?', [path]).then(
(row) =>
new Promise((resolve, reject) => {
if (row == null) {
resolve(null)
} else {
resolve(row.CRC)
}
})
)
return dbApi
.dbGet(db, 'SELECT CRC FROM PACKAGE WHERE PATH = ? AND IS_IN_SYNC = 1', [
path,
])
.then(
(row) =>
new Promise((resolve, reject) => {
if (row == null) {
resolve(null)
} else {
resolve(row.CRC)
}
})
)
}

/**
Expand Down Expand Up @@ -300,10 +317,11 @@ async function registerTopLevelPackage(
type,
version = null,
category = null,
description = null
description = null,
isTopLevelPackageInSync = true
) {
let row = await getPackageByPathAndType(db, path, type)
if (row == null) {
if (row == null || !isTopLevelPackageInSync) {
// Doesn't exist. We have to add it.
let id = await dbApi.dbInsert(
db,
Expand Down Expand Up @@ -339,7 +357,22 @@ async function updatePathCrc(db, path, crc, parentId) {
return dbApi.dbUpdate(
db,
'UPDATE PACKAGE SET CRC = ? WHERE PATH = ? AND PARENT_PACKAGE_REF = ?',
[path, crc, parentId]
[crc, path, parentId]
)
}

/**
* Updates a is in sync in the package table.
* @param {*} db
* @param {*} packageRef
* @param {*} isInSync
* @returns Promise of an update.
*/
async function updatePackageIsInSync(db, packageRef, isInSync) {
return dbApi.dbUpdate(
db,
'UPDATE PACKAGE SET IS_IN_SYNC = ? WHERE PACKAGE_ID = ?',
[dbApi.toDbBool(isInSync), packageRef]
)
}

Expand Down Expand Up @@ -650,8 +683,10 @@ async function getAllPackages(db) {
CATEGORY,
DESCRIPTION,
PARENT_PACKAGE_REF
FROM
PACKAGE`
FROM
PACKAGE
WHERE
IS_IN_SYNC = 1`
)
.then((rows) => rows.map(dbMapping.map.package))
}
Expand Down Expand Up @@ -1117,3 +1152,4 @@ exports.insertSessionKeyValuesFromPackageDefaults =
exports.getPackagesByCategoryAndType = getPackagesByCategoryAndType
exports.getPackagesByPackageIds = getPackagesByPackageIds
exports.getPackageByPathAndType = getPackageByPathAndType
exports.updatePackageIsInSync = updatePackageIsInSync
1 change: 1 addition & 0 deletions src-electron/db/zap-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ CREATE TABLE "PACKAGE" (
"VERSION" integer,
"CATEGORY" text,
"DESCRIPTION" text,
"IS_IN_SYNC" boolean default 1,
foreign key (PARENT_PACKAGE_REF) references PACKAGE(PACKAGE_ID) ON DELETE CASCADE ON UPDATE CASCADE
);
/*
Expand Down
3 changes: 2 additions & 1 deletion src-electron/generator/generation-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ async function recordTemplatesPackage(context) {
dbEnum.packageType.genTemplatesJson,
context.templateData.version,
context.templateData.category,
context.templateData.description
context.templateData.description,
true
)
context.packageId = topLevel.id
if (topLevel.existedPreviously) return context
Expand Down
8 changes: 8 additions & 0 deletions src-electron/util/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ export function builtinSilabsZclMetafile() {
return locateProjectResource('./zcl-builtin/silabs/zcl.json')
}

/**
*
* @returns path to general.xml file
*/
export function builtinSilabsZclGeneralXmlFile() {
return locateProjectResource('./zcl-builtin/silabs/general.xml')
}

export function builtinMatterZclMetafile() {
return locateProjectResource('./zcl-builtin/matter/zcl.json')
}
Expand Down
75 changes: 70 additions & 5 deletions src-electron/zcl/zcl-loader-silabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1983,6 +1983,55 @@ async function parseSingleZclFile(db, packageId, file, context) {
}
}

/**
* Checks if there is a crc mismatch on any xml file. This can be used to
* decide if there is a need to reload all the xml files. Also check if the
* package is not loaded before.
* @param {*} db
* @param {*} packageId
* @param {*} files
* @returns the status of crc mismatch and whether a package is present in an
* object
*/
async function isCrcMismatchOrPackageDoesNotExist(db, packageId, files) {
let packagesNotFound = 0
let packagesFound = 0
let result = { isCrcMismatch: false, areSomePackagesNotLoaded: false }
for (let file of files) {
let fileContent = await fsp.readFile(file)
let filePath = file
let actualCrc = util.checksum(fileContent)

let pkg = await queryPackage.getPackageByPathAndParent(
db,
filePath,
packageId,
false
)

if (pkg != null && pkg.crc != actualCrc) {
env.logDebug(
`CRC missmatch for file ${pkg.path}, (${pkg.crc} vs ${actualCrc}) package id ${pkg.id}, parsing.
Mismatch with package id: ${packageId}`
)
result.isCrcMismatch = true
return result
} else if (pkg == null) {
// This is executed if there is no CRC in the database.
packagesNotFound++
env.logDebug(
`No CRC in the database for file ${filePath}. Package needs to be loaded`
)
} else if (pkg != null && pkg.crc == actualCrc) {
packagesFound++
}
}
result.areSomePackagesNotLoaded = !(
packagesNotFound == files.length || packagesFound == files.length
)
return result
}

/**
*
* Promises to iterate over all the XML files and returns an aggregate promise
Expand Down Expand Up @@ -2473,18 +2522,34 @@ async function loadZclJsonOrProperties(db, metafile, isJson = false) {

try {
Object.assign(ctx, await util.readFileContentAndCrc(ctx.metadataFile))
ctx.packageId = await zclLoader.recordToplevelPackage(
db,
ctx.metadataFile,
ctx.crc
)
let ret
if (isJson) {
ret = await collectDataFromJsonFile(ctx.metadataFile, ctx.data)
} else {
ret = await collectDataFromPropertiesFile(ctx.metadataFile, ctx.data)
}
Object.assign(ctx, ret)
ctx.packageId = await zclLoader.recordToplevelPackage(
db,
ctx.metadataFile,
ctx.crc,
true
)
let packageStatus = await isCrcMismatchOrPackageDoesNotExist(
db,
ctx.packageId,
ctx.zclFiles
)
if (packageStatus.isCrcMismatch || packageStatus.areSomePackagesNotLoaded) {
await queryPackage.updatePackageIsInSync(db, ctx.packageId, 0)
ctx.packageId = await zclLoader.recordToplevelPackage(
db,
ctx.metadataFile,
ctx.crc,
false
)
}

if (
ctx.version != null ||
ctx.category != null ||
Expand Down
15 changes: 13 additions & 2 deletions src-electron/zcl/zcl-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,24 @@ const queryNotification = require('../db/query-session-notification')
* @param {*} db
* @param {*} metadataFile
* @param {*} crc
* @param {*} isTopLevelPackageInSync
* @returns packageId
*/
async function recordToplevelPackage(db, metadataFile, crc) {
async function recordToplevelPackage(
db,
metadataFile,
crc,
isTopLevelPackageInSync
) {
let topLevel = await queryPackage.registerTopLevelPackage(
db,
metadataFile,
crc,
dbEnum.packageType.zclProperties
dbEnum.packageType.zclProperties,
null,
null,
null,
isTopLevelPackageInSync
)
return topLevel.id
}
Expand Down Expand Up @@ -269,6 +279,7 @@ async function loadIndividualFile(db, filePath, sessionId) {
* @param {*} db
* @param {*} info
* @param {*} parentPackageId
* @param {*} isCustom
* @returns Promise that resolves int he object of data.
*/
async function qualifyZclFile(
Expand Down
45 changes: 45 additions & 0 deletions test/zcl-loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const env = require('../src-electron/util/env')
const types = require('../src-electron/util/types')
const testUtil = require('./test-util')
const testQuery = require('./test-query')
const fs = require('fs')

beforeAll(async () => {
env.setDevelopmentEnv()
Expand Down Expand Up @@ -188,6 +189,50 @@ test(
`Found Non Unique Enum in Silabs XML: ${c.NAME} ${c.TYPE} ${c.PACKAGE_REF}`
)
})

// Test Reloading of the zcl packages when an xml file changes
// (Simulating a gsdk upgrade from one branch to another which can change xml files)
// Step 1: Modify one of the xml files
let xmlFilePath = env.builtinSilabsZclGeneralXmlFile()
let originalString =
'<attribute side="server" code="0x0001" define="APPLICATION_VERSION" type="INT8U" min="0x00" max="0xFF" writable="false" default="0x00" optional="true">application version</attribute>'
let editString =
'<attribute side="server" code="0x0001" define="APPLICATION_VERSION" type="INT8U" min="0x00" max="0xFF" writable="false" default="0x01" optional="true">application version</attribute>'
let generalXmlFileOriginalContent = fs.readFileSync(xmlFilePath, 'utf8')
let generalXmlFileUpdatedContent = generalXmlFileOriginalContent.replace(
originalString,
editString
)
fs.writeFileSync(xmlFilePath, generalXmlFileUpdatedContent, 'utf8')

// Step 2: This will cause the all zcl packages from top level to all its
// children to be reloaded. Check for 2 top level packages with same path now.
// Count packages belonging to each top level package to make sure all packages
// are reloaded
ctx = await zclLoader.loadZcl(db, env.builtinSilabsZclMetafile())
let newPackageId = ctx.packageId
// Making sure the top level packages do not have the same packageId
expect(packageId).not.toEqual(newPackageId)
let oldPackages = await dbApi.dbAll(
db,
`SELECT * FROM PACKAGE WHERE PARENT_PACKAGE_REF = ${packageId}`
)
let newPackages = await dbApi.dbAll(
db,
`SELECT * FROM PACKAGE WHERE PARENT_PACKAGE_REF = ${newPackageId}`
)
// Making sure all packages are loaded again
expect(oldPackages.length).toEqual(newPackages.length)

let topLevelZclPackages = await dbApi.dbAll(
db,
`SELECT * FROM PACKAGE WHERE TYPE = '${dbEnum.packageType.zclProperties}' ORDER BY PACKAGE_ID`
)
expect(topLevelZclPackages[0].IS_IN_SYNC).toEqual(0)
expect(topLevelZclPackages[1].IS_IN_SYNC).toEqual(1)

// Step 3: Revert the xml file change in step 1.
fs.writeFileSync(xmlFilePath, generalXmlFileOriginalContent, 'utf8')
} finally {
await dbApi.closeDatabase(db)
}
Expand Down
Loading
Loading