mirror of
https://github.com/Koenkk/zigbee-OTA.git
synced 2026-10-08 20:07:07 +00:00
fix: Switch to biome & vitest (#726)
This commit is contained in:
+80
-74
@@ -1,28 +1,28 @@
|
||||
import type {ExtraMetas, ExtraMetasWithFileName, ImageHeader, RepoImageMeta} from './types';
|
||||
import type {ExtraMetas, ExtraMetasWithFileName, ImageHeader, RepoImageMeta} from "./types";
|
||||
|
||||
import assert from 'assert';
|
||||
import {exec} from 'child_process';
|
||||
import {createHash} from 'crypto';
|
||||
import {existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync} from 'fs';
|
||||
import path from 'path';
|
||||
import assert from "node:assert";
|
||||
import {exec} from "node:child_process";
|
||||
import {createHash} from "node:crypto";
|
||||
import {existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync} from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
export const UPGRADE_FILE_IDENTIFIER = Buffer.from([0x1e, 0xf1, 0xee, 0x0b]);
|
||||
export const BASE_REPO_URL = `https://raw.githubusercontent.com/Koenkk/zigbee-OTA/`;
|
||||
export const REPO_BRANCH = 'master';
|
||||
export const BASE_REPO_URL = "https://raw.githubusercontent.com/Koenkk/zigbee-OTA/";
|
||||
export const REPO_BRANCH = "master";
|
||||
/** Images used by OTA upgrade process */
|
||||
export const BASE_IMAGES_DIR = 'images';
|
||||
export const BASE_IMAGES_DIR = "images";
|
||||
/** Images used by OTA downgrade process */
|
||||
export const PREV_IMAGES_DIR = 'images1';
|
||||
export const PREV_IMAGES_DIR = "images1";
|
||||
/** Manifest used by OTA upgrade process */
|
||||
export const BASE_INDEX_MANIFEST_FILENAME = 'index.json';
|
||||
export const BASE_INDEX_MANIFEST_FILENAME = "index.json";
|
||||
/** Manifest used by OTA downgrade process */
|
||||
export const PREV_INDEX_MANIFEST_FILENAME = 'index1.json';
|
||||
export const CACHE_DIR = '.cache';
|
||||
export const TMP_DIR = 'tmp';
|
||||
export const PR_ARTIFACT_DIR = 'pr';
|
||||
export const PR_DIFF_FILENAME = 'PR_DIFF';
|
||||
export const PR_ERROR_FILENAME = 'PR_ERROR';
|
||||
export const PR_NUMBER_FILENAME = 'PR_NUMBER';
|
||||
export const PREV_INDEX_MANIFEST_FILENAME = "index1.json";
|
||||
export const CACHE_DIR = ".cache";
|
||||
export const TMP_DIR = "tmp";
|
||||
export const PR_ARTIFACT_DIR = "pr";
|
||||
export const PR_DIFF_FILENAME = "PR_DIFF";
|
||||
export const PR_ERROR_FILENAME = "PR_ERROR";
|
||||
export const PR_NUMBER_FILENAME = "PR_NUMBER";
|
||||
export const PR_ARTIFACT_DIFF_FILEPATH = path.join(PR_ARTIFACT_DIR, PR_DIFF_FILENAME);
|
||||
export const PR_ARTIFACT_ERROR_FILEPATH = path.join(PR_ARTIFACT_DIR, PR_ERROR_FILENAME);
|
||||
export const PR_ARTIFACT_NUMBER_FILEPATH = path.join(PR_ARTIFACT_DIR, PR_NUMBER_FILENAME);
|
||||
@@ -30,17 +30,17 @@ export const PR_ARTIFACT_NUMBER_FILEPATH = path.join(PR_ARTIFACT_DIR, PR_NUMBER_
|
||||
* 'ikea_new' first, to prioritize downloads from new URL
|
||||
*/
|
||||
export const ALL_AUTODL_MANUFACTURERS = [
|
||||
'gammatroniques',
|
||||
'hue',
|
||||
'ikea_new',
|
||||
'ikea',
|
||||
'inovelli',
|
||||
'jethome',
|
||||
'ledvance',
|
||||
'lixee',
|
||||
'salus',
|
||||
'ubisys',
|
||||
'xyzroe',
|
||||
"gammatroniques",
|
||||
"hue",
|
||||
"ikea_new",
|
||||
"ikea",
|
||||
"inovelli",
|
||||
"jethome",
|
||||
"ledvance",
|
||||
"lixee",
|
||||
"salus",
|
||||
"ubisys",
|
||||
"xyzroe",
|
||||
];
|
||||
|
||||
export async function execute(command: string): Promise<string> {
|
||||
@@ -60,11 +60,11 @@ export function primitivesArrayEquals(a: (string | number | boolean)[], b: (stri
|
||||
}
|
||||
|
||||
export function computeSHA512(buffer: Buffer): string {
|
||||
const hash = createHash('sha512');
|
||||
const hash = createHash("sha512");
|
||||
|
||||
hash.update(buffer);
|
||||
|
||||
return hash.digest('hex');
|
||||
return hash.digest("hex");
|
||||
}
|
||||
|
||||
export function getOutDir(folderName: string, basePath: string = BASE_IMAGES_DIR): string {
|
||||
@@ -82,21 +82,21 @@ export function getRepoFirmwareFileUrl(folderName: string, fileName: string, bas
|
||||
}
|
||||
|
||||
export function writeManifest(fileName: string, firmwareList: RepoImageMeta[]): void {
|
||||
writeFileSync(fileName, JSON.stringify(firmwareList, undefined, 2), 'utf8');
|
||||
writeFileSync(fileName, JSON.stringify(firmwareList, undefined, 2), "utf8");
|
||||
}
|
||||
|
||||
export function readManifest(fileName: string): RepoImageMeta[] {
|
||||
return JSON.parse(readFileSync(fileName, 'utf8'));
|
||||
return JSON.parse(readFileSync(fileName, "utf8"));
|
||||
}
|
||||
|
||||
export function writeCacheJson<T>(fileName: string, contents: T, basePath: string = CACHE_DIR): void {
|
||||
writeFileSync(path.join(basePath, `${fileName}.json`), JSON.stringify(contents), 'utf8');
|
||||
writeFileSync(path.join(basePath, `${fileName}.json`), JSON.stringify(contents), "utf8");
|
||||
}
|
||||
|
||||
export function readCacheJson<T>(fileName: string, basePath: string = CACHE_DIR): T | undefined {
|
||||
const filePath = path.join(basePath, `${fileName}.json`);
|
||||
|
||||
return existsSync(filePath) ? JSON.parse(readFileSync(filePath, 'utf8')) : undefined;
|
||||
return existsSync(filePath) ? JSON.parse(readFileSync(filePath, "utf8")) : undefined;
|
||||
}
|
||||
|
||||
export function parseImageHeader(buffer: Buffer): ImageHeader {
|
||||
@@ -110,7 +110,7 @@ export function parseImageHeader(buffer: Buffer): ImageHeader {
|
||||
imageType: buffer.readUInt16LE(12),
|
||||
fileVersion: buffer.readUInt32LE(14),
|
||||
zigbeeStackVersion: buffer.readUInt16LE(18),
|
||||
otaHeaderString: buffer.toString('utf8', 20, 52),
|
||||
otaHeaderString: buffer.toString("utf8", 20, 52),
|
||||
totalImageSize: buffer.readUInt32LE(52),
|
||||
};
|
||||
let headerPos = 56;
|
||||
@@ -132,7 +132,7 @@ export function parseImageHeader(buffer: Buffer): ImageHeader {
|
||||
headerPos += 2;
|
||||
}
|
||||
|
||||
assert(UPGRADE_FILE_IDENTIFIER.equals(header.otaUpgradeFileIdentifier), `Invalid upgrade file identifier`);
|
||||
assert(UPGRADE_FILE_IDENTIFIER.equals(header.otaUpgradeFileIdentifier), "Invalid upgrade file identifier");
|
||||
|
||||
return header;
|
||||
} catch (error) {
|
||||
@@ -199,25 +199,27 @@ export function getLatestImage<T>(list: T[] | undefined, compareFn: (a: T, b: T)
|
||||
return sortedList.slice(0, sortedList.length > 1 && process.env.PREV ? -1 : undefined).pop();
|
||||
}
|
||||
|
||||
export const enum ParsedImageStatus {
|
||||
NEW = 0,
|
||||
NEWER = 1,
|
||||
OLDER = 2,
|
||||
IDENTICAL = 3,
|
||||
export enum ParsedImageStatus {
|
||||
New = 0,
|
||||
Newer = 1,
|
||||
Older = 2,
|
||||
Identical = 3,
|
||||
}
|
||||
|
||||
export function getParsedImageStatus(parsedImage: ImageHeader, match?: RepoImageMeta): ParsedImageStatus {
|
||||
if (match) {
|
||||
if (match.fileVersion > parsedImage.fileVersion) {
|
||||
return ParsedImageStatus.OLDER;
|
||||
} else if (match.fileVersion < parsedImage.fileVersion) {
|
||||
return ParsedImageStatus.NEWER;
|
||||
} else {
|
||||
return ParsedImageStatus.IDENTICAL;
|
||||
return ParsedImageStatus.Older;
|
||||
}
|
||||
} else {
|
||||
return ParsedImageStatus.NEW;
|
||||
|
||||
if (match.fileVersion < parsedImage.fileVersion) {
|
||||
return ParsedImageStatus.Newer;
|
||||
}
|
||||
|
||||
return ParsedImageStatus.Identical;
|
||||
}
|
||||
|
||||
return ParsedImageStatus.New;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,8 +233,8 @@ export function getValidMetas(metas: Partial<ExtraMetas & ExtraMetasWithFileName
|
||||
const validMetas: ExtraMetasWithFileName = {};
|
||||
|
||||
if (!ignoreFileName) {
|
||||
if (metas.fileName != undefined) {
|
||||
if (typeof metas.fileName != 'string') {
|
||||
if (metas.fileName != null) {
|
||||
if (typeof metas.fileName !== "string") {
|
||||
throw new Error(`Invalid format for 'fileName', expected 'string' type.`);
|
||||
}
|
||||
|
||||
@@ -240,72 +242,76 @@ export function getValidMetas(metas: Partial<ExtraMetas & ExtraMetasWithFileName
|
||||
}
|
||||
}
|
||||
|
||||
if (metas.originalUrl != undefined) {
|
||||
if (typeof metas.originalUrl != 'string') {
|
||||
if (metas.originalUrl != null) {
|
||||
if (typeof metas.originalUrl !== "string") {
|
||||
throw new Error(`Invalid format for 'originalUrl', expected 'string' type.`);
|
||||
}
|
||||
|
||||
validMetas.originalUrl = metas.originalUrl;
|
||||
}
|
||||
|
||||
if (metas.force != undefined) {
|
||||
if (typeof metas.force != 'boolean') {
|
||||
if (metas.force != null) {
|
||||
if (typeof metas.force !== "boolean") {
|
||||
throw new Error(`Invalid format for 'force', expected 'boolean' type.`);
|
||||
}
|
||||
|
||||
validMetas.force = metas.force;
|
||||
}
|
||||
|
||||
if (metas.hardwareVersionMax != undefined) {
|
||||
if (typeof metas.hardwareVersionMax != 'number') {
|
||||
if (metas.hardwareVersionMax != null) {
|
||||
if (typeof metas.hardwareVersionMax !== "number") {
|
||||
throw new Error(`Invalid format for 'hardwareVersionMax', expected 'number' type.`);
|
||||
}
|
||||
|
||||
validMetas.hardwareVersionMax = metas.hardwareVersionMax;
|
||||
}
|
||||
|
||||
if (metas.hardwareVersionMin != undefined) {
|
||||
if (typeof metas.hardwareVersionMin != 'number') {
|
||||
if (metas.hardwareVersionMin != null) {
|
||||
if (typeof metas.hardwareVersionMin !== "number") {
|
||||
throw new Error(`Invalid format for 'hardwareVersionMin', expected 'number' type.`);
|
||||
}
|
||||
|
||||
validMetas.hardwareVersionMin = metas.hardwareVersionMin;
|
||||
}
|
||||
|
||||
if (metas.manufacturerName != undefined) {
|
||||
if (!Array.isArray(metas.manufacturerName) || metas.manufacturerName.length < 1 || metas.manufacturerName.some((m) => typeof m != 'string')) {
|
||||
if (metas.manufacturerName != null) {
|
||||
if (
|
||||
!Array.isArray(metas.manufacturerName) ||
|
||||
metas.manufacturerName.length < 1 ||
|
||||
metas.manufacturerName.some((m) => typeof m !== "string")
|
||||
) {
|
||||
throw new Error(`Invalid format for 'manufacturerName', expected 'array of string' type.`);
|
||||
}
|
||||
|
||||
validMetas.manufacturerName = metas.manufacturerName;
|
||||
}
|
||||
|
||||
if (metas.maxFileVersion != undefined) {
|
||||
if (typeof metas.maxFileVersion != 'number') {
|
||||
if (metas.maxFileVersion != null) {
|
||||
if (typeof metas.maxFileVersion !== "number") {
|
||||
throw new Error(`Invalid format for 'maxFileVersion', expected 'number' type.`);
|
||||
}
|
||||
|
||||
validMetas.maxFileVersion = metas.maxFileVersion;
|
||||
}
|
||||
|
||||
if (metas.minFileVersion != undefined) {
|
||||
if (typeof metas.minFileVersion != 'number') {
|
||||
if (metas.minFileVersion != null) {
|
||||
if (typeof metas.minFileVersion !== "number") {
|
||||
throw new Error(`Invalid format for 'minFileVersion', expected 'number' type.`);
|
||||
}
|
||||
|
||||
validMetas.minFileVersion = metas.minFileVersion;
|
||||
}
|
||||
|
||||
if (metas.modelId != undefined) {
|
||||
if (typeof metas.modelId != 'string') {
|
||||
if (metas.modelId != null) {
|
||||
if (typeof metas.modelId !== "string") {
|
||||
throw new Error(`Invalid format for 'modelId', expected 'string' type.`);
|
||||
}
|
||||
|
||||
validMetas.modelId = metas.modelId;
|
||||
}
|
||||
|
||||
if (metas.releaseNotes != undefined) {
|
||||
if (typeof metas.releaseNotes != 'string') {
|
||||
if (metas.releaseNotes != null) {
|
||||
if (typeof metas.releaseNotes !== "string") {
|
||||
throw new Error(`Invalid format for 'releaseNotes', expected 'string' type.`);
|
||||
}
|
||||
|
||||
@@ -337,7 +343,7 @@ export function addImageToPrev(
|
||||
prevManifest.splice(prevMatchIndex, 1);
|
||||
|
||||
// make sure fileName exists for migration from old system
|
||||
const prevFileName = prevMatch.fileName ? prevMatch.fileName : prevMatch.url.split('/').pop()!;
|
||||
const prevFileName = prevMatch.fileName ? prevMatch.fileName : prevMatch.url.split("/").pop()!;
|
||||
|
||||
rmSync(path.join(prevOutDir, prevFileName), {force: true});
|
||||
}
|
||||
@@ -380,23 +386,23 @@ export function addImageToBase(
|
||||
const [prevMatchIndex, prevMatch] = findMatchImage(parsedImage, prevManifest, extraMetas);
|
||||
const prevStatus = getParsedImageStatus(parsedImage, prevMatch);
|
||||
|
||||
if (prevStatus !== ParsedImageStatus.OLDER && prevStatus !== ParsedImageStatus.NEW) {
|
||||
if (prevStatus !== ParsedImageStatus.Older && prevStatus !== ParsedImageStatus.New) {
|
||||
console.warn(`${logPrefix} Base image is new/newer but prev image is not older/non-existing.`);
|
||||
}
|
||||
|
||||
if (prevStatus !== ParsedImageStatus.NEW) {
|
||||
if (prevStatus !== ParsedImageStatus.New) {
|
||||
console.log(`${logPrefix} Removing prev image.`);
|
||||
prevManifest.splice(prevMatchIndex, 1);
|
||||
|
||||
// make sure fileName exists for migration from old system
|
||||
const prevFileName = prevMatch!.fileName ? prevMatch!.fileName : prevMatch!.url.split('/').pop()!;
|
||||
const prevFileName = prevMatch!.fileName ? prevMatch!.fileName : prevMatch!.url.split("/").pop()!;
|
||||
|
||||
rmSync(path.join(prevOutDir, prevFileName), {force: true});
|
||||
}
|
||||
|
||||
// relocate base to prev
|
||||
// make sure fileName exists for migration from old system
|
||||
const baseFileName = baseMatch.fileName ? baseMatch.fileName : baseMatch.url.split('/').pop()!;
|
||||
const baseFileName = baseMatch.fileName ? baseMatch.fileName : baseMatch.url.split("/").pop()!;
|
||||
const baseFilePath = path.join(baseOutDir, baseFileName);
|
||||
|
||||
// if for some reason the file is no longer present (should not happen), don't add it to prev since link is broken
|
||||
|
||||
Reference in New Issue
Block a user