Remove Fibers from meteor-tools:

- Adapt forkJoin and other files functions to correctly be awaited.
This commit is contained in:
Matheus Castro
2022-12-22 14:09:27 -03:00
parent f7c419a3d9
commit 170e5d3f6d
13 changed files with 168 additions and 171 deletions

View File

@@ -1725,7 +1725,7 @@ var maybeUpdateRelease = async function (options) {
await projectContext.prepareProjectForBuild();
});
projectContext.writeReleaseFileAndDevBundleLink(releaseName);
await projectContext.writeReleaseFileAndDevBundleLink(releaseName);
projectContext.packageMapDelta.displayOnConsole({
title: ("Changes to your project's package version selections from " +
@@ -2734,7 +2734,7 @@ main.registerCommand({
throw Error("missing tool for " + osArch);
}
tmpTropo.linkToLatestMeteor(files.pathJoin(
await tmpTropo.linkToLatestMeteor(files.pathJoin(
tmpTropo.packagePath(toolPackage, toolVersion, true),
toolRecord.path,
'meteor'));

View File

@@ -928,6 +928,7 @@ makeGlobalAsyncLocalStorage().run({}, async function () {
appReleaseFile = new projectContextModule.ReleaseFile({
projectDir: appDir
});
await appReleaseFile.init();
// This is what happens if the file exists and is empty. This really
// shouldn't happen unless the user did it manually.
if (appReleaseFile.noReleaseSpecified()) {

View File

@@ -487,7 +487,7 @@ function pathIsDirectory(path: string) {
// If options.ignore is present, it should be a list of regexps. Any
// file whose basename matches one of the regexps, before
// transformation, will be skipped.
export function cp_r(from: string, to: string, options: {
export async function cp_r(from: string, to: string, options: {
preserveSymlinks?: boolean;
ignore?: RegExp[];
transformFilename?: (f: string) => string;
@@ -531,7 +531,7 @@ export function cp_r(from: string, to: string, options: {
mkdir_p(pathDirname(to));
if (stat.isSymbolicLink()) {
symlinkWithOverwrite(readlink(from), to);
await symlinkWithOverwrite(readlink(from), to);
} else if (options.transformContents) {
writeFile(to, options.transformContents(
@@ -557,7 +557,7 @@ export function cp_r(from: string, to: string, options: {
// create a symlink, overwriting the target link, file, or directory
// if it exists
export const symlinkWithOverwrite =
Profile("files.symlinkWithOverwrite", function symlinkWithOverwrite(
Profile("files.symlinkWithOverwrite", async function symlinkWithOverwrite(
source: string,
target: string,
) {
@@ -586,7 +586,7 @@ Profile("files.symlinkWithOverwrite", function symlinkWithOverwrite(
return;
}
// overwrite existing link, file, or directory
rm_recursive(target);
await rm_recursive(target);
symlink(...args);
} else {
throw e;
@@ -746,10 +746,10 @@ export function changeTempDirStatus(dir: string, status: boolean) {
if (! process.env.METEOR_SAVE_TMPDIRS) {
cleanup.onExit(function () {
Object.entries(tempDirs).filter(([_, isTmp]) => !!isTmp).map(([dir]) => dir).forEach(dir => {
return Object.entries(tempDirs).filter(([_, isTmp]) => !!isTmp).map(([dir]) => dir).map(async dir => {
delete tempDirs[dir];
try {
rm_recursive(dir);
await rm_recursive(dir);
} catch (err) {
// Don't crash and print a stack trace because we failed to delete
// a temp directory. This happens sometimes on Windows and seems
@@ -768,7 +768,7 @@ type TarOptions = {
// into a destination directory. destPath should not exist yet, and
// the archive should contain a single top-level directory, which will
// be renamed atomically to destPath.
export function extractTarGz(
export async function extractTarGz(
buffer: Buffer,
destPath: string,
options: TarOptions = {},
@@ -784,9 +784,7 @@ export function extractTarGz(
const startTime = +new Date;
// standardize only one way of extracting, as native ones can be tricky
const promise = tryExtractWithNpmTar(buffer, tempDir, options)
promise.await();
await tryExtractWithNpmTar(buffer, tempDir, options);
// succeed!
const topLevelOfArchive = readdir(tempDir)
@@ -800,8 +798,8 @@ export function extractTarGz(
}
const extractDir = pathJoin(tempDir, topLevelOfArchive[0]);
rename(extractDir, destPath);
rm_recursive(tempDir);
await rename(extractDir, destPath);
await rm_recursive(tempDir);
if (options.verbose) {
console.log("Finished extracting in", Date.now() - startTime, "ms");
@@ -978,7 +976,7 @@ Profile("files.renameDirAlmostAtomically", async (fromDir: string, toDir: string
});
export const writeFileAtomically =
Profile("files.writeFileAtomically", function (filename: string, contents: string | Buffer) {
Profile("files.writeFileAtomically", async function (filename: string, contents: string | Buffer) {
const parentDir = pathDirname(filename);
mkdir_p(parentDir);
@@ -988,19 +986,19 @@ Profile("files.writeFileAtomically", function (filename: string, contents: strin
);
writeFile(tmpFile, contents);
rename(tmpFile, filename);
await rename(tmpFile, filename);
});
// Like fs.symlinkSync, but creates a temporary link and renames it over the
// file; this means it works even if the file already exists.
// Do not use this function on Windows, it won't work.
export function symlinkOverSync(linkText: string, file: string) {
export async function symlinkOverSync(linkText: string, file: string) {
file = pathResolve(file);
const tmpSymlink = pathJoin(
pathDirname(file),
"." + pathBasename(file) + ".tmp" + utils.randomToken());
symlink(linkText, tmpSymlink);
rename(tmpSymlink, file);
await rename(tmpSymlink, file);
}
// Return the result of evaluating `code` using
@@ -1375,7 +1373,7 @@ export function _getLocationFromScriptLinkToMeteorScript(script: string | Buffer
return convertToPosixPath(scriptLocation, ! isAbsolute);
}
export function linkToMeteorScript(
export async function linkToMeteorScript(
scriptLocation: string,
linkLocation: string,
platform: string,
@@ -1390,7 +1388,7 @@ export function linkToMeteorScript(
writeFile(linkLocation, script, { encoding: "ascii" });
} else {
// Symlink meteor tool
symlinkOverSync(scriptLocation, linkLocation);
await symlinkOverSync(scriptLocation, linkLocation);
}
}
@@ -1615,11 +1613,11 @@ export const rename = isWindowsLikeFilesystem() ? function (from: string, to: st
}
}
attempt();
}).catch((error: any) => {
}).catch(async (error: any) => {
if (error.code === 'EPERM' ||
error.code === 'EACCESS') {
cp_r(from, to, { preserveSymlinks: true });
rm_recursive(from);
await rm_recursive(from);
} else {
throw error;
}

View File

@@ -312,7 +312,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
const absPath = files.pathJoin(this.buildPath, relPath);
if (symlink) {
symlinkWithOverwrite(symlink, absPath);
await symlinkWithOverwrite(symlink, absPath);
} else {
hash = hash || sha1(getData());
@@ -604,7 +604,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
return this._copyDirectory(options);
}
_copyDirectory({
async _copyDirectory({
from, to,
ignore,
specificFiles,
@@ -642,12 +642,12 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
const rootDir = realpath(from);
const walk = (absFrom, relTo) => {
const walk = async (absFrom, relTo) => {
if (symlink && ! (relTo in this.usedAsFile)) {
this._ensureDirectory(files.pathDirname(relTo));
const absTo = files.pathResolve(this.buildPath, relTo);
if (this.previousCreatedSymlinks[absFrom] !== relTo) {
symlinkWithOverwrite(absFrom, absTo);
await symlinkWithOverwrite(absFrom, absTo);
}
this.usedAsFile[relTo] = false;
this.createdSymlinks[absFrom] = relTo;
@@ -656,12 +656,12 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
this._ensureDirectory(relTo);
optimisticReaddir(absFrom).forEach(item => {
for (const item of optimisticReaddir(absFrom)) {
let thisAbsFrom = files.pathResolve(absFrom, item);
const thisRelTo = files.pathJoin(relTo, item);
if (specificPaths && !(thisRelTo in specificPaths)) {
return;
continue;
}
// Returns files.realpath(thisAbsFrom), if it is external to
@@ -684,7 +684,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
}
const isExternal =
files.pathRelative(rootDir, real).startsWith("..");
files.pathRelative(rootDir, real).startsWith("..");
// Now cachedExternalPath is either a string or false.
return cachedExternalPath = isExternal && real;
@@ -709,7 +709,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
if (! fileStatus) {
// If the file did not exist, skip it.
return;
continue;
}
let itemForMatch = item;
@@ -720,22 +720,22 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
// skip excluded files
if (ignore.some(pattern => itemForMatch.match(pattern))) {
return;
continue;
}
if (typeof filter === "function" &&
! filter(thisAbsFrom, isDirectory)) {
return;
continue;
}
if (npmDiscards instanceof NpmDiscards &&
npmDiscards.shouldDiscard(thisAbsFrom, isDirectory)) {
return;
continue;
}
if (isDirectory) {
walk(thisAbsFrom, thisRelTo);
return;
await walk(thisAbsFrom, thisRelTo);
continue;
}
if (fileStatus.isSymbolicLink()) {
@@ -743,16 +743,16 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
// portable than absolute links, so getExternalPath() is
// preferred if it returns a path.
const linkSource = getExternalPath() ||
files.readlink(thisAbsFrom);
files.readlink(thisAbsFrom);
const linkTarget =
files.pathResolve(this.buildPath, thisRelTo);
files.pathResolve(this.buildPath, thisRelTo);
if (symlinkIfPossible(linkSource, linkTarget)) {
if (await symlinkIfPossible(linkSource, linkTarget)) {
// A symlink counts as a file, as far as "can you put
// something under it" goes.
this.usedAsFile[thisRelTo] = true;
return;
continue;
}
}
@@ -767,28 +767,28 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
const content = optimisticReadFile(thisAbsFrom);
files.writeFile(
files.pathResolve(this.buildPath, thisRelTo),
// The reason we call files.writeFile here instead of
// files.copyFile is so that we can read the file using
// optimisticReadFile instead of files.createReadStream.
content,
// Logic borrowed from files.copyFile: "Create the file as
// readable and writable by everyone, and executable by everyone
// if the original file is executably by owner. (This mode will be
// modified by umask.) We don't copy the mode *directly* because
// this function is used by 'meteor create' which is copying from
// the read-only tools tree into a writable app."
{ mode: (fileStatus.mode & 0o100) ? 0o777 : 0o666 },
files.pathResolve(this.buildPath, thisRelTo),
// The reason we call files.writeFile here instead of
// files.copyFile is so that we can read the file using
// optimisticReadFile instead of files.createReadStream.
content,
// Logic borrowed from files.copyFile: "Create the file as
// readable and writable by everyone, and executable by everyone
// if the original file is executably by owner. (This mode will be
// modified by umask.) We don't copy the mode *directly* because
// this function is used by 'meteor create' which is copying from
// the read-only tools tree into a writable app."
{ mode: (fileStatus.mode & 0o100) ? 0o777 : 0o666 },
);
}
this.writtenHashes[thisRelTo] = hash;
this.usedAsFile[thisRelTo] = true;
}
});
}
};
walk(rootDir, to);
await walk(rootDir, to);
}
// Returns a new Builder-compatible object that works just like a
@@ -801,7 +801,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
//
// TODO(benjamn) This nonsense should be ripped out by any means
// necessary... whenever someone has the time.
enter(relPath) {
async enter(relPath) {
const subBuilder = {};
const relPathWithSep = relPath + files.pathSep;
const methods = [
@@ -814,8 +814,8 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
"enter",
];
methods.forEach(method => {
subBuilder[method] = (...args) => {
for (const method of methods) {
subBuilder[method] = async (...args) => {
if (method === "copyDirectory" ||
method === "copyNodeModulesDirectory") {
// The copy methods take their relative paths via options.to.
@@ -825,7 +825,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
args[0] = files.pathJoin(relPath, args[0]);
}
let ret = this[method](...args);
let ret = await this[method](...args);
if (method === "generateFilename") {
// fix up the returned path to be relative to the
@@ -835,14 +835,14 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}`
}
if (ret.substr(0, relPathWithSep.length) !== relPathWithSep) {
throw new Error("generateFilename returned path outside of " +
"sub-bundle?");
"sub-bundle?");
}
ret = ret.substr(relPathWithSep.length);
}
return ret;
};
});
}
// Methods that don't have to fix up arguments or return values, because
// they are implemented purely in terms of other methods which do.
@@ -943,9 +943,9 @@ async function atomicallyRewriteFile(path, data, options) {
}
}
function symlinkIfPossible(source, target) {
async function symlinkIfPossible(source, target) {
try {
symlinkWithOverwrite(source, target);
await symlinkWithOverwrite(source, target);
return true;
} catch (e) {
return false;

View File

@@ -2503,7 +2503,7 @@ class JsImage {
// them, and 'meteor run' symlinks them. If these contain
// arch-specific code then the target will end up having an
// appropriately specific arch.
_.each(nodeModulesDirectories, function (nmd) {
for (const nmd of Object.values(nodeModulesDirectories)) {
assert.strictEqual(typeof nmd.preferredBundlePath, "string");
// Skip calculating isPortable in 'meteor run' since the
@@ -2522,15 +2522,15 @@ class JsImage {
};
const prodPackagePredicate =
// This condition essentially means we don't strip devDependencies
// when running tests, which is important for use cases like the one
// described in #7953. Note that devDependencies can still be used
// when buildMode === "development" because the app has access to
// the original node_modules.
(buildMode === "production" ||
buildMode === "development") &&
nmd.local && // Only filter local node_modules directories.
nmd.getProdPackagePredicate();
// This condition essentially means we don't strip devDependencies
// when running tests, which is important for use cases like the one
// described in #7953. Note that devDependencies can still be used
// when buildMode === "development" because the app has access to
// the original node_modules.
(buildMode === "production" ||
buildMode === "development") &&
nmd.local && // Only filter local node_modules directories.
nmd.getProdPackagePredicate();
if (prodPackagePredicate) {
// When copying a local node_modules directory, ignore any npm
@@ -2546,9 +2546,9 @@ class JsImage {
copyOptions.filter = prodPackagePredicate;
}
builder.copyNodeModulesDirectory(copyOptions);
await builder.copyNodeModulesDirectory(copyOptions);
}
});
}
// This JSON file will be read by npm-rebuild.js, which is executed to
// trigger rebuilds for all non-portable npm packages.

View File

@@ -97,7 +97,7 @@ const reifyCompileWithCache = Profile("reifyCompileWithCache", wrap(function (
if (cacheFilePath) {
Promise.resolve().then(
() => writeFileAtomically(cacheFilePath, result),
async () => await writeFileAtomically(cacheFilePath, result),
);
}

View File

@@ -1163,7 +1163,7 @@ Object.assign(Isopack.prototype, {
var pluginDir = builder.generateFilename(
'plugin.' + colonConverter.convert(name) + '.' + plugin.arch,
{ directory: true });
var pluginBuild = await plugin.write(builder.enter(pluginDir));
var pluginBuild = await plugin.write(await builder.enter(pluginDir));
var pluginEntry = {
name: name,
arch: plugin.arch,

View File

@@ -580,7 +580,7 @@ export async function bundleAndDeploy(options) {
if (options.isCacheBuildEnabled) {
Console.info('Saving build in cache (--cache-build)...');
options.projectContext.saveBuildCache({
await options.projectContext.saveBuildCache({
buildDir,
bundlePath,
gitCommitHash

View File

@@ -39,10 +39,10 @@ var generateBlankReadme = function () {
};
// Save a readme file to a temporary path.
var saveReadmeToTmp = function (readmeInfo) {
var saveReadmeToTmp = async function (readmeInfo) {
var tempReadmeDir = files.mkdtemp('readme');
var readmePath = files.pathJoin(tempReadmeDir, "Readme.md");
files.writeFileAtomically(readmePath, readmeInfo.contents);
await files.writeFileAtomically(readmePath, readmeInfo.contents);
return readmePath;
};

View File

@@ -618,10 +618,10 @@ Object.assign(exports.Tropohouse.prototype, {
return files.readLinkToMeteorScript(linkPath, self.platform);
},
linkToLatestMeteor: function (scriptLocation) {
linkToLatestMeteor: async function (scriptLocation) {
var self = this;
var linkPath = files.pathJoin(self.root, 'meteor');
files.linkToMeteorScript(scriptLocation, linkPath, self.platform);
await files.linkToMeteorScript(scriptLocation, linkPath, self.platform);
},
_getPlatform: function () {

View File

@@ -391,9 +391,9 @@ Object.assign(ProjectContext.prototype, {
var self = this;
buildmessage.assertInCapture();
await buildmessage.enterJob('reading project metadata', function () {
await buildmessage.enterJob('reading project metadata', async function () {
// Ensure this is actually a project directory.
self._ensureProjectDir();
await self._ensureProjectDir();
if (buildmessage.jobHasMessages())
return;
@@ -402,6 +402,7 @@ Object.assign(ProjectContext.prototype, {
projectDir: self.projectDir,
catalog: self._officialCatalog,
});
await self.releaseFile.init();
if (buildmessage.jobHasMessages())
return;
@@ -424,6 +425,7 @@ Object.assign(ProjectContext.prototype, {
self.cordovaPluginsFile = new exports.CordovaPluginsFile({
projectDir: self.projectDir
});
await self.cordovaPluginsFile.init();
if (buildmessage.jobHasMessages())
return;
@@ -431,11 +433,13 @@ Object.assign(ProjectContext.prototype, {
self.platformList = new exports.PlatformList({
projectDir: self.projectDir
});
await self.platformList._init();
if (buildmessage.jobHasMessages())
return;
// Read .meteor/.id, creating it if necessary.
self._ensureAppIdentifier();
await self._ensureAppIdentifier();
if (buildmessage.jobHasMessages())
return;
@@ -460,12 +464,12 @@ Object.assign(ProjectContext.prototype, {
// Write the new release to .meteor/release and create a
// .meteor/dev_bundle symlink to the corresponding dev_bundle.
writeReleaseFileAndDevBundleLink(releaseName) {
async writeReleaseFileAndDevBundleLink(releaseName) {
assert.strictEqual(files.inCheckout(), false);
this.releaseFile.write(releaseName);
await this.releaseFile.write(releaseName);
},
_ensureProjectDir: function () {
_ensureProjectDir: async function () {
var self = this;
files.mkdir_p(files.pathJoin(self.projectDir, '.meteor'));
@@ -473,13 +477,13 @@ Object.assign(ProjectContext.prototype, {
// so let's make sure it exists!
var constraintFilePath = files.pathJoin(self.projectDir, '.meteor', 'packages');
if (! files.exists(constraintFilePath)) {
files.writeFileAtomically(constraintFilePath, '');
await files.writeFileAtomically(constraintFilePath, '');
}
// Let's also make sure we have a minimal gitignore.
var gitignorePath = files.pathJoin(self.projectDir, '.meteor', '.gitignore');
if (! files.exists(gitignorePath)) {
files.writeFileAtomically(gitignorePath, 'local\n');
await files.writeFileAtomically(gitignorePath, 'local\n');
}
},
@@ -526,7 +530,7 @@ Object.assign(ProjectContext.prototype, {
return self.isopackCache.getLintingMessagesForLocalPackages();
},
_ensureAppIdentifier: function () {
_ensureAppIdentifier: async function () {
var self = this;
var identifierFile = files.pathJoin(self.projectDir, '.meteor', '.id');
@@ -551,7 +555,7 @@ Object.assign(ProjectContext.prototype, {
"# - ensuring you don't accidentally deploy one app on top of another\n" +
"# - providing package authors with aggregated statistics\n" +
"\n");
files.writeFileAtomically(identifierFile, comment + appId + '\n');
await files.writeFileAtomically(identifierFile, comment + appId + '\n');
}
self.appIdentifier = appId;
@@ -660,7 +664,7 @@ Object.assign(ProjectContext.prototype, {
await self.packageMapDelta.init();
self._saveResolverResultCache();
await self._saveResolverResultCache();
self._completedStage = STAGE.RESOLVE_CONSTRAINTS;
});
@@ -684,8 +688,8 @@ Object.assign(ProjectContext.prototype, {
return this._resolverResultCache;
},
_saveResolverResultCache() {
files.writeFileAtomically(
async _saveResolverResultCache() {
await files.writeFileAtomically(
files.pathJoin(
this.projectLocalDir,
"resolver-result-cache.json"
@@ -705,8 +709,8 @@ Object.assign(ProjectContext.prototype, {
}
},
saveBuildCache(buildCache) {
files.writeFileAtomically(
async saveBuildCache(buildCache) {
await files.writeFileAtomically(
files.pathJoin(
this.projectLocalDir,
"build-cache.json"
@@ -968,12 +972,12 @@ Object.assign(ProjectContext.prototype, {
self._completedStage = STAGE.BUILD_LOCAL_PACKAGES;
}),
_saveChangedMetadata: Profile('_saveChangedMetadata', function () {
_saveChangedMetadata: Profile('_saveChangedMetadata', async function () {
var self = this;
// Save any changes to .meteor/packages.
if (! self._neverWriteProjectConstraintsFile)
self.projectConstraintsFile.writeIfModified();
await self.projectConstraintsFile.writeIfModified();
// Write .meteor/versions if the command always wants to (create/update),
// or if the release of the app matches the release of the process.
@@ -983,7 +987,7 @@ Object.assign(ProjectContext.prototype, {
(! release.current.isCheckout() &&
release.current.name === self.releaseFile.fullReleaseName))) {
self.packageMapFile.write(self.packageMap);
await self.packageMapFile.write(self.packageMap);
}
self._completedStage = STAGE.SAVE_CHANGED_METADATA;
@@ -1098,12 +1102,12 @@ Object.assign(exports.ProjectConstraintsFile.prototype, {
});
},
writeIfModified: function () {
writeIfModified: async function () {
var self = this;
self._modified && self._write();
self._modified && (await self._write());
},
_write: function () {
_write: async function () {
var self = this;
var lines = _.map(self._constraintLines, function (lineRecord) {
// Don't write packages that were not loaded from .meteor/packages
@@ -1119,7 +1123,7 @@ Object.assign(exports.ProjectConstraintsFile.prototype, {
lineParts.push(lineRecord.trailingSpaceAndComment, '\n');
return lineParts.join('');
});
files.writeFileAtomically(self.filename, lines.join(''));
await files.writeFileAtomically(self.filename, lines.join(''));
var messages = buildmessage.capture(
{ title: 're-reading .meteor/packages' },
function () {
@@ -1299,7 +1303,7 @@ Object.assign(exports.PackageMapFile.prototype, {
return _.clone(self._versions);
},
write: function (packageMap) {
write: async function (packageMap) {
var self = this;
var newVersions = packageMap.toVersionMap();
@@ -1316,7 +1320,7 @@ Object.assign(exports.PackageMapFile.prototype, {
lines.push(packageName + "@" + self._versions[packageName] + "\n");
});
var fileContents = Buffer.from(lines.join(''));
files.writeFileAtomically(self.filename, fileContents);
await files.writeFileAtomically(self.filename, fileContents);
// Replace our watchSet with one for the new contents of the file.
var hash = watch.sha1(fileContents);
@@ -1335,15 +1339,17 @@ exports.PlatformList = function (options) {
self.filename = files.pathJoin(options.projectDir, '.meteor', 'platforms');
self.watchSet = null;
self._platforms = null;
self._readFile();
};
// These platforms are always present and can be neither added or removed
exports.PlatformList.DEFAULT_PLATFORMS = ['browser', 'server'];
Object.assign(exports.PlatformList.prototype, {
_readFile: function () {
_init: async function() {
const self = this;
await self._readFile();
},
_readFile: async function () {
var self = this;
// Reset the WatchSet.
@@ -1363,7 +1369,7 @@ Object.assign(exports.PlatformList.prototype, {
// Write the platforms to disk (automatically adding DEFAULT_PLATFORMS and
// sorting), which automatically calls this function recursively to
// re-reads them.
self.write(platforms);
await self.write(platforms);
return;
}
@@ -1372,14 +1378,14 @@ Object.assign(exports.PlatformList.prototype, {
// Replaces the current platform file with the given list and resets this
// object (and its WatchSet) to track the new value.
write: function (platforms) {
write: async function (platforms) {
var self = this;
self._platforms = null;
platforms = _.uniq(
platforms.concat(exports.PlatformList.DEFAULT_PLATFORMS));
platforms.sort();
files.writeFileAtomically(self.filename, platforms.join('\n') + '\n');
self._readFile();
await files.writeFileAtomically(self.filename, platforms.join('\n') + '\n');
await self._readFile();
},
getPlatforms: function () {
@@ -1426,11 +1432,13 @@ exports.CordovaPluginsFile = function (options) {
self.watchSet = null;
// Map from plugin name to version.
self._plugins = null;
self._readFile();
};
Object.assign(exports.CordovaPluginsFile.prototype, {
init: async function() {
const self = this;
await self._readFile();
},
_readFile: function () {
var self = this;
buildmessage.assertInCapture();
@@ -1476,18 +1484,18 @@ Object.assign(exports.CordovaPluginsFile.prototype, {
return _.clone(self._plugins);
},
write: function (plugins) {
write: async function (plugins) {
var self = this;
var pluginNames = Object.keys(plugins);
pluginNames.sort();
var lines = _.map(pluginNames, function (pluginName) {
return pluginName + '@' + plugins[pluginName] + '\n';
});
files.writeFileAtomically(self.filename, lines.join(''));
var messages = buildmessage.capture(
await files.writeFileAtomically(self.filename, lines.join(''));
var messages = await buildmessage.capture(
{ title: 're-reading .meteor/cordova-plugins' },
function () {
self._readFile();
async function () {
await self._readFile();
});
// We shouldn't choke on something we just wrote!
if (messages.hasMessages())
@@ -1516,10 +1524,13 @@ exports.ReleaseFile = function (options) {
// Just the track.
self.releaseTrack = null;
self.releaseVersion = null;
self._readFile();
};
Object.assign(exports.ReleaseFile.prototype, {
init: async function() {
const self = this;
await self._readFile();
},
fileMissing: function () {
var self = this;
return self.unnormalizedReleaseName === null;
@@ -1538,7 +1549,7 @@ Object.assign(exports.ReleaseFile.prototype, {
|| self.isCheckout());
},
_readFile: function () {
_readFile: async function () {
var self = this;
// Start a new watchSet, in case we just overwrote this.
@@ -1566,7 +1577,7 @@ Object.assign(exports.ReleaseFile.prototype, {
self.releaseTrack = parts[0];
self.releaseVersion = parts[1];
self.ensureDevBundleLink();
await self.ensureDevBundleLink();
},
// Returns an absolute path to the dev_bundle appropriate for the
@@ -1598,7 +1609,7 @@ Object.assign(exports.ReleaseFile.prototype, {
},
// Make a symlink from .meteor/local/dev_bundle to the actual dev_bundle.
ensureDevBundleLink() {
async ensureDevBundleLink() {
import { makeLink, readLink } from "./cli/dev-bundle-links.js";
const dotMeteorDir = files.pathDirname(this.filename);
@@ -1608,7 +1619,7 @@ Object.assign(exports.ReleaseFile.prototype, {
if (this.isCheckout()) {
// Only create .meteor/local/dev_bundle if .meteor/release refers to
// an actual release, and remove it otherwise.
files.rm_recursive(devBundleLink);
await files.rm_recursive(devBundleLink);
return;
}
@@ -1643,10 +1654,10 @@ Object.assign(exports.ReleaseFile.prototype, {
}
},
write: function (releaseName) {
write: async function (releaseName) {
var self = this;
files.writeFileAtomically(self.filename, releaseName + '\n');
self._readFile();
await files.writeFileAtomically(self.filename, releaseName + '\n');
await self._readFile();
}
});

View File

@@ -1,26 +1,19 @@
// A simple interface to register functions to be called when the process exits.
import { noYieldsAllowed } from "../utils/fiber-helpers.js";
const exitHandlers = [];
export function onExit(func) {
exitHandlers.push(func);
}
function runHandlers() {
noYieldsAllowed(() => {
// Empty and execute all queued exit handlers.
exitHandlers.splice(0).forEach((f) => {
f();
});
});
async function runHandlers() {
await Promise.all(exitHandlers.splice(0).map(f => f()));
}
process.on('exit', runHandlers);
['SIGINT', 'SIGHUP', 'SIGTERM'].forEach((sig) => {
process.once(sig, () => {
runHandlers();
process.once(sig, async () => {
await runHandlers();
process.kill(process.pid, sig);
});
});

View File

@@ -583,7 +583,7 @@ var mergeMessagesIntoCurrentJob = function (innerMessages) {
};
// Like _.each, but runs each operation in a separate job
var forkJoin = function (options, iterable, fn) {
var forkJoin = async function (options, iterable, fn) {
if (!_.isFunction(fn)) {
fn = iterable;
iterable = options;
@@ -602,44 +602,38 @@ var forkJoin = function (options, iterable, fn) {
const parallel = (options.parallel !== undefined) ? options.parallel : true;
return enterJobAsync(options).then(() => {
const errors = [];
let results = _.map(iterable, (...args) => {
const promise = enterJobAsync({
await enterJobAsync(options);
const errors = [];
let results = [];
const mappedPromises = iterable.map(async (...args) => {
try {
await enterJobAsync({
title: (options.title || "") + " child"
}).then(() => fn(...args))
// Collect any errors thrown (and later re-throw the first one),
// but don't stop processing remaining jobs.
.catch(error => (errors.push(error), null));
if (parallel) {
// If the jobs are intended to run in parallel, return each
// promise without awaiting it, so that Promise.all can wait for
// them all to be fulfilled.
return promise;
}
// By awaiting the promise during each iteration, we effectively
// serialize the execution of the jobs.
return promise.await();
});
if (parallel) {
// If the jobs ran in parallel, then results is an array of Promise
// objects that still need to be resolved.
results = Promise.all(results).await();
});
await fn(...args);
} catch (e) {
errors.push(e);
}
});
if (errors.length > 0) {
// If any errors were thrown, re-throw the first one. Note that this
// allows jobs to complete successfully (and have whatever
// side-effects they should have) after the first error is thrown,
// though the final results will not be returned below.
throw errors[0];
if (parallel) {
results = await Promise.all(mappedPromises);
} else {
for (const mappedPromise of mappedPromises) {
results.push(await mappedPromise);
}
}
return results;
}).await();
if (errors.length > 0) {
// If any errors were thrown, re-throw the first one. Note that this
// allows jobs to complete successfully (and have whatever
// side-effects they should have) after the first error is thrown,
// though the final results will not be returned below.
throw errors[0];
}
return results;
};