Files
2020-03-02 14:53:23 +07:00

241 lines
7.4 KiB
JavaScript

"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault.js");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _common = require("../prelude/common.js");
var _log = require("./log.js");
var _multistream = _interopRequireDefault(require("multistream"));
var _assert = _interopRequireDefault(require("assert"));
var _fabricator = require("./fabricator.js");
var _fs = _interopRequireDefault(require("fs"));
var _intoStream = _interopRequireDefault(require("into-stream"));
var _streamMeter = _interopRequireDefault(require("stream-meter"));
function discoverPlaceholder(binaryBuffer, searchString, padder) {
const placeholder = Buffer.from(searchString);
const position = binaryBuffer.indexOf(placeholder);
if (position === -1) return {
notFound: true
};
return {
position,
size: placeholder.length,
padder
};
}
function injectPlaceholder(fd, placeholder, value, cb) {
const {
notFound,
position,
size,
padder
} = placeholder;
if (notFound) (0, _assert.default)(false, 'Placeholder for not found');
if (typeof value === 'number') value = value.toString();
if (typeof value === 'string') value = Buffer.from(value);
const padding = Buffer.from(padder.repeat(size - value.length));
value = Buffer.concat([value, padding]);
_fs.default.write(fd, value, 0, value.length, position, cb);
}
function discoverPlaceholders(binaryBuffer) {
return {
BAKERY: discoverPlaceholder(binaryBuffer, '\0' + '// BAKERY '.repeat(20), '\0'),
PAYLOAD_POSITION: discoverPlaceholder(binaryBuffer, '// PAYLOAD_POSITION //', ' '),
PAYLOAD_SIZE: discoverPlaceholder(binaryBuffer, '// PAYLOAD_SIZE //', ' '),
PRELUDE_POSITION: discoverPlaceholder(binaryBuffer, '// PRELUDE_POSITION //', ' '),
PRELUDE_SIZE: discoverPlaceholder(binaryBuffer, '// PRELUDE_SIZE //', ' ')
};
}
function injectPlaceholders(fd, placeholders, values, cb) {
injectPlaceholder(fd, placeholders.BAKERY, values.BAKERY, error => {
if (error) return cb(error);
injectPlaceholder(fd, placeholders.PAYLOAD_POSITION, values.PAYLOAD_POSITION, error2 => {
if (error2) return cb(error2);
injectPlaceholder(fd, placeholders.PAYLOAD_SIZE, values.PAYLOAD_SIZE, error3 => {
if (error3) return cb(error3);
injectPlaceholder(fd, placeholders.PRELUDE_POSITION, values.PRELUDE_POSITION, error4 => {
if (error4) return cb(error4);
injectPlaceholder(fd, placeholders.PRELUDE_SIZE, values.PRELUDE_SIZE, cb);
});
});
});
});
}
function makeBakeryValueFromBakes(bakes) {
const parts = [];
if (bakes.length) {
for (let i = 0; i < bakes.length; i += 1) {
parts.push(Buffer.from(bakes[i]));
parts.push(Buffer.alloc(1));
}
parts.push(Buffer.alloc(1));
}
return Buffer.concat(parts);
}
function replaceDollarWise(s, sf, st) {
return s.replace(sf, () => st);
}
function makePreludeBufferFromPrelude(prelude) {
return Buffer.from('(function(process, require, console, EXECPATH_FD, PAYLOAD_POSITION, PAYLOAD_SIZE) { ' + prelude + '\n})' // dont remove \n
);
}
function _default({
backpack,
bakes,
slash,
target
}) {
return new Promise((resolve, reject) => {
if (!Buffer.alloc) {
throw (0, _log.wasReported)('Your node.js does not have Buffer.alloc. Please upgrade!');
}
let {
prelude,
entrypoint,
stripes
} = backpack;
entrypoint = (0, _common.snapshotify)(entrypoint, slash);
stripes = stripes.slice();
const vfs = {};
for (const stripe of stripes) {
let {
snap
} = stripe;
snap = (0, _common.snapshotify)(snap, slash);
if (!vfs[snap]) vfs[snap] = {};
}
let meter;
let count = 0;
function pipeToNewMeter(s) {
meter = (0, _streamMeter.default)();
return s.pipe(meter);
}
function next(s) {
count += 1;
return pipeToNewMeter(s);
}
const binaryBuffer = _fs.default.readFileSync(target.binaryPath);
const placeholders = discoverPlaceholders(binaryBuffer);
let track = 0;
let prevStripe;
let payloadPosition;
let payloadSize;
let preludePosition;
let preludeSize;
new _multistream.default(cb => {
if (count === 0) {
return cb(undefined, next((0, _intoStream.default)(binaryBuffer)));
} else if (count === 1) {
payloadPosition = meter.bytes;
return cb(undefined, next((0, _intoStream.default)(Buffer.alloc(0))));
} else if (count === 2) {
if (prevStripe && !prevStripe.skip) {
let {
snap,
store
} = prevStripe;
snap = (0, _common.snapshotify)(snap, slash);
vfs[snap][store] = [track, meter.bytes];
track += meter.bytes;
}
if (stripes.length) {
// clone to prevent 'skip' propagate
// to other targets, since same stripe
// is used for several targets
const stripe = Object.assign({}, stripes.shift());
prevStripe = stripe;
if (stripe.buffer) {
if (stripe.store === _common.STORE_BLOB) {
const snap = (0, _common.snapshotify)(stripe.snap, slash);
return (0, _fabricator.fabricateTwice)(bakes, target.fabricator, snap, stripe.buffer, (error, buffer) => {
if (error) {
_log.log.warn(error.message);
stripe.skip = true;
return cb(undefined, (0, _intoStream.default)(Buffer.alloc(0)));
}
cb(undefined, pipeToNewMeter((0, _intoStream.default)(buffer)));
});
} else {
return cb(undefined, pipeToNewMeter((0, _intoStream.default)(stripe.buffer)));
}
} else if (stripe.file) {
if (stripe.file === target.output) {
return cb((0, _log.wasReported)('Trying to take executable into executable', stripe.file));
}
_assert.default.equal(stripe.store, _common.STORE_CONTENT); // others must be buffers from walker
return cb(undefined, pipeToNewMeter(_fs.default.createReadStream(stripe.file)));
} else {
(0, _assert.default)(false, 'producer: bad stripe');
}
} else {
payloadSize = track;
preludePosition = payloadPosition + payloadSize;
return cb(undefined, next((0, _intoStream.default)(makePreludeBufferFromPrelude(replaceDollarWise(replaceDollarWise(prelude, '%VIRTUAL_FILESYSTEM%', JSON.stringify(vfs)), '%DEFAULT_ENTRYPOINT%', JSON.stringify(entrypoint))))));
}
} else {
return cb();
}
}).on('error', error => {
reject(error);
}).pipe(_fs.default.createWriteStream(target.output)).on('error', error => {
reject(error);
}).on('close', () => {
preludeSize = meter.bytes;
_fs.default.open(target.output, 'r+', (error, fd) => {
if (error) return reject(error);
injectPlaceholders(fd, placeholders, {
BAKERY: makeBakeryValueFromBakes(bakes),
PAYLOAD_POSITION: payloadPosition,
PAYLOAD_SIZE: payloadSize,
PRELUDE_POSITION: preludePosition,
PRELUDE_SIZE: preludeSize
}, error2 => {
if (error2) return reject(error2);
_fs.default.close(fd, error3 => {
if (error3) return reject(error3);
resolve();
});
});
});
});
});
}