From f4a2cc57296a97c8579307ceeea25fc5fe97375f Mon Sep 17 00:00:00 2001 From: octocorvus Date: Wed, 7 Jun 2023 17:57:12 +0000 Subject: [PATCH 1/2] prefix addition/removal with plus/minus sign in diff output Improves output of diff commands (diff-files, diff-props and diff-vintf) by prefixing addition and removal by plus (+) and minus (-) sign, respectively. Adds `--type` command line flag to specify output type (can use one of `all`, `added` and `removed`; `all` is default). Also, solves an issue where information (about which files/props/vintf are added/removed) is lost when piping the output of diff commands (in some shells). --- src/commands/diff-files.ts | 35 ++++++---------- src/commands/diff-props.ts | 36 +++++------------ src/commands/diff-vintf.ts | 32 ++++++--------- src/util/diff.ts | 82 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 66 deletions(-) create mode 100644 src/util/diff.ts diff --git a/src/commands/diff-files.ts b/src/commands/diff-files.ts index a43d9b8a..62515f1e 100644 --- a/src/commands/diff-files.ts +++ b/src/commands/diff-files.ts @@ -1,20 +1,13 @@ -import { Command, flags } from '@oclif/command' -import chalk from 'chalk' +import { Command } from '@oclif/command' import { diffLists, listPart } from '../blobs/file-list' +import { DIFF_FLAGS, DiffList, printDiffList } from '../util/diff' import { ALL_SYS_PARTITIONS } from '../util/partitions' 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, - }), - } + static flags = DIFF_FLAGS static args = [ { name: 'sourceRef', description: 'path to root of reference system', required: true }, @@ -23,10 +16,12 @@ export default class DiffFiles extends Command { async run() { let { - flags: { all }, + flags: { type }, args: { sourceRef, sourceNew }, } = this.parse(DiffFiles) + let diffs = [] + for (let partition of ALL_SYS_PARTITIONS) { let filesRef = await listPart(partition, sourceRef) if (filesRef == null) { @@ -35,17 +30,13 @@ export default class DiffFiles extends Command { let filesNew = (await listPart(partition, sourceNew)) ?? [] - this.log(chalk.bold(partition)) - - let newAdded = diffLists(filesRef, filesNew) - let newRemoved = diffLists(filesNew, filesRef) - - newRemoved.forEach(f => this.log(chalk.red(` ${f}`))) - if (all) { - newAdded.forEach(f => this.log(chalk.green(` ${f}`))) - } - - this.log() + diffs.push({ + partition, + added: diffLists(filesRef, filesNew), + removed: diffLists(filesNew, filesRef), + } as DiffList) } + + printDiffList(diffs, type, this.log) } } diff --git a/src/commands/diff-props.ts b/src/commands/diff-props.ts index f325f4cd..2598d5ef 100644 --- a/src/commands/diff-props.ts +++ b/src/commands/diff-props.ts @@ -1,7 +1,7 @@ import { Command, flags } from '@oclif/command' -import chalk from 'chalk' import { diffPartitionProps, loadPartitionProps, PartitionProps } from '../blobs/props' +import { DIFF_FLAGS, DiffMap, printDiffMap } from '../util/diff' const BUILD_KEY_PATTERN = /^ro(?:\.(?:system|system_ext|product|vendor|odm|vendor_dlkm|odm_dlkm))?\.build\..+$/ @@ -15,25 +15,12 @@ function removeBuildProps(partProps: PartitionProps) { } } -function forEachPropLine(props: Map, callback: (prop: string) => void) { - for (let [key, value] of props.entries()) { - callback(`${key}=${chalk.bold(value)}`) - } -} - -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))}`) - } -} - 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 }), + ...DIFF_FLAGS } static args = [ @@ -43,7 +30,7 @@ export default class DiffProps extends Command { async run() { let { - flags: { all, includeBuild }, + flags: { type, includeBuild }, args: { sourceRef, sourceNew }, } = this.parse(DiffProps) @@ -58,16 +45,15 @@ export default class DiffProps extends Command { let partChanges = diffPartitionProps(propsRef, propsNew) - for (let [partition, changes] of partChanges.entries()) { - this.log(chalk.bold(partition)) - - forEachPropLine(changes.removed, p => this.log(chalk.red(` ${p}`))) - if (all) { - forEachPropLine(changes.added, p => this.log(chalk.green(` ${p}`))) - forEachPropLineModified(changes.modified, p => this.log(` ${p}`)) - } + let diffs = [] - this.log() + for (let [partition, changes] of partChanges.entries()) { + diffs.push({ + partition, + ...changes + } as DiffMap) } + + printDiffMap(diffs, type, this.log) } } diff --git a/src/commands/diff-vintf.ts b/src/commands/diff-vintf.ts index 8701ee4f..b3d80c3b 100644 --- a/src/commands/diff-vintf.ts +++ b/src/commands/diff-vintf.ts @@ -1,21 +1,14 @@ -import { Command, flags } from '@oclif/command' +import { Command } from '@oclif/command' import { promises as fs } from 'fs' -import chalk from 'chalk' import { diffVintfHals, getHalFqNames, loadPartVintfInfo, serializeVintfHals } from '../blobs/vintf' +import { DIFF_FLAGS, DiffList, printDiffList } from '../util/diff' import { EXT_PARTITIONS } from '../util/partitions' 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, - }), - } + static flags = DIFF_FLAGS static args = [ { name: 'sourceRef', description: 'path to root of reference system', required: true }, @@ -25,13 +18,15 @@ export default class DiffVintf extends Command { async run() { let { - flags: { all }, + flags: { type }, args: { sourceRef, sourceNew, outPath }, } = this.parse(DiffVintf) let vintfRef = await loadPartVintfInfo(sourceRef) let vintfNew = await loadPartVintfInfo(sourceNew) + let diffs = [] + for (let partition of EXT_PARTITIONS) { let halsRef = vintfRef.get(partition)?.manifest if (halsRef == null) { @@ -40,22 +35,21 @@ export default class DiffVintf extends Command { let halsNew = vintfNew.get(partition)?.manifest ?? [] - this.log(chalk.bold(partition)) - let newAdded = diffVintfHals(halsRef, halsNew) let newRemoved = diffVintfHals(halsNew, halsRef) - getHalFqNames(newRemoved).forEach(f => this.log(chalk.red(` ${f}`))) - if (all) { - getHalFqNames(newAdded).forEach(f => this.log(chalk.green(` ${f}`))) - } + diffs.push({ + partition, + added: getHalFqNames(newAdded), + removed: getHalFqNames(newRemoved), + } as DiffList) if (outPath != undefined) { let outManifest = serializeVintfHals(newRemoved) await fs.writeFile(outPath, outManifest) } - - this.log() } + + printDiffList(diffs, type, this.log) } } diff --git a/src/util/diff.ts b/src/util/diff.ts new file mode 100644 index 00000000..ee042229 --- /dev/null +++ b/src/util/diff.ts @@ -0,0 +1,82 @@ +import { flags } from "@oclif/command" +import chalk from "chalk" + +export enum DiffTypes { + ALL = 'all', + ADDED = 'added', + REMOVED = 'removed', +} + +export interface DiffList { + partition: string + added: Array + removed: Array +} + +export interface DiffMap { + partition: string + added: Map + modified: Map> + removed: Map +} + +export const DIFF_FLAGS = { + help: flags.help({ char: 'h' }), + type: flags.enum({ + char: 't', + description: 'output type of diff', + options: Object.values(DiffTypes), + default: DiffTypes.ALL, + }), +} + +export function printDiffList( + diffs: DiffList[], + type: DiffTypes, + callback: (message?: string) => void, +) { + let showAdded = [DiffTypes.ALL, DiffTypes.ADDED].includes(type) + let showRemoved = [DiffTypes.ALL, DiffTypes.REMOVED].includes(type) + + for (let diff of diffs) { + callback(chalk.bold(diff.partition)) + + if (showAdded) { + diff.added.forEach((value) => callback(chalk.green(`+ ${value}`))) + } + if (showRemoved) { + diff.removed.forEach((value) => callback(chalk.red(`- ${value}`))) + } + + callback() + } +} + +export function printDiffMap( + diffs: DiffMap[], + type: DiffTypes, + callback: (message?: string) => void, +) { + let showAddedAndModified = [DiffTypes.ALL, DiffTypes.ADDED].includes(type) + let showRemoved = [DiffTypes.ALL, DiffTypes.REMOVED].includes(type) + + for (let diff of diffs) { + callback(chalk.bold(diff.partition)) + + if (showAddedAndModified) { + diff.added.forEach((value, key) => { + callback(chalk.green(`+ ${key}=${chalk.bold(value)}`)) + }) + diff.modified.forEach(([oldValue, newValue], key) => { + callback(`${key}=${chalk.bold(oldValue)} -> ${chalk.bold(chalk.bold.blue(newValue))}`) + }) + } + if (showRemoved) { + diff.removed.forEach((value, key) => { + callback(chalk.red(`- ${key}=${chalk.bold(value)}`)) + }) + } + + callback() + } +} From f3b02b6d86a7185bdec7ef40c62cf0d82d372daa Mon Sep 17 00:00:00 2001 From: octocorvus Date: Wed, 7 Jun 2023 18:04:27 +0000 Subject: [PATCH 2/2] add support for printing output as JSON for diff commands --- src/util/diff.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/util/diff.ts b/src/util/diff.ts index ee042229..db01dcb6 100644 --- a/src/util/diff.ts +++ b/src/util/diff.ts @@ -1,10 +1,13 @@ import { flags } from "@oclif/command" import chalk from "chalk" +const JSON_INDENT = 2 + export enum DiffTypes { ALL = 'all', ADDED = 'added', REMOVED = 'removed', + JSON = 'json', } export interface DiffList { @@ -30,11 +33,24 @@ export const DIFF_FLAGS = { }), } +function stringify(object: object) { + return JSON.stringify( + object, + (_key, value) => value instanceof Map ? Object.fromEntries(value) : value, + JSON_INDENT, + ) +} + export function printDiffList( diffs: DiffList[], type: DiffTypes, callback: (message?: string) => void, ) { + if (type === DiffTypes.JSON) { + callback(stringify(diffs)) + return + } + let showAdded = [DiffTypes.ALL, DiffTypes.ADDED].includes(type) let showRemoved = [DiffTypes.ALL, DiffTypes.REMOVED].includes(type) @@ -57,6 +73,11 @@ export function printDiffMap( type: DiffTypes, callback: (message?: string) => void, ) { + if (type === DiffTypes.JSON) { + callback(stringify(diffs)) + return + } + let showAddedAndModified = [DiffTypes.ALL, DiffTypes.ADDED].includes(type) let showRemoved = [DiffTypes.ALL, DiffTypes.REMOVED].includes(type)