mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-24 22:48:06 +00:00
795d083264
* feat(datasource): add APK datasource support * remove missing manager link for now * lint docs * update tests * replace binary fixtures * fix coverage * Update lib/modules/datasource/apk/readme.md Co-authored-by: Jamie Tanna <github@jamietanna.co.uk> * Apply suggestion from @viceice Co-authored-by: Michael Kriese <michael.kriese@gmx.de> * use tar instead of tar-stream * use codeBlock * add ignore back * make method private * use an async extract instead of list * add usage example * stream apkindex download and parse line-by-line * refactor(datasource): address review comments on APK datasource Co-authored-by: Cursor <cursoragent@cursor.com> * chore: sync pnpm-lock.yaml after merge Co-authored-by: Cursor <cursoragent@cursor.com> * test: remove ignored lines As they seem to be covered, anyway. * fixup! Merge remote-tracking branch 'origin/HEAD' into apk-datasource * fixup! fixup! Merge remote-tracking branch 'origin/HEAD' into apk-datasource * lint: use `node:` prefix * Update lib/modules/datasource/apk/index.ts Co-authored-by: Michael Kriese <michael.kriese@gmx.de> * refactor(datasource/apk): use asTimestamp millis instead of new Date Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(datasource/apk): rename uncached method to _getPackages Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(datasource/apk): encode registry URL parts as query parameters Co-authored-by: Cursor <cursoragent@cursor.com> * fix(datasource/apk): reject invalid registry URLs, skip caching empty indexes Co-authored-by: Cursor <cursoragent@cursor.com> * fix(datasource/apk): throw on unparseable registry URL and drop unset sourceUrl support Co-authored-by: Cursor <cursoragent@cursor.com> * docs(datasource/apk): show how registry URL parameters build the index URLs Co-authored-by: Cursor <cursoragent@cursor.com> * Apply suggestions from code review Co-authored-by: RahulGautamSingh <rahultesnik@gmail.com> * fix(datasource/apk): keep credentials and port in component URLs Co-authored-by: Cursor <cursoragent@cursor.com> * fix(datasource/apk): extract APKINDEX by basename and key packages by name Co-authored-by: Cursor <cursoragent@cursor.com> * fix(datasource/apk): report a version served by two components only once Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Jamie Tanna <github@jamietanna.co.uk> Co-authored-by: Michael Kriese <michael.kriese@gmx.de> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Jamie Tanna <jamie.tanna@mend.io> Co-authored-by: RahulGautamSingh <rahultesnik@gmail.com>
89 lines
2.2 KiB
TypeScript
89 lines
2.2 KiB
TypeScript
import readline from 'node:readline';
|
|
import is from '@sindresorhus/is';
|
|
import { logger } from '../../../logger/index.ts';
|
|
import * as fs from '../../../util/fs/index.ts';
|
|
import type { ApkPackage } from './types.ts';
|
|
|
|
function applyApkIndexLine(
|
|
line: string,
|
|
packageInfo: Partial<ApkPackage>,
|
|
): void {
|
|
const colonIndex = line.indexOf(':');
|
|
if (colonIndex === -1) {
|
|
return;
|
|
}
|
|
|
|
// get fields based on the PKGINFO spec - https://wiki.alpinelinux.org/wiki/Apk_spec
|
|
const key = line.substring(0, colonIndex);
|
|
const value = line.substring(colonIndex + 1).trim();
|
|
|
|
switch (key) {
|
|
case 'P':
|
|
packageInfo.name = value;
|
|
break;
|
|
case 'V':
|
|
packageInfo.version = value;
|
|
break;
|
|
case 'U':
|
|
packageInfo.url = value;
|
|
break;
|
|
case 't':
|
|
packageInfo.buildDate = parseInt(value, 10);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
function flushApkPackage(packageInfo: Partial<ApkPackage>): ApkPackage | null {
|
|
if (packageInfo.name && packageInfo.version) {
|
|
return packageInfo as ApkPackage;
|
|
}
|
|
if (is.nonEmptyObject(packageInfo)) {
|
|
logger.warn(
|
|
{ packageInfo },
|
|
'Skipping package entry due to missing required fields',
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Parses an APK index file line-by-line to avoid loading large indexes into memory.
|
|
*
|
|
* @param extractedFile - Path to the extracted `APKINDEX` file (relative to Renovate cache).
|
|
*/
|
|
export async function parseApkIndexFile(
|
|
extractedFile: string,
|
|
): Promise<ApkPackage[]> {
|
|
logger.debug(`Parsing APK index file ${extractedFile}`);
|
|
|
|
const packages: ApkPackage[] = [];
|
|
const rl = readline.createInterface({
|
|
input: fs.createCacheReadStream(extractedFile),
|
|
terminal: false,
|
|
});
|
|
|
|
let packageInfo: Partial<ApkPackage> = {};
|
|
|
|
for await (const line of rl) {
|
|
if (line === '') {
|
|
const pkg = flushApkPackage(packageInfo);
|
|
if (pkg) {
|
|
packages.push(pkg);
|
|
}
|
|
packageInfo = {};
|
|
} else {
|
|
applyApkIndexLine(line, packageInfo);
|
|
}
|
|
}
|
|
|
|
const last = flushApkPackage(packageInfo);
|
|
if (last) {
|
|
packages.push(last);
|
|
}
|
|
|
|
logger.debug(`Parsed ${packages.length} packages from APK index`);
|
|
return packages;
|
|
}
|