You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
5.0 KiB
JavaScript

'use strict';
const split = require("split");
const through2 = require("through2");
const path = require("path");
const rightPad = require("right-pad");
const defaultValue = require("default-value");
let unfound = {};
let found = {};
let foundBase = {};
let probablyNotReallyMissing = {};
let ceaseProcessing = false;
let bannedPrefixes = [
"/dev/",
"/sys/",
"/run/"
]
function isLibrary(name) {
return (name.match(/\.so(?:\.[0-9]+)?$/) && !name.match(/\.so(?:\.[0-9]+)\.so$/));
}
function getLibraryName(name) {
let match = /^(.+)\.so(?:\.[0-9]+)?$/.exec(name);
if (match == null) {
throw new Error(`Library name regex failed for library: ${name}`);
} else {
return match[1];
}
}
process.stdin
.pipe(split())
.pipe(through2.obj(function(item, enc, cb) {
if (item.trim().length === 0) {
cb();
} else {
let match = /^\s*(?:\[pid\s*[0-9]+\] )?(?:open|stat)\("([^"]+)", ([A-Z_|]+|0x[0-9a-f]+|\{[^\}]+\})\) = (-?[0-9]+)(?: ([A-Z]+))?/.exec(item.toString());
if (match != null) {
let path = match[1];
if (!bannedPrefixes.some(prefix => path.indexOf(prefix) === 0)) {
this.push({
path: match[1],
flags: match[2].split("|"),
status: parseInt(match[3]),
error: match[4]
});
}
}
cb();
}
}))
.pipe(through2.obj(function(item, enc, cb) {
let basename = path.basename(item.path);
if (basename === "gdb") {
ceaseProcessing = true;
found["-- GDB ENCOUNTERED --"] = "";
unfound["-- GDB ENCOUNTERED --"] = "";
}
if (ceaseProcessing === false) {
if (item.status === -1) {
unfound[basename] = item.path;
} else {
delete unfound[basename];
found[basename] = item.path;
if (isLibrary(basename)) {
foundBase[getLibraryName(basename)] = item.path;
}
}
}
cb();
}))
.on("finish", () => {
Object.keys(unfound).forEach((basename) => {
function markNotMissing(reason) {
delete unfound[basename];
probablyNotReallyMissing[basename] = reason;
}
if (basename.match(/\.dll.so$/) && found[basename.slice(0, -3)]) {
markNotMissing("mono: is actually a DLL");
} else if (basename.match(/\.dll.so.la$/) && found[basename.slice(0, -6)]) {
markNotMissing("mono: is actually a DLL");
} else if (basename.match(/\.res(?:G|S)?$/)) {
markNotMissing("unity: .res / .resG / .resS file");
} else if (unfound[basename].match(/\/aot-cache\/[^\/]+\/[^\/]+$/)) {
markNotMissing("mono: is an AOT cache path");
} else if (isLibrary(basename) && foundBase[getLibraryName(basename)]) {
markNotMissing("other library version was already found")
}
});
function toArray(obj) {
return Object.keys(obj).map((key) => {
let value = obj[key];
return {
basename: key,
path: value
}
});
}
let foundItems = toArray(found);
let missingItems = toArray(unfound);
let probablyNotReallyMissingItems = toArray(probablyNotReallyMissing);
let missingLibraries = [];
let missingOther = [];
missingItems.forEach((item) => {
if (isLibrary(item.basename)) {
missingLibraries.push(item);
} else {
missingOther.push(item);
}
});
function printCategory(name, items, options = {}) {
let maxWidth = Math.max.apply(null, items.map(item => item.basename.length));
let cutoff = defaultValue(options.cutoff, 30);
let pathFormat = defaultValue(options.pathFormat, "%");
console.log(`\n${name}:`);
if (items.length === 0) {
console.log(" (none)");
} else {
items.slice(0, cutoff).forEach((item) => {
console.log(` ${rightPad(item.basename, maxWidth + 5)}${pathFormat.replace("%", item.path)}`);
});
if (items.length > cutoff) {
console.log(` (... ${items.length - cutoff} more ...)`);
}
}
}
printCategory("Found", foundItems);
printCategory("Probably found", probablyNotReallyMissingItems, {
pathFormat: "reason: %"
});
printCategory("Missing miscellaneous", missingOther, {
pathFormat: "(last attempted path: %)"
});
printCategory("MISSING LIBRARIES", missingLibraries, {
pathFormat: "(last attempted path: %)"
});
})
.pipe(process.stdout);