From 5a371055b2bff7e5df766b2821a7db255a753e00 Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Sat, 25 Dec 2021 01:47:33 -0800 Subject: [PATCH] Reformat all code with Prettier --- src/blobs/apex.ts | 8 +- src/blobs/build.ts | 34 +++- src/blobs/copy.ts | 2 +- src/blobs/entry.ts | 3 +- src/blobs/file-list.ts | 4 +- src/blobs/overlays.ts | 41 +++-- src/blobs/presigned.ts | 15 +- src/blobs/vintf.ts | 2 +- src/build/make.ts | 16 +- src/build/soong-info.ts | 6 +- src/build/soong.ts | 118 ++++++------ src/commands/check-presigned.ts | 26 ++- src/commands/collect-state.ts | 34 ++-- src/commands/diff-files.ts | 19 +- src/commands/diff-props.ts | 20 +- src/commands/diff-vintf.ts | 19 +- src/commands/download.ts | 46 +++-- src/commands/extract.ts | 17 +- src/commands/fix-certs.ts | 50 +++-- src/commands/generate-all.ts | 295 ++++++++++++++++++------------ src/commands/generate-prep.ts | 124 +++++++------ src/commands/list-files.ts | 14 +- src/commands/resolve-overrides.ts | 24 ++- src/config/device.ts | 5 +- src/config/filters.ts | 11 +- src/config/system-state.ts | 61 +++--- src/frontend/devices.ts | 2 +- src/frontend/generate.ts | 73 ++++---- src/frontend/source.ts | 44 ++--- src/images/download.ts | 16 +- src/selinux/contexts.ts | 6 +- src/selinux/keys.ts | 22 ++- src/selinux/labels.ts | 8 +- src/util/cli.ts | 5 +- src/util/partitions.ts | 25 +-- 35 files changed, 695 insertions(+), 520 deletions(-) diff --git a/src/blobs/apex.ts b/src/blobs/apex.ts index ab7ebf3..5685c4a 100644 --- a/src/blobs/apex.ts +++ b/src/blobs/apex.ts @@ -56,8 +56,9 @@ async function listPayload( // Get SELinux labels let labels = await enumerateSelinuxLabels(mountpoint) // Fix paths - labels = new Map(Array.from(labels.entries()) - .map(([file, context]) => [`/${apexRoot}/${path.relative(mountpoint, file)}`, context])) + labels = new Map( + Array.from(labels.entries()).map(([file, context]) => [`/${apexRoot}/${path.relative(mountpoint, file)}`, context]), + ) return { entries: entries, @@ -126,8 +127,7 @@ export async function flattenAllApexs( // Flatten and add new entries let apex = await flattenApex(entry.partition, apexPath, subTmp, progressCallback) apex.entries.forEach(e => entries.add(e)) - Array.from(apex.labels.entries()) - .forEach(([path, context]) => labels.set(path, context)) + Array.from(apex.labels.entries()).forEach(([path, context]) => labels.set(path, context)) // Remove the APEX blob entry entries.delete(entry) diff --git a/src/blobs/build.ts b/src/blobs/build.ts index 4176a57..5ba9944 100644 --- a/src/blobs/build.ts +++ b/src/blobs/build.ts @@ -1,8 +1,30 @@ import path from 'path' import { promises as fs } from 'fs' -import { blobToFileCopy, BoardMakefile, ModulesMakefile, DeviceMakefile, sanitizeBasename, serializeBoardMakefile, serializeModulesMakefile, serializeDeviceMakefile, Symlink, ProductsMakefile, ProductMakefile, serializeProductMakefile, serializeProductsMakefile } from '../build/make' -import { blobToSoongModule, serializeBlueprint, SharedLibraryModule, SoongBlueprint, SoongModule, SPECIAL_FILE_EXTENSIONS, TYPE_SHARED_LIBRARY } from '../build/soong' +import { + blobToFileCopy, + BoardMakefile, + ModulesMakefile, + DeviceMakefile, + sanitizeBasename, + serializeBoardMakefile, + serializeModulesMakefile, + serializeDeviceMakefile, + Symlink, + ProductsMakefile, + ProductMakefile, + serializeProductMakefile, + serializeProductsMakefile, +} from '../build/make' +import { + blobToSoongModule, + serializeBlueprint, + SharedLibraryModule, + SoongBlueprint, + SoongModule, + SPECIAL_FILE_EXTENSIONS, + TYPE_SHARED_LIBRARY, +} from '../build/soong' import { BlobEntry, blobNeedsSoong } from './entry' export interface BuildFiles { @@ -84,9 +106,11 @@ export async function generateBuild( let needsMakeFallback = false if (namedModules.has(name)) { let conflictModule = namedModules.get(name)! - if (conflictModule._type == TYPE_SHARED_LIBRARY && - (conflictModule as SharedLibraryModule).compile_multilib == 'both' && - conflictModule._entry?.path.split('/').at(-1) == pathParts.at(-1)) { + if ( + conflictModule._type == TYPE_SHARED_LIBRARY && + (conflictModule as SharedLibraryModule).compile_multilib == 'both' && + conflictModule._entry?.path.split('/').at(-1) == pathParts.at(-1) + ) { // Same partition = skip arch variant if (conflictModule._entry?.partition == entry.partition) { continue diff --git a/src/blobs/copy.ts b/src/blobs/copy.ts index 7932304..c3daa1c 100644 --- a/src/blobs/copy.ts +++ b/src/blobs/copy.ts @@ -20,7 +20,7 @@ export async function copyBlobs(entries: Iterable, srcDir: string, de } // Create directory structure - await fs.mkdir(path.dirname(outPath), {recursive: true}) + await fs.mkdir(path.dirname(outPath), { recursive: true }) // Some files need patching if (entry.path.endsWith('.xml')) { diff --git a/src/blobs/entry.ts b/src/blobs/entry.ts index 08e7216..4dc99da 100644 --- a/src/blobs/entry.ts +++ b/src/blobs/entry.ts @@ -60,8 +60,7 @@ export function blobNeedsSoong(entry: BlobEntry, ext: string) { } // Soong is also required for APKs, framework JARs, and vintf XMLs - if (ext == '.apk' || ext == '.jar' || - (entry.path.startsWith('etc/vintf/') && ext == '.xml')) { + if (ext == '.apk' || ext == '.jar' || (entry.path.startsWith('etc/vintf/') && ext == '.xml')) { return true } diff --git a/src/blobs/file-list.ts b/src/blobs/file-list.ts index 2ff28b3..bfe4b4c 100644 --- a/src/blobs/file-list.ts +++ b/src/blobs/file-list.ts @@ -44,12 +44,12 @@ export async function listPart( showSpinner: boolean = false, ) { let partRoot = `${systemRoot}/${partition}` - if (!await exists(partRoot)) { + if (!(await exists(partRoot))) { return null } // Unwrap system-as-root - if (partition == 'system' && await exists(`${partRoot}/system`)) { + if (partition == 'system' && (await exists(`${partRoot}/system`))) { partRoot += '/system' } let refRoot = path.dirname(partRoot) diff --git a/src/blobs/overlays.ts b/src/blobs/overlays.ts index 6b7b085..dc3dd83 100644 --- a/src/blobs/overlays.ts +++ b/src/blobs/overlays.ts @@ -45,17 +45,19 @@ export type PartResValues = { [part: string]: ResValues } function makeManifestRegex(attr: string) { return new RegExp( - (/^\s+A: http:\/\/schemas.android.com\/apk\/res\/android:/).source + - attr + - (/\(0x[a-z0-9]+\)="(.+)" \(Raw: ".*$/).source, - 'm' // multiline flag + /^\s+A: http:\/\/schemas.android.com\/apk\/res\/android:/.source + + attr + + /\(0x[a-z0-9]+\)="(.+)" \(Raw: ".*$/.source, + 'm', // multiline flag ) } function encodeResKey(key: ResKey) { // pkg/name:type/key|flags - return `${key.targetPkg}${key.targetName?.length ? `/${key.targetName}` : ''}:` + + return ( + `${key.targetPkg}${key.targetName?.length ? `/${key.targetName}` : ''}:` + `${key.type}/${key.key}${key.flags?.length ? `|${key.flags}` : ''}` + ) } export function decodeResKey(encoded: string) { @@ -66,7 +68,7 @@ export function decodeResKey(encoded: string) { return { targetPkg: targetPkg, - targetName: targetName != undefined ? targetName: null, + targetName: targetName != undefined ? targetName : null, type: type, key: key, flags: flags != undefined ? flags : null, @@ -327,8 +329,7 @@ function filterValues(keyFilters: Filters, valueFilters: Filters, values: ResVal for (let [rawKey, value] of values.entries()) { let key = decodeResKey(rawKey) - if (shouldDeleteKey(keyFilters, rawKey, key) || - (typeof value == 'string' && !filterValue(valueFilters, value))) { + if (shouldDeleteKey(keyFilters, rawKey, key) || (typeof value == 'string' && !filterValue(valueFilters, value))) { // Key/value filter values.delete(rawKey) } else if (DIFF_MAP_PACKAGES.has(key.targetPkg)) { @@ -402,15 +403,17 @@ export async function serializePartOverlays(partValues: PartResValues, overlaysD let rroName = `${genTarget}.auto_generated_rro_${partition}_adevtool__` let bp = serializeBlueprint({ - modules: [{ - _type: 'runtime_resource_overlay', - name: rroName, + modules: [ + { + _type: 'runtime_resource_overlay', + name: rroName, - ...(partition == 'system_ext' && { system_ext_specific: true }), - ...(partition == 'product' && { product_specific: true }), - ...(partition == 'vendor' && { soc_specific: true }), - ...(partition == 'odm' && { device_specific: true }), - }], + ...(partition == 'system_ext' && { system_ext_specific: true }), + ...(partition == 'product' && { product_specific: true }), + ...(partition == 'vendor' && { soc_specific: true }), + ...(partition == 'odm' && { device_specific: true }), + }, + ], }) let manifest = serializeXmlObject({ @@ -429,12 +432,12 @@ export async function serializePartOverlays(partValues: PartResValues, overlaysD }, }, ], - application: [ { $: { 'android:hasCode': 'false' } } ], + application: [{ $: { 'android:hasCode': 'false' } }], }, }) - let valuesObj = { resources: { } as { [type: string]: Array } } - for (let [{type, key}, value] of values.entries()) { + let valuesObj = { resources: {} as { [type: string]: Array } } + for (let [{ type, key }, value] of values.entries()) { let entry = { $: { name: key, diff --git a/src/blobs/presigned.ts b/src/blobs/presigned.ts index b8c3e2d..8545069 100644 --- a/src/blobs/presigned.ts +++ b/src/blobs/presigned.ts @@ -19,8 +19,7 @@ export async function parsePresignedRecursive(sepolicyDirs: Array) { } } - return new Set(contexts.filter(c => c.seinfo != 'platform') - .map(c => c.name)) + return new Set(contexts.filter(c => c.seinfo != 'platform').map(c => c.name)) } async function getPkgName(aapt2Path: string, apkPath: string) { @@ -45,8 +44,10 @@ export async function updatePresignedBlobs( entryCallback(entry) } - if ((filters != null && filterValue(filters, entry.srcPath)) || - presignedPkgs.has(await getPkgName(aapt2Path, `${source}/${entry.srcPath}`))) { + if ( + (filters != null && filterValue(filters, entry.srcPath)) || + presignedPkgs.has(await getPkgName(aapt2Path, `${source}/${entry.srcPath}`)) + ) { entry.isPresigned = true updatedEntries.push(entry) } @@ -55,11 +56,7 @@ export async function updatePresignedBlobs( return updatedEntries } -export async function enumeratePresignedBlobs( - aapt2Path: string, - source: string, - presignedPkgs: Set, -) { +export async function enumeratePresignedBlobs(aapt2Path: string, source: string, presignedPkgs: Set) { let presignedPaths = [] for await (let file of listFilesRecursive(source)) { if (path.extname(file) != '.apk') { diff --git a/src/blobs/vintf.ts b/src/blobs/vintf.ts index 3a1149e..2c9ff51 100644 --- a/src/blobs/vintf.ts +++ b/src/blobs/vintf.ts @@ -101,7 +101,7 @@ export function serializeVintfHals(hals: Array) { type: 'device', }, hal: hals, - } + }, }) } diff --git a/src/build/make.ts b/src/build/make.ts index a99b88b..ec36b62 100644 --- a/src/build/make.ts +++ b/src/build/make.ts @@ -95,10 +95,7 @@ export function blobToFileCopy(entry: BlobEntry, proprietaryDir: string) { export function serializeModulesMakefile(mk: ModulesMakefile) { let blocks = startBlocks() - blocks.push( - 'LOCAL_PATH := $(call my-dir)', - `ifeq ($(TARGET_DEVICE),${mk.device})`, - ) + blocks.push('LOCAL_PATH := $(call my-dir)', `ifeq ($(TARGET_DEVICE),${mk.device})`) if (mk.radioFiles != undefined) { blocks.push(mk.radioFiles.map(img => `$(call add-radio-file,${img})`).join('\n')) @@ -169,15 +166,14 @@ TARGET_COPY_OUT_ODM_DLKM := odm_dlkm`) } if (mk.sepolicyResolutions != undefined) { - for (let [partition, {sepolicyDirs, missingContexts}] of mk.sepolicyResolutions.entries()) { + for (let [partition, { sepolicyDirs, missingContexts }] of mk.sepolicyResolutions.entries()) { let partVar = SEPOLICY_PARTITION_VARS[partition] if (sepolicyDirs.length > 0) { addContBlock(blocks, partVar, sepolicyDirs) } if (missingContexts.length > 0) { - blocks.push(missingContexts.map(c => `# Missing ${partition} SELinux context: ${c}`) - .join('\n')) + blocks.push(missingContexts.map(c => `# Missing ${partition} SELinux context: ${c}`).join('\n')) } } } @@ -244,7 +240,11 @@ PRODUCT_MANUFACTURER := ${mk.manufacturer}`) export function serializeProductsMakefile(mk: ProductsMakefile) { let blocks = [MAKEFILE_HEADER] - addContBlock(blocks, 'PRODUCT_MAKEFILES', mk.products.map(p => `$(LOCAL_DIR)/${p}.mk`)) + addContBlock( + blocks, + 'PRODUCT_MAKEFILES', + mk.products.map(p => `$(LOCAL_DIR)/${p}.mk`), + ) return finishBlocks(blocks) } diff --git a/src/build/soong-info.ts b/src/build/soong-info.ts index 2162759..39acda4 100644 --- a/src/build/soong-info.ts +++ b/src/build/soong-info.ts @@ -19,11 +19,7 @@ export interface TargetModuleInfo { export type SoongModuleInfo = Map -const EXCLUDE_MODULE_CLASSES = new Set([ - "NATIVE_TESTS", - "FAKE", - "ROBOLECTRIC", -]) +const EXCLUDE_MODULE_CLASSES = new Set(['NATIVE_TESTS', 'FAKE', 'ROBOLECTRIC']) export function parseModuleInfo(info: string) { return new Map(Object.entries(JSON.parse(info))) as SoongModuleInfo diff --git a/src/build/soong.ts b/src/build/soong.ts index b08dee9..8e04f4f 100644 --- a/src/build/soong.ts +++ b/src/build/soong.ts @@ -3,13 +3,7 @@ import util from 'util' import { BlobEntry, partPathToSrcPath } from '../blobs/entry' import { SOONG_HEADER } from '../util/headers' -export const SPECIAL_FILE_EXTENSIONS = new Set([ - '.so', - '.apk', - '.jar', - '.xml', - '.apex', -]) +export const SPECIAL_FILE_EXTENSIONS = new Set(['.so', '.apk', '.jar', '.xml', '.apex']) export const TYPE_SHARED_LIBRARY = 'cc_prebuilt_library_shared' @@ -89,24 +83,23 @@ export interface RroModule { theme?: string } -export interface SoongNamespace { -} +export interface SoongNamespace {} export type SoongModuleSpecific = { // This is used initially, but deleted before serialization _type?: string } & ( - SharedLibraryModule | - ExecutableModule | - ScriptModule | - ApkModule | - ApexModule | - JarModule | - EtcModule | - EtcXmlModule | - DspModule | - SoongNamespace | - RroModule + | SharedLibraryModule + | ExecutableModule + | ScriptModule + | ApkModule + | ApexModule + | JarModule + | EtcModule + | EtcXmlModule + | DspModule + | SoongNamespace + | RroModule ) export type SoongModule = { @@ -151,7 +144,8 @@ export function blobToSoongModule( // Type and info is based on file extension let moduleSpecific: SoongModuleSpecific // High-precedence extension-based types first - if (ext == '.sh') { // check before bin/ to catch .sh files in bin + if (ext == '.sh') { + // check before bin/ to catch .sh files in bin let relPath = getRelativeInstallPath(entry, pathParts, 'bin') moduleSpecific = { @@ -168,7 +162,7 @@ export function blobToSoongModule( filename_from_src: true, ...(relPath && { sub_dir: relPath }), } - // Then special paths + // Then special paths } else if (pathParts[0] == 'bin') { let relPath = getRelativeInstallPath(entry, pathParts, 'bin') @@ -201,7 +195,7 @@ export function blobToSoongModule( filename_from_src: true, ...(relPath && { sub_dir: relPath }), } - // Then other extension-based types + // Then other extension-based types } else if (ext == '.so') { // Extract architecture from lib dir let libDir = pathParts.at(0)! @@ -234,12 +228,18 @@ export function blobToSoongModule( } as TargetSrcs // For multi-arch - let targetSrcs32 = (curArch == '32') ? targetSrcs : { - srcs: [otherSrcPath], - } as TargetSrcs - let targetSrcs64 = (curArch == '64') ? targetSrcs : { - srcs: [otherSrcPath], - } as TargetSrcs + let targetSrcs32 = + curArch == '32' + ? targetSrcs + : ({ + srcs: [otherSrcPath], + } as TargetSrcs) + let targetSrcs64 = + curArch == '64' + ? targetSrcs + : ({ + srcs: [otherSrcPath], + } as TargetSrcs) let origFileName = pathParts.at(-1)?.replace(/\.so$/, '') moduleSpecific = { @@ -265,7 +265,7 @@ export function blobToSoongModule( moduleSpecific = { _type: 'android_app_import', apk: entry.srcPath, - ...(entry.isPresigned && { presigned: true } || { certificate: 'platform' }), + ...((entry.isPresigned && { presigned: true }) || { certificate: 'platform' }), ...(entry.path.startsWith('priv-app/') && { privileged: true }), dex_preopt: { enabled: false, @@ -301,35 +301,35 @@ export function blobToSoongModule( } export function serializeModule(module: SoongModule) { - // Type is prepended to Soong module props, so remove it from the object - let type = module._type - delete module._type + // Type is prepended to Soong module props, so remove it from the object + let type = module._type + delete module._type - // Delete internal blob entry reference as well - delete module._entry + // Delete internal blob entry reference as well + delete module._entry - // Initial serialization pass. Node.js util.inspect happens to be very similar to Soong format. - let serialized = util.inspect(module, { - depth: Infinity, - maxArrayLength: Infinity, - maxStringLength: Infinity, - breakLength: 100, - }) + // Initial serialization pass. Node.js util.inspect happens to be very similar to Soong format. + let serialized = util.inspect(module, { + depth: Infinity, + maxArrayLength: Infinity, + maxStringLength: Infinity, + breakLength: 100, + }) - // ' -> " - serialized = serialized.replaceAll("'", '"') - // 4-space indentation - serialized = serialized.replaceAll(' ', ' ') - // Prepend type - serialized = `${type} ${serialized}` - // Add trailing comma to last prop - let serialLines = serialized.split('\n') - if (serialLines.length > 1) { - serialLines[serialLines.length - 2] = serialLines.at(-2) + ',' - serialized = serialLines.join('\n') - } + // ' -> " + serialized = serialized.replaceAll("'", '"') + // 4-space indentation + serialized = serialized.replaceAll(' ', ' ') + // Prepend type + serialized = `${type} ${serialized}` + // Add trailing comma to last prop + let serialLines = serialized.split('\n') + if (serialLines.length > 1) { + serialLines[serialLines.length - 2] = serialLines.at(-2) + ',' + serialized = serialLines.join('\n') + } - return serialized + return serialized } export function serializeBlueprint(bp: SoongBlueprint) { @@ -337,9 +337,11 @@ export function serializeBlueprint(bp: SoongBlueprint) { // Declare namespace if (bp.namespace) { - serializedModules.push(serializeModule({ - _type: 'soong_namespace', - })) + serializedModules.push( + serializeModule({ + _type: 'soong_namespace', + }), + ) } if (bp.modules != undefined) { diff --git a/src/commands/check-presigned.ts b/src/commands/check-presigned.ts index 9e89785..840fa64 100644 --- a/src/commands/check-presigned.ts +++ b/src/commands/check-presigned.ts @@ -10,19 +10,31 @@ export default class CheckPresigned extends Command { static description = 'check for APKs that should be presigned' static flags = { - help: flags.help({char: 'h'}), - aapt2: flags.string({char: 'a', description: 'path to aapt2 executable', default: 'out/host/linux-x86/bin/aapt2'}), - sepolicy: flags.string({char: 'p', description: 'paths to device and vendor sepolicy dirs', required: true, multiple: true}), - outList: flags.string({char: 'o', description: 'output path for new proprietary-files.txt with PRESIGNED tags'}), + help: flags.help({ char: 'h' }), + aapt2: flags.string({ + char: 'a', + description: 'path to aapt2 executable', + default: 'out/host/linux-x86/bin/aapt2', + }), + sepolicy: flags.string({ + char: 'p', + description: 'paths to device and vendor sepolicy dirs', + required: true, + multiple: true, + }), + outList: flags.string({ char: 'o', description: 'output path for new proprietary-files.txt with PRESIGNED tags' }), } static args = [ - {name: 'source', description: 'path to mounted factory images', required: true}, - {name: 'listPath', description: 'path to LineageOS-compatible proprietary-files.txt list'}, + { name: 'source', description: 'path to mounted factory images', required: true }, + { name: 'listPath', description: 'path to LineageOS-compatible proprietary-files.txt list' }, ] async run() { - let {flags: {aapt2: aapt2Path, sepolicy: sepolicyDirs, outList: outPath}, args: {source, listPath}} = this.parse(CheckPresigned) + let { + flags: { aapt2: aapt2Path, sepolicy: sepolicyDirs, outList: outPath }, + args: { source, listPath }, + } = this.parse(CheckPresigned) // Parse list this.log(chalk.bold(chalk.greenBright('Parsing list'))) diff --git a/src/commands/collect-state.ts b/src/commands/collect-state.ts index 9d93286..d0e3b6b 100644 --- a/src/commands/collect-state.ts +++ b/src/commands/collect-state.ts @@ -8,27 +8,31 @@ export default class CollectState extends Command { static description = 'collect built system state for use with other commands' static flags = { - help: flags.help({char: 'h'}), - aapt2: flags.string({char: 'a', description: 'path to aapt2 executable', default: 'out/host/linux-x86/bin/aapt2'}), - device: flags.string({char: 'd', description: 'name of target device', required: true, multiple: true}), - outRoot: flags.string({char: 'r', description: 'path to AOSP build output directory (out/)', default: 'out'}), - parallel: flags.boolean({char: 'p', description: 'generate devices in parallel (causes buggy progress spinners)', default: false}), + help: flags.help({ char: 'h' }), + aapt2: flags.string({ + char: 'a', + description: 'path to aapt2 executable', + default: 'out/host/linux-x86/bin/aapt2', + }), + device: flags.string({ char: 'd', description: 'name of target device', required: true, multiple: true }), + outRoot: flags.string({ char: 'r', description: 'path to AOSP build output directory (out/)', default: 'out' }), + parallel: flags.boolean({ + char: 'p', + description: 'generate devices in parallel (causes buggy progress spinners)', + default: false, + }), } - static args = [ - {name: 'output_path', description: 'output path for system state JSON file(s)', required: true}, - ] + static args = [{ name: 'output_path', description: 'output path for system state JSON file(s)', required: true }] async run() { - let {flags: { - aapt2: aapt2Path, - device: devices, - outRoot, - parallel, - }, args: {output_path: outPath}} = this.parse(CollectState) + let { + flags: { aapt2: aapt2Path, device: devices, outRoot, parallel }, + args: { output_path: outPath }, + } = this.parse(CollectState) let isDir = (await fs.stat(outPath)).isDirectory() - await forEachDevice(devices, parallel, async (device) => { + await forEachDevice(devices, parallel, async device => { let state = await collectSystemState(device, outRoot, aapt2Path) // Write diff --git a/src/commands/diff-files.ts b/src/commands/diff-files.ts index 8d68b8f..a43d9b8 100644 --- a/src/commands/diff-files.ts +++ b/src/commands/diff-files.ts @@ -8,17 +8,24 @@ export default class DiffFiles extends Command { static description = 'find missing system files compared to a reference system' static flags = { - help: flags.help({char: 'h'}), - all: flags.boolean({char: 'a', description: 'show all differences, not only missing/removed files', default: false}) + help: flags.help({ char: 'h' }), + all: flags.boolean({ + char: 'a', + description: 'show all differences, not only missing/removed files', + default: false, + }), } static args = [ - {name: 'sourceRef', description: 'path to root of reference system', required: true}, - {name: 'sourceNew', description: 'path to root of new system', required: true}, + { name: 'sourceRef', description: 'path to root of reference system', required: true }, + { name: 'sourceNew', description: 'path to root of new system', required: true }, ] async run() { - let {flags: {all}, args: {sourceRef, sourceNew}} = this.parse(DiffFiles) + let { + flags: { all }, + args: { sourceRef, sourceNew }, + } = this.parse(DiffFiles) for (let partition of ALL_SYS_PARTITIONS) { let filesRef = await listPart(partition, sourceRef) @@ -26,7 +33,7 @@ export default class DiffFiles extends Command { continue } - let filesNew = await listPart(partition, sourceNew) ?? [] + let filesNew = (await listPart(partition, sourceNew)) ?? [] this.log(chalk.bold(partition)) diff --git a/src/commands/diff-props.ts b/src/commands/diff-props.ts index 1449700..f325f4c 100644 --- a/src/commands/diff-props.ts +++ b/src/commands/diff-props.ts @@ -21,10 +21,7 @@ function forEachPropLine(props: Map, callback: (prop: string) => } } -function forEachPropLineModified( - props: Map>, - callback: (prop: string) => void, -) { +function forEachPropLineModified(props: Map>, callback: (prop: string) => void) { for (let [key, [refValue, newValue]] of props.entries()) { callback(`${key}=${chalk.bold(refValue)} -> ${chalk.bold(chalk.blue(newValue))}`) } @@ -34,18 +31,21 @@ export default class DiffProps extends Command { static description = 'find missing and different properties compared to a reference system' static flags = { - help: flags.help({char: 'h'}), - all: flags.boolean({char: 'a', description: 'show all differences, not only missing props', default: false}), - includeBuild: flags.boolean({char: 'b', description: 'include build props', default: false}), + help: flags.help({ char: 'h' }), + all: flags.boolean({ char: 'a', description: 'show all differences, not only missing props', default: false }), + includeBuild: flags.boolean({ char: 'b', description: 'include build props', default: false }), } static args = [ - {name: 'sourceRef', description: 'path to root of reference system', required: true}, - {name: 'sourceNew', description: 'path to root of new system', required: true}, + { name: 'sourceRef', description: 'path to root of reference system', required: true }, + { name: 'sourceNew', description: 'path to root of new system', required: true }, ] async run() { - let {flags: {all, includeBuild}, args: {sourceRef, sourceNew}} = this.parse(DiffProps) + let { + flags: { all, includeBuild }, + args: { sourceRef, sourceNew }, + } = this.parse(DiffProps) let propsRef = await loadPartitionProps(sourceRef) let propsNew = await loadPartitionProps(sourceNew) diff --git a/src/commands/diff-vintf.ts b/src/commands/diff-vintf.ts index c4851ba..8701ee4 100644 --- a/src/commands/diff-vintf.ts +++ b/src/commands/diff-vintf.ts @@ -9,18 +9,25 @@ export default class DiffVintf extends Command { static description = 'find missing vintf declarations compared to a reference system' static flags = { - help: flags.help({char: 'h'}), - all: flags.boolean({char: 'a', description: 'show all differences, not only missing/removed HALs', default: false}) + help: flags.help({ char: 'h' }), + all: flags.boolean({ + char: 'a', + description: 'show all differences, not only missing/removed HALs', + default: false, + }), } static args = [ - {name: 'sourceRef', description: 'path to root of reference system', required: true}, - {name: 'sourceNew', description: 'path to root of new system', required: true}, - {name: 'outPath', description: 'output path for manifest fragment with missing HALs'}, + { name: 'sourceRef', description: 'path to root of reference system', required: true }, + { name: 'sourceNew', description: 'path to root of new system', required: true }, + { name: 'outPath', description: 'output path for manifest fragment with missing HALs' }, ] async run() { - let {flags: {all}, args: {sourceRef, sourceNew, outPath}} = this.parse(DiffVintf) + let { + flags: { all }, + args: { sourceRef, sourceNew, outPath }, + } = this.parse(DiffVintf) let vintfRef = await loadPartVintfInfo(sourceRef) let vintfNew = await loadPartVintfInfo(sourceNew) diff --git a/src/commands/download.ts b/src/commands/download.ts index 865ede7..325e511 100644 --- a/src/commands/download.ts +++ b/src/commands/download.ts @@ -4,35 +4,55 @@ import chalk from 'chalk' import { downloadFile, ImageType, IndexCache } from '../images/download' const IMAGE_TYPE_MAP: { [type: string]: ImageType } = { - 'factory': ImageType.Factory, - 'ota': ImageType.Ota, - 'vendor': ImageType.Vendor, + factory: ImageType.Factory, + ota: ImageType.Ota, + vendor: ImageType.Vendor, } export default class Download extends Command { static description = 'download device factory images, OTAs, and/or vendor packages' static flags = { - help: flags.help({char: 'h'}), - type: flags.string({char: 't', options: ['factory', 'ota', 'vendor'], description: 'type(s) of images to download', default: ['factory'], multiple: true}), - buildId: flags.string({char: 'b', description: 'build ID(s) of the images to download', required: true, multiple: true, default: ['latest']}), - device: flags.string({char: 'd', description: 'device(s) to download images for', required: true, multiple: true}), + help: flags.help({ char: 'h' }), + type: flags.string({ + char: 't', + options: ['factory', 'ota', 'vendor'], + description: 'type(s) of images to download', + default: ['factory'], + multiple: true, + }), + buildId: flags.string({ + char: 'b', + description: 'build ID(s) of the images to download', + required: true, + multiple: true, + default: ['latest'], + }), + device: flags.string({ + char: 'd', + description: 'device(s) to download images for', + required: true, + multiple: true, + }), } - static args = [ - {name: 'out', description: 'directory to save downloaded files in', required: true}, - ] + static args = [{ name: 'out', description: 'directory to save downloaded files in', required: true }] async run() { - let {flags, args: {out}} = this.parse(Download) + let { + flags, + args: { out }, + } = this.parse(Download) await fs.mkdir(out, { recursive: true }) this.log(chalk.bold(chalk.yellowBright("By downloading images, you agree to Google's terms and conditions:"))) - this.log(chalk.yellow(` - https://developers.google.com/android/images#legal + this.log( + chalk.yellow(` - https://developers.google.com/android/images#legal - https://developers.google.com/android/ota#legal - https://policies.google.com/terms -`)) +`), + ) let cache: IndexCache = {} for (let device of flags.device) { diff --git a/src/commands/extract.ts b/src/commands/extract.ts index 01589b3..948e5b6 100644 --- a/src/commands/extract.ts +++ b/src/commands/extract.ts @@ -10,19 +10,22 @@ export default class Extract extends Command { static description = 'extract proprietary files' static flags = { - help: flags.help({char: 'h'}), - vendor: flags.string({char: 'v', description: 'device vendor/OEM name', required: true}), - device: flags.string({char: 'd', description: 'device codename', required: true}), - skipCopy: flags.boolean({char: 'k', description: 'skip file copying and only generate build files'}), + help: flags.help({ char: 'h' }), + vendor: flags.string({ char: 'v', description: 'device vendor/OEM name', required: true }), + device: flags.string({ char: 'd', description: 'device codename', required: true }), + skipCopy: flags.boolean({ char: 'k', description: 'skip file copying and only generate build files' }), } static args = [ - {name: 'source', description: 'path to mounted factory images', required: true}, - {name: 'listPath', description: 'path to LineageOS-compatible proprietary-files.txt list', required: true}, + { name: 'source', description: 'path to mounted factory images', required: true }, + { name: 'listPath', description: 'path to LineageOS-compatible proprietary-files.txt list', required: true }, ] async run() { - let {args: {source, listPath}, flags: {vendor, device, skipCopy}} = this.parse(Extract) + let { + args: { source, listPath }, + flags: { vendor, device, skipCopy }, + } = this.parse(Extract) // Parse list this.log(chalk.bold(chalk.greenBright('Parsing list'))) diff --git a/src/commands/fix-certs.ts b/src/commands/fix-certs.ts index 6f614ae..0e0df53 100644 --- a/src/commands/fix-certs.ts +++ b/src/commands/fix-certs.ts @@ -1,7 +1,15 @@ import { Command, flags } from '@oclif/command' import { wrapSystemSrc } from '../frontend/source' -import { KeyInfo, MacSigner, readKeysConfRecursive, readMacPermissionsRecursive, readPartMacPermissions, resolveKeys, writeMappedKeys } from '../selinux/keys' +import { + KeyInfo, + MacSigner, + readKeysConfRecursive, + readMacPermissionsRecursive, + readPartMacPermissions, + resolveKeys, + writeMappedKeys, +} from '../selinux/keys' import { withSpinner } from '../util/cli' import { withTempDir } from '../util/fs' @@ -9,22 +17,42 @@ export default class FixCerts extends Command { static description = 'fix SELinux presigned app certificates' static flags = { - help: flags.help({char: 'h'}), - sepolicy: flags.string({char: 'p', description: 'paths to device and vendor sepolicy dirs', required: true, multiple: true}), - device: flags.string({char: 'd', description: 'device codename', required: true}), - buildId: flags.string({char: 'b', description: 'build ID of the stock images (optional, only used for locating factory images)'}), - stockSrc: flags.string({char: 's', description: 'path to (extracted) factory images, (mounted) images, (extracted) OTA package, OTA payload, or directory containing any such files (optionally under device and/or build ID directory)', required: true}), - useTemp: flags.boolean({char: 't', description: 'use a temporary directory for all extraction (prevents reusing extracted files across runs)', default: false}), + help: flags.help({ char: 'h' }), + sepolicy: flags.string({ + char: 'p', + description: 'paths to device and vendor sepolicy dirs', + required: true, + multiple: true, + }), + device: flags.string({ char: 'd', description: 'device codename', required: true }), + buildId: flags.string({ + char: 'b', + description: 'build ID of the stock images (optional, only used for locating factory images)', + }), + stockSrc: flags.string({ + char: 's', + description: + 'path to (extracted) factory images, (mounted) images, (extracted) OTA package, OTA payload, or directory containing any such files (optionally under device and/or build ID directory)', + required: true, + }), + useTemp: flags.boolean({ + char: 't', + description: 'use a temporary directory for all extraction (prevents reusing extracted files across runs)', + default: false, + }), } async run() { - let {flags: {sepolicy: sepolicyDirs, device, buildId, stockSrc, useTemp}} = this.parse(FixCerts) + let { + flags: { sepolicy: sepolicyDirs, device, buildId, stockSrc, useTemp }, + } = this.parse(FixCerts) - await withTempDir(async (tmp) => { + await withTempDir(async tmp => { // Prepare stock system source let wrapBuildId = buildId == undefined ? null : buildId - let wrapped = await withSpinner('Extracting stock system source', (spinner) => - wrapSystemSrc(stockSrc, device, wrapBuildId, useTemp, tmp, spinner)) + let wrapped = await withSpinner('Extracting stock system source', spinner => + wrapSystemSrc(stockSrc, device, wrapBuildId, useTemp, tmp, spinner), + ) stockSrc = wrapped.src! let srcSigners: Array = [] diff --git a/src/commands/generate-all.ts b/src/commands/generate-all.ts index 8899805..409aaed 100644 --- a/src/commands/generate-all.ts +++ b/src/commands/generate-all.ts @@ -5,7 +5,20 @@ import { copyBlobs } from '../blobs/copy' import { BlobEntry } from '../blobs/entry' import { DeviceConfig, loadDeviceConfigs } from '../config/device' import { forEachDevice } from '../frontend/devices' -import { enumerateFiles, extractFirmware, extractOverlays, extractProps, extractVintfManifests, flattenApexs, generateBuildFiles, loadCustomState, PropResults, resolveOverrides, resolveSepolicyDirs, updatePresigned } from '../frontend/generate' +import { + enumerateFiles, + extractFirmware, + extractOverlays, + extractProps, + extractVintfManifests, + flattenApexs, + generateBuildFiles, + loadCustomState, + PropResults, + resolveOverrides, + resolveSepolicyDirs, + updatePresigned, +} from '../frontend/generate' import { wrapSystemSrc } from '../frontend/source' import { SelinuxPartResolutions } from '../selinux/contexts' import { withSpinner } from '../util/cli' @@ -20,139 +33,181 @@ const doDevice = ( factoryPath: string | undefined, skipCopy: boolean, useTemp: boolean, -) => withTempDir(async (tmp) => { - // Prepare stock system source - let wrapBuildId = buildId == undefined ? null : buildId - let wrapped = await withSpinner('Extracting stock system source', (spinner) => - wrapSystemSrc(stockSrc, config.device.name, wrapBuildId, useTemp, tmp, spinner)) - stockSrc = wrapped.src! - if (wrapped.factoryPath != null && factoryPath == undefined) { - factoryPath = wrapped.factoryPath - } - - // customSrc can point to a (directory containing) system state JSON or out/ - let customState = await loadCustomState(config, aapt2Path, customSrc) - - // Each step will modify this. Key = combined part path - let namedEntries = new Map() - - // Prepare output directories - let dirs = await createVendorDirs(config.device.vendor, config.device.name) - - // 1. Diff files - await withSpinner('Enumerating files', (spinner) => - enumerateFiles(spinner, config.filters.files, config.filters.dep_files, - namedEntries, customState, stockSrc)) - - // 2. Overrides - let buildPkgs: string[] = [] - if (config.generate.overrides) { - let builtModules = await withSpinner('Replacing blobs with buildable modules', () => - resolveOverrides(config, customState, dirs, namedEntries)) - buildPkgs.push(...builtModules) - } - // After this point, we only need entry objects - let entries = Array.from(namedEntries.values()) - - // 3. Presigned - if (config.generate.presigned) { - await withSpinner('Marking apps as presigned', (spinner) => - updatePresigned(spinner, config, entries, aapt2Path, stockSrc)) - } - - // 4. Flatten APEX modules - if (config.generate.flat_apex) { - entries = await withSpinner('Flattening APEX modules', (spinner) => - flattenApexs(spinner, entries, dirs, tmp, stockSrc)) - } - - // 5. Extract - // Copy blobs (this has its own spinner) - if (config.generate.files && !skipCopy) { - await copyBlobs(entries, stockSrc, dirs.proprietary) - } - - // 6. Props - let propResults: PropResults | null = null - if (config.generate.props) { - propResults = await withSpinner('Extracting properties', () => - extractProps(config, customState, stockSrc)) - } - - // 7. SELinux policies - let sepolicyResolutions: SelinuxPartResolutions | null = null - if (config.generate.sepolicy_dirs) { - sepolicyResolutions = await withSpinner('Adding missing SELinux policies', () => - resolveSepolicyDirs(config, customState, dirs, stockSrc)) - } - - // 8. Overlays - if (config.generate.overlays) { - let overlayPkgs = await withSpinner('Extracting overlays', (spinner) => - extractOverlays(spinner, config, customState, dirs, aapt2Path, stockSrc)) - buildPkgs.push(...overlayPkgs) - } - - // 9. vintf manifests - let vintfManifestPaths: Map | null = null - if (config.generate.vintf) { - vintfManifestPaths = await withSpinner('Extracting vintf manifests', () => - extractVintfManifests(customState, dirs, stockSrc)) - } - - // 10. Firmware - let fwPaths: Array | null = null - if (config.generate.factory_firmware && factoryPath != undefined) { - if (propResults == null) { - throw new Error('Factory firmware extraction depends on properties') +) => + withTempDir(async tmp => { + // Prepare stock system source + let wrapBuildId = buildId == undefined ? null : buildId + let wrapped = await withSpinner('Extracting stock system source', spinner => + wrapSystemSrc(stockSrc, config.device.name, wrapBuildId, useTemp, tmp, spinner), + ) + stockSrc = wrapped.src! + if (wrapped.factoryPath != null && factoryPath == undefined) { + factoryPath = wrapped.factoryPath } - fwPaths = await withSpinner('Extracting firmware', () => - extractFirmware(config, dirs, propResults!.stockProps, factoryPath!)) - } + // customSrc can point to a (directory containing) system state JSON or out/ + let customState = await loadCustomState(config, aapt2Path, customSrc) - // 11. Build files - await withSpinner('Generating build files', () => - generateBuildFiles(config, dirs, entries, buildPkgs, propResults, fwPaths, - vintfManifestPaths, sepolicyResolutions, stockSrc)) -}) + // Each step will modify this. Key = combined part path + let namedEntries = new Map() + + // Prepare output directories + let dirs = await createVendorDirs(config.device.vendor, config.device.name) + + // 1. Diff files + await withSpinner('Enumerating files', spinner => + enumerateFiles(spinner, config.filters.files, config.filters.dep_files, namedEntries, customState, stockSrc), + ) + + // 2. Overrides + let buildPkgs: string[] = [] + if (config.generate.overrides) { + let builtModules = await withSpinner('Replacing blobs with buildable modules', () => + resolveOverrides(config, customState, dirs, namedEntries), + ) + buildPkgs.push(...builtModules) + } + // After this point, we only need entry objects + let entries = Array.from(namedEntries.values()) + + // 3. Presigned + if (config.generate.presigned) { + await withSpinner('Marking apps as presigned', spinner => + updatePresigned(spinner, config, entries, aapt2Path, stockSrc), + ) + } + + // 4. Flatten APEX modules + if (config.generate.flat_apex) { + entries = await withSpinner('Flattening APEX modules', spinner => + flattenApexs(spinner, entries, dirs, tmp, stockSrc), + ) + } + + // 5. Extract + // Copy blobs (this has its own spinner) + if (config.generate.files && !skipCopy) { + await copyBlobs(entries, stockSrc, dirs.proprietary) + } + + // 6. Props + let propResults: PropResults | null = null + if (config.generate.props) { + propResults = await withSpinner('Extracting properties', () => extractProps(config, customState, stockSrc)) + } + + // 7. SELinux policies + let sepolicyResolutions: SelinuxPartResolutions | null = null + if (config.generate.sepolicy_dirs) { + sepolicyResolutions = await withSpinner('Adding missing SELinux policies', () => + resolveSepolicyDirs(config, customState, dirs, stockSrc), + ) + } + + // 8. Overlays + if (config.generate.overlays) { + let overlayPkgs = await withSpinner('Extracting overlays', spinner => + extractOverlays(spinner, config, customState, dirs, aapt2Path, stockSrc), + ) + buildPkgs.push(...overlayPkgs) + } + + // 9. vintf manifests + let vintfManifestPaths: Map | null = null + if (config.generate.vintf) { + vintfManifestPaths = await withSpinner('Extracting vintf manifests', () => + extractVintfManifests(customState, dirs, stockSrc), + ) + } + + // 10. Firmware + let fwPaths: Array | null = null + if (config.generate.factory_firmware && factoryPath != undefined) { + if (propResults == null) { + throw new Error('Factory firmware extraction depends on properties') + } + + fwPaths = await withSpinner('Extracting firmware', () => + extractFirmware(config, dirs, propResults!.stockProps, factoryPath!), + ) + } + + // 11. Build files + await withSpinner('Generating build files', () => + generateBuildFiles( + config, + dirs, + entries, + buildPkgs, + propResults, + fwPaths, + vintfManifestPaths, + sepolicyResolutions, + stockSrc, + ), + ) + }) export default class GenerateFull extends Command { static description = 'generate all vendor parts automatically' static flags = { - help: flags.help({char: 'h'}), - aapt2: flags.string({char: 'a', description: 'path to aapt2 executable', default: 'out/host/linux-x86/bin/aapt2'}), - buildId: flags.string({char: 'b', description: 'build ID of the stock images'}), - stockSrc: flags.string({char: 's', description: 'path to (extracted) factory images, (mounted) images, (extracted) OTA package, OTA payload, or directory containing any such files (optionally under device and/or build ID directory)', required: true}), - customSrc: flags.string({char: 'c', description: 'path to AOSP build output directory (out/) or (directory containing) JSON state file', default: 'out'}), - factoryPath: flags.string({char: 'f', description: 'path to stock factory images zip (for extracting firmware if stockSrc is not factory images)'}), - skipCopy: flags.boolean({char: 'k', description: 'skip file copying and only generate build files', default: false}), - useTemp: flags.boolean({char: 't', description: 'use a temporary directory for all extraction (prevents reusing extracted files across runs)', default: false}), - parallel: flags.boolean({char: 'p', description: 'generate devices in parallel (causes buggy progress spinners)', default: false}), + help: flags.help({ char: 'h' }), + aapt2: flags.string({ + char: 'a', + description: 'path to aapt2 executable', + default: 'out/host/linux-x86/bin/aapt2', + }), + buildId: flags.string({ char: 'b', description: 'build ID of the stock images' }), + stockSrc: flags.string({ + char: 's', + description: + 'path to (extracted) factory images, (mounted) images, (extracted) OTA package, OTA payload, or directory containing any such files (optionally under device and/or build ID directory)', + required: true, + }), + customSrc: flags.string({ + char: 'c', + description: 'path to AOSP build output directory (out/) or (directory containing) JSON state file', + default: 'out', + }), + factoryPath: flags.string({ + char: 'f', + description: 'path to stock factory images zip (for extracting firmware if stockSrc is not factory images)', + }), + skipCopy: flags.boolean({ + char: 'k', + description: 'skip file copying and only generate build files', + default: false, + }), + useTemp: flags.boolean({ + char: 't', + description: 'use a temporary directory for all extraction (prevents reusing extracted files across runs)', + default: false, + }), + parallel: flags.boolean({ + char: 'p', + description: 'generate devices in parallel (causes buggy progress spinners)', + default: false, + }), } - static args = [ - {name: 'config', description: 'path to device-specific YAML config', required: true}, - ] + static args = [{ name: 'config', description: 'path to device-specific YAML config', required: true }] async run() { - let {flags: { - aapt2: aapt2Path, - buildId, - stockSrc, - customSrc, - factoryPath, - skipCopy, - useTemp, - parallel, - }, args: {config: configPath}} = this.parse(GenerateFull) + let { + flags: { aapt2: aapt2Path, buildId, stockSrc, customSrc, factoryPath, skipCopy, useTemp, parallel }, + args: { config: configPath }, + } = this.parse(GenerateFull) let devices = await loadDeviceConfigs(configPath) - await forEachDevice(devices, parallel, async (config) => { - await doDevice(config, stockSrc, customSrc, aapt2Path, buildId, - factoryPath, skipCopy, useTemp) - }, config => config.device.name) + await forEachDevice( + devices, + parallel, + async config => { + await doDevice(config, stockSrc, customSrc, aapt2Path, buildId, factoryPath, skipCopy, useTemp) + }, + config => config.device.name, + ) } } diff --git a/src/commands/generate-prep.ts b/src/commands/generate-prep.ts index bfa7ce8..3f5de3a 100644 --- a/src/commands/generate-prep.ts +++ b/src/commands/generate-prep.ts @@ -16,77 +16,95 @@ const doDevice = ( buildId: string | undefined, skipCopy: boolean, useTemp: boolean, -) => withTempDir(async (tmp) => { - // Prepare stock system source - let wrapBuildId = buildId == undefined ? null : buildId - let wrapped = await withSpinner('Extracting stock system source', (spinner) => - wrapSystemSrc(stockSrc, config.device.name, wrapBuildId, useTemp, tmp, spinner)) - stockSrc = wrapped.src! +) => + withTempDir(async tmp => { + // Prepare stock system source + let wrapBuildId = buildId == undefined ? null : buildId + let wrapped = await withSpinner('Extracting stock system source', spinner => + wrapSystemSrc(stockSrc, config.device.name, wrapBuildId, useTemp, tmp, spinner), + ) + stockSrc = wrapped.src! - // Each step will modify this. Key = combined part path - let namedEntries = new Map() + // Each step will modify this. Key = combined part path + let namedEntries = new Map() - // Prepare output directories - let dirs = await createVendorDirs(config.device.vendor, config.device.name) + // Prepare output directories + let dirs = await createVendorDirs(config.device.vendor, config.device.name) - // 1. Diff files - await withSpinner('Enumerating files', (spinner) => - enumerateFiles(spinner, config.filters.dep_files, null, namedEntries, null, - stockSrc)) + // 1. Diff files + await withSpinner('Enumerating files', spinner => + enumerateFiles(spinner, config.filters.dep_files, null, namedEntries, null, stockSrc), + ) - // After this point, we only need entry objects - let entries = Array.from(namedEntries.values()) + // After this point, we only need entry objects + let entries = Array.from(namedEntries.values()) - // 2. Extract - // Copy blobs (this has its own spinner) - if (config.generate.files && !skipCopy) { - await copyBlobs(entries, stockSrc, dirs.proprietary) - } + // 2. Extract + // Copy blobs (this has its own spinner) + if (config.generate.files && !skipCopy) { + await copyBlobs(entries, stockSrc, dirs.proprietary) + } - // 3. Props - let propResults: PropResults | null = null - if (config.generate.props) { - propResults = await withSpinner('Extracting properties', () => - extractProps(config, null, stockSrc)) - delete propResults.missingProps - delete propResults.fingerprint - } + // 3. Props + let propResults: PropResults | null = null + if (config.generate.props) { + propResults = await withSpinner('Extracting properties', () => extractProps(config, null, stockSrc)) + delete propResults.missingProps + delete propResults.fingerprint + } - // 4. Build files - await withSpinner('Generating build files', () => - generateBuildFiles(config, dirs, entries, [], propResults, null, null, null, - stockSrc, false, true)) -}) + // 4. Build files + await withSpinner('Generating build files', () => + generateBuildFiles(config, dirs, entries, [], propResults, null, null, null, stockSrc, false, true), + ) + }) export default class GeneratePrep extends Command { static description = 'generate vendor parts to prepare for reference AOSP build (e.g. for collect-state)' static flags = { - help: flags.help({char: 'h'}), - buildId: flags.string({char: 'b', description: 'build ID of the stock images'}), - stockSrc: flags.string({char: 's', description: 'path to (extracted) factory images, (mounted) images, (extracted) OTA package, OTA payload, or directory containing any such files (optionally under device and/or build ID directory)', required: true}), - skipCopy: flags.boolean({char: 'k', description: 'skip file copying and only generate build files', default: false}), - useTemp: flags.boolean({char: 't', description: 'use a temporary directory for all extraction (prevents reusing extracted files across runs)', default: false}), - parallel: flags.boolean({char: 'p', description: 'generate devices in parallel (causes buggy progress spinners)', default: false}), + help: flags.help({ char: 'h' }), + buildId: flags.string({ char: 'b', description: 'build ID of the stock images' }), + stockSrc: flags.string({ + char: 's', + description: + 'path to (extracted) factory images, (mounted) images, (extracted) OTA package, OTA payload, or directory containing any such files (optionally under device and/or build ID directory)', + required: true, + }), + skipCopy: flags.boolean({ + char: 'k', + description: 'skip file copying and only generate build files', + default: false, + }), + useTemp: flags.boolean({ + char: 't', + description: 'use a temporary directory for all extraction (prevents reusing extracted files across runs)', + default: false, + }), + parallel: flags.boolean({ + char: 'p', + description: 'generate devices in parallel (causes buggy progress spinners)', + default: false, + }), } - static args = [ - {name: 'config', description: 'path to device-specific YAML config', required: true}, - ] + static args = [{ name: 'config', description: 'path to device-specific YAML config', required: true }] async run() { - let {flags: { - buildId, - stockSrc, - skipCopy, - useTemp, - parallel, - }, args: {config: configPath}} = this.parse(GeneratePrep) + let { + flags: { buildId, stockSrc, skipCopy, useTemp, parallel }, + args: { config: configPath }, + } = this.parse(GeneratePrep) let devices = await loadDeviceConfigs(configPath) - await forEachDevice(devices, parallel, async (config) => { - await doDevice(config, stockSrc, buildId, skipCopy, useTemp) - }, config => config.device.name) + await forEachDevice( + devices, + parallel, + async config => { + await doDevice(config, stockSrc, buildId, skipCopy, useTemp) + }, + config => config.device.name, + ) } } diff --git a/src/commands/list-files.ts b/src/commands/list-files.ts index 0a806fa..0cb43a4 100644 --- a/src/commands/list-files.ts +++ b/src/commands/list-files.ts @@ -8,16 +8,22 @@ export default class ListFiles extends Command { static description = 'list system files and symlinks important for blobs' static flags = { - help: flags.help({char: 'h'}), + help: flags.help({ char: 'h' }), } static args = [ - {name: 'systemRoot', description: 'path to root of mounted system images (./system_ext, ./product, etc.)', required: true}, - {name: 'out', description: 'directory to write partition file lists to', required: true}, + { + name: 'systemRoot', + description: 'path to root of mounted system images (./system_ext, ./product, etc.)', + required: true, + }, + { name: 'out', description: 'directory to write partition file lists to', required: true }, ] async run() { - let {args: {systemRoot, out}} = this.parse(ListFiles) + let { + args: { systemRoot, out }, + } = this.parse(ListFiles) await fs.mkdir(out, { recursive: true }) diff --git a/src/commands/resolve-overrides.ts b/src/commands/resolve-overrides.ts index 1f7f43a..fd2a23d 100644 --- a/src/commands/resolve-overrides.ts +++ b/src/commands/resolve-overrides.ts @@ -9,28 +9,38 @@ export default class ResolveOverrides extends Command { static description = 'resolve packages to build from a list of overridden targets' static flags = { - help: flags.help({char: 'h'}), + help: flags.help({ char: 'h' }), } static args = [ - {name: 'overrideList', description: 'path to root of mounted system images (./system_ext, ./product, etc.)', required: true}, - {name: 'moduleInfo', description: 'path to Soong module-info.json (out/target/product/$device/module-info.json)', required: true}, + { + name: 'overrideList', + description: 'path to root of mounted system images (./system_ext, ./product, etc.)', + required: true, + }, + { + name: 'moduleInfo', + description: 'path to Soong module-info.json (out/target/product/$device/module-info.json)', + required: true, + }, ] async run() { - let {args: {overrideList: listPath, moduleInfo}} = this.parse(ResolveOverrides) + let { + args: { overrideList: listPath, moduleInfo }, + } = this.parse(ResolveOverrides) let overridesList = await readFile(listPath) let overrides = parseOverrides(overridesList) let modulesMap = parseModuleInfo(await readFile(moduleInfo)) - let {modules, missingPaths} = findOverrideModules(overrides, modulesMap) + let { modules, missingPaths } = findOverrideModules(overrides, modulesMap) let makefile = serializeDeviceMakefile({ packages: modules, }) - let missing = missingPaths.length == 0 ? '' : '\n\n# Missing paths:\n' + - missingPaths.map(path => `# ${path}`).join('\n') + let missing = + missingPaths.length == 0 ? '' : '\n\n# Missing paths:\n' + missingPaths.map(path => `# ${path}`).join('\n') this.log(makefile + missing) } diff --git a/src/config/device.ts b/src/config/device.ts index b8ca503..185891f 100644 --- a/src/config/device.ts +++ b/src/config/device.ts @@ -145,8 +145,9 @@ async function loadAndMergeConfig(configPath: string) { let merged = overlays.reduce((base, overlay) => mergeConfigs(base, overlay), base) // Parse filters - merged.filters = Object.fromEntries(Object.entries(merged.filters) - .map(([group, filters]) => [group, parseFilters(filters as SerializedFilters)])) + merged.filters = Object.fromEntries( + Object.entries(merged.filters).map(([group, filters]) => [group, parseFilters(filters as SerializedFilters)]), + ) // Finally, cast it to the parsed config type delete merged.includes diff --git a/src/config/filters.ts b/src/config/filters.ts index 76f08ef..e0a6ac9 100644 --- a/src/config/filters.ts +++ b/src/config/filters.ts @@ -41,17 +41,17 @@ export function parseFilters(src: SerializedFilters) { } function _matchFilters(filters: Filters, value: string) { - return filters.match.has(value) || + return ( + filters.match.has(value) || filters.prefix.find(prefix => value.startsWith(prefix)) != undefined || filters.suffix.find(suffix => value.endsWith(suffix)) != undefined || filters.substring.find(substring => value.includes(substring)) != undefined || filters.regex.find(regex => value.match(regex)) != null + ) } export function filterValue(filters: Filters, value: string) { - return filters.include ? - _matchFilters(filters, value) : - !_matchFilters(filters, value) + return filters.include ? _matchFilters(filters, value) : !_matchFilters(filters, value) } export function filterValues(filters: Filters, values: string[]) { @@ -71,6 +71,5 @@ export function filterKeys(filters: Filters, map: Map) { // Map, copy export function filterKeysCopy(filters: Filters, map: Map) { - return new Map(Array.from(map.entries()) - .filter(([key]) => filterValue(filters, key))) + return new Map(Array.from(map.entries()).filter(([key]) => filterValue(filters, key))) } diff --git a/src/config/system-state.ts b/src/config/system-state.ts index 0291845..c161894 100644 --- a/src/config/system-state.ts +++ b/src/config/system-state.ts @@ -1,12 +1,12 @@ -import { listPart } from "../blobs/file-list" -import { parsePartOverlayApks, PartResValues } from "../blobs/overlays" -import { loadPartitionProps, PartitionProps } from "../blobs/props" -import { loadPartVintfInfo, PartitionVintfInfo } from "../blobs/vintf" -import { minimizeModules, parseModuleInfo, SoongModuleInfo } from "../build/soong-info" -import { parsePartContexts, SelinuxPartContexts } from "../selinux/contexts" -import { withSpinner } from "../util/cli" -import { readFile } from "../util/fs" -import { ALL_SYS_PARTITIONS } from "../util/partitions" +import { listPart } from '../blobs/file-list' +import { parsePartOverlayApks, PartResValues } from '../blobs/overlays' +import { loadPartitionProps, PartitionProps } from '../blobs/props' +import { loadPartVintfInfo, PartitionVintfInfo } from '../blobs/vintf' +import { minimizeModules, parseModuleInfo, SoongModuleInfo } from '../build/soong-info' +import { parsePartContexts, SelinuxPartContexts } from '../selinux/contexts' +import { withSpinner } from '../util/cli' +import { readFile } from '../util/fs' +import { ALL_SYS_PARTITIONS } from '../util/partitions' const STATE_VERSION = 4 @@ -36,16 +36,20 @@ export function serializeSystemState(state: SystemState) { ...state, } - return JSON.stringify(diskState, (k, v) => { - if (v instanceof Map) { - return { - _type: 'Map', - data: Object.fromEntries(v.entries()), + return JSON.stringify( + diskState, + (k, v) => { + if (v instanceof Map) { + return { + _type: 'Map', + data: Object.fromEntries(v.entries()), + } + } else { + return v } - } else { - return v - } - }, 2) + }, + 2, + ) } export function parseSystemState(json: string) { @@ -75,7 +79,7 @@ export async function collectSystemState(device: string, outRoot: string, aapt2P } as SystemState // Files - await withSpinner('Enumerating files', async (spinner) => { + await withSpinner('Enumerating files', async spinner => { for (let partition of ALL_SYS_PARTITIONS) { spinner.text = partition @@ -87,26 +91,25 @@ export async function collectSystemState(device: string, outRoot: string, aapt2P }) // Props - state.partitionProps = await withSpinner('Extracting properties', () => - loadPartitionProps(systemRoot)) + state.partitionProps = await withSpinner('Extracting properties', () => loadPartitionProps(systemRoot)) // SELinux contexts - state.partitionSecontexts = await withSpinner('Extracting SELinux contexts', () => - parsePartContexts(systemRoot)) + state.partitionSecontexts = await withSpinner('Extracting SELinux contexts', () => parsePartContexts(systemRoot)) // Overlays - state.partitionOverlays = await withSpinner('Extracting overlays', (spinner) => + state.partitionOverlays = await withSpinner('Extracting overlays', spinner => parsePartOverlayApks(aapt2Path, systemRoot, path => { spinner.text = path - })) + }), + ) // vintf info - state.partitionVintfInfo = await withSpinner('Extracting vintf manifests', () => - loadPartVintfInfo(systemRoot)) + state.partitionVintfInfo = await withSpinner('Extracting vintf manifests', () => loadPartVintfInfo(systemRoot)) // Module info state.moduleInfo = await withSpinner('Parsing module info', async () => - parseModuleInfo(await readFile(moduleInfoPath))) + parseModuleInfo(await readFile(moduleInfoPath)), + ) - return state; + return state } diff --git a/src/frontend/devices.ts b/src/frontend/devices.ts index 25d6553..31149d6 100644 --- a/src/frontend/devices.ts +++ b/src/frontend/devices.ts @@ -1,4 +1,4 @@ -import chalk from "chalk" +import chalk from 'chalk' export async function forEachDevice( devices: Device[], diff --git a/src/frontend/generate.ts b/src/frontend/generate.ts index 893a8f5..3a5c7b4 100644 --- a/src/frontend/generate.ts +++ b/src/frontend/generate.ts @@ -16,7 +16,14 @@ import { DeviceConfig } from '../config/device' import { filterKeys, Filters, filterValue, filterValues } from '../config/filters' import { collectSystemState, parseSystemState, SystemState } from '../config/system-state' import { ANDROID_INFO, extractFactoryFirmware, generateAndroidInfo, writeFirmwareImages } from '../images/firmware' -import { diffPartContexts, parseContextsRecursive, parsePartContexts, resolvePartContextDiffs, SelinuxContexts, SelinuxPartResolutions } from '../selinux/contexts' +import { + diffPartContexts, + parseContextsRecursive, + parsePartContexts, + resolvePartContextDiffs, + SelinuxContexts, + SelinuxPartResolutions, +} from '../selinux/contexts' import { generateFileContexts } from '../selinux/labels' import { exists, readFile, TempState } from '../util/fs' import { ALL_SYS_PARTITIONS } from '../util/partitions' @@ -29,11 +36,7 @@ export interface PropResults { missingOtaParts: Array } -export async function loadCustomState( - config: DeviceConfig, - aapt2Path: string, - customSrc: string, -) { +export async function loadCustomState(config: DeviceConfig, aapt2Path: string, customSrc: string) { if ((await fs.stat(customSrc)).isFile()) { return parseSystemState(await readFile(customSrc)) } else { @@ -96,7 +99,7 @@ export async function resolveOverrides( let modulesMap = customState.moduleInfo removeSelfModules(modulesMap, dirs.proprietary) - let {modules: builtModules, builtPaths} = findOverrideModules(targetPaths, modulesMap) + let { modules: builtModules, builtPaths } = findOverrideModules(targetPaths, modulesMap) // Remove new modules from entries for (let path of builtPaths) { @@ -114,9 +117,16 @@ export async function updatePresigned( stockSrc: string, ) { let presignedPkgs = await parsePresignedRecursive(config.platform.sepolicy_dirs) - await updatePresignedBlobs(aapt2Path, stockSrc, presignedPkgs, entries, entry => { - spinner.text = entry.srcPath - }, config.filters.presigned) + await updatePresignedBlobs( + aapt2Path, + stockSrc, + presignedPkgs, + entries, + entry => { + spinner.text = entry.srcPath + }, + config.filters.presigned, + ) } export async function flattenApexs( @@ -126,7 +136,7 @@ export async function flattenApexs( tmp: TempState, stockSrc: string, ) { - let apex = await flattenAllApexs(entries, stockSrc, tmp, (progress) => { + let apex = await flattenAllApexs(entries, stockSrc, tmp, progress => { spinner.text = progress }) @@ -137,11 +147,7 @@ export async function flattenApexs( return apex.entries } -export async function extractProps( - config: DeviceConfig, - customState: SystemState | null, - stockSrc: string, -) { +export async function extractProps(config: DeviceConfig, customState: SystemState | null, stockSrc: string) { let stockProps = await loadPartitionProps(stockSrc) let customProps = customState?.partitionProps ?? new Map>() @@ -160,15 +166,13 @@ export async function extractProps( let missingProps: PartitionProps | undefined = undefined if (customProps != null) { let propChanges = diffPartitionProps(stockProps, customProps) - missingProps = new Map(Array.from(propChanges.entries()) - .map(([part, props]) => [part, props.removed])) + missingProps = new Map(Array.from(propChanges.entries()).map(([part, props]) => [part, props.removed])) } // A/B OTA partitions let stockOtaParts = stockProps.get('product')!.get('ro.product.ab_ota_partitions')!.split(',') let customOtaParts = new Set(customProps.get('product')?.get('ro.product.ab_ota_partitions')?.split(',') ?? []) - let missingOtaParts = stockOtaParts.filter(p => !customOtaParts.has(p) && - filterValue(config.filters.partitions, p)) + let missingOtaParts = stockOtaParts.filter(p => !customOtaParts.has(p) && filterValue(config.filters.partitions, p)) return { stockProps, @@ -219,13 +223,22 @@ export async function extractOverlays( aapt2Path: string, stockSrc: string, ) { - let stockOverlays = await parsePartOverlayApks(aapt2Path, stockSrc, path => { - spinner.text = path - }, config.filters.overlay_files) + let stockOverlays = await parsePartOverlayApks( + aapt2Path, + stockSrc, + path => { + spinner.text = path + }, + config.filters.overlay_files, + ) let customOverlays = customState.partitionOverlays - let missingOverlays = diffPartOverlays(stockOverlays, customOverlays, - config.filters.overlay_keys, config.filters.overlay_values) + let missingOverlays = diffPartOverlays( + stockOverlays, + customOverlays, + config.filters.overlay_keys, + config.filters.overlay_values, + ) // Generate RROs and get a list of modules to build let buildPkgs = await serializePartOverlays(missingOverlays, dirs.overlays) @@ -243,11 +256,7 @@ export async function extractOverlays( return buildPkgs } -export async function extractVintfManifests( - customState: SystemState, - dirs: VendorDirectories, - stockSrc: string, -) { +export async function extractVintfManifests(customState: SystemState, dirs: VendorDirectories, stockSrc: string) { let customVintf = customState.partitionVintfInfo let stockVintf = await loadPartVintfInfo(stockSrc) let missingHals = diffPartVintfManifests(customVintf, stockVintf) @@ -305,8 +314,8 @@ export async function generateBuildFiles( // Add board parts build.boardMakefile = { ...(sepolicyResolutions != null && { sepolicyResolutions: sepolicyResolutions }), - ...(propResults != null && propResults.missingOtaParts.length > 0 && - { + ...(propResults != null && + propResults.missingOtaParts.length > 0 && { buildPartitions: propResults.missingOtaParts, ...(addAbOtaParts && { abOtaPartitions: propResults.missingOtaParts }), }), diff --git a/src/frontend/source.ts b/src/frontend/source.ts index 422b853..bfc6fa7 100644 --- a/src/frontend/source.ts +++ b/src/frontend/source.ts @@ -55,17 +55,11 @@ class SourceResolver { } } - private async mountImg( - img: string, - dest: string, - ) { + private async mountImg(img: string, dest: string) { // Convert sparse image to raw if (await isSparseImage(img)) { this.spinner.text = `converting sparse image: ${img}` - let sparseTmp = await this.createDynamicTmp( - `sparse_img/${path.basename(path.dirname(img))}`, - path.dirname(img), - ) + let sparseTmp = await this.createDynamicTmp(`sparse_img/${path.basename(path.dirname(img))}`, path.dirname(img)) let rawImg = `${sparseTmp.dir}/${path.basename(img)}.raw` await run(`simg2img ${img} ${rawImg}`) @@ -78,11 +72,7 @@ class SourceResolver { this.tmp.mounts.push(dest) } - private async mountParts( - src: string, - mountTmp: TempState, - suffix: string = '.img', - ) { + private async mountParts(src: string, mountTmp: TempState, suffix: string = '.img') { let mountRoot = mountTmp.dir for (let part of ALL_SYS_PARTITIONS) { @@ -95,14 +85,8 @@ class SourceResolver { } } - private async wrapLeafFile( - file: string, - factoryPath: string | null, - ): Promise { - let imagesTmp = await this.createDynamicTmp( - `src_images/${path.basename(file)}`, - path.dirname(file), - ) + private async wrapLeafFile(file: string, factoryPath: string | null): Promise { + let imagesTmp = await this.createDynamicTmp(`src_images/${path.basename(file)}`, path.dirname(file)) // Extract images from OTA payload if (path.basename(file) == 'payload.bin') { @@ -151,10 +135,7 @@ class SourceResolver { } } - private async searchLeafDir( - src: string, - factoryPath: string | null, - ): Promise { + private async searchLeafDir(src: string, factoryPath: string | null): Promise { if (!(await exists(src))) { return { src: null, @@ -186,8 +167,7 @@ class SourceResolver { return await this.wrapLeafFile(imagesZip, factoryPath || src) } - let newFactoryPath = (await fs.readdir(src)) - .find(f => f.startsWith(`${this.device}-${this.buildId}-factory-`)) + let newFactoryPath = (await fs.readdir(src)).find(f => f.startsWith(`${this.device}-${this.buildId}-factory-`)) if (newFactoryPath != undefined) { // Factory images zip return await this.wrapLeafFile(`${src}/${newFactoryPath}`, newFactoryPath) @@ -206,21 +186,19 @@ class SourceResolver { // Directory let tryDirs = [ - ...(this.buildId != null && [ + ...((this.buildId != null && [ `${src}/${this.buildId}`, `${src}/${this.device}/${this.buildId}`, `${src}/${this.buildId}/${this.device}`, - ] || []), + ]) || + []), `${src}/${this.device}`, src, ] // Also try to find extracted factory images first: device-buildId if (this.buildId != null) { - tryDirs = [ - ...tryDirs.map(p => `${p}/${this.device}-${this.buildId}`), - ...tryDirs, - ] + tryDirs = [...tryDirs.map(p => `${p}/${this.device}-${this.buildId}`), ...tryDirs] } for (let dir of tryDirs) { diff --git a/src/images/download.ts b/src/images/download.ts index e451518..f023f72 100644 --- a/src/images/download.ts +++ b/src/images/download.ts @@ -52,7 +52,8 @@ async function getUrl(type: ImageType, buildId: string, device: string, cache: I cache[type] = index } - let filePrefix = filePattern.replace('DEVICE', device) + let filePrefix = filePattern + .replace('DEVICE', device) .replace('BUILDID', buildId == 'latest' ? '' : buildId.toLowerCase() + '-') let urlPrefix = DL_URL_PREFIX + filePrefix @@ -63,9 +64,7 @@ async function getUrl(type: ImageType, buildId: string, device: string, cache: I } if (buildId == 'latest') { - return matches - .map(m => m[1]) - .sort((a, b) => b.localeCompare(a))[0] + return matches.map(m => m[1]).sort((a, b) => b.localeCompare(a))[0] } else { return matches[0][1] } @@ -87,9 +86,12 @@ export async function downloadFile( throw new Error(`Error ${resp.status}: ${resp.statusText}`) } - let bar = new cliProgress.SingleBar({ - format: ' {bar} {percentage}% | {value}/{total} MB', - }, cliProgress.Presets.shades_classic) + let bar = new cliProgress.SingleBar( + { + format: ' {bar} {percentage}% | {value}/{total} MB', + }, + cliProgress.Presets.shades_classic, + ) let progress = 0 let totalSize = parseInt(resp.headers.get('content-length') ?? '0') / 1e6 bar.start(Math.round(totalSize), 0) diff --git a/src/selinux/contexts.ts b/src/selinux/contexts.ts index ead1530..b1272df 100644 --- a/src/selinux/contexts.ts +++ b/src/selinux/contexts.ts @@ -11,8 +11,7 @@ const CONTEXT_FILENAMES = new Set([ // Plain TYPE_contexts for AOSP sources ...CONTEXT_TYPES.map(type => `${type}_contexts`), // PART_TYPE_contexts for built systems - ...CONTEXT_TYPES.flatMap(type => Array.from(EXT_PARTITIONS.values()) - .map(part => `${part}_${type}_contexts`)), + ...CONTEXT_TYPES.flatMap(type => Array.from(EXT_PARTITIONS.values()).map(part => `${part}_${type}_contexts`)), // Special case for vendor 'vndservice_contexts', ]) @@ -60,8 +59,7 @@ export async function parsePartContexts(root: string) { } function diffContexts(ctxRef: SelinuxContexts, ctxNew: SelinuxContexts) { - return new Map(Array.from(ctxNew.entries()) - .filter(([ctx]) => !ctxRef.has(ctx))) + return new Map(Array.from(ctxNew.entries()).filter(([ctx]) => !ctxRef.has(ctx))) } export function diffPartContexts(pctxRef: SelinuxPartContexts, pctxNew: SelinuxPartContexts) { diff --git a/src/selinux/keys.ts b/src/selinux/keys.ts index d69aea5..6a09a81 100644 --- a/src/selinux/keys.ts +++ b/src/selinux/keys.ts @@ -30,7 +30,14 @@ async function parseMacPermissions(xml: string) { let signers = [] if (doc.policy) { - for (let { $: { signature: rawSig }, seinfo: [{ $: { value: seinfoId }}]} of doc.policy.signer) { + for (let { + $: { signature: rawSig }, + seinfo: [ + { + $: { value: seinfoId }, + }, + ], + } of doc.policy.signer) { // Parse base64 cert or leave it as a reference let cert = rawSig.startsWith('@') ? rawSig.slice(1) : parseHex(rawSig) signers.push({ @@ -132,13 +139,16 @@ export function resolveKeys( let keyToPaths = new Map(srcKeys.map(k => [k.keyId, Array.from(k.certPaths.values())])) // Build seinfo -> paths map - let seinfoToPaths = new Map(srcMacPerms.filter(s => typeof s.cert == 'string') - .map(s => [s.seinfoId, keyToPaths.get(s.cert as string)!])) + let seinfoToPaths = new Map( + srcMacPerms.filter(s => typeof s.cert == 'string').map(s => [s.seinfoId, keyToPaths.get(s.cert as string)!]), + ) // Build cert -> paths map - return new Map(compiledMacPerms - .filter(s => seinfoToPaths.has(s.seinfoId) && s.cert instanceof Uint8Array) - .map(s => [s.cert as Uint8Array, seinfoToPaths.get(s.seinfoId)!])) + return new Map( + compiledMacPerms + .filter(s => seinfoToPaths.has(s.seinfoId) && s.cert instanceof Uint8Array) + .map(s => [s.cert as Uint8Array, seinfoToPaths.get(s.seinfoId)!]), + ) } function serializeCert(cert: Uint8Array, lineLength: number) { diff --git a/src/selinux/labels.ts b/src/selinux/labels.ts index c399ce3..b1753b0 100644 --- a/src/selinux/labels.ts +++ b/src/selinux/labels.ts @@ -30,7 +30,9 @@ export async function enumerateSelinuxLabels(root: string) { } export function generateFileContexts(labels: SelinuxFileLabels) { - return Array.from(labels.entries()) - .map(([path, context]) => `${_.escapeRegExp(path)} ${context}`) - .join('\n') + '\n' + return ( + Array.from(labels.entries()) + .map(([path, context]) => `${_.escapeRegExp(path)} ${context}`) + .join('\n') + '\n' + ) } diff --git a/src/util/cli.ts b/src/util/cli.ts index b274db3..c81c7b6 100644 --- a/src/util/cli.ts +++ b/src/util/cli.ts @@ -18,10 +18,7 @@ export function stopActionSpinner(spinner: ora.Ora) { spinner.stopAndPersist() } -export async function withSpinner( - action: string, - callback: (spinner: ora.Ora) => Promise, -) { +export async function withSpinner(action: string, callback: (spinner: ora.Ora) => Promise) { let spinner = startActionSpinner(action) let ret = await callback(spinner) stopActionSpinner(spinner) diff --git a/src/util/partitions.ts b/src/util/partitions.ts index f432f9f..6067da6 100644 --- a/src/util/partitions.ts +++ b/src/util/partitions.ts @@ -21,30 +21,15 @@ export enum Partition { } // Android system partitions, excluding "system" -export type ExtSysPartition = Partition.SystemExt | - Partition.Product | - Partition.Vendor | - Partition.Odm -export const EXT_SYS_PARTITIONS = new Set([ - 'system_ext', - 'product', - 'vendor', - 'odm', -]) +export type ExtSysPartition = Partition.SystemExt | Partition.Product | Partition.Vendor | Partition.Odm +export const EXT_SYS_PARTITIONS = new Set(['system_ext', 'product', 'vendor', 'odm']) // GKI DLKM partitions -export type DlkmPartition = Partition.VendorDlkm | - Partition.OdmDlkm -export const DLKM_PARTITIONS = new Set([ - 'vendor_dlkm', - 'odm_dlkm', -]) +export type DlkmPartition = Partition.VendorDlkm | Partition.OdmDlkm +export const DLKM_PARTITIONS = new Set(['vendor_dlkm', 'odm_dlkm']) export type ExtPartition = ExtSysPartition | DlkmPartition -export const EXT_PARTITIONS = new Set([ - ...EXT_SYS_PARTITIONS, - ...DLKM_PARTITIONS, -]) +export const EXT_PARTITIONS = new Set([...EXT_SYS_PARTITIONS, ...DLKM_PARTITIONS]) // All system partitions export type SysPartition = Partition.System | ExtPartition