Created
July 5, 2023 05:25
-
-
Save esafirm/d0cbe7a6b43f66f27520120c0cdbdca2 to your computer and use it in GitHub Desktop.
Poor Man's Ruler (https://github.com/spotify/ruler)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Parse the result from [apkanalyzer dex packages <apk>] and give us summary about the data | |
* | |
* Author @esafirm | |
*/ | |
// (type/state/defined methods/referenced methods /byte size/name) | |
// P, C, M, and F indicate packages, classes, methods, and fields, respectively. And x, k, r, and d indicate removed, kept, referenced and defined nodes, respectively. | |
enum Type { | |
Packages, | |
Classes, | |
Methods, | |
Fields, | |
} | |
namespace Type { | |
export function of(type: string): Type { | |
switch (type) { | |
case "P": | |
return Type.Packages; | |
case "C": | |
return Type.Classes; | |
case "M": | |
return Type.Methods; | |
case "F": | |
return Type.Fields; | |
} | |
throw new Error(`Unknown type: ${type}`); | |
} | |
} | |
enum State { | |
Removed, | |
Kept, | |
Referenced, | |
Defined, | |
} | |
namespace State { | |
export function of(state: string): State { | |
switch (state) { | |
case "x": | |
return State.Removed; | |
case "k": | |
return State.Kept; | |
case "r": | |
return State.Referenced; | |
case "d": | |
return State.Defined; | |
} | |
throw new Error(`Unknown state: ${state}`); | |
} | |
} | |
function sizeToHumandReadable(size: string): string { | |
const sizeInByte = parseInt(size); | |
const sizeInKb = sizeInByte / 1024; | |
const sizeInMb = sizeInKb / 1024; | |
if (sizeInMb > 1) { | |
return `${sizeInMb.toFixed(2)} MB`; | |
} else if (sizeInKb > 1) { | |
return `${sizeInKb.toFixed(2)} KB`; | |
} else { | |
return `${sizeInByte} B`; | |
} | |
} | |
type TableRow = { | |
size: string; | |
name: string; | |
}; | |
/* Main */ | |
/* ------------------------------------------ */ | |
//@ts-ignore also declaared in index.ts | |
const fs = require("fs"); | |
const readline = require("readline"); | |
//@ts-ignore also declaared in index.ts | |
const inputPath = "info.txt"; | |
const outputPath = "info.html"; | |
if (!fs.existsSync(inputPath)) { | |
throw new Error(`Input not exists at: ${inputPath}`); | |
} | |
const lineReader = readline.createInterface({ | |
input: fs.createReadStream(inputPath), | |
}); | |
const rows: TableRow[] = []; | |
lineReader.on("line", (line: string) => { | |
const [typeString, stateString, defined, referenced, size, name] = line.split(/\s+/); | |
const type = Type.of(typeString); | |
if (type === Type.Packages) { | |
if (name.split(".").length <= 3) { | |
rows.push({ | |
size: sizeToHumandReadable(size), | |
name: name, | |
}); | |
} | |
} | |
}); | |
lineReader.on("error", (err: Error) => { | |
throw err; | |
}); | |
lineReader.on("close", () => { | |
// create HTML table from the rows data | |
const content = ` | |
<html> | |
<head> | |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css"> | |
</head> | |
<body> | |
<table> | |
<tr> | |
<th>Size</th> | |
<th>Name</th> | |
</tr> | |
${rows.map((row) => `<tr><td>${row.size}</td><td>${row.name}</td></tr>`).join("\n")} | |
</table> | |
</body> | |
</html> | |
`; | |
fs.writeFile(outputPath, content, (err: Error) => { | |
if (err) { | |
console.log("Error is happening!"); | |
console.error(err); | |
} else { | |
console.log("Report parsing success!"); | |
} | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment