UNPKG

appium-chromedriver

Version:
173 lines 6.81 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.findChildNode = findChildNode; exports.parseNotes = parseNotes; exports.parseGoogleapiStorageXml = parseGoogleapiStorageXml; const xpath_1 = require("xpath"); const support_1 = require("@appium/support"); const utils_1 = require("../utils"); const asyncbox_1 = require("asyncbox"); const constants_1 = require("../constants"); const xmldom_1 = require("@xmldom/xmldom"); const node_path_1 = __importDefault(require("node:path")); const log = support_1.logger.getLogger('ChromedriverGoogleapisStorageClient'); const MAX_PARALLEL_DOWNLOADS = 5; /** * Finds a child node in an XML node by name and/or text content * * @param parent - The parent XML node to search in * @param childName - Optional child node name to match * @param text - Optional text content to match * @returns The matching child node or null if not found */ function findChildNode(parent, childName = null, text = null) { if (!childName && !text) { return null; } if (!parent.hasChildNodes()) { return null; } for (let childNodeIdx = 0; childNodeIdx < parent.childNodes.length; childNodeIdx++) { const childNode = parent.childNodes[childNodeIdx]; if (childName && !text && childName === childNode.localName) { return childNode; } if (text) { const childText = extractNodeText(childNode); if (!childText) { continue; } if (childName && childName === childNode.localName && text === childText) { return childNode; } if (!childName && text === childText) { return childNode; } } } return null; } /** * Gets additional chromedriver details from chromedriver * release notes * * @param content - Release notes of the corresponding chromedriver * @returns AdditionalDriverDetails */ function parseNotes(content) { const result = {}; const versionMatch = /^\s*[-]+ChromeDriver[\D]+([\d.]+)/im.exec(content); if (versionMatch) { result.version = versionMatch[1]; } const minBrowserVersionMatch = /^\s*Supports Chrome[\D]+(\d+)/im.exec(content); if (minBrowserVersionMatch) { result.minBrowserVersion = minBrowserVersionMatch[1]; } return result; } /** * Parses chromedriver storage XML and returns * the parsed results * * @param xml - The chromedriver storage XML * @param shouldParseNotes [true] - If set to `true` * then additional drivers information is going to be parsed * and assigned to `this.mapping` * @returns Promise<ChromedriverDetailsMapping> */ async function parseGoogleapiStorageXml(xml, shouldParseNotes = true) { const doc = new xmldom_1.DOMParser().parseFromString(xml, 'text/xml'); const driverNodes = (0, xpath_1.select)(`//*[local-name(.)='Contents']`, doc); log.debug(`Parsed ${driverNodes.length} entries from storage XML`); if (driverNodes.length === 0) { throw new Error('Cannot retrieve any valid Chromedriver entries from the storage config'); } const infoParsers = []; const mapping = {}; for (const driverNode of driverNodes) { const k = extractNodeText(findChildNode(driverNode, 'Key')); if (!String(k).includes('/chromedriver_')) { continue; } const key = String(k); const versionSegment = key.split('/')[0]; if (!versionSegment) { continue; } const etag = extractNodeText(findChildNode(driverNode, 'ETag')); if (!etag) { log.debug(`The entry '${key}' does not contain the checksum. Skipping it`); continue; } const filename = node_path_1.default.basename(key); const osNameMatch = /_([a-z]+)/i.exec(filename); if (!osNameMatch) { log.debug(`The entry '${key}' does not contain valid OS name. Skipping it`); continue; } const cdInfo = { url: `${constants_1.GOOGLEAPIS_CDN}/${key}`, etag: etag.replace(/^"+|"+$/g, ''), version: versionSegment, minBrowserVersion: null, os: { name: osNameMatch[1], arch: filename.includes(constants_1.ARCH.X64) ? constants_1.ARCH.X64 : constants_1.ARCH.X86, cpu: constants_1.APPLE_ARM_SUFFIXES.some((suffix) => filename.includes(suffix)) ? constants_1.CPU.ARM : constants_1.CPU.INTEL, }, }; mapping[key] = cdInfo; const notesPath = `${cdInfo.version}/notes.txt`; const isNotesPresent = !!driverNodes.reduce((acc, node) => Boolean(acc || findChildNode(node, 'Key', notesPath)), false); if (!isNotesPresent) { cdInfo.minBrowserVersion = null; if (shouldParseNotes) { log.info(`The entry '${key}' does not contain any notes. Skipping it`); } continue; } else if (!shouldParseNotes) { continue; } infoParsers.push(async () => { await retrieveAdditionalDriverInfo(key, `${constants_1.GOOGLEAPIS_CDN}/${notesPath}`, cdInfo); }); } await (0, asyncbox_1.asyncmap)(infoParsers, async (parseInfo) => { await parseInfo(); }, { concurrency: MAX_PARALLEL_DOWNLOADS }); log.info(`The total count of entries in the mapping: ${Object.keys(mapping).length}`); return mapping; } /** * Downloads chromedriver release notes and updates the driver info dictionary * * Mutates `infoDict` by setting `minBrowserVersion` if found in notes * @param driverKey - Driver version plus archive name * @param notesUrl - The URL of chromedriver notes * @param infoDict - The dictionary containing driver info (will be mutated) * @param timeout - Request timeout in milliseconds */ async function retrieveAdditionalDriverInfo(driverKey, notesUrl, infoDict, timeout = constants_1.STORAGE_REQ_TIMEOUT_MS) { const notes = await (0, utils_1.retrieveData)(notesUrl, { 'user-agent': 'appium', accept: '*/*', }, { timeout }); const { minBrowserVersion } = parseNotes(notes); if (!minBrowserVersion) { log.debug(`The driver '${driverKey}' does not contain valid release notes at ${notesUrl}. ` + `Skipping it`); return; } infoDict.minBrowserVersion = minBrowserVersion; } function extractNodeText(node) { return !node?.firstChild || !support_1.util.hasValue(node.firstChild.nodeValue) ? null : node.firstChild.nodeValue; } //# sourceMappingURL=googleapis.js.map