Merge branch 'devel' into feature/docs-accounts-configurations

This commit is contained in:
Jan Dvorak
2021-10-24 15:19:28 +02:00
committed by GitHub
32 changed files with 408 additions and 260 deletions

View File

@@ -1,4 +1,4 @@
name: Meteor Docs
name: Meteor Docs Devel
on:
push:
paths:
@@ -8,30 +8,28 @@ jobs:
runs-on: ubuntu-latest
defaults:
run:
working-directory: guide/site/
working-directory: docs/
if:
contains('
refs/heads/devel
refs/heads/master
', github.ref)
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 12.x
cache: npm
- name: Build the Guide
- name: Build the Docs
run: npm ci && npm run build
- name: Deploy to Netlify for preview
- name: Deploy to Netlify
uses: nwtgck/actions-netlify@v1.2.2
with:
publish-dir: './docs/public'
production-branch: devel
github-token: ${{ secrets.GITHUB_TOKEN }}
deploy-message: Deploy from GitHub Actions ${{ github.event.pull_request.title }}
deploy-message: Deploy from GitHub Actions devel
netlify-config-path: './docs/netlify.toml'
enable-pull-request-comment: false
enable-commit-comment: false
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_GUIDE_SITE_ID }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DOCS_SITE_ID }}

View File

@@ -1,4 +1,4 @@
name: Meteor Docs
name: Meteor Docs PR
on:
pull_request:
paths:

View File

@@ -1,4 +1,4 @@
name: Meteor Guide main deploy
name: Meteor Guide Devel
on:
push:
paths:
@@ -12,7 +12,6 @@ jobs:
if:
contains('
refs/heads/devel
refs/heads/master
', github.ref)
steps:
- uses: actions/checkout@v2
@@ -30,7 +29,6 @@ jobs:
if:
contains('
refs/heads/devel
refs/heads/master
', github.ref)
steps:
- uses: actions/checkout@v2
@@ -39,13 +37,13 @@ jobs:
node-version: 12.x
- name: Build the Guide
run: npm ci && npm run build
- name: Deploy to Netlify for preview
- name: Deploy to Netlify
uses: nwtgck/actions-netlify@v1.2.2
with:
publish-dir: './guide/site/public'
production-branch: devel
github-token: ${{ secrets.GITHUB_TOKEN }}
deploy-message: Deploy from GitHub Actions ${{ github.event.pull_request.title }}
deploy-message: Deploy from GitHub Actions devel
netlify-config-path: './guide/netlify.toml'
enable-pull-request-comment: false
enable-commit-comment: false

3
.gitmodules vendored
View File

@@ -1,9 +1,6 @@
[submodule "packages/non-core/blaze"]
path = packages/non-core/blaze
url = https://github.com/meteor/blaze.git
[submodule "guide/site/themes/meteor"]
path = guide/site/themes/meteor
url = https://github.com/meteor/hexo-theme-meteor.git
[submodule "docs/themes/meteor"]
path = docs/themes/meteor
url = https://github.com/meteor/hexo-theme-meteor.git

View File

@@ -1,4 +1,4 @@
## v2.5, UNRELEASED
## v2.5, 2021-10-21
#### Highlights

View File

@@ -80,3 +80,4 @@ sudo rm /usr/local/bin/meteor
```
On Windows, [read here](npm-packages/meteor-installer/README.md).

View File

@@ -1 +0,0 @@
# Readme

View File

@@ -34,4 +34,4 @@ Meteor is a full-stack JavaScript platform for developing modern web and mobile
{% oldRedirects %}
<!-- ABC: hidden comment for cache testing -->
<!-- hidden comment to trigger a change again -->

View File

@@ -80,3 +80,5 @@ The decisions made and practices outlined in the guide must necessarily be **opi
An important function of the guide is to **shape future development** in the Meteor platform. By documenting best practices, the guide shines a spotlight on areas of the platform that could be better, easier, or more performant, and thus will be used to focus a lot of future platform choices.
Similarly, gaps in the platform highlighted by the guide can often be plugged by **community packages**; we hope that if you see an opportunity to improve the Meteor workflow by writing a package, that you take it! If you're not sure how best to design or architect your package, reach out on the forums and start a discussion.
<!-- hidden comment to trigger a change -->

18
meteor
View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
BUNDLE_VERSION=14.18.1.1
BUNDLE_VERSION=14.18.1.2
# OS Check. Put here because here is where we download the precompiled
# bundles that are arch specific.
@@ -11,14 +11,18 @@ if [ "$UNAME" != "Linux" -a "$UNAME" != "Darwin" ] ; then
fi
if [ "$UNAME" = "Darwin" ] ; then
if [ "i386" != "$(uname -p)" -o "1" != "$(sysctl -n hw.cpu64bit_capable 2>/dev/null || echo 0)" ] ; then
if [ "arm64" == "$(uname -m)" ]; then
ARCH="arm64"
else
if [ "i386" != "$(uname -p)" -o "1" != "$(sysctl -n hw.cpu64bit_capable 2>/dev/null || echo 0)" ] ; then
# Can't just test uname -m = x86_64, because Snow Leopard can
# return other values.
echo "Only 64-bit Intel processors are supported at this time."
exit 1
# Can't just test uname -m = x86_64, because Snow Leopard can
# return other values.
echo "Only 64-bit and arm64 processors are supported at this time."
exit 1
fi
ARCH="x86_64"
fi
ARCH="x86_64"
elif [ "$UNAME" = "Linux" ] ; then
ARCH="$(uname -m)"
if [ "$ARCH" != "x86_64" ] ; then

View File

@@ -10,9 +10,6 @@ MONGO_VERSION_64BIT=4.4.4
MONGO_VERSION_32BIT=3.2.22
NPM_VERSION=6.14.15
# If we built Node from source on Jenkins, this is the build number.
NODE_BUILD_NUMBER=
if [ "$UNAME" == "Linux" ] ; then
if [ "$ARCH" != "i686" -a "$ARCH" != "x86_64" ] ; then
echo "Unsupported architecture: $ARCH"

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'A user account system',
version: '2.2.0-rc250.1',
version: '2.2.0',
});
Package.onUse(api => {

View File

@@ -5,7 +5,7 @@ Package.describe({
// 2.2.x in the future. The version was also bumped to 2.0.0 temporarily
// during the Meteor 1.5.1 release process, so versions 2.0.0-beta.2
// through -beta.5 and -rc.0 have already been published.
version: '2.2.0-rc250.1',
version: '2.2.0',
});
Npm.depends({

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'No-password login/sign-up support for accounts',
version: '1.0.0-rc250.1',
version: '1.0.0',
});
Package.onUse(api => {

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'Unstyled version of login widgets',
version: '1.6.0-rc250.1',
version: '1.6.0',
});
Package.onUse(function(api) {

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'Update the client when new client code is available',
version: '1.8.0-rc250.1',
version: '1.8.0',
});
Package.onUse(function(api) {

View File

@@ -1,6 +1,6 @@
Package.describe({
name: 'ecmascript',
version: '0.16.0-rc250.1',
version: '0.16.0',
summary: 'Compiler plugin that supports ES2015+ in all .js files',
documentation: 'README.md',
});

View File

@@ -1,6 +1,6 @@
Package.describe({
name: 'hot-module-replacement',
version: '0.4.0-rc250.1',
version: '0.4.0',
summary: 'Update code in development without reloading the page',
documentation: 'README.md',
debugOnly: true,

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'The Meteor command-line tool',
version: '2.5.0-rc250.1',
version: '2.5.0',
});
Package.includeTool();

View File

@@ -1,6 +1,6 @@
Package.describe({
name: 'modules-runtime-hot',
version: '0.14.0-rc250.1',
version: '0.14.0',
summary: 'Patches modules-runtime to support Hot Module Replacement',
git: 'https://github.com/benjamn/install',
documentation: 'README.md',

View File

@@ -1,6 +1,6 @@
Package.describe({
name: 'react-fast-refresh',
version: '0.2.0-rc250.1',
version: '0.2.0',
summary: 'Automatically update React components with HMR',
documentation: 'README.md',
devOnly: true,

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'Manage the configuration for third-party services',
version: '1.3.0-rc250.1',
version: '1.3.0',
});
Package.onUse(function(api) {

View File

@@ -1,6 +1,6 @@
Package.describe({
name: 'typescript',
version: '4.4.0-rc250.1',
version: '4.4.0',
summary:
'Compiler plugin that compiles TypeScript and ECMAScript in .ts and .tsx files',
documentation: 'README.md',

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: 'Serves a Meteor app over HTTP',
version: '1.13.0-rc250.1',
version: '1.13.0',
});
Npm.depends({

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# Requires awscli to be installed and an appropriate ~/.aws/config.
# Usage:
# scripts/admin/copy-dev-bundle-from-jenkins.sh [--prod] BUILDNUMBER
# where BUILDNUMBER is the small integer Jenkins build number.
set -e
set -u
cd "`dirname "$0"`"
arg=$1
TARGET="s3://com.meteor.static/test/"
TEST=no
if [ $# -ge 1 -a ${arg} = '--prod' ]; then
shift
arg=$1
TARGET="s3://com.meteor.static/"
else
TEST=yes
fi
if [ $# -ne 1 ]; then
echo "usage: $0 [--prod] jenkins-build-number" 1>&2
exit 1
fi
DIRNAME=$(aws s3 ls s3://com.meteor.jenkins/ | perl -nle 'print $1 if m!(dev-bundle-.+--'${arg}'--.+mac-m1)/!')
if [ -z "$DIRNAME" ]; then
echo "build not found" 1>&2
exit 1
fi
echo Found build $DIRNAME
trap "echo Found surprising number of tarballs." EXIT
# Check to make sure the proper number of each kind of file is there.
aws s3 ls s3://com.meteor.jenkins/$DIRNAME/ | \
perl -nle 'if (/\.tar\.gz/) { ++$TAR } else { die "something weird" } END { exit !($TAR == 1) }'
trap - EXIT
# This awful perl line means "print everything after the last whitespace".
for FILE in $(aws s3 ls s3://com.meteor.jenkins/$DIRNAME/ | perl -nla -e 'print $F[-1]'); do
if aws s3 ls $TARGET$FILE >/dev/null; then
echo "$TARGET$FILE already exists (maybe from another branch?)"
exit 1
fi
done
echo Copying to $TARGET
aws s3 cp --acl public-read --recursive s3://com.meteor.jenkins/$DIRNAME/ $TARGET

View File

@@ -1,6 +1,6 @@
{
"track": "METEOR",
"version": "2.4",
"version": "2.5",
"recommended": false,
"official": true,
"description": "The Official Meteor Distribution"

View File

@@ -10,8 +10,6 @@ MONGO_VERSION_64BIT=4.4.4
MONGO_VERSION_32BIT=3.2.22
NPM_VERSION=6.14.15
# If we built Node from source on Jenkins, this is the build number.
NODE_BUILD_NUMBER=
if [ "$UNAME" == "Linux" ] ; then
if [ "$ARCH" != "i686" -a "$ARCH" != "x86_64" ] ; then
@@ -26,18 +24,20 @@ if [ "$UNAME" == "Linux" ] ; then
strip --remove-section=.comment --remove-section=.note $1
}
elif [ "$UNAME" == "Darwin" ] ; then
SYSCTL_64BIT=$(sysctl -n hw.cpu64bit_capable 2>/dev/null || echo 0)
if [ "$ARCH" == "i386" -a "1" != "$SYSCTL_64BIT" ] ; then
# some older macos returns i386 but can run 64 bit binaries.
# Probably should distribute binaries built on these machines,
# but it should be OK for users to run.
ARCH="x86_64"
fi
if [ "$ARCH" != "arm64" ] ; then
SYSCTL_64BIT=$(sysctl -n hw.cpu64bit_capable 2>/dev/null || echo 0)
if [ "$ARCH" == "i386" -a "1" != "$SYSCTL_64BIT" ] ; then
# some older macos returns i386 but can run 64 bit binaries.
# Probably should distribute binaries built on these machines,
# but it should be OK for users to run.
ARCH="x86_64"
fi
if [ "$ARCH" != "x86_64" ] ; then
echo "Unsupported architecture: $ARCH"
echo "Meteor only supports x86_64 for now."
exit 1
if [ "$ARCH" != "x86_64" ] ; then
echo "Unsupported architecture: $ARCH"
echo "Meteor only supports x86_64 for now."
exit 1
fi
fi
OS="macos"
@@ -69,7 +69,11 @@ then
fi
elif [ "$UNAME" == "Darwin" ]
then
NODE_TGZ="node-v${NODE_VERSION}-darwin-x64.tar.gz"
if [ "$ARCH" == "arm64" ] ; then
NODE_TGZ="node-v${NODE_VERSION}-darwin-arm64.tar.gz"
else
NODE_TGZ="node-v${NODE_VERSION}-darwin-x64.tar.gz"
fi
else
echo "Unknown architecture: $UNAME $ARCH"
exit 1

View File

@@ -28,7 +28,7 @@ mkdir node-build
cd node-build
echo "Downloading Node from ${NODE_URL}"
curl -sL "${NODE_URL}" | tar zx --strip-components 1
curl -sL "${NODE_URL}" | tar -xz --strip 1
node_configure_flags=(
# Enable the ICU internationalization library.
@@ -40,15 +40,20 @@ then
node_configure_flags+=('--debug')
fi
# "make binary" includes DESTDIR and PORTABLE=1 options.
TARBALL_NAME="node_${PLATFORM}_v${NODE_VERSION}"
INSTALL_DIR="${DIR}/node-build/${TARBALL_NAME}"
./configure --prefix="${INSTALL_DIR}"
# Unsetting BUILD_DOWNLOAD_FLAGS allows the ICU download above to work.
make -j4 binary \
# -j8 from sysctl -n hw.ncpu
make -j "$(sysctl -n hw.ncpu)" install \
BUILD_DOWNLOAD_FLAGS= \
RELEASE_URLBASE=https://nodejs.org/download/release/ \
CONFIG_FLAGS="${node_configure_flags[@]+"${node_configure_flags[@]}"}"
TARBALL_PATH="${CHECKOUT_DIR}/node_${PLATFORM}_v${NODE_VERSION}.tar.gz"
mv node-*.tar.gz "${TARBALL_PATH}"
TARBALL_PATH="${CHECKOUT_DIR}/${TARBALL_NAME}.tar.gz"
cd "$INSTALL_DIR"
tar vcfz node.tar.gz .
mv node.tar.gz "${TARBALL_PATH}"
cd "$DIR"
rm -rf node-build

View File

@@ -33,7 +33,7 @@ downloadNodeFromS3() {
S3_TGZ="node_${UNAME}_${ARCH}_v${NODE_VERSION}.tar.gz"
NODE_URL="https://${S3_HOST}/dev-bundle-node-${NODE_BUILD_NUMBER}/${S3_TGZ}"
echo "Downloading Node from ${NODE_URL}" >&2
curl "${NODE_URL}" | tar zx --strip-components 1
curl "${NODE_URL}" | tar zx --strip 1
}
downloadOfficialNode() {
@@ -70,7 +70,13 @@ case $OS in
;;
esac
MONGO_NAME="mongodb-${OS}-${ARCH}-${MONGO_VERSION}"
if [ $OS = "macos" ] && [ "$(uname -m)" = "arm64" ] ; then
MONGO_NAME="mongodb-${OS}-x86_64-${MONGO_VERSION}"
else
MONGO_NAME="mongodb-${OS}-${ARCH}-${MONGO_VERSION}"
fi
MONGO_TGZ="${MONGO_NAME}.tgz"
MONGO_URL="${MONGO_BASE_URL}/${MONGO_TGZ}"
echo "Downloading Mongo from ${MONGO_URL}"

View File

@@ -12,16 +12,19 @@ var Console = require('../console/console.js').Console;
// Given a Mongo URL, open an interative Mongo shell on this terminal
// on that database.
var runMongoShell = function (url) {
var runMongoShell = function(url) {
var mongoPath = files.pathJoin(
files.getDevBundle(), 'mongodb', 'bin', 'mongo'
files.getDevBundle(),
'mongodb',
'bin',
'mongo'
);
// XXX mongo URLs are not real URLs (notably, the comma-separation for
// multiple hosts). We've had a little better luck using the mongodb-uri npm
// package.
var mongoUrl = require('url').parse(url);
var auth = mongoUrl.auth && mongoUrl.auth.split(':');
var ssl = require('querystring').parse(mongoUrl.query).ssl === "true";
var ssl = require('querystring').parse(mongoUrl.query).ssl === 'true';
var args = [];
if (ssl) {
@@ -35,8 +38,15 @@ var runMongoShell = function (url) {
}
args.push(mongoUrl.hostname + ':' + mongoUrl.port + mongoUrl.pathname);
child_process.spawn(files.convertToOSPath(mongoPath),
args, { stdio: 'inherit' });
// run with rosetta on mac m1
if (process.platform === 'darwin' && process.arch === 'arm64') {
args = ['-x86_64', mongoPath, ...args];
mongoPath = 'arch';
}
child_process.spawn(files.convertToOSPath(mongoPath), args, {
stdio: 'inherit',
});
};
// Start mongod with a dummy replSet and wait for it to listen.
@@ -46,16 +56,21 @@ function spawnMongod(mongodPath, port, dbPath, replSetName) {
mongodPath = files.convertToOSPath(mongodPath);
dbPath = files.convertToOSPath(dbPath);
const args = [
let args = [
// nb: cli-test.sh and findMongoPids make strong assumptions about the
// order of the arguments! Check them before changing any arguments.
'--bind_ip', (process.env.METEOR_MONGO_BIND_IP || '127.0.0.1'),
'--port', port,
'--dbpath', dbPath,
'--bind_ip',
process.env.METEOR_MONGO_BIND_IP || '127.0.0.1',
'--port',
port,
'--dbpath',
dbPath,
// Use an 8MB oplog rather than 256MB. Uses less space on disk and
// initializes faster. (Not recommended for production!)
'--oplogSize', '8',
'--replSet', replSetName,
'--oplogSize',
'8',
'--replSet',
replSetName,
'--noauth',
// Starting with version 4.0.8/4.1.10, MongoDB performs a step down
@@ -67,7 +82,8 @@ function spawnMongod(mongodPath, port, dbPath, replSetName) {
// parameter disables the step down. This will be the default for single-
// node replica sets in MongoDB 4.3 (relevant commit: https://git.io/JeNkT),
// so the parameter can be removed in the future.
'--setParameter', 'waitForStepDownOnNonCommandShutdown=false'
'--setParameter',
'waitForStepDownOnNonCommandShutdown=false',
];
// Use mmapv1 on 32bit platforms, as our binary doesn't support WT
@@ -83,6 +99,11 @@ function spawnMongod(mongodPath, port, dbPath, replSetName) {
args.push('--enableFreeMonitoring', 'off');
}
// run with rosetta on mac m1
if (process.platform === 'darwin' && process.arch === 'arm64') {
args = ['-x86_64', mongodPath, ...args];
mongodPath = 'arch';
}
return child_process.spawn(mongodPath, args, {
// Apparently in some contexts, Mongo crashes if your locale isn't set up
// right. I wasn't able to reproduce it, but many people on #4019
@@ -90,10 +111,13 @@ function spawnMongod(mongodPath, port, dbPath, replSetName) {
// they aren't set already. If these few aren't good enough, we'll at least
// detect the locale error and print a link to #4019 (look for
// `detectedErrors.badLocale` below).
env: Object.assign({
LANG: 'en_US.UTF-8',
LC_ALL: 'en_US.UTF-8'
}, process.env)
env: Object.assign(
{
LANG: 'en_US.UTF-8',
LC_ALL: 'en_US.UTF-8',
},
process.env
),
});
}
@@ -106,47 +130,52 @@ var findMongoPids;
if (process.platform === 'win32') {
// Windows doesn't have a ps equivalent that (reliably) includes the command
// line, so approximate using the combined output of tasklist and netstat.
findMongoPids = function (dbDir_unused, port) {
findMongoPids = function(dbDir_unused, port) {
var promise = fiberHelpers.makeFulfillablePromise();
child_process.exec('tasklist /fi "IMAGENAME eq mongod.exe"',
function (error, stdout, stderr) {
if (error) {
var additionalInfo = JSON.stringify(error);
if (error.code === 'ENOENT') {
additionalInfo = "tasklist wasn't found on your system, it usually can be found at C:\\Windows\\System32\\.";
child_process.exec('tasklist /fi "IMAGENAME eq mongod.exe"', function(
error,
stdout,
stderr
) {
if (error) {
var additionalInfo = JSON.stringify(error);
if (error.code === 'ENOENT') {
additionalInfo =
"tasklist wasn't found on your system, it usually can be found at C:\\Windows\\System32\\.";
}
promise.reject(
new Error("Couldn't run tasklist.exe: " + additionalInfo)
);
return;
} else {
// Find the pids of all mongod processes
var mongo_pids = [];
stdout.split('\n').forEach(function(line) {
var m = line.match(/^mongod.exe\s+(\d+) /);
if (m) {
mongo_pids[m[1]] = true;
}
promise.reject(
new Error("Couldn't run tasklist.exe: " + additionalInfo)
);
return;
} else {
// Find the pids of all mongod processes
var mongo_pids = [];
stdout.split('\n').forEach(function (line) {
var m = line.match(/^mongod.exe\s+(\d+) /);
if (m) {
mongo_pids[m[1]] = true;
}
});
});
// Now get the corresponding port numbers
child_process.exec(
'netstat -ano',
{maxBuffer: 1024 * 1024 * 10},
function (error, stdout, stderr) {
// Now get the corresponding port numbers
child_process.exec(
'netstat -ano',
{ maxBuffer: 1024 * 1024 * 10 },
function(error, stdout, stderr) {
if (error) {
promise.reject(
new Error("Couldn't run netstat -ano: " +
JSON.stringify(error))
new Error("Couldn't run netstat -ano: " + JSON.stringify(error))
);
return;
} else {
var pids = [];
stdout.split('\n').forEach(function (line) {
var m = line.match(/^\s*TCP\s+\S+:(\d+)\s+\S+\s+LISTENING\s+(\d+)/);
stdout.split('\n').forEach(function(line) {
var m = line.match(
/^\s*TCP\s+\S+:(\d+)\s+\S+\s+LISTENING\s+(\d+)/
);
if (m) {
var found_pid = parseInt(m[2], 10);
var found_pid = parseInt(m[2], 10);
var found_port = parseInt(m[1], 10);
// We can't check the path app_dir so assume it always matches
@@ -158,21 +187,23 @@ if (process.platform === 'win32') {
pids.push({
pid: found_pid,
port: found_port,
app_dir: null});
app_dir: null,
});
}
}
});
promise.resolve(pids);
}
});
}
});
}
);
}
});
return promise.await();
};
} else {
findMongoPids = function (dbDir, port) {
findMongoPids = function(dbDir, port) {
var promise = fiberHelpers.makeFulfillablePromise();
// 'ps ax' should be standard across all MacOS and Linux.
@@ -208,7 +239,7 @@ if (process.platform === 'win32') {
// If the child process output includes unicode, make sure it's
// handled properly.
const {
LANG = "en_US.UTF-8",
LANG = 'en_US.UTF-8',
LC_ALL = LANG,
LANGUAGE = LANG,
// Remainder of process.env without above properties.
@@ -229,40 +260,48 @@ if (process.platform === 'win32') {
// (#2158).
maxBuffer: 1024 * 1024 * 10,
},
function (error, stdout, stderr) {
function(error, stdout, stderr) {
if (error) {
promise.reject(
new Error("Couldn't run ps ax: " +
JSON.stringify(error) + "; " +
error.message)
new Error(
"Couldn't run ps ax: " +
JSON.stringify(error) +
'; ' +
error.message
)
);
return;
}
var ret = [];
stdout.split('\n').forEach(function (line) {
stdout.split('\n').forEach(function(line) {
// Matches mongos we start. Note that this matches
// 'fake-mongod' (our mongod stub for automated tests) as well
// as 'mongod'.
var m = line.match(/^\s*(\d+).+mongod .+--port (\d+) --dbpath (.+(?:\/|\\)db)/);
var m = line.match(
/^\s*(\d+).+mongod .+--port (\d+) --dbpath (.+(?:\/|\\)db)/
);
if (m && m.length === 4) {
var foundPid = parseInt(m[1], 10);
var foundPid = parseInt(m[1], 10);
var foundPort = parseInt(m[2], 10);
var foundPath = m[3];
if ( (! port || port === foundPort) &&
(! dbDir || dbDir === foundPath)) {
if (
(!port || port === foundPort) &&
(!dbDir || dbDir === foundPath)
) {
ret.push({
pid: foundPid,
port: foundPort,
dbDir: foundPath
dbDir: foundPath,
});
}
}
});
promise.resolve(ret);
});
}
);
return promise.await();
};
@@ -270,7 +309,7 @@ if (process.platform === 'win32') {
// See if mongo is running already. Yields. Returns the port that
// mongo is running on or null if mongo is not running.
var findMongoPort = function (dbDir) {
var findMongoPort = function(dbDir) {
var pids = findMongoPids(dbDir);
if (pids.length !== 1) {
@@ -300,7 +339,7 @@ if (process.platform === 'win32') {
// where we try to connect to a mongod that is not running, or a wrong
// mongod if our current app is not running but there is a left-over file
// lying around. This still can be better than always failing to connect.
findMongoPort = function (dbPath) {
findMongoPort = function(dbPath) {
var mongoPort = null;
var portFile = files.pathJoin(dbPath, 'METEOR-PORT');
@@ -314,36 +353,40 @@ if (process.platform === 'win32') {
var net = require('net');
return new Promise(resolve => {
var client = net.connect({
port: mongoPort
}, () => {
// The server is running.
client.end();
resolve(mongoPort);
});
var client = net.connect(
{
port: mongoPort,
},
() => {
// The server is running.
client.end();
resolve(mongoPort);
}
);
client.on('error', () => resolve(null));
}).catch(() => null).await();
})
.catch(() => null)
.await();
};
}
// Kill any mongos running on 'port'. Yields, and returns once they
// are all dead. Throws an exception on failure.
//
// This is a big hammer for dealing with still running mongos, but
// smaller hammers have failed before and it is getting tiresome.
var findMongoAndKillItDead = function (port, dbPath) {
var findMongoAndKillItDead = function(port, dbPath) {
var pids = findMongoPids(null, port);
// Go through the list serially. There really should only ever be
// at most one but we're not taking any chances.
_.each(pids, function (processInfo) {
_.each(pids, function(processInfo) {
var pid = processInfo.pid;
// Send kill attempts and wait. First a SIGINT, then if it isn't
// dead within 2 sec, SIGKILL. Check every 100ms to see if it's
// dead.
for (var attempts = 1; attempts <= 40; attempts ++) {
for (var attempts = 1; attempts <= 40; attempts++) {
var signal = 0;
if (attempts === 1) {
signal = 'SIGINT';
@@ -365,19 +408,19 @@ var findMongoAndKillItDead = function (port, dbPath) {
// XXX should actually catch this higher up and print a nice
// error. foreseeable conditions should never result in exceptions
// for the user.
throw new Error("Can't kill running mongo (pid " + pid + ").");
throw new Error("Can't kill running mongo (pid " + pid + ').');
});
// If we had to kill mongod with SIGKILL, or on Windows where all calls to
// `process.kill` work like SIGKILL, mongod will not have the opportunity to
// close gracefully. Delete a lock file that may have been left over.
var mongodLockFile = files.pathJoin(dbPath, "mongod.lock");
var mongodLockFile = files.pathJoin(dbPath, 'mongod.lock');
if (files.exists(mongodLockFile)) {
files.unlink(mongodLockFile)
files.unlink(mongodLockFile);
}
};
var StoppedDuringLaunch = function () {};
var StoppedDuringLaunch = function() {};
// Starts a single instance of mongod, and configures it properly as a singleton
// replica set. Yields. Returns once the mongod is successfully listening (or
@@ -393,12 +436,15 @@ var StoppedDuringLaunch = function () {};
// are killed (and onExit is then invoked). Also, the entirety of all three
// databases is deleted before starting up. This is mode intended for testing
// mongo failover, not for normal development or production use.
var launchMongo = function (options) {
var onExit = options.onExit || function () {};
var launchMongo = function(options) {
var onExit = options.onExit || function() {};
var noOplog = false;
var mongod_path = files.pathJoin(
files.getDevBundle(), 'mongodb', 'bin', 'mongod'
files.getDevBundle(),
'mongodb',
'bin',
'mongod'
);
var replSetName = 'meteor';
@@ -411,10 +457,14 @@ var launchMongo = function (options) {
}
var fakeMongodCommand =
process.platform === "win32" ? "fake-mongod.bat" : "fake-mongod";
process.platform === 'win32' ? 'fake-mongod.bat' : 'fake-mongod';
mongod_path = files.pathJoin(
files.getCurrentToolsDir(), 'tools',
'tests', 'fake-mongod', fakeMongodCommand);
files.getCurrentToolsDir(),
'tools',
'tests',
'fake-mongod',
fakeMongodCommand
);
// oplog support requires sending admin commands to mongod, so
// it'd be hard to make fake-mongod support it.
@@ -425,12 +475,12 @@ var launchMongo = function (options) {
var stopped = false;
var handle = {};
var stopPromise = new Promise((resolve, reject) => {
handle.stop = function () {
handle.stop = function() {
if (stopped) {
return;
}
stopped = true;
_.each(subHandles, function (handle) {
_.each(subHandles, function(handle) {
handle.stop();
});
@@ -438,23 +488,26 @@ var launchMongo = function (options) {
options.onStopped();
}
reject(new StoppedDuringLaunch);
reject(new StoppedDuringLaunch());
};
});
var yieldingMethod = function (object, methodName, ...args) {
var yieldingMethod = function(object, methodName, ...args) {
return Promise.race([
stopPromise,
new Promise((resolve, reject) => {
object[methodName](...args, (err, res) => {
err ? reject(err) : resolve(res);
});
})
}),
]).await();
};
var launchOneMongoAndWaitForReadyForInitiate = function (dbPath, port,
portFile) {
var launchOneMongoAndWaitForReadyForInitiate = function(
dbPath,
port,
portFile
) {
files.mkdir_p(dbPath, 0o755);
var proc = null;
@@ -472,7 +525,7 @@ var launchMongo = function (options) {
var portFileExists = false;
var matchingPortFileExists = false;
try {
matchingPortFileExists = +(files.readFile(portFile)) === port;
matchingPortFileExists = +files.readFile(portFile) === port;
portFileExists = true;
} catch (e) {
if (!e || e.code !== 'ENOENT') {
@@ -503,7 +556,7 @@ var launchMongo = function (options) {
throw e;
}
}
_.each(dbFiles, function (dbFile) {
_.each(dbFiles, function(dbFile) {
if (/^local\./.test(dbFile)) {
files.unlink(files.pathJoin(dbPath, dbFile));
}
@@ -527,10 +580,10 @@ var launchMongo = function (options) {
proc = null;
}
}
require("../tool-env/cleanup.js").onExit(stop);
require('../tool-env/cleanup.js').onExit(stop);
subHandles.push({ stop });
var procExitHandler = fiberHelpers.bindEnvironment(function (code, signal) {
var procExitHandler = fiberHelpers.bindEnvironment(function(code, signal) {
// Defang subHandle.stop().
proc = null;
@@ -549,11 +602,13 @@ var launchMongo = function (options) {
var replSetReady = false;
var maybeReadyToTalk;
var readyToTalkPromise = new Promise(function (resolve) {
maybeReadyToTalk = function () {
if (resolve &&
listening &&
(noOplog || replSetReadyToBeInitiated || replSetReady)) {
var readyToTalkPromise = new Promise(function(resolve) {
maybeReadyToTalk = function() {
if (
resolve &&
listening &&
(noOplog || replSetReadyToBeInitiated || replSetReady)
) {
proc.stdout.removeListener('data', stdoutOnData);
resolve();
resolve = null;
@@ -561,13 +616,10 @@ var launchMongo = function (options) {
};
});
var stopOrReadyPromise = Promise.race([
stopPromise,
readyToTalkPromise,
]);
var stopOrReadyPromise = Promise.race([stopPromise, readyToTalkPromise]);
var detectedErrors = {};
var stdoutOnData = fiberHelpers.bindEnvironment(function (data) {
var stdoutOnData = fiberHelpers.bindEnvironment(function(data) {
// note: don't use "else ifs" in this, because 'data' can have multiple
// lines
if (
@@ -601,15 +653,24 @@ var launchMongo = function (options) {
}
// Running against a old mmapv1 engine, probably from pre-mongo-3.2 Meteor
if (/created by the 'mmapv1' storage engine, so setting the active storage engine to 'mmapv1'/.test(data)) {
if (
/created by the 'mmapv1' storage engine, so setting the active storage engine to 'mmapv1'/.test(
data
)
) {
Console.warn();
Console.warn('Your development database is using mmapv1, '
+ 'the old, pre-MongoDB 3.0 database engine. '
+ 'You should consider upgrading to Wired Tiger, the new engine. '
+ 'The easiest way to do so in development is to run '
+ Console.command('meteor reset') + '. '
+ "If you'd like to migrate your database, please consult "
+ Console.url('https://docs.mongodb.org/v3.0/release-notes/3.0-upgrade/'))
Console.warn(
'Your development database is using mmapv1, ' +
'the old, pre-MongoDB 3.0 database engine. ' +
'You should consider upgrading to Wired Tiger, the new engine. ' +
'The easiest way to do so in development is to run ' +
Console.command('meteor reset') +
'. ' +
"If you'd like to migrate your database, please consult " +
Console.url(
'https://docs.mongodb.org/v3.0/release-notes/3.0-upgrade/'
)
);
Console.warn();
}
@@ -622,29 +683,27 @@ var launchMongo = function (options) {
var stderrOutput = '';
proc.stderr.setEncoding('utf8');
proc.stderr.on('data', function (data) {
proc.stderr.on('data', function(data) {
stderrOutput += data;
});
stopOrReadyPromise.await();
};
var initiateReplSetAndWaitForReady = function () {
var initiateReplSetAndWaitForReady = function() {
try {
// Load mongo so we'll be able to talk to it.
const {
MongoClient,
Server
} = loadIsopackage('npm-mongo').NpmModuleMongodb;
const { MongoClient, Server } = loadIsopackage(
'npm-mongo'
).NpmModuleMongodb;
// Connect to the intended primary and start a replset.
const client = new MongoClient(
new Server('127.0.0.1', options.port, {
poolSize: 1,
socketOptions: {
connectTimeoutMS: 60000
}
connectTimeoutMS: 60000,
},
})
);
@@ -659,17 +718,17 @@ var launchMongo = function (options) {
_id: replSetName,
version: 1,
protocolVersion: 1,
members: [{_id: 0, host: '127.0.0.1:' + options.port, priority: 100}]
members: [{ _id: 0, host: '127.0.0.1:' + options.port, priority: 100 }],
};
try {
const config = yieldingMethod(db.admin(), "command", {
const config = yieldingMethod(db.admin(), 'command', {
replSetGetConfig: 1,
}).config;
// If a replication set configuration already exists, it's
// important that the new version number is greater than the old.
if (config && _.has(config, "version")) {
if (config && _.has(config, 'version')) {
configuration.version = config.version + 1;
}
} catch (e) {}
@@ -679,10 +738,14 @@ var launchMongo = function (options) {
// could in theory become primary, and one of which can never be
// primary.
configuration.members.push({
_id: 1, host: '127.0.0.1:' + (options.port + 1), priority: 5
_id: 1,
host: '127.0.0.1:' + (options.port + 1),
priority: 5,
});
configuration.members.push({
_id: 2, host: '127.0.0.1:' + (options.port + 2), priority: 0
_id: 2,
host: '127.0.0.1:' + (options.port + 2),
priority: 0,
});
}
@@ -697,7 +760,7 @@ var launchMongo = function (options) {
force: true,
});
} else {
throw Error("rs.initiate error: " + e.message);
throw Error('rs.initiate error: ' + e.message);
}
}
@@ -710,20 +773,20 @@ var launchMongo = function (options) {
// Wait until the primary is writable. If it isn't writable after one
// minute, throw an error and report the replica set status.
while (!stopped) {
const { ismaster } = yieldingMethod(db.admin(), "command", {
isMaster: 1
const { ismaster } = yieldingMethod(db.admin(), 'command', {
isMaster: 1,
});
if (ismaster) {
break;
} else if (Date.now() - writableTimestamp > 60000) {
const status = yieldingMethod(db.admin(), "command", {
replSetGetStatus: 1
const status = yieldingMethod(db.admin(), 'command', {
replSetGetStatus: 1,
});
throw new Error(
"Primary not writable after one minute. Last replica set status: " +
JSON.stringify(status)
'Primary not writable after one minute. Last replica set status: ' +
JSON.stringify(status)
);
}
@@ -734,7 +797,7 @@ var launchMongo = function (options) {
} catch (e) {
// If the process has exited, we're doing another form of error
// handling. No need to throw random low-level errors farther.
if (!stopped || (e instanceof StoppedDuringLaunch)) {
if (!stopped || e instanceof StoppedDuringLaunch) {
throw e;
}
}
@@ -743,13 +806,13 @@ var launchMongo = function (options) {
try {
if (options.multiple) {
var dbBasePath = files.pathJoin(options.projectLocalDir, 'dbs');
_.each(_.range(3), function (i) {
_.each(_.range(3), function(i) {
// Did we get stopped (eg, by one of the processes exiting) by now? Then
// don't start anything new.
if (stopped) {
return;
}
var dbPath = files.pathJoin(options.projectLocalDir, 'dbs', ''+i);
var dbPath = files.pathJoin(options.projectLocalDir, 'dbs', '' + i);
launchOneMongoAndWaitForReadyForInitiate(dbPath, options.port + i);
});
if (!stopped) {
@@ -763,7 +826,7 @@ var launchMongo = function (options) {
initiateReplSetAndWaitForReady();
if (!stopped) {
// Write down that we configured the database properly.
files.writeFile(portFile, ''+options.port);
files.writeFile(portFile, '' + options.port);
}
}
}
@@ -785,7 +848,7 @@ var launchMongo = function (options) {
// logged, and onFailure is called.
//
// options: projectLocalDir, port, onFailure, multiple
var MongoRunner = function (options) {
var MongoRunner = function(options) {
var self = this;
self.projectLocalDir = options.projectLocalDir;
self.port = options.port;
@@ -812,11 +875,11 @@ Object.assign(MRp, {
//
// If the server fails to start for the first time (after a few
// restarts), we'll print a message and give up.
start: function () {
start: function() {
var self = this;
if (self.handle) {
throw new Error("already running?");
throw new Error('already running?');
}
self._startOrRestart();
@@ -832,8 +895,8 @@ Object.assign(MRp, {
}
// Otherwise, wait for a successful _startOrRestart, or a failure.
if (! self.resolveStartupPromise) {
new Promise(function (resolve) {
if (!self.resolveStartupPromise) {
new Promise(function(resolve) {
self.resolveStartupPromise = resolve;
}).await();
}
@@ -850,16 +913,16 @@ Object.assign(MRp, {
//
// In case (a), self.handle will be the handle returned from launchMongo; in
// case (b) self.handle will be null.
_startOrRestart: function () {
_startOrRestart: function() {
var self = this;
if (self.handle) {
throw new Error("already running?");
throw new Error('already running?');
}
var allowKilling = self.multiple || self.firstStart;
self.firstStart = false;
if (! allowKilling) {
if (!allowKilling) {
// If we're not going to try to kill an existing mongod first, then we
// shouldn't annoy the user by telling it that we couldn't start up.
self.suppressExitMessage = true;
@@ -883,7 +946,7 @@ Object.assign(MRp, {
}
},
_exited: function (code, signal, stderr, detectedErrors) {
_exited: function(code, signal, stderr, detectedErrors) {
var self = this;
self.handle = null;
@@ -899,12 +962,17 @@ Object.assign(MRp, {
// wrong. If we didn't try to kill Mongo, we'll do that on the next
// restart. Not killing it on the first try is important for speed,
// since findMongoAndKillItDead is a very slow operation.
if (! self.suppressExitMessage) {
if (!self.suppressExitMessage) {
// Print the last 20 lines of stderr.
runLog.log(
stderr.split('\n').slice(-20).join('\n') +
"Unexpected mongo exit code " + code +
(self.multiple ? "." : ". Restarting."));
stderr
.split('\n')
.slice(-20)
.join('\n') +
'Unexpected mongo exit code ' +
code +
(self.multiple ? '.' : '. Restarting.')
);
}
// If we're in multiple mode, we never try to restart. That's to keep the
@@ -918,21 +986,24 @@ Object.assign(MRp, {
// when 5 seconds goes without a restart. (Note that by using a
// timer instead of looking at the current date, we avoid getting
// confused by time changes.)
self.errorCount ++;
self.errorCount++;
if (self.errorTimer) {
clearTimeout(self.errorTimer);
}
self.errorTimer = setTimeout(function () {
self.errorTimer = setTimeout(function() {
self.errorTimer = null;
self.errorCount = 0;
}, 5000);
if (self.errorCount < 3) {
// Wait a second, then restart.
self.restartTimer = setTimeout(fiberHelpers.bindEnvironment(function () {
self.restartTimer = null;
self._startOrRestart();
}), 1000);
self.restartTimer = setTimeout(
fiberHelpers.bindEnvironment(function() {
self.restartTimer = null;
self._startOrRestart();
}),
1000
);
return;
}
@@ -941,35 +1012,45 @@ Object.assign(MRp, {
var explanation = MongoExitCodes[code];
var message = "Can't start Mongo server.";
if (explanation && explanation.symbol === 'EXIT_UNCAUGHT' &&
detectedErrors.freeSpace) {
message += "\n\n" +
"Looks like you are out of free disk space under .meteor/local.";
if (
explanation &&
explanation.symbol === 'EXIT_UNCAUGHT' &&
detectedErrors.freeSpace
) {
message +=
'\n\n' +
'Looks like you are out of free disk space under .meteor/local.';
} else if (explanation) {
message += "\n" + explanation.longText;
message += '\n' + explanation.longText;
} else if (process.platform === 'win32') {
message += "\n\n" +
"Check how to troubleshoot here " +
"https://docs.meteor.com/windows.html#cant-start-mongo-server";
message +=
'\n\n' +
'Check how to troubleshoot here ' +
'https://docs.meteor.com/windows.html#cant-start-mongo-server';
}
if (explanation && explanation.symbol === 'EXIT_NET_ERROR') {
message += "\n\n" +
"Check for other processes listening on port " + self.port + "\n" +
"or other Meteor instances running in the same project.";
message +=
'\n\n' +
'Check for other processes listening on port ' +
self.port +
'\n' +
'or other Meteor instances running in the same project.';
}
if (! explanation && /GLIBC/i.test(stderr)) {
message += "\n\n" +
"Looks like you are trying to run Meteor on an old Linux distribution.\n" +
"Meteor on Linux requires glibc version 2.9 or above. Try upgrading your\n" +
"distribution to the latest version.";
if (!explanation && /GLIBC/i.test(stderr)) {
message +=
'\n\n' +
'Looks like you are trying to run Meteor on an old Linux distribution.\n' +
'Meteor on Linux requires glibc version 2.9 or above. Try upgrading your\n' +
'distribution to the latest version.';
}
if (detectedErrors.badLocale) {
message += "\n\n" +
"Looks like MongoDB doesn't understand your locale settings. See\n" +
"https://github.com/meteor/meteor/issues/4019 for more details.";
message +=
'\n\n' +
"Looks like MongoDB doesn't understand your locale settings. See\n" +
'https://github.com/meteor/meteor/issues/4019 for more details.';
}
runLog.log(message);
@@ -977,7 +1058,7 @@ Object.assign(MRp, {
},
// Idempotent
stop: function () {
stop: function() {
var self = this;
if (self.shuttingDown) {
@@ -995,7 +1076,7 @@ Object.assign(MRp, {
}
},
_allowStartupToReturn: function () {
_allowStartupToReturn: function() {
var self = this;
if (self.resolveStartupPromise) {
var resolve = self.resolveStartupPromise;
@@ -1004,36 +1085,35 @@ Object.assign(MRp, {
}
},
_fail: function () {
_fail: function() {
var self = this;
self.stop();
self.onFailure && self.onFailure();
self._allowStartupToReturn();
},
_mongoHosts: function () {
_mongoHosts: function() {
var self = this;
var ports = [self.port];
if (self.multiple) {
ports.push(self.port + 1, self.port + 2);
}
return _.map(ports, function (port) {
return "127.0.0.1:" + port;
}).join(",");
return _.map(ports, function(port) {
return '127.0.0.1:' + port;
}).join(',');
},
mongoUrl: function () {
mongoUrl: function() {
var self = this;
return "mongodb://" + self._mongoHosts() + "/meteor";
return 'mongodb://' + self._mongoHosts() + '/meteor';
},
oplogUrl: function () {
oplogUrl: function() {
var self = this;
return "mongodb://" + self._mongoHosts() + "/local";
}
return 'mongodb://' + self._mongoHosts() + '/local';
},
});
exports.runMongoShell = runMongoShell;
exports.findMongoPort = findMongoPort;
exports.MongoRunner = MongoRunner;

View File

@@ -129,6 +129,7 @@ const utils = require('./utils');
// Valid architectures that Meteor officially supports.
export const VALID_ARCHITECTURES: Record<string, boolean> = {
"os.osx.x86_64": true,
"os.osx.arm64": true,
"os.linux.x86_64": true,
"os.windows.x86_64": true,
};
@@ -157,9 +158,11 @@ export function host() {
if (platform === "darwin") {
// Can't just test uname -m = x86_64, because Snow Leopard can
// return other values.
if (run('uname', '-p') !== "i386" ||
const arch = run('uname', '-p');
if ((arch !== "i386" && arch !== "arm") ||
run('sysctl', '-n', 'hw.cpu64bit_capable') !== "1") {
throw new Error("Only 64-bit Intel processors are supported on OS X");
throw new Error("Only 64-bit Intel and M1 processors are supported on OS X");
}
_host = "os.osx.x86_64";
} else if (platform === "linux") {