diff --git a/History.md b/History.md index e0e4cbb4db..2ee7ca4410 100644 --- a/History.md +++ b/History.md @@ -64,8 +64,12 @@ [#7978](https://github.com/meteor/meteor/issues/7978) * Miscellaneous fixed bugs: - [#7974](https://github.com/meteor/meteor/issues/7974) + [#2876](https://github.com/meteor/meteor/issues/2876) + [#7154](https://github.com/meteor/meteor/issues/7154) [#7956](https://github.com/meteor/meteor/issues/7956) + [#7974](https://github.com/meteor/meteor/issues/7974) + [#7999](https://github.com/meteor/meteor/issues/7999) + [#8005](https://github.com/meteor/meteor/issues/8005) [#8007](https://github.com/meteor/meteor/issues/8007) ## v1.4.2 diff --git a/packages/accounts-oauth/package.js b/packages/accounts-oauth/package.js index 184ecb8a8b..41e5f9d9e4 100644 --- a/packages/accounts-oauth/package.js +++ b/packages/accounts-oauth/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Common code for OAuth-based login services", - version: "1.1.15-rc.0" + version: "1.1.15" }); Package.onUse(function (api) { diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 9a4f9a593b..42bf1c7298 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Password support for accounts", - version: "1.3.2-rc.0" + version: "1.3.2" }); Package.onUse(function(api) { diff --git a/packages/babel-runtime/package.js b/packages/babel-runtime/package.js index 31df3ec5e3..54b3b2db82 100644 --- a/packages/babel-runtime/package.js +++ b/packages/babel-runtime/package.js @@ -1,7 +1,7 @@ Package.describe({ name: "babel-runtime", summary: "Runtime support for output of Babel transpiler", - version: '1.0.0-rc.0', + version: '1.0.0', documentation: 'README.md' }); diff --git a/packages/caching-compiler/package.js b/packages/caching-compiler/package.js index 78abb3c474..470e4d04be 100644 --- a/packages/caching-compiler/package.js +++ b/packages/caching-compiler/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'caching-compiler', - version: '1.1.9-rc.0', + version: '1.1.9', summary: 'An easy way to make compiler plugins cache', documentation: 'README.md' }); diff --git a/packages/coffeescript/package.js b/packages/coffeescript/package.js index c4c6a4f7a2..22828ffe22 100644 --- a/packages/coffeescript/package.js +++ b/packages/coffeescript/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Javascript dialect with fewer braces and semicolons", - version: "1.11.1-3-rc.0" + version: "1.11.1_3" }); Package.registerBuildPlugin({ diff --git a/packages/ddp-common/package.js b/packages/ddp-common/package.js index d167e4c623..42a831899b 100644 --- a/packages/ddp-common/package.js +++ b/packages/ddp-common/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Code shared beween ddp-client and ddp-server", - version: '1.2.8-rc.0', + version: '1.2.8', documentation: null }); diff --git a/packages/ddp-server/package.js b/packages/ddp-server/package.js index 40e65bb6bb..99e29c6daf 100644 --- a/packages/ddp-server/package.js +++ b/packages/ddp-server/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data server", - version: '1.3.12-rc.0', + version: '1.3.12', documentation: null }); diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index 1678e3063f..4b4f0cdd87 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'ecmascript', - version: '0.5.9', + version: '0.6.0', summary: 'Compiler plugin that supports ES2015+ in all .js files', documentation: 'README.md' }); diff --git a/packages/less/package.js b/packages/less/package.js index f12e82dbee..3111131fb2 100644 --- a/packages/less/package.js +++ b/packages/less/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'less', - version: '2.7.7-rc.0', + version: '2.7.7', summary: 'Leaner CSS language', documentation: 'README.md' }); diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index 071a89cffd..4ab26584dd 100644 --- a/packages/meteor-tool/package.js +++ b/packages/meteor-tool/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "The Meteor command-line tool", - version: '1.4.2-1-rc.0' + version: '1.4.2_1' }); Package.includeTool(); diff --git a/packages/stylus/package.js b/packages/stylus/package.js index a5d296621f..89e0ed22a5 100644 --- a/packages/stylus/package.js +++ b/packages/stylus/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Expressive, dynamic, robust CSS', - version: "2.513.7-rc.0" + version: "2.513.7" }); Package.registerBuildPlugin({ diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 895b657dd8..2f1bc59a03 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.4.2.1-rc.0", + "version": "1.4.2.1-rc.2", "recommended": false, "official": false, "description": "Meteor" diff --git a/scripts/admin/meteor-release-official.json b/scripts/admin/meteor-release-official.json index 71219f1d08..0a21c31d02 100644 --- a/scripts/admin/meteor-release-official.json +++ b/scripts/admin/meteor-release-official.json @@ -1,6 +1,7 @@ { "track": "METEOR", - "version": "1.4.2", + "version": "1.4.2.1", + "patchFrom": ["1.4.2"], "recommended": false, "official": true, "description": "The Official Meteor Distribution" diff --git a/tools/fs/optimistic.js b/tools/fs/optimistic.js index 687016366f..74290628a2 100644 --- a/tools/fs/optimistic.js +++ b/tools/fs/optimistic.js @@ -174,6 +174,14 @@ export function dirtyNodeModulesDirectory(nodeModulesDir) { export const optimisticStatOrNull = makeOptimistic("statOrNull", statOrNull); export const optimisticLStat = makeOptimistic("lstat", lstat); +export const optimisticLStatOrNull = makeOptimistic("lstatOrNull", path => { + try { + return optimisticLStat(path); + } catch (e) { + if (e.code !== "ENOENT") throw e; + return null; + } +}); export const optimisticReadFile = makeOptimistic("readFile", readFile); export const optimisticReaddir = makeOptimistic("readdir", readdir); export const optimisticHashOrNull = makeOptimistic("hashOrNull", (...args) => { diff --git a/tools/fs/watch.js b/tools/fs/watch.js index ded8d3c21e..0a930c545e 100644 --- a/tools/fs/watch.js +++ b/tools/fs/watch.js @@ -257,10 +257,10 @@ export function readFile(absPath) { } }; -export function sha1(contents) { +export function sha1(...args) { return Profile("sha1", function () { var hash = createHash('sha1'); - hash.update(contents); + args.forEach(arg => hash.update(arg)); return hash.digest('hex'); })(); } diff --git a/tools/isobuild/builder.js b/tools/isobuild/builder.js index a864ba6f9f..f964f2a671 100644 --- a/tools/isobuild/builder.js +++ b/tools/isobuild/builder.js @@ -1,3 +1,4 @@ +import assert from "assert"; import {WatchSet, readAndWatchFile, sha1} from '../fs/watch.js'; import files from '../fs/files.js'; import NpmDiscards from './npm-discards.js'; @@ -5,7 +6,7 @@ import {Profile} from '../tool-env/profile.js'; import { optimisticReadFile, optimisticReaddir, - optimisticLStat, + optimisticLStatOrNull, } from "../fs/optimistic.js"; // Builder is in charge of writing "bundles" to disk, which are @@ -65,6 +66,8 @@ export default class Builder { this.writtenHashes = {}; this.previousWrittenHashes = {}; + this._realpathCache = Object.create(null); + // foo/bar => foo/.build1234.bar // Should we include a random number? The advantage is that multiple // builds can run in parallel. The disadvantage is that stale build @@ -443,7 +446,11 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` }); } - let walk = (absFrom, relTo) => { + const walk = ( + absFrom, + relTo, + _currentRealRootDir = absFrom + ) => { if (symlink && ! (relTo in this.usedAsFile)) { this._ensureDirectory(files.pathDirname(relTo)); const absTo = files.pathResolve(this.buildPath, relTo); @@ -454,14 +461,74 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` this._ensureDirectory(relTo); optimisticReaddir(absFrom).forEach(item => { - const thisAbsFrom = files.pathResolve(absFrom, item); + let thisAbsFrom = files.pathResolve(absFrom, item); const thisRelTo = files.pathJoin(relTo, item); if (specificPaths && !(thisRelTo in specificPaths)) { return; } - const fileStatus = optimisticLStat(thisAbsFrom); + // Returns files.realpath(thisAbsFrom), iff it is external to + // _currentRealRootDir, using caching because this function might + // be called more than once. + let cachedExternalPath; + const getExternalPath = () => { + if (typeof cachedExternalPath !== "undefined") { + return cachedExternalPath; + } + + try { + var real = files.realpath( + thisAbsFrom, + this._realpathCache + ); + } catch (e) { + if (e.code !== "ENOENT" && + e.code !== "ELOOP") { + throw e; + } + return cachedExternalPath = false; + } + + const isExternal = + files.pathRelative(_currentRealRootDir, real).startsWith(".."); + + // Now cachedExternalPath is either a string or false. + return cachedExternalPath = isExternal && real; + }; + + let fileStatus = optimisticLStatOrNull(thisAbsFrom); + + if (! symlink && + fileStatus && + fileStatus.isSymbolicLink()) { + // If copyDirectory is not allowed to create symbolic links to + // external files, and this file is a symbolic link that points + // to an external file, update fileStatus so that we copy this + // file as a normal file rather than as a symbolic link. + + const externalPath = getExternalPath(); + if (externalPath) { + // Copy from the real path rather than the link path. + thisAbsFrom = externalPath; + + // Update fileStatus to match the actual file rather than the + // symbolic link, thus forcing the file to be copied below. + fileStatus = optimisticLStatOrNull(externalPath); + + if (fileStatus && fileStatus.isDirectory()) { + // Update _currentRealRootDir so that we can judge + // isExternal relative to this new root directory when + // traversing nested directories. + _currentRealRootDir = externalPath; + } + } + } + + if (! fileStatus) { + // If the file did not exist, skip it. + return; + } let itemForMatch = item; const isDirectory = fileStatus.isDirectory(); @@ -482,12 +549,15 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` if (isDirectory) { if (typeof directoryFilter !== "function" || directoryFilter(thisAbsFrom)) { - walk(thisAbsFrom, thisRelTo); + walk(thisAbsFrom, thisRelTo, _currentRealRootDir); } } else if (fileStatus.isSymbolicLink()) { symlinkWithOverwrite( - files.readlink(thisAbsFrom), + // Symbolic links pointing to relative external paths are less + // portable than absolute links, so getExternalPath() is + // preferred if it returns a path. + getExternalPath() || files.readlink(thisAbsFrom), files.pathResolve(this.buildPath, thisRelTo) ); @@ -518,7 +588,7 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` }); }; - walk(from, to); + walk(files.realpath(from, this._realpathCache), to); } // Returns a new Builder-compatible object that works just like a diff --git a/tools/isobuild/bundler.js b/tools/isobuild/bundler.js index 022550d6c9..218de26b6e 100644 --- a/tools/isobuild/bundler.js +++ b/tools/isobuild/bundler.js @@ -553,17 +553,31 @@ class File { this.assets = null; this._contents = options.data || null; // contents, if known, as a Buffer - this._hash = options.hash || null; // hash, if known, as a hex string + this._hashOfContents = options.hash || null; + this._hash = null; } toString() { return `File: [info=${this.info}]`; } + static _salt() { + // Increment this number to force rehashing. + return 1; + } + hash() { if (! this._hash) { - this._hash = watch.sha1(this.contents()); + if (! this._hashOfContents) { + this._hashOfContents = watch.sha1(this.contents()); + } + + this._hash = watch.sha1( + String(File._salt()), + this._hashOfContents, + ); } + return this._hash; } @@ -587,7 +601,7 @@ class File { } this._contents = b; // Un-cache hash. - this._hash = null; + this._hashOfContents = this._hash = null; } size() { diff --git a/tools/isobuild/compiler-plugin.js b/tools/isobuild/compiler-plugin.js index c13be9eca7..8e493a3d22 100644 --- a/tools/isobuild/compiler-plugin.js +++ b/tools/isobuild/compiler-plugin.js @@ -62,7 +62,7 @@ import { isTestFilePath } from './test-files.js'; // Cache the (slightly post-processed) results of linker.fullLink. const CACHE_SIZE = process.env.METEOR_LINKER_CACHE_SIZE || 1024*1024*100; const CACHE_DEBUG = !! process.env.METEOR_TEST_PRINT_LINKER_CACHE_DEBUG; -const LINKER_CACHE_SALT = 11; // Increment this number to force relinking. +const LINKER_CACHE_SALT = 12; // Increment this number to force relinking. const LINKER_CACHE = new LRU({ max: CACHE_SIZE, // Cache is measured in bytes. We don't care about servePath. diff --git a/tools/isobuild/compiler.js b/tools/isobuild/compiler.js index 23afa1417e..3006b93896 100644 --- a/tools/isobuild/compiler.js +++ b/tools/isobuild/compiler.js @@ -34,7 +34,7 @@ var compiler = exports; // dependencies. (At least for now, packages only used in target creation (eg // minifiers) don't require you to update BUILT_BY, though you will need to quit // and rerun "meteor run".) -compiler.BUILT_BY = 'meteor/24'; +compiler.BUILT_BY = 'meteor/25'; // This is a list of all possible architectures that a build can target. (Client // is expanded into 'web.browser' and 'web.cordova') diff --git a/tools/isobuild/import-scanner.js b/tools/isobuild/import-scanner.js index 1649e37567..9f49737b27 100644 --- a/tools/isobuild/import-scanner.js +++ b/tools/isobuild/import-scanner.js @@ -648,7 +648,12 @@ export default class ImportScanner { if (this.name) { // If we're bundling a package, prefix path with // node_modules//. - path = pathJoin("node_modules", "meteor", this.name, path); + path = pathJoin( + "node_modules", + "meteor", + this.name.replace(/^local-test[:_]/, ""), + path, + ); } // Install paths should always be delimited by /. diff --git a/tools/isobuild/meteor-npm.js b/tools/isobuild/meteor-npm.js index 71451e0a1c..90bd3ef028 100644 --- a/tools/isobuild/meteor-npm.js +++ b/tools/isobuild/meteor-npm.js @@ -22,6 +22,7 @@ import { convert as convertColonsInPath } from "../utils/colon-converter.js"; +import { wrap as wrapOptimistic } from "optimism"; import { dirtyNodeModulesDirectory, optimisticLStat, @@ -133,7 +134,7 @@ meteorNpm.updateDependencies = function (packageName, // Returns a flattened dictionary of npm package names used in production, // or false if there is no package.json file in the parent directory. -export function getProdPackageNames(nodeModulesDir) { +export const getProdPackageNames = wrapOptimistic(nodeModulesDir => { const names = Object.create(null); const dirs = Object.create(null); const nodeModulesDirStack = []; @@ -208,7 +209,7 @@ export function getProdPackageNames(nodeModulesDir) { // Concretely, this means your app needs to have a package.json file if // you want any npm packages to be excluded in production. return walk(files.pathDirname(nodeModulesDir)) && names; -} +}); const lastRebuildJSONFilename = ".meteor-last-rebuild-version.json"; diff --git a/tools/tests/apps/modules/package.json b/tools/tests/apps/modules/package.json index 48935553db..8d2f07e96d 100644 --- a/tools/tests/apps/modules/package.json +++ b/tools/tests/apps/modules/package.json @@ -16,6 +16,7 @@ "winston": "^2.2.0" }, "scripts": { - "test": "METEOR_PROFILE=100 ../../../../meteor test --full-app --driver-package avital:mocha" + "test": "METEOR_PROFILE=100 ../../../../meteor test --full-app --driver-package avital:mocha", + "test-packages": "../../../../meteor test-packages --driver-package avital:mocha packages/modules-test-package" } } diff --git a/tools/tests/apps/modules/packages/modules-test-package/package.js b/tools/tests/apps/modules/packages/modules-test-package/package.js index efb8aba134..3e708129ad 100644 --- a/tools/tests/apps/modules/packages/modules-test-package/package.js +++ b/tools/tests/apps/modules/packages/modules-test-package/package.js @@ -7,7 +7,8 @@ Package.describe({ Npm.depends({ "os-browserify": "0.2.0", - "assert": "1.3.0" + "assert": "1.3.0", + "cheerio": "0.22.0" }); Package.onUse(function(api) { @@ -17,3 +18,10 @@ Package.onUse(function(api) { api.mainModule("server.js", "server"); api.export("ModulesTestPackage"); }); + +Package.onTest(function (api) { + api.use("ecmascript"); + api.use("tinytest"); + api.use("modules-test-package"); + api.mainModule("tests.js"); +}); diff --git a/tools/tests/apps/modules/packages/modules-test-package/tests.js b/tools/tests/apps/modules/packages/modules-test-package/tests.js new file mode 100644 index 0000000000..67378a6352 --- /dev/null +++ b/tools/tests/apps/modules/packages/modules-test-package/tests.js @@ -0,0 +1,9 @@ +import assert from "assert"; + +describe("cheerio", () => { + it("should be importable", () => { + import cheerio from "cheerio"; + assert.strictEqual(typeof cheerio, "object"); + assert.deepEqual(Object.keys(cheerio), ["cheerio"]); + }); +});