feature/node-rewrite
Sven Slootweg 4 years ago
parent 98a4bcb6d8
commit f85ab90be1

@ -1,5 +1,6 @@
MARKER:
- Move to pegjs-import
- Replace all 'this is a bug' errors with @joepie91/unreachable
- LVM / mdraid support and tabs (+ complete refactoring LVM implementation)
- Switch hashing to argon2id
- Switch child_process to execa

@ -14,16 +14,19 @@
"license": "WTFPL",
"dependencies": {
"@babel/register": "^7.8.3",
"@invisible/pegjs-import": "^1.1.1",
"@joepie91/express-react-views": "^1.0.1",
"@joepie91/unreachable": "^1.0.0",
"@validatem/allow-extra-properties": "^0.1.0",
"@validatem/anything": "^0.1.0",
"@validatem/array-of": "^0.1.2",
"@validatem/core": "^0.3.15",
"@validatem/default-to": "^0.1.0",
"@validatem/dynamic": "^0.1.2",
"@validatem/either": "^0.1.9",
"@validatem/error": "^1.1.0",
"@validatem/is-array": "^0.1.1",
"@validatem/is-boolean": "^0.1.1",
"@validatem/is-function": "^0.1.0",
"@validatem/is-number": "^0.1.3",
"@validatem/is-plain-object": "^0.1.1",

@ -101,6 +101,9 @@ module.exports = function () {
// }
console.log(errorChain.getContext(sourceError));
res.render("error", {
error: err
});

@ -7,7 +7,7 @@ const util = require("util");
const execFileAsync = util.promisify(require("child_process").execFile);
const debug = require("debug")("cvm:execBinary");
const asExpression = require("as-expression");
const { rethrowAs } = require("error-chain");
const { rethrowAs, chain } = require("error-chain");
const textParser = require("../text-parser");
const errors = require("./errors");
@ -194,7 +194,7 @@ module.exports = function createBinaryInvocation(command, args = []) {
if (!this._settings.expectedExitCodes.includes(exitCode)) {
// FIXME: Can we actually pass `error` to be chained onto here, when there's a case where `error` is undefined? Namely, when requiring a non-zero exit code, but the process exits with 0.
throw new errors.NonZeroExitCode.chain(error, `Expected exit code to be one of ${JSON.stringify(this._settings.expectedExitCodes)}, but got '${exitCode}'`, {
throw chain(error, errors.NonZeroExitCode, `Expected exit code to be one of ${JSON.stringify(this._settings.expectedExitCodes)}, but got '${exitCode}'`, {
exitCode: exitCode,
stdout: stdout,
stderr: stderr
@ -212,6 +212,7 @@ module.exports = function createBinaryInvocation(command, args = []) {
return undefined;
}
} else {
// FIXME: use @joepie91/unreachable
throw new Error(`Encountered expectation for unexpected channel '${expectation.channel}'; this is a bug, please report it`, {
failedChannel: expectation.channel
});
@ -230,7 +231,7 @@ module.exports = function createBinaryInvocation(command, args = []) {
return undefined;
}
} else {
throw errors.OutputParsingFailed.chain(error, `An error occurred while parsing '${expectation.channel}'`, {
throw chain(error, errors.OutputParsingFailed, `An error occurred while parsing '${expectation.channel}'`, {
failedChannel: expectation.channel
});
}
@ -270,7 +271,7 @@ module.exports = function createBinaryInvocation(command, args = []) {
? `Failed while processing ${error.failedChannel} of command`
: "Failed while processing result of command execution";
throw errors.CommandExecutionFailed.chain(error, message, {
throw chain(error, errors.CommandExecutionFailed, message, {
exitCode: exitCode,
stdout: stdout,
stderr: stderr

@ -1,6 +1,7 @@
"use strict";
const Promise = require("bluebird");
const { chain } = require("error-chain");
const execBinary = require("../exec-binary");
const parseIECBytes = require("../parse-bytes-iec");
@ -120,11 +121,11 @@ module.exports = {
}).then((_output) => {
return true;
}).catch(hasFlag("deviceNotFound"), (error) => {
throw errors.InvalidPath.chain(error, `Specified device '${devicePath}' does not exist`, {
throw chain(error, errors.InvalidPath, `Specified device '${devicePath}' does not exist`, {
path: devicePath
});
}).catch(hasFlag("partitionTableExists"), (error) => {
throw errors.PartitionExists.chain(error, `Refused to create a Physical Volume, as a partition or partition table already exists on device '${devicePath}'`, {
throw chain(error, errors.PartitionExists, `Refused to create a Physical Volume, as a partition or partition table already exists on device '${devicePath}'`, {
path: devicePath
});
});
@ -141,11 +142,11 @@ module.exports = {
}).then((_output) => {
return true;
}).catch(hasFlag("deviceNotFound"), (error) => {
throw errors.InvalidPath.chain(error, `Specified device '${devicePath}' does not exist`, {
throw chain(error, errors.InvalidPath, `Specified device '${devicePath}' does not exist`, {
path: devicePath
});
}).catch(hasFlag("notAPhysicalVolume"), (error) => {
throw errors.InvalidPath.chain(error, `Specified device '${devicePath}' is not a Physical Volume`, {
throw chain(error, errors.InvalidPath, `Specified device '${devicePath}' is not a Physical Volume`, {
path: devicePath
});
});
@ -178,17 +179,17 @@ module.exports = {
}).catch(hasFlag("deviceNotFound"), (error) => {
let failedDevices = error.getAllContext().result.deviceNotFound;
throw errors.InvalidPath.chain(error, `The following specified devices do not exist: ${failedDevices.join(", ")}`, {
throw chain(error, errors.InvalidPath, `The following specified devices do not exist: ${failedDevices.join(", ")}`, {
paths: failedDevices
});
}).catch(hasFlag("partitionTableExists"), (error) => {
let failedDevices = error.getAllContext().result.partitionTableExists;
throw errors.PartitionExists.chain(error, `Refused to create a Volume Group, as partitions or partition tables already exist on the following devices: ${failedDevices.join(", ")}`, {
throw chain(error, errors.PartitionExists, `Refused to create a Volume Group, as partitions or partition tables already exist on the following devices: ${failedDevices.join(", ")}`, {
paths: failedDevices
});
}).catch(hasFlag("volumeGroupExists"), (error) => {
throw errors.VolumeGroupExists.chain(error, `A volume group with the name '${name}' already exists`, {
throw chain(error, errors.VolumeGroupExists, `A volume group with the name '${name}' already exists`, {
volumeGroupName: name
});
}).catch(hasFlag("physicalVolumeInUse"), (error) => {
@ -198,7 +199,7 @@ module.exports = {
return `${device} (${volumeGroup})`;
}).join(", ");
throw errors.PhysicalVolumeInUse.chain(error, `The following specified Physical Volumes are already in use in another Volume Group: ${failedItemString}`, {
throw chain(error, errors.PhysicalVolumeInUse, `The following specified Physical Volumes are already in use in another Volume Group: ${failedItemString}`, {
volumes: failedItems
});
});
@ -218,21 +219,21 @@ module.exports = {
}).then((_output) => {
return true;
}).catch(hasFlag("deviceNotFound"), (error) => {
throw errors.InvalidPath.chain(error, `Specified device '${physicalVolume}' does not exist`, {
throw chain(error, errors.InvalidPath, `Specified device '${physicalVolume}' does not exist`, {
path: physicalVolume
});
}).catch(hasFlag("volumeGroupNotFound"), (error) => {
throw errors.InvalidVolumeGroup.chain(error, `Specified Volume Group '${volumeGroup}' does not exist`, {
throw chain(error, errors.InvalidVolumeGroup, `Specified Volume Group '${volumeGroup}' does not exist`, {
volumeGroupName: volumeGroup
});
}).catch(hasFlag("physicalVolumeInUse"), (error) => {
let volume = error.getAllContext().result.physicalVolumeInUse;
throw errors.PhysicalVolumeInUse.chain(error, `Specified Physical Volume '${physicalVolume}' is already in use in another Volume Group (${volume.volumeGroup})`, {
throw chain(error, errors.PhysicalVolumeInUse, `Specified Physical Volume '${physicalVolume}' is already in use in another Volume Group (${volume.volumeGroup})`, {
volume: volume
});
}).catch(hasFlag("partitionTableExists"), (error) => {
throw errors.PartitionExists.chain(error, `Refused to add device to Volume Group, as a partition or partition table already exists on device '${physicalVolume}'`, {
throw chain(error, errors.PartitionExists, `Refused to add device to Volume Group, as a partition or partition table already exists on device '${physicalVolume}'`, {
path: physicalVolume
});
});

@ -8,22 +8,25 @@ const itemsToObject = require("../items-to-object");
/* FIXME: Error handling, eg. device not found errors */
function outputParser(rootRule) {
function outputParser(parserPath) {
return createPegParser({
grammarFile: path.join(__dirname, "./parser.pegjs"),
options: {
allowedStartRules: [ rootRule ]
}
grammarFile: path.join(__dirname, parserPath)
});
}
let attributesParser = outputParser("./parsers/commands/attributes.pegjs");
let infoParser = outputParser("./parsers/commands/info.pegjs");
let scanParser = outputParser("./parsers/commands/scan.pegjs");
module.exports = {
attributes: function ({ devicePath }) {
return Promise.try(() => {
return attributesParser;
}).then((parser) => {
return execBinary("smartctl", [devicePath])
.asRoot()
.withFlags({ attributes: true })
.requireOnStdout(outputParser("RootAttributes"))
.requireOnStdout(parser)
.execute();
}).then((output) => {
// NOTE: Ignore the header, for now
@ -32,10 +35,12 @@ module.exports = {
},
info: function ({ devicePath }) {
return Promise.try(() => {
return infoParser;
}).then((parser) => {
return execBinary("smartctl", [devicePath])
.asRoot()
.withFlags({ info: true })
.requireOnStdout(outputParser("RootInfo"))
.requireOnStdout(parser)
.execute();
}).then((output) => {
// NOTE: Ignore the header, for now
@ -44,10 +49,12 @@ module.exports = {
},
scan: function () {
return Promise.try(() => {
return scanParser;
}).then((parser) => {
return execBinary("smartctl")
.asRoot()
.withFlags({ scan: true })
.requireOnStdout(outputParser("RootScan"))
.requireOnStdout(parser)
.execute();
}).then((output) => {
// NOTE: Ignore the header, for now

@ -1,249 +0,0 @@
{
const matchValue = require("match-value");
const syncpipe = require("syncpipe");
const {B} = require("../unit-bytes-iec");
const mapAttributeFlags = require("./map-attribute-flags");
}
RootInfo
= header:Header infoSection:InfoSection Newline* {
return { ...header, fields: infoSection }
};
RootScan
= devices:ScanDevice* {
return { devices: devices };
}
RootAttributes
= header:Header attributesSection:AttributesSection Newline* {
return { ...header, attributes: attributesSection }
};
_
= (" " / "\t")*
RestOfLine
= content:$[^\n]+ Newline {
return content;
}
Newline
= "\n"
/ "\r\n"
Header 'header'
= "smartctl " versionString:RestOfLine "Copyright" copyrightStatement:RestOfLine Newline {
return { versionString, copyrightStatement };
}
BytesValue
= value:SeparatedNumberValue {
return B(value);
}
NumberValue
= value:$[0-9]+ {
return parseInt(value);
}
SeparatedNumberValue
= value:$[0-9,]+ {
return syncpipe(value, [
(_) => _.replace(/,/g, ""),
(_) => parseInt(_)
]);
}
HexNumberValue
= value:$[0-9A-Fa-f]+ {
return parseInt(value, 16);
}
IdentifierValue
= value:$[a-zA-Z_-]+ {
return value;
}
// smartctl --scan
ScanDevice 'scanned device'
= path:$[^ ]+ _ "-d" _ interface_:$[^ ]+ _ RestOfLine {
return { path: path, interface: interface_ };
}
// smartctl --info
InfoSection 'information section'
= "=== START OF INFORMATION SECTION ===" Newline fields:(InfoField+) {
return fields.filter((field) => field != null);
}
InfoField 'information field'
= InfoFieldSimple
/ InfoFieldIgnored
/ InfoFieldSize
/ InfoFieldRPM
/ InfoFieldSectorSizes
/ InfoFieldBoolean
/ InfoFieldUnknown
InfoFieldSimpleKey
= "Device Model" { return "model"; }
/ "Model Number" { return "model"; }
/ "Model Family" { return "modelFamily"; }
/ "Serial Number" { return "serialNumber"; }
/ "LU WWN Device Id" { return "wwn"; }
/ "Firmware Version" { return "firmwareVersion"; }
/ "Form Factor" { return "formFactor"; }
/ "ATA Version is" { return "ataVersion"; }
/ "SATA Version is" { return "sataVersion"; }
InfoFieldSimple
= key:InfoFieldSimpleKey ":" _ value:RestOfLine {
return { key: key, value: value };
}
InfoFieldUnknown
= key:$[^:]+ ":" _ RestOfLine {
console.warn(`Encountered unrecognized SMART info key: ${key}`);
return null;
}
InfoFieldIgnoredKey
= "Device is"
/ "Local Time is"
InfoFieldIgnored
= key:InfoFieldIgnoredKey ":" _ RestOfLine {
return null;
}
/ "SMART support is:" _ ("Available" / "Unavailable") RestOfLine {
// We don't actually care about this entry, but have to specify its possible values explicitly, to distinguish it from the entry we *do* care about that (annoyingly) uses the same key; see InfoFieldBoolean
return null;
}
InfoFieldSize
// NOTE: We don't actually care about the human-friendly display size after the 'bytes' specifier, hence the RestOfLine
= InfoFieldSizeKey _ value:SeparatedNumberValue _ "bytes"? _ RestOfLine {
return {
key: "size",
value: B(value)
};
}
InfoFieldSizeKey
= "User Capacity:"
/ "Total NVM Capacity:"
InfoFieldRPM
= "Rotation Rate:" _ value:NumberValue _ "rpm" Newline {
return {
key: "rpm",
value: value
};
}
InfoFieldSectorSizes
= "Sector Sizes:" _ logicalSize:BytesValue _ "bytes logical," _ physicalSize:BytesValue _ "bytes physical" Newline {
return {
key: "sectorSizes",
value: {
logical: logicalSize,
physical: physicalSize
}
};
}
InfoFieldBooleanKey
= "SMART support is" { return "smartEnabled"; }
InfoFieldBoolean
= key:InfoFieldBooleanKey ":" _ value:RestOfLine {
return {
key: key,
value: matchValue(value, {
Enabled: true,
Disabled: false
})
};
}
// smartctl --attributes
AttributesSection
= AttributesSectionSATA
/ AttributesSectionNVMe
AttributesSectionSATA
= "=== START OF READ SMART DATA SECTION ===" Newline
"SMART Attributes Data Structure revision number:" _ NumberValue Newline
"Vendor Specific SMART Attributes with Thresholds:" Newline
"ID#" _ "ATTRIBUTE_NAME" _ "FLAG" _ "VALUE" _ "WORST" _ "THRESH" _ "TYPE" _ "UPDATED" _ "WHEN_FAILED" _ "RAW_VALUE" Newline
attributes:AttributeFieldSATA+ {
return attributes;
}
AttributesSectionNVMe
= "=== START OF SMART DATA SECTION ===" Newline
"SMART/Health Information (NVMe Log 0x02)" Newline
attributes:AttributeFieldNVMe+ {
return attributes;
}
AttributeFlags
= "0x" number:HexNumberValue {
return mapAttributeFlags(number);
}
AttributeUpdatedWhen
= "Always"
/ "Offline"
AttributeFailedWhen
= "FAILING_NOW"
/ "In_the_past"
/ "-"
AttributeFieldType
= "Pre-fail"
/ "Old_age"
AttributeFieldSATA
= _ id:NumberValue
_ attributeName:IdentifierValue
_ flags:AttributeFlags
_ value:NumberValue
_ worstValue:NumberValue
_ threshold:NumberValue
_ type:AttributeFieldType
_ updatedWhen:AttributeUpdatedWhen
_ failedWhen:AttributeFailedWhen
_ rawValue:RestOfLine {
return {
id,
attributeName,
flags,
value,
worstValue,
threshold,
rawValue,
updatedWhen: matchValue(updatedWhen, {
"Always": "always",
"Offline": "offline"
}),
type: matchValue(type, {
"Pre-fail": "preFail",
"Old_age": "oldAge"
}),
failingNow: (failedWhen === "FAILING_NOW"),
/* TODO: Should the below include the FAILING_NOW state? */
failedBefore: (failedWhen === "In_the_past")
};
}
AttributeFieldNVMe
= label:$[^:]+ ":" _ value:RestOfLine {
return { label: label, value };
}

@ -0,0 +1,88 @@
import { _, RestOfLine, Newline, NumberValue, HexNumberValue, IdentifierValue } from "../primitives"
import { Header } from "../shared"
{
const matchValue = require("match-value");
const mapAttributeFlags = require("../../map-attribute-flags");
}
RootAttributes
= header:Header attributesSection:AttributesSection Newline* {
return { ...header, attributes: attributesSection }
};
AttributesSection
= AttributesSectionSATA
/ AttributesSectionNVMe
AttributesSectionSATA
= "=== START OF READ SMART DATA SECTION ===" Newline
"SMART Attributes Data Structure revision number:" _ NumberValue Newline
"Vendor Specific SMART Attributes with Thresholds:" Newline
"ID#" _ "ATTRIBUTE_NAME" _ "FLAG" _ "VALUE" _ "WORST" _ "THRESH" _ "TYPE" _ "UPDATED" _ "WHEN_FAILED" _ "RAW_VALUE" Newline
attributes:AttributeFieldSATA+ {
return attributes;
}
AttributesSectionNVMe
= "=== START OF SMART DATA SECTION ===" Newline
"SMART/Health Information (NVMe Log 0x02)" Newline
attributes:AttributeFieldNVMe+ {
return attributes;
}
AttributeFlags
= "0x" number:HexNumberValue {
return mapAttributeFlags(number);
}
AttributeUpdatedWhen
= "Always"
/ "Offline"
AttributeFailedWhen
= "FAILING_NOW"
/ "In_the_past"
/ "-"
AttributeFieldType
= "Pre-fail"
/ "Old_age"
AttributeFieldSATA
= _ id:NumberValue
_ attributeName:IdentifierValue
_ flags:AttributeFlags
_ value:NumberValue
_ worstValue:NumberValue
_ threshold:NumberValue
_ type:AttributeFieldType
_ updatedWhen:AttributeUpdatedWhen
_ failedWhen:AttributeFailedWhen
_ rawValue:RestOfLine {
return {
id,
attributeName,
flags,
value,
worstValue,
threshold,
rawValue,
updatedWhen: matchValue(updatedWhen, {
"Always": "always",
"Offline": "offline"
}),
type: matchValue(type, {
"Pre-fail": "preFail",
"Old_age": "oldAge"
}),
failingNow: (failedWhen === "FAILING_NOW"),
/* TODO: Should the below include the FAILING_NOW state? */
failedBefore: (failedWhen === "In_the_past")
};
}
AttributeFieldNVMe
= label:$[^:]+ ":" _ value:RestOfLine {
return { label: label, value };
}

@ -0,0 +1,106 @@
import { _, RestOfLine, Newline, NumberValue, SeparatedNumberValue, BytesValue } from "../primitives"
import { Header } from "../shared"
{
const matchValue = require("match-value");
}
RootInfo
= header:Header infoSection:InfoSection Newline* {
return { ...header, fields: infoSection }
};
InfoSection 'information section'
= "=== START OF INFORMATION SECTION ===" Newline fields:(InfoField+) {
return fields.filter((field) => field != null);
}
InfoField 'information field'
= InfoFieldSimple
/ InfoFieldIgnored
/ InfoFieldSize
/ InfoFieldRPM
/ InfoFieldSectorSizes
/ InfoFieldBoolean
/ InfoFieldUnknown
InfoFieldSimpleKey
= "Device Model" { return "model"; }
/ "Model Number" { return "model"; }
/ "Model Family" { return "modelFamily"; }
/ "Serial Number" { return "serialNumber"; }
/ "LU WWN Device Id" { return "wwn"; }
/ "Firmware Version" { return "firmwareVersion"; }
/ "Form Factor" { return "formFactor"; }
/ "ATA Version is" { return "ataVersion"; }
/ "SATA Version is" { return "sataVersion"; }
InfoFieldSimple
= key:InfoFieldSimpleKey ":" _ value:RestOfLine {
return { key: key, value: value };
}
InfoFieldUnknown
= key:$[^:]+ ":" _ RestOfLine {
console.warn(`Encountered unrecognized SMART info key: ${key}`);
return null;
}
InfoFieldIgnoredKey
= "Device is"
/ "Local Time is"
InfoFieldIgnored
= key:InfoFieldIgnoredKey ":" _ RestOfLine {
return null;
}
/ "SMART support is:" _ ("Available" / "Unavailable") RestOfLine {
// We don't actually care about this entry, but have to specify its possible values explicitly, to distinguish it from the entry we *do* care about that (annoyingly) uses the same key; see InfoFieldBoolean
return null;
}
InfoFieldSize
// NOTE: We don't actually care about the human-friendly display size after the 'bytes' specifier, hence the RestOfLine
= InfoFieldSizeKey _ value:SeparatedNumberValue _ "bytes"? _ RestOfLine {
return {
key: "size",
value: B(value)
};
}
InfoFieldSizeKey
= "User Capacity:"
/ "Total NVM Capacity:"
InfoFieldRPM
= "Rotation Rate:" _ value:NumberValue _ "rpm" Newline {
return {
key: "rpm",
value: value
};
}
InfoFieldSectorSizes
= "Sector Sizes:" _ logicalSize:BytesValue _ "bytes logical," _ physicalSize:BytesValue _ "bytes physical" Newline {
return {
key: "sectorSizes",
value: {
logical: logicalSize,
physical: physicalSize
}
};
}
InfoFieldBooleanKey
= "SMART support is" { return "smartEnabled"; }
InfoFieldBoolean
= key:InfoFieldBooleanKey ":" _ value:RestOfLine {
return {
key: key,
value: matchValue(value, {
Enabled: true,
Disabled: false
})
};
}

@ -0,0 +1,11 @@
import { _, RestOfLine } from "../primitives"
RootScan
= devices:ScanDevice* {
return { devices: devices };
}
ScanDevice 'scanned device'
= path:$[^ ]+ _ "-d" _ interface_:$[^ ]+ _ RestOfLine {
return { path: path, interface: interface_ };
}

@ -0,0 +1,44 @@
{
const syncpipe = require("syncpipe");
const {B} = require("../../unit-bytes-iec");
}
_
= (" " / "\t")*
RestOfLine
= content:$[^\n]+ Newline {
return content;
}
Newline
= "\n"
/ "\r\n"
BytesValue
= value:SeparatedNumberValue {
return B(value);
}
NumberValue
= value:$[0-9]+ {
return parseInt(value);
}
SeparatedNumberValue
= value:$[0-9,]+ {
return syncpipe(value, [
(_) => _.replace(/,/g, ""),
(_) => parseInt(_)
]);
}
HexNumberValue
= value:$[0-9A-Fa-f]+ {
return parseInt(value, 16);
}
IdentifierValue
= value:$[a-zA-Z_-]+ {
return value;
}

@ -0,0 +1,6 @@
import { RestOfLine, Newline } from "./primitives"
Header 'header'
= "smartctl " versionString:RestOfLine "Copyright" copyrightStatement:RestOfLine Newline {
return { versionString, copyrightStatement };
}

@ -1,10 +1,11 @@
"use strict";
const pegjs = require("pegjs");
const fs = require("fs");
const Promise = require("bluebird");
const pegRedux = require("peg-redux");
const moduleEval = require("eval");
const vm = require("vm");
const asExpression = require("as-expression");
const { chain } = require("error-chain");
const textParser = require("../text-parser");
const { validateOptions } = require("@validatem/core");
@ -12,8 +13,8 @@ const isString = require("@validatem/is-string");
const isPlainObject = require("@validatem/is-plain-object");
const requireEither = require("@validatem/require-either");
module.exports = function createPegParser({ grammar, grammarFile, options }) {
validateOptions(arguments, [
module.exports = function createPegParser(_options) {
let { grammar, grammarFile, options } = validateOptions(arguments, [
{
grammar: [ isString ],
grammarFile: [ isString ],
@ -21,17 +22,17 @@ module.exports = function createPegParser({ grammar, grammarFile, options }) {
}, requireEither([ "grammar", "grammarFile" ])
]);
if (grammarFile != null) {
// FIXME: cache
grammar = fs.readFileSync(grammarFile, "utf8");
}
let parserCode = pegjs.generate(grammar, {
let parserOptions = {
... options,
output: "source",
format: "commonjs"
});
};
return Promise.try(() => {
return (grammarFile != null)
? pegRedux.generateFromFile(grammarFile, parserOptions)
: pegRedux.generate(grammar, parserOptions);
}).then((parserCode) => {
let parser = asExpression(() => {
if (grammarFile != null) {
return moduleEval(parserCode, grammarFile, {}, true);
@ -62,11 +63,12 @@ module.exports = function createPegParser({ grammar, grammarFile, options }) {
return parser.parse(text);
} catch (error) {
if (error.name === "SyntaxError") {
throw textParser.NoResult.chain(error, "Parsing output failed");
throw chain(error, textParser.NoResult, "Parsing output failed");
} else {
throw error;
}
}
}
};
});
};

@ -26,11 +26,11 @@ return Promise.try(() => {
// return lvm.addVolumeToVolumeGroup({ volumeGroup: "vg-name", physicalVolume: "/dev/loop1" });
// return lvm.destroyPhysicalVolume({ devicePath: "/dev/loop0" });
// return lsblk();
// return smartctl.scan();
return smartctl.scan();
// return smartctl.info({ devicePath: "/dev/sda" })
// return smartctl.info({ devicePath: process.argv[2] })
// return smartctl.attributes({ devicePath: process.argv[2] });
return findmnt();
// return findmnt();
// return nvmeCli.listNamespaces({ devicePath: "/dev/nvme0" });
}).then((result) => {
console.log(util.inspect(result, {colors: true, depth: null}));

@ -949,6 +949,13 @@
lodash "^4.17.19"
to-fast-properties "^2.0.0"
"@invisible/pegjs-import@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@invisible/pegjs-import/-/pegjs-import-1.1.1.tgz#1c5feb6fd768604cadd63efc9dfb999e8b0a0c7f"
integrity sha512-TiUoDxO08miDb6EQaWQeuBtkPPAsOpw55HBCbBN+EtIXy7URT1fwWNt/5k/k0pI+U58FnnGSj361oRSPATuSmw==
dependencies:
pegjs "^0.10.0"
"@joepie91/eslint-config@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@joepie91/eslint-config/-/eslint-config-1.1.0.tgz#9397e6ce0a010cb57dcf8aef8754d3a5ce0ae36a"

Loading…
Cancel
Save