Spaces:
Runtime error
Runtime error
File size: 5,532 Bytes
8fd7a1d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
// From the NPM docs:
// "If you need to perform operations on your package before it is used, in a way that is not dependent on the
// operating system or architecture of the target system, use a prepublish script."
// Once this step is complete, a developer should be able to work without an Internet connection.
// See also: https://docs.npmjs.com/cli/using-npm/scripts
import fs from 'fs';
import path from 'path';
import nodeCrypto from 'crypto';
import crossFetch from 'cross-fetch';
import yauzl from 'yauzl';
import {fileURLToPath} from 'url';
/** @typedef {import('yauzl').Entry} ZipEntry */
/** @typedef {import('yauzl').ZipFile} ZipFile */
// these aren't set in ESM mode
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// base/root path for the project
const basePath = path.join(__dirname, '..');
/**
* Extract the first matching file from a zip buffer.
* The path within the zip file is ignored: the destination path is `${destinationDirectory}/${basename(entry.name)}`.
* Prints warnings if more than one matching file is found.
* @param {function(ZipEntry): boolean} filter Returns true if the entry should be extracted.
* @param {string} relativeDestDir The directory to extract to, relative to `basePath`.
* @param {Buffer} zipBuffer A buffer containing the zip file.
* @returns {Promise<string>} A Promise for the base name of the written file (without directory).
*/
const extractFirstMatchingFile = (filter, relativeDestDir, zipBuffer) => new Promise((resolve, reject) => {
try {
let extractedFileName;
yauzl.fromBuffer(zipBuffer, {lazyEntries: true}, (zipError, zipfile) => {
if (zipError) {
throw zipError;
}
zipfile.readEntry();
zipfile.on('end', () => {
resolve(extractedFileName);
});
zipfile.on('entry', entry => {
if (!filter(entry)) {
// ignore non-matching file
return zipfile.readEntry();
}
if (extractedFileName) {
console.warn(`Multiple matching files found. Ignoring: ${entry.fileName}`);
return zipfile.readEntry();
}
extractedFileName = entry.fileName;
console.info(`Found matching file: ${entry.fileName}`);
zipfile.openReadStream(entry, (fileError, readStream) => {
if (fileError) {
throw fileError;
}
const baseName = path.basename(entry.fileName);
const relativeDestFile = path.join(relativeDestDir, baseName);
console.info(`Extracting ${relativeDestFile}`);
const absoluteDestDir = path.join(basePath, relativeDestDir);
fs.mkdirSync(absoluteDestDir, {recursive: true});
const absoluteDestFile = path.join(basePath, relativeDestFile);
const outStream = fs.createWriteStream(absoluteDestFile);
readStream.on('end', () => {
outStream.close();
zipfile.readEntry();
});
readStream.pipe(outStream);
});
});
});
} catch (error) {
reject(error);
}
});
const downloadMicrobitHex = async () => {
const url = 'https://packagerdata.turbowarp.org/scratch-microbit-1.2.0.hex.zip';
const expectedSHA256 = 'dfd574b709307fe76c44dbb6b0ac8942e7908f4d5c18359fae25fbda3c9f4399';
console.info(`Downloading ${url}`);
const response = await crossFetch(url);
const zipBuffer = Buffer.from(await response.arrayBuffer());
const sha256 = nodeCrypto.createHash('sha-256').update(zipBuffer).digest('hex');
if (sha256 !== expectedSHA256) {
throw new Error(`microbit hex has SHA-256 ${sha256} but expected ${expectedSHA256}`);
}
const relativeHexDir = path.join('static', 'microbit');
const hexFileName = await extractFirstMatchingFile(
entry => /\.hex$/.test(entry.fileName),
path.join('static', 'microbit'),
zipBuffer
);
const relativeHexFile = path.join(relativeHexDir, hexFileName);
const relativeGeneratedDir = path.join('src', 'generated');
const relativeGeneratedFile = path.join(relativeGeneratedDir, 'microbit-hex-url.cjs');
const absoluteGeneratedDir = path.join(basePath, relativeGeneratedDir);
fs.mkdirSync(absoluteGeneratedDir, {recursive: true});
const absoluteGeneratedFile = path.join(basePath, relativeGeneratedFile);
const requirePath = `./${path
.relative(relativeGeneratedDir, relativeHexFile)
.split(path.win32.sep)
.join(path.posix.sep)}`;
fs.writeFileSync(
absoluteGeneratedFile,
[
'// This file is generated by scripts/prepublish.mjs',
'// Do not edit this file directly',
'// This file relies on a loader to turn this `require` into a URL',
`module.exports = require('${requirePath}');`,
'' // final newline
].join('\n')
);
console.info(`Wrote ${relativeGeneratedFile}`);
};
const prepublish = async () => {
await downloadMicrobitHex();
};
prepublish().then(
() => {
console.info('Prepublish script complete');
process.exit(0);
},
e => {
console.error(e);
process.exit(1);
}
);
|