From c1d6ead121707dd6c1a817c73830fe58421cdbbe Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Mon, 28 Oct 2024 13:05:47 +0100 Subject: [PATCH 1/3] chore: Move download-url from https://github.com/mongodb-js/download-url --- .github/workflows/publish-packages.yaml | 1 - package-lock.json | 191 +++- packages/devtools-connect/package.json | 4 +- packages/download-url/.eslintrc | 15 + packages/download-url/.gitignore | 12 + packages/download-url/.npmignore | 12 + packages/download-url/LICENSE | 201 ++++ packages/download-url/README.md | 41 + .../download-url/bin/mongodb-download-url.js | 2 + packages/download-url/package.json | 66 ++ packages/download-url/src/bin.ts | 21 + packages/download-url/src/index.ts | 353 +++++++ packages/download-url/src/linux-distro.ts | 146 +++ packages/download-url/src/version-list.ts | 162 ++++ packages/download-url/test/index.test.ts | 866 ++++++++++++++++++ packages/download-url/tsconfig.json | 21 + packages/download-url/usage.txt | 15 + 17 files changed, 2087 insertions(+), 42 deletions(-) create mode 100644 packages/download-url/.eslintrc create mode 100644 packages/download-url/.gitignore create mode 100644 packages/download-url/.npmignore create mode 100644 packages/download-url/LICENSE create mode 100644 packages/download-url/README.md create mode 100755 packages/download-url/bin/mongodb-download-url.js create mode 100644 packages/download-url/package.json create mode 100644 packages/download-url/src/bin.ts create mode 100644 packages/download-url/src/index.ts create mode 100644 packages/download-url/src/linux-distro.ts create mode 100644 packages/download-url/src/version-list.ts create mode 100644 packages/download-url/test/index.test.ts create mode 100644 packages/download-url/tsconfig.json create mode 100644 packages/download-url/usage.txt diff --git a/.github/workflows/publish-packages.yaml b/.github/workflows/publish-packages.yaml index 449a3904..8ed48e64 100644 --- a/.github/workflows/publish-packages.yaml +++ b/.github/workflows/publish-packages.yaml @@ -42,7 +42,6 @@ jobs: - name: Install Dependencies run: | - npm ci npm run bootstrap-ci shell: bash diff --git a/package-lock.json b/package-lock.json index bf8a0b4a..223f23c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11818,6 +11818,26 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, "node_modules/eslint-plugin-es-x": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz", @@ -12065,6 +12085,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" + } + }, "node_modules/eslint-plugin-promise": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", @@ -18669,33 +18710,8 @@ } }, "node_modules/mongodb-download-url": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/mongodb-download-url/-/mongodb-download-url-1.5.1.tgz", - "integrity": "sha512-AJH2lqb7mBo7tT7RyFWK3P/ZMh7RC1qWJgOaAVrBdKeuPuCWGCESrti+ZMt6FA6mJ4eU58Lm7iG2rTkl94pBdQ==", - "license": "Apache-2.0", - "dependencies": { - "debug": "^4.1.1", - "minimist": "^1.2.3", - "node-fetch": "^2.6.1", - "semver": "^7.1.1" - }, - "bin": { - "mongodb-download-url": "bin/mongodb-download-url.js" - } - }, - "node_modules/mongodb-download-url/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } + "resolved": "packages/download-url", + "link": true }, "node_modules/mongodb-log-writer": { "version": "1.4.2", @@ -25389,7 +25405,7 @@ "os-dns-native": "^1.2.0", "resolve-mongodb-srv": "^1.1.1", "sinon-chai": "^3.7.0", - "ts-node": "^10.2.1", + "ts-node": "^10.9.2", "ts-sinon": "^2.0.1", "typescript": "^5.0.4" }, @@ -26211,6 +26227,63 @@ "node": ">=14.17" } }, + "packages/download-url": { + "name": "mongodb-download-url", + "version": "1.5.4", + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.1", + "minimist": "^1.2.3", + "node-fetch": "^2.6.1", + "semver": "^7.1.1" + }, + "bin": { + "mongodb-download-url": "bin/mongodb-download-url.js" + }, + "devDependencies": { + "@types/mocha": "^9.1.1", + "@types/node": "^17.0.35", + "@typescript-eslint/eslint-plugin": "^5.59.0", + "@typescript-eslint/parser": "^5.59.0", + "eslint": "^7.22.0", + "eslint-config-semistandard": "^17.0.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.1.1", + "gen-esm-wrapper": "^1.1.1", + "mocha": "^8.4.0", + "nyc": "^15.1.0", + "ts-node": "^10.9.2", + "typescript": "^5.0.4" + } + }, + "packages/download-url/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "packages/download-url/node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "packages/ejson-shell-parser": { "version": "2.0.2", "extraneous": true, @@ -32191,7 +32264,7 @@ "resolve-mongodb-srv": "^1.1.1", "sinon-chai": "^3.7.0", "socks": "^2.7.3", - "ts-node": "^10.2.1", + "ts-node": "^10.9.2", "ts-sinon": "^2.0.1", "typescript": "^5.0.4" }, @@ -38198,6 +38271,16 @@ } } }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + } + }, "eslint-plugin-es-x": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz", @@ -38382,6 +38465,20 @@ } } }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + } + }, "eslint-plugin-promise": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", @@ -43379,23 +43476,39 @@ } }, "mongodb-download-url": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/mongodb-download-url/-/mongodb-download-url-1.5.1.tgz", - "integrity": "sha512-AJH2lqb7mBo7tT7RyFWK3P/ZMh7RC1qWJgOaAVrBdKeuPuCWGCESrti+ZMt6FA6mJ4eU58Lm7iG2rTkl94pBdQ==", + "version": "file:packages/download-url", "requires": { + "@types/mocha": "^9.1.1", + "@types/node": "^17.0.35", + "@typescript-eslint/eslint-plugin": "^5.59.0", + "@typescript-eslint/parser": "^5.59.0", "debug": "^4.1.1", + "eslint": "^7.22.0", + "eslint-config-semistandard": "^17.0.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.1.1", + "gen-esm-wrapper": "^1.1.1", "minimist": "^1.2.3", + "mocha": "^8.4.0", "node-fetch": "^2.6.1", - "semver": "^7.1.1" + "nyc": "^15.1.0", + "semver": "^7.1.1", + "ts-node": "^10.9.2", + "typescript": "^5.0.4" }, "dependencies": { "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==" + }, + "typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true } } }, diff --git a/packages/devtools-connect/package.json b/packages/devtools-connect/package.json index d3f20a7f..5b27ef85 100644 --- a/packages/devtools-connect/package.json +++ b/packages/devtools-connect/package.json @@ -11,7 +11,7 @@ "access": "public" }, "bugs": { - "url": "https://github.com/mongodb-js/devtools-connect/issues" + "url": "https://github.com/mongodb-js/devtools-shared/issues" }, "main": "dist/index.js", "exports": { @@ -81,7 +81,7 @@ "os-dns-native": "^1.2.0", "resolve-mongodb-srv": "^1.1.1", "sinon-chai": "^3.7.0", - "ts-node": "^10.2.1", + "ts-node": "^10.9.2", "ts-sinon": "^2.0.1", "typescript": "^5.0.4" }, diff --git a/packages/download-url/.eslintrc b/packages/download-url/.eslintrc new file mode 100644 index 00000000..b25496fd --- /dev/null +++ b/packages/download-url/.eslintrc @@ -0,0 +1,15 @@ +{ + "extends": [ + "semistandard", + "plugin:promise/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-empty-function": 0, + "no-return-assign": 0, + "camelcase": 0, + "no-cond-assign": 0, + "space-before-function-paren": ["error", "never"] + } +} diff --git a/packages/download-url/.gitignore b/packages/download-url/.gitignore new file mode 100644 index 00000000..34b004ba --- /dev/null +++ b/packages/download-url/.gitignore @@ -0,0 +1,12 @@ +.DS_Store +node_modules/ +.dist/ +.build/ +npm-debug.log +coverage/ + +package-lock.json +.esm-wrapper.mjs +lib/ +.nyc_output +tmp-*/ diff --git a/packages/download-url/.npmignore b/packages/download-url/.npmignore new file mode 100644 index 00000000..745df1bc --- /dev/null +++ b/packages/download-url/.npmignore @@ -0,0 +1,12 @@ +test/ +coverage/ +.eslintrc +.jsfmtrc +.travis.yml +.DS_Store +.dist/ +.build/ +npm-debug.log +coverage/ +.nyc_output +tmp-*/ diff --git a/packages/download-url/LICENSE b/packages/download-url/LICENSE new file mode 100644 index 00000000..5e0fd33c --- /dev/null +++ b/packages/download-url/LICENSE @@ -0,0 +1,201 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or +Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices +stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works +that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of +the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its +distribution, then any Derivative Works that You distribute must +include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not +pertain to any part of the Derivative Works, in at least one +of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, +within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and +do not modify the License. You may add Your own attribution +notices within Derivative Works that You distribute, alongside +or as an addendum to the NOTICE text from the Work, provided +that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "{}" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright {yyyy} {name of copyright owner} + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/packages/download-url/README.md b/packages/download-url/README.md new file mode 100644 index 00000000..ac7ec436 --- /dev/null +++ b/packages/download-url/README.md @@ -0,0 +1,41 @@ +# mongodb-download-url [![][npm_img]][npm_url] [![][travis_img]][travis_url] [![][coverage_img]][coverage_url] [![][gitter_img]][gitter_url] + +Lookup download URL's for MongoDB versions. + +## Installation + +```bash +npm install -g mongodb-download-url +``` + +## Usage + +``` +Usage: mongodb-download-url + +Get the URL to download a MongoDB tarball or zip. + +Usage: + mongodb-download-url + +Options: + --version A semver-ish version string [Default: `stable`]. + --platform The operating system [Default: `process.platform`]. + --bits CPU arch [Default: `process.arch`]. + --debug Debug build [Default: `false`]. + -h --help Show this screen. + --version Show version. +``` + +## License + +Apache 2.0 + +[travis_img]: https://secure.travis-ci.org/mongodb-js/mongodb-download-url.svg?branch=master +[travis_url]: https://travis-ci.org/mongodb-js/download-url +[npm_img]: https://img.shields.io/npm/v/mongodb-download-url.svg +[npm_url]: https://www.npmjs.org/package/mongodb-download-url +[coverage_img]: https://coveralls.io/repos/mongodb-js/mongodb-download-url/badge.svg?branch=master +[coverage_url]: https://coveralls.io/r/mongodb-js/mongodb-download-url +[gitter_img]: https://badges.gitter.im/Join%20Chat.svg +[gitter_url]: https://gitter.im/mongodb-js/mongodb-js diff --git a/packages/download-url/bin/mongodb-download-url.js b/packages/download-url/bin/mongodb-download-url.js new file mode 100755 index 00000000..fa80df6d --- /dev/null +++ b/packages/download-url/bin/mongodb-download-url.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/bin.js'); diff --git a/packages/download-url/package.json b/packages/download-url/package.json new file mode 100644 index 00000000..a3eb89b5 --- /dev/null +++ b/packages/download-url/package.json @@ -0,0 +1,66 @@ +{ + "name": "mongodb-download-url", + "version": "1.5.4", + "description": "Lookup download URLs for MongoDB versions.", + "scripts": { + "lint": "eslint src/**/*.ts test/**/*.ts", + "lint-fix": "eslint src/**/*.ts test/**/*.ts --fix", + "test": "npm run lint && npm run build && nyc -r text -r html mocha --colors -r ts-node/register test/*.ts", + "build": "npm run compile-ts && gen-esm-wrapper . ./.esm-wrapper.mjs", + "prepare": "npm run build", + "compile-ts": "tsc -p tsconfig.json" + }, + "main": "lib/index.js", + "exports": { + "require": "./lib/index.js", + "import": "./.esm-wrapper.mjs" + }, + "typings": "lib/index.d.ts", + "bin": { + "mongodb-download-url": "bin/mongodb-download-url.js" + }, + "check": { + "ignore": [ + "coverage/{*,**/*}" + ] + }, + "precommit": [ + "check", + "test" + ], + "dependencies": { + "debug": "^4.1.1", + "minimist": "^1.2.3", + "node-fetch": "^2.6.1", + "semver": "^7.1.1" + }, + "devDependencies": { + "@types/mocha": "^9.1.1", + "@types/node": "^17.0.35", + "@typescript-eslint/eslint-plugin": "^5.59.0", + "@typescript-eslint/parser": "^5.59.0", + "eslint": "^7.22.0", + "eslint-config-semistandard": "^17.0.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.1.1", + "gen-esm-wrapper": "^1.1.1", + "mocha": "^8.4.0", + "nyc": "^15.1.0", + "ts-node": "^10.9.2", + "typescript": "^5.0.4" + }, + "keywords": [ + "mongodb", + "mongodb.js" + ], + "repository": { + "type": "git", + "url": "https://github.com/mongodb-js/devtools-shared.git" + }, + "author": "Lucas Hrabovsky (http://imlucas.com)", + "license": "Apache-2.0", + "homepage": "https://github.com/mongodb-js/devtools-shared/tree/main/packages/download-url" + +} \ No newline at end of file diff --git a/packages/download-url/src/bin.ts b/packages/download-url/src/bin.ts new file mode 100644 index 00000000..c5a2aadf --- /dev/null +++ b/packages/download-url/src/bin.ts @@ -0,0 +1,21 @@ +import path from 'path'; +import fs from 'fs'; +import minimist from 'minimist'; +import getURL from './index'; + +/* eslint no-sync:0 no-console:0 */ +const usage = fs.readFileSync(path.resolve(__dirname, '../usage.txt'), 'utf8'); +const args = minimist(process.argv.slice(2), { + boolean: ['debug'] +}); + +args.version = args._[0] || args.version || 'stable'; + +if (args.help || args.h) { + console.error(usage); + process.exitCode = 1; +} else { + getURL(args as any) + .then(pkg => console.log(pkg.url)) + .catch(err => { process.nextTick(() => { throw err; }); }); +} diff --git a/packages/download-url/src/index.ts b/packages/download-url/src/index.ts new file mode 100644 index 00000000..70af8f1f --- /dev/null +++ b/packages/download-url/src/index.ts @@ -0,0 +1,353 @@ +import os from 'os'; +import path from 'path'; +import semver from 'semver'; +import { getVersion, DownloadInfo, VersionListOpts, clearCache } from './version-list'; +import { getCurrentLinuxDistro } from './linux-distro'; +import { inspect } from 'util'; +import _debug from 'debug'; +const debug = _debug('mongodb-download-url'); + +type PriorityValue = { value: T; priority: number; } + +type ArtifactOptions = { + /** + * Specify the version as a semver string. This also accepts the special values: + * - 'stable' (or 'latest') for the latest stable version (default) + * - 'unstable' for the latest unstable version + * - 'latest-alpha' for the latest alpha release of the server + */ + version?: string; + /** + * Specify the binary architecture. Default is host architecture. + */ + arch?: string; + /** + * Specify the binary platforn. Default is host platform, as given by + * `process.platform`. + */ + platform?: string; + /** + * If known, specify a mongodb DISTRO_ID string to pick a specific Linux distro. + */ + distro?: string; + /** + * If true, this will return enterprise servers rather than community servers. + */ + enterprise?: boolean; + /** + * If true, this will return the mongocryptd-only package, if available. + * (This typically only makes sense with { enterprise: true }.) + */ + cryptd?: boolean; + /** + * If true, this will return the mongo_crypt_shared library package, if available. + * (This typically only makes sense with { enterprise: true }.) + */ + crypt_shared?: boolean; + /** + * @deprecated Use crypt_shared instead. + */ + csfle?: boolean; + /** + * @deprecated Use arch instead. + */ + bits?: '32' | '64' | 32 | 64 +}; + +export type Options = ArtifactOptions & VersionListOpts; + +export type DownloadArtifactInfo = Required> & { + /** Full download URL. */ + url: string; + /** Filename for the given download URL. */ + artifact: string; + /** Currently always 'mongodb'. */ + name: string; + // Legacy properties: + /** @deprecated */ + ext: string; + /** @deprecated */ + filenamePlatform: string; + /** @deprecated */ + debug: false; + /** @deprecated */ + branch: 'master'; +}; + +type ProcessedOptions = { + version: string; + arch: string[]; + target: PriorityValue[]; + enterprise: boolean; + cryptd: boolean; + crypt_shared: boolean; +}; + +function getPriority(values: PriorityValue[], candidate: T): number { + for (const { value, priority } of values) { + if (value === candidate) { + return priority; + } + } + return 0; +} + +function maximizer(values: T[], evaluator: (v: T) => number): T | undefined { + let max = -Infinity; + let maximizer: T | undefined; + for (const v of values) { + const result = evaluator(v); + if (result > max) { + max = result; + maximizer = v; + } + } + return maximizer; +} + +function parseArch(arch: string): string[] { + if (['i686', 'i386', 'x86', 'ia32'].includes(arch)) { + return ['i686', 'i386', 'x86', 'ia32']; + } + if (['x86_64', 'x64'].includes(arch)) { + return ['x86_64', 'x64']; + } + if (['arm64', 'aarch64'].includes(arch)) { + return ['arm64', 'aarch64']; + } + if (['ppc64', 'ppc64le'].includes(arch)) { + return ['ppc64', 'ppc64le']; + } + return [arch]; +} + +async function parseTarget(distro: string | undefined, platform: string, archs: string[], version: string): Promise[]> { + if (platform === 'linux') { + const results: PriorityValue[] = []; + if (distro) { + results.push({ value: distro, priority: 1000 }); + + if (archs.includes('x86_64')) { + if (distro === 'amzn64' || distro === 'amazon1') { + results.push({ value: 'amazon', priority: 900 }); + } + if (distro === 'amazon' || distro === 'amazon1') { + results.push({ value: 'amzn64', priority: 900 }); + } + } + } + + if (archs.includes('x86_64')) { + results.push({ value: 'linux_x86_64', priority: 1 }); + } else if (archs.includes('i686')) { + results.push({ value: 'linux_i686', priority: 1 }); + } + + let distroResultsErr; + try { + results.push(...await getCurrentLinuxDistro()); + } catch (err) { + distroResultsErr = err; + } + if (distro === undefined && + distroResultsErr && + (version === '*' || + version === 'latest-alpha' || + semver.gte(version, '4.0.0'))) { + throw distroResultsErr; + } + return results; + } else if (platform === 'sunos') { + return [{ value: 'sunos5', priority: 1 }]; + } else if (['win32', 'windows'].includes(platform)) { + if (archs.includes('i686')) { + return [ + { value: 'windows', priority: 1 }, + { value: 'windows_i686', priority: 10 } + ]; + } else { + return [ + { value: 'windows', priority: 1 }, + { value: 'windows_x86_64', priority: 10 }, + { value: 'windows_x86_64-2008plus', priority: 10 }, + { value: 'windows_x86_64-2008plus-ssl', priority: 100 }, + { value: 'windows_x86_64-2012plus', priority: 100 } + ]; + } + } else if (['darwin', 'osx', 'macos'].includes(platform)) { + return [ + { value: 'osx', priority: 1 }, + { value: 'osx-ssl', priority: 10 }, + { value: 'darwin', priority: 1 }, + { value: 'macos', priority: 1 } + ]; + } + return [{ value: platform, priority: 1 }]; +} + +async function resolve(opts: ProcessedOptions): Promise { + let download: DownloadInfo; + if (opts.version === 'latest-alpha' && opts.enterprise) { + const targets = opts.target.map(({ value }) => value); + const arch = opts.arch.includes('arm64') ? 'arm64' : 'x86_64'; + let url, target; + if (targets.includes('macos')) { + url = `https://downloads.mongodb.com/osx/mongodb-macos-${arch}-enterprise-latest.tgz`; + target = 'macos'; + } else if (targets.includes('linux_x86_64')) { + target = maximizer(opts.target, candidate => candidate.priority).value; + url = `https://downloads.mongodb.com/linux/mongodb-linux-${arch}-enterprise-${target}-latest.tgz`; + } else if (targets.includes('windows_x86_64')) { + target = 'windows'; + url = `https://downloads.mongodb.com/windows/mongodb-windows-${arch}-enterprise-latest.zip`; + } + if (url) { + download = { + target, + edition: 'enterprise', + arch: 'x86_64', + archive: { + url, + sha1: '', + sha256: '', + debug_symbols: '' + } + }; + } + } + + let version; + if (!download) { + version = await getVersion(opts); + if (!version) { + throw new Error(`Could not find version matching ${inspect(opts)}`); + } + const bestDownload = maximizer(version.downloads.map((candidate: DownloadInfo) => { + if (opts.enterprise) { + if (candidate.edition !== 'enterprise') { + return { value: candidate, priority: 0 }; + } + } else { + if (candidate.edition !== 'targeted' && candidate.edition !== 'base') { + return { value: candidate, priority: 0 }; + } + } + + if (!opts.arch.includes(candidate.arch)) { + return { value: candidate, priority: 0 }; + } + + const targetPriority = getPriority(opts.target, candidate.target); + return { value: candidate, priority: targetPriority }; + }), (candidate: PriorityValue) => candidate.priority); + if (bestDownload.priority > 0) { + download = bestDownload.value; + } + } + if (!download) { + throw new Error(`Could not find download URL for version ${version?.version} ${inspect(opts)}`); + } + + const wantsCryptd = opts.cryptd && download.target; + const wantsCryptShared = opts.crypt_shared && download.target; + + if (wantsCryptShared && !download.crypt_shared && !download.csfle) { + throw new Error(`No crypt_shared library download for version ${version?.version} available ${inspect(opts)}`); + } + + debug('fully resolved', JSON.stringify(opts, null, 2), download); + // mongocryptd is contained in the regular enterprise archive, the csfle lib is not + let { url } = wantsCryptShared + ? (download.crypt_shared ?? download.csfle) + : ((wantsCryptd ? download.cryptd : null) ?? download.archive); + if (wantsCryptd) { + // cryptd package on Windows was buggy: https://jira.mongodb.org/browse/BUILD-13653 + url = url.replace('mongodb-shell-windows', 'mongodb-cryptd-windows'); + } + + return { + ...opts, + name: 'mongodb', + url: url, + arch: download.arch, + distro: download.target, + platform: download.target, + filenamePlatform: download.target, + version: version?.version ?? '*', + artifact: path.basename(url), + debug: false, + enterprise: download.edition === 'enterprise', + branch: 'master', + bits: ['i386', 'i686'].includes(download.arch) ? '32' : '64', + ext: url.match(/\.([^.]+)$/)?.[1] ?? 'tgz' + }; +} + +async function options(opts: Options | string = {}): Promise { + if (typeof opts === 'string') { + opts = { + version: opts + }; + } else { + opts = { ...opts }; + } + + opts.crypt_shared ??= opts.csfle; + + if (opts.cryptd && opts.crypt_shared) { + throw new Error('Cannot request both cryptd and csfle package'); + } + + if (opts.bits && !opts.arch) { + opts.arch = +opts.bits === 32 ? 'ia32' : 'x64'; + } + if (!opts.arch) { + opts.arch = os.arch(); + } + if (!opts.platform) { + opts.platform = os.platform(); + } + if (!opts.version) { + opts.version = process.env.MONGODB_VERSION || 'stable'; + } + if (opts.productionOnly) { + opts.allowedTags = ['production_release']; + } + + if (opts.version === 'stable' || opts.version === 'latest' || opts.version === '*') { + opts.version = '*'; + opts.allowedTags ??= ['production_release']; + } else if (opts.version === 'rapid' || opts.version === 'continuous') { // a.k.a. quarterly etc. + opts.version = '*'; + opts.allowedTags ??= ['production_release', 'continuous_release']; + } else if (opts.version === 'unstable') { + opts.version = '*'; + opts.allowedTags ??= ['*']; + } + + const processedOptions: ProcessedOptions & VersionListOpts = { + ...opts, + arch: parseArch(opts.arch), + target: [], + enterprise: !!opts.enterprise, + cryptd: !!opts.cryptd, + crypt_shared: !!opts.crypt_shared, + version: opts.version as string + }; + processedOptions.target = await parseTarget( + opts.distro, + opts.platform, + processedOptions.arch, + processedOptions.version); + return processedOptions; +} + +export async function getDownloadURL(opts?: Options | string): Promise { + const parsedOptions = await options(opts); + + debug('Building URL for options `%j`', parsedOptions); + return await resolve(parsedOptions); +} + +export default getDownloadURL; +export { clearCache }; diff --git a/packages/download-url/src/linux-distro.ts b/packages/download-url/src/linux-distro.ts new file mode 100644 index 00000000..4907a519 --- /dev/null +++ b/packages/download-url/src/linux-distro.ts @@ -0,0 +1,146 @@ +import childProcess from 'child_process'; +import { promises as fs } from 'fs'; +import { promisify } from 'util'; +import _debug from 'debug'; +const debug = _debug('mongodb-download-url:linux-distro'); +const execFile = promisify(childProcess.execFile); + +type PriorityValue = { value: T; priority: number; } + +let osRelease: string; +export async function getCurrentLinuxDistro(): Promise[]> { + if (process.env.DISTRO_ID) { + const distroId = process.env.DISTRO_ID.split('-')[0].split('_')[0]; + debug('Using environment-provided linux distro ID', distroId); + let match; + if (match = distroId.match(/^ubuntu(\d\d)(\d\d)$/)) { + return listDistroIds({ id: 'ubuntu', version: match[1] }); + } else if (match = distroId.match(/^debian([8-9])\d$/)) { + return listDistroIds({ id: 'debian', version: match[1] }); + } else if (match = distroId.match(/^debian([1-7]\d)$/)) { + return listDistroIds({ id: 'debian', version: match[1] }); + } else if (match = distroId.match(/^suse(\d+)-?(sp\d+)?$/)) { + return listDistroIds({ id: 'suse', version: match[1] }); + } else if (match = distroId.match(/^rhel(\d+)$/)) { + return listDistroIds({ id: 'redhatenterprise', version: match[1] }); + } else if (['amazon', 'amzn64', 'amazon1'].includes(distroId)) { + return listDistroIds({ id: 'amazon', version: '2018.03' }); + } else if (match = distroId.match(/^amazon([0-9.]+)$/)) { + return listDistroIds({ id: 'amazon', version: match[1] }); + } + return [{ value: distroId, priority: 100 }]; + } + + let osReleaseId: string; + try { + osRelease ??= await fs.readFile('/etc/os-release', 'utf8'); + debug('loaded /etc/os-release'); + } catch (err) { + if (err.code === 'ENOENT') { + osRelease = ''; + } + } + if (osRelease) { + const id = osReleaseId = osRelease.match(/^ID="?(.+?)"?$/m)?.[1]; + const version = osRelease.match(/^VERSION_ID="?(.+?)"?$/m)?.[1]; + const codename = osRelease.match(/^VERSION_CODENAME="?(.+?)"?$/m)?.[1]; + if (id && (version || codename)) { + debug('got os-release info', { id, version, codename }); + const results = listDistroIds({ id, version, codename }); + if (results.length > 0) { + return results; + } + } + } + const { id, version, codename } = await lsbReleaseInfo(); + const results = listDistroIds({ id, version, codename }); + if (results.length > 0) { + return results; + } + throw new Error(`Could not figure out current Linux distro (${id}, ${osReleaseId})`); +} + +function listDistroIds({ id, version, codename }: { id: string, version: string, codename?: string }): PriorityValue[] { + const results: PriorityValue[] = []; + switch (id.toLowerCase()) { + case 'ubuntu': { + const major = +version.split('.')[0]; + if (major >= 12) results.push({ value: 'ubuntu1204', priority: 100 }); + if (major >= 14) results.push({ value: 'ubuntu1404', priority: 200 }); + if (major >= 16) results.push({ value: 'ubuntu1604', priority: 300 }); + if (major >= 18) results.push({ value: 'ubuntu1804', priority: 400 }); + if (major >= 20) results.push({ value: 'ubuntu2004', priority: 500 }); + if (major >= 22) results.push({ value: 'ubuntu2204', priority: 600 }); + if (major >= 24) results.push({ value: 'ubuntu2404', priority: 700 }); + if (major > 24) results.push({ value: 'ubuntu' + version.replace('.', '') + '04', priority: 700 }); + return results; + } + case 'debian': { + if (+version >= 8) results.push({ value: 'debian81', priority: 100 }); + if (+version >= 9) results.push({ value: 'debian92', priority: 200 }); + if (+version >= 10) results.push({ value: 'debian10', priority: 300 }); + if (+version > 10) results.push({ value: 'debian' + version, priority: 400 }); + if (!version) { + if (codename === 'buster') results.push({ value: 'debian10', priority: 100 }); + if (codename === 'bullseye') results.push({ value: 'debian11', priority: 200 }); + if (codename === 'bookworm') results.push({ value: 'debian12', priority: 300 }); + if (codename === 'trixie') results.push({ value: 'debian13', priority: 400 }); + if (codename === 'forky') results.push({ value: 'debian14', priority: 500 }); + } + return results; + } + case 'suse': + case 'sles': + return [{ value: 'suse' + version.split('.')[0], priority: 100 }]; + case 'amzn': + case 'amzn64': + case 'amazon': + if (version.match(/^201[0-9]\./)) { + return [{ value: 'amazon', priority: 100 }, { value: 'amzn64', priority: 100 }]; + } else if (version.match(/^\d\d\d\d\./)) { + return [{ value: 'amazon' + version.replace(/\..+$/, ''), priority: 100 }]; + } else { + return [{ value: 'amazon' + version.replace('.', ''), priority: 100 }]; + } + case 'centos': + return [{ value: 'rhel' + version + '0', priority: 100 }]; + case 'redhatenterprise': + case 'redhatenterpriseserver': { + // Since releases made in Aug 2024, the server uses 'rhel8' instead of 'rhel8x' + // for 8.x releases, so we multiply low version numbers by 10 and give them + // the highest priority in that class (e.g. 'rhel8' trumps 'rhel83') + let want = +version.replace('.', ''); + + // If the desired version is supplied as a single digit, assume the user wants + // the latest release in that series - e.g. rhel7 should return rhel72 + if (want < 10) { + want = want * 10 + 9; + } + const known = [55, 57, 62, 67, 70, 71, 72, 80, 81, 82, 83, 8, 90, 93, 9]; + const allowedVersions = known.filter(v => v > 50 ? v <= want : v * 10 <= want); + + return allowedVersions.map((v, i) => ({ value: 'rhel' + v, priority: (i + 1) * 100 })); + } + } + return []; +} + +async function lsbReleaseInfo(): Promise<{ id: string, version: string, codename: string }> { + const [ + id, + version, + codename + ] = await Promise.all([ + (async() => { + return (await execFile('lsb_release', ['-si'], { encoding: 'utf8' })).stdout.trim(); + })(), + (async() => { + return (await execFile('lsb_release', ['-sr'], { encoding: 'utf8' })).stdout.trim(); + })(), + (async() => { + return (await execFile('lsb_release', ['-sc'], { encoding: 'utf8' })).stdout.trim(); + })() + ]); + debug('got lsb info', { id, version, codename }); + return { id, version, codename }; +} diff --git a/packages/download-url/src/version-list.ts b/packages/download-url/src/version-list.ts new file mode 100644 index 00000000..cf90545f --- /dev/null +++ b/packages/download-url/src/version-list.ts @@ -0,0 +1,162 @@ +import zlib from 'zlib'; +import { promises as fs } from 'fs'; +import { promisify } from 'util'; +import path from 'path'; +import os from 'os'; +import fetch from 'node-fetch'; +import semver from 'semver'; +import _debug from 'debug'; +const debug = _debug('mongodb-download-url:version-list'); +const gunzip = promisify(zlib.gunzip); +const gzip = promisify(zlib.gzip); + +export type ArchiveBaseInfo = { + sha1: string; + sha256: string; + url: string; +}; + +export type DownloadInfo = { + edition: 'enterprise' | 'targeted' | 'base' | 'source' | 'subscription'; + target?: string; + arch?: string; + + archive: { + debug_symbols: string; + } & ArchiveBaseInfo; + + cryptd?: ArchiveBaseInfo; + csfle?: ArchiveBaseInfo; + crypt_shared?: ArchiveBaseInfo; + shell?: ArchiveBaseInfo; + packages?: string[]; + msi?: string; +}; + +export type VersionInfo = { + changes: string; + notes: string; + date: string; + githash: string; + + continuous_release: boolean; + current: boolean; + development_release: boolean; + lts_release: boolean; + production_release: boolean; + release_candidate: boolean; + version: string; + + downloads: DownloadInfo[]; +}; + +type FullJSON = { + versions: VersionInfo[]; +}; + +export type ReleaseTag = + | 'continuous_release' + | 'development_release' + | 'production_release' + | 'release_candidate' + | '*'; +export type VersionListOpts = { + version?: string; + versionListUrl?: string; + cachePath?: string; + cacheTimeMs?: number; + // @deprecated use allowedTags instead + productionOnly?: boolean; + allowedTags?: readonly ReleaseTag[]; +}; + +function defaultCachePath(): string { + return path.join(os.tmpdir(), '.mongodb-full.json.gz'); +} + +let fullJSON: FullJSON | undefined; +let fullJSONFetchTime = 0; +async function getFullJSON(opts: VersionListOpts): Promise { + const versionListUrl = opts.versionListUrl ?? 'https://downloads.mongodb.org/full.json'; + const cachePath = opts.cachePath ?? defaultCachePath(); + const cacheTimeMs = opts.cacheTimeMs ?? 24 * 3600 * 1000; + let tryWriteCache = cacheTimeMs > 0; + const inMemoryCopyUpToDate = () => fullJSONFetchTime >= new Date().getTime() - cacheTimeMs; + + try { + if ((!fullJSON || !inMemoryCopyUpToDate()) && cacheTimeMs > 0) { + debug('trying to load versions from cache', cachePath); + const fh = await fs.open(cachePath, 'r'); + try { + const stat = await fh.stat(); + if (process.getuid && (stat.uid !== process.getuid() || (stat.mode & 0o022) !== 0)) { + tryWriteCache = false; + debug('cannot use cache because it is not a file or we do not own it'); + throw new Error(); + } + if (stat.mtime.getTime() < new Date().getTime() - cacheTimeMs) { + debug('cache is outdated'); + throw new Error(); + } + debug('cache up-to-date'); + tryWriteCache = false; + fullJSON = JSON.parse((await gunzip(await fh.readFile())).toString()); + fullJSONFetchTime = new Date().getTime(); + } finally { + await fh.close(); + } + } + } catch {} + if (!fullJSON || !inMemoryCopyUpToDate()) { + debug('trying to load versions from source', versionListUrl); + const response = await fetch(versionListUrl); + if (!response.ok) { + throw new Error(`Could not get mongodb versions from ${versionListUrl}: ${response.statusText}`); + } + fullJSON = await response.json(); + fullJSONFetchTime = new Date().getTime(); + if (tryWriteCache) { + const partialFilePath = cachePath + `.partial.${process.pid}`; + await fs.mkdir(path.dirname(cachePath), { recursive: true }); + try { + const compressed = await gzip(JSON.stringify(fullJSON), { level: 9 }); + await fs.writeFile(partialFilePath, compressed, { mode: 0o644, flag: 'wx' }); + await fs.rename(partialFilePath, cachePath); + debug('wrote cache', cachePath); + } catch { + try { + await fs.unlink(partialFilePath); + } catch {} + } + } + } + return fullJSON; +} + +export async function getVersion(opts: VersionListOpts): Promise { + const fullJSON = await getFullJSON(opts); + let versions = fullJSON.versions; + versions = versions.filter((info: VersionInfo) => info.downloads.length > 0); + if (opts.allowedTags && !opts.allowedTags.includes('*')) { + versions = versions.filter((info: VersionInfo) => opts.allowedTags.some(tag => !!info[tag])); + } + if (opts.version && opts.version !== '*') { + versions = versions.filter((info: VersionInfo) => semver.satisfies(info.version, opts.version)); + } + versions = versions.sort((a: VersionInfo, b: VersionInfo) => semver.rcompare(a.version, b.version)); + return versions[0]; +} + +export async function clearCache(cachePath?: string): Promise { + debug('clearing cache'); + fullJSON = undefined; + fullJSONFetchTime = 0; + if (cachePath !== '') { + try { + await fs.unlink(cachePath ?? defaultCachePath()); + } catch (err) { + if (err.code === 'ENOENT') return; + throw err; + } + } +} diff --git a/packages/download-url/test/index.test.ts b/packages/download-url/test/index.test.ts new file mode 100644 index 00000000..cd693519 --- /dev/null +++ b/packages/download-url/test/index.test.ts @@ -0,0 +1,866 @@ +import assert from 'assert'; +import fetch from 'node-fetch'; +import { promises as fs } from 'fs'; +import path from 'path'; +import zlib from 'zlib'; +import http from 'http'; +import { once } from 'events'; +import resolve, { Options, clearCache } from '../'; + +const kUnknownUrl = Symbol('kUnknownUrl'); + +async function verify(query: Options | string | undefined, expectedURL: string | typeof kUnknownUrl): Promise { + const res = await resolve(query); + if (expectedURL !== kUnknownUrl) { + assert.strictEqual(res.url, expectedURL); + } + + const response = await fetch(res.url, { method: 'HEAD' }); + if (!response.ok) { + throw new Error(`Failed to get url: ${res.url}: ${response.statusText}`); + } +} + +function withFakeDistro(distro) { + let origDistroId; + before(function() { + origDistroId = process.env.DISTRO_ID; + process.env.DISTRO_ID = distro; + }); + after(function() { + if (origDistroId) { + process.env.DISTRO_ID = origDistroId; + } else { + delete process.env.DISTRO_ID; + } + }); +} + +describe('mongodb-download-url', function() { + this.slow(10_000); + this.timeout(20_000); + + before(async function() { + await clearCache(); + }); + + describe('linux', function() { + it('should resolve 2.4.14', async function() { + const query = { + version: '2.4.14', + platform: 'linux', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.14.tgz'); + }); + + it('should resolve 2.6.11', async function() { + const query = { + version: '2.6.11', + platform: 'linux', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz'); + }); + + it('should resolve 3.1.9 enterprise', async function() { + const query = { + version: '3.1.9', + platform: 'linux', + distro: 'ubuntu1404', + enterprise: true, + bits: 64 + } as const; + await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1404-3.1.9.tgz'); + }); + + it('should resolve 5.0.2 enterprise cryptd-only on Linux', async function() { + const query = { + version: '5.0.2', + platform: 'linux', + distro: 'ubuntu2004', + enterprise: true, + cryptd: true, + bits: 64 + } as const; + await verify(query, 'https://downloads.mongodb.com/linux/mongodb-cryptd-linux-x86_64-enterprise-ubuntu2004-5.0.2.tgz'); + }); + + it('should resolve 5.0.2 enterprise cryptd-only on Windows', async function() { + const query = { + version: '5.0.2', + platform: 'windows', + distro: 'windows', + enterprise: true, + cryptd: true, + bits: 64 + } as const; + await verify(query, 'https://downloads.mongodb.com/windows/mongodb-cryptd-windows-x86_64-enterprise-5.0.2.zip'); + }); + + it('should resolve 6.0.1 enterprise csfle-only on Linux', async function() { + const query = { + version: '6.0.1', + platform: 'linux', + distro: 'ubuntu2004', + enterprise: true, + csfle: true, + bits: 64 + } as const; + await verify(query, 'https://downloads.mongodb.com/linux/mongo_crypt_shared_v1-linux-x86_64-enterprise-ubuntu2004-6.0.1.tgz'); + }); + + it('should resolve 6.0.1 enterprise csfle-only on Windows', async function() { + const query = { + version: '6.0.1', + platform: 'windows', + distro: 'windows', + enterprise: true, + csfle: true, + bits: 64 + } as const; + await verify(query, 'https://downloads.mongodb.com/windows/mongo_crypt_shared_v1-windows-x86_64-enterprise-6.0.1.zip'); + }); + + it('should resolve 3.0.7 (32-bit)', async function() { + const query = { + version: '3.0.7', + platform: 'linux', + bits: 32 + } as const; + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-i686-3.0.7.tgz'); + }); + + describe('ubuntu 18.04', function() { + withFakeDistro('ubuntu1804'); + + it('should resolve 4.2.0-rc1 with ubuntu-specific url', async function() { + const query = { + version: '4.2.0-rc1', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.0-rc1.tgz'); + }); + + it('should resolve 4.0.0 with ubuntu-specific url and fallback to an older version of ubuntu', async function() { + const query = { + version: '4.0.0', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.0.0.tgz'); + }); + + it('should resolve 3.6.0 with ubuntu-specific url and fallback to an older version of ubuntu', async function() { + const query = { + version: '3.6.0', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-3.6.0.tgz'); + }); + + it('should resolve 2.6.11 with generic linux url', async function() { + const query = { + version: '2.6.11', + platform: 'linux', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz'); + }); + }); + + describe('ubuntu 20.04', function() { + withFakeDistro('ubuntu2004'); + + it('should resolve * with ubuntu-specific url', async function() { + const query = { + version: '*', + platform: 'linux' + }; + + await verify(query, kUnknownUrl); + }); + + it('should resolve 4.4.4 with ubuntu-specific url', async function() { + const query = { + version: '4.4.4', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2004-4.4.4.tgz'); + }); + + it('should resolve 4.2.3 with ubuntu-specific url', async function() { + const query = { + version: '4.2.3', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.3.tgz'); + }); + + it('should resolve 4.4.0 with ubuntu-specific url for arm', async function() { + const query = { + version: '4.4.0', + platform: 'linux', + arch: 'arm64' + }; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-aarch64-ubuntu2004-4.4.0.tgz'); + }); + + it('should resolve 6.2.0 as a continuous release', async function() { + const query = { + version: '>= 6.1 <= 6.2.0', + platform: 'linux', + arch: 'arm64', + allowedTags: ['production_release', 'continuous_release'] + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-aarch64-ubuntu2004-6.2.0.tgz'); + }); + }); + + describe('sunos', function() { + it('should resolve 3.5.8 with sunos-specific url', async function() { + const query = { + version: '3.5.8', + platform: 'sunos', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/sunos5/mongodb-sunos5-x86_64-3.5.8.tgz'); + }); + }); + + describe('suse 12', function() { + withFakeDistro('suse12'); + + it('should resolve 4.4.0 with suse-specific url', async function() { + const query = { + version: '4.4.0', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-suse12-4.4.0.tgz'); + }); + }); + + describe('suse 15', function() { + withFakeDistro('suse15'); + + it('should resolve 4.4.0 with suse-specific url', async function() { + const query = { + version: '4.4.0', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-suse15-4.4.0.tgz'); + }); + }); + + describe('suse 15', function() { + withFakeDistro('suse15sp4'); + + it('should resolve 4.4.0 with suse-specific url', async function() { + const query = { + version: '4.4.0', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-suse15-4.4.0.tgz'); + }); + }); + + describe('RHEL 7.7', function() { + withFakeDistro('rhel77'); + + it('should resolve 7.0.14 with RHEL-specific url', async function() { + const query = { + version: '7.0.14', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-7.0.14.tgz'); + }); + + it('should resolve 4.4.0 with RHEL-specific url', async function() { + const query = { + version: '4.4.0', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.0.tgz'); + }); + }); + + describe('RHEL 8.3', function() { + withFakeDistro('rhel83'); + + it('should resolve 7.0.14 with new schema RHEL-specific url', async function() { + const query = { + version: '7.0.14', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel8-7.0.14.tgz'); + }); + }); + + describe('RHEL 8.0', function() { + withFakeDistro('rhel80'); + + it('should resolve 6.0.17 with new schema RHEL-specific url', async function() { + const query = { + version: '6.0.17', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel8-6.0.17.tgz'); + }); + + it('should resolve 6.0.16 with old schema RHEL-specific url', async function() { + const query = { + version: '6.0.16', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-6.0.16.tgz'); + }); + }); + + describe('RHEL 5.5', function() { + withFakeDistro('rhel55'); + + it('should resolve 3.0.0 with RHEL-specific url', async function() { + const query = { + version: '3.0.0', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel55-3.0.0.tgz'); + }); + }); + + describe('RHEL 7', function() { + withFakeDistro('rhel7'); + + it('should resolve 7.2 with RHEL-specific url', async function() { + const query = { + platform: 'linux', + arch: 's390x', + enterprise: true, + version: '6.0.19' + } as const; + + await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-s390x-enterprise-rhel72-6.0.19.tgz'); + }); + }); + + describe('RHEL 8', function() { + withFakeDistro('rhel8'); + + it('should resolve zseries with RHEL8.3-specific url', async function() { + const query = { + platform: 'linux', + arch: 's390x', + enterprise: true, + version: '6.0.19' + } as const; + + // We don't have zseries release tagged as rhel8, so this should fallback to rhel83 as the latest one + await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-s390x-enterprise-rhel83-6.0.19.tgz'); + }); + + it('should resolve x64 with RHEL8-specific url', async function() { + const query = { + platform: 'linux', + enterprise: true, + version: '6.0.19', + bits: 64 + } as const; + + await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-rhel8-6.0.19.tgz'); + }); + }); + + describe('debian 9.2', function() { + withFakeDistro('debian92'); + + it('should resolve 4.4.4 with debian-specific url', async function() { + const query = { + version: '4.4.4', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-4.4.4.tgz'); + }); + + it('should resolve 4.0.0 with debian-specific url', async function() { + const query = { + version: '4.0.0', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-4.0.0.tgz'); + }); + + it('should resolve 3.6.0 with debian-specific url', async function() { + const query = { + version: '3.6.0', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian81-3.6.0.tgz'); + }); + + it('should resolve 2.6.11 with generic linux url', async function() { + const query = { + version: '2.6.11', + platform: 'linux', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz'); + }); + }); + + describe('debian 10', function() { + withFakeDistro('debian10'); + + it('should resolve 4.4.4 with debian-specific url', async function() { + const query = { + version: '4.4.4', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-4.4.4.tgz'); + }); + + it('should resolve 4.2.1 with debian-specific url', async function() { + const query = { + version: '4.2.1', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-4.2.1.tgz'); + }); + + it('should resolve 4.1.1 with debian-specific url', async function() { + const query = { + version: '4.1.1', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-4.1.1.tgz'); + }); + + it('should resolve 3.6.0 with debian-specific url', async function() { + const query = { + version: '3.6.0', + platform: 'linux', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian81-3.6.0.tgz'); + }); + + it('should resolve 2.6.11 with generic linux url', async function() { + const query = { + version: '2.6.11', + platform: 'linux', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz'); + }); + }); + + describe('rhel 7.1 ppc', function() { + withFakeDistro('rhel71'); + + it('should resolve 4.4.5 with rhel-specific url', async function() { + const query = { + version: '4.4.5', + platform: 'linux', + arch: 'ppc64', + enterprise: true + }; + + await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-ppc64le-enterprise-rhel71-4.4.5.tgz'); + }); + }); + }); + + describe('windows', function() { + it('should resolve 3.1.9', async function() { + const query = { + version: '3.1.9', + platform: 'win32', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-3.1.9.zip'); + }); + it('should resolve 3.1.19 enterprise', async function() { + const query = { + version: '3.1.9', + platform: 'win32', + enterprise: true, + bits: 64 + } as const; + await verify(query, 'https://downloads.mongodb.com/win32/mongodb-win32-x86_64-enterprise-windows-64-3.1.9.zip'); + }); + it('should resolve 2.6.11', async function() { + const query = { + version: '2.6.11', + platform: 'win32', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-2.6.11.zip'); + }); + it('should resolve 3.0.7 (32-bit)', async function() { + const query = { + version: '3.0.7', + platform: 'win32', + bits: 32 + } as const; + await verify(query, 'https://fastdl.mongodb.org/win32/mongodb-win32-i386-3.0.7.zip'); + }); + it('should resolve 4.2.1 (64-bit)', async function() { + const query = { + version: '4.2.1', + platform: 'win32', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2012plus-4.2.1.zip'); + }); + it('should resolve stable (64-bit)', async function() { + const query = { + version: 'stable', + platform: 'win32', + bits: 64 + } as const; + await verify(query, kUnknownUrl); + }); + }); + + describe('osx', function() { + it('should resolve 3.1.19 enterprise', async function() { + const query = { + version: '3.1.9', + platform: 'osx', + enterprise: true, + bits: 64 + } as const; + await verify(query, 'https://downloads.mongodb.com/osx/mongodb-osx-x86_64-enterprise-3.1.9.tgz'); + }); + + it('should resolve 3.6.8', async function() { + const query = { + version: '3.6.8', + platform: 'osx', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.6.8.tgz'); + }); + + it('should resolve 4.0.3', async function() { + const query = { + version: '4.0.3', + platform: 'osx', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-4.0.3.tgz'); + }); + + it('should resolve 4.1.3', async function() { + const query = { + version: '4.1.3', + platform: 'osx', + bits: 64 + } as const; + await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-macos-x86_64-4.1.3.tgz'); + }); + + it('should resolve 3.5.13 community', async function() { + const query = { + version: '3.5.13', + platform: 'osx', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.5.13.tgz'); + }); + + it('should resolve 3.0.0 without ssl', async function() { + const query = { + version: '3.0.0', + platform: 'osx', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-3.0.0.tgz'); + }); + + it('should resolve 2.6.0 without ssl', async function() { + const query = { + version: '2.6.0', + platform: 'osx', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-2.6.0.tgz'); + }); + + it('should resolve 3.2.0 with ssl', async function() { + const query = { + version: '3.2.0', + platform: 'osx', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.2.0.tgz'); + }); + + it('should resolve 3.6.0-rc3 with ssl', async function() { + const query = { + version: '3.6.0-rc3', + platform: 'osx', + bits: 64 + } as const; + + await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.6.0-rc3.tgz'); + }); + }); + + describe('version aliases', function() { + it('should resolve `stable`', async function() { + const query = { + version: 'stable' + }; + await verify(query, kUnknownUrl); + }); + + it('should resolve `unstable`', async function() { + const query = { + version: 'unstable' + }; + await verify(query, kUnknownUrl); + }); + + it('should resolve `latest`', async function() { + const query = { + version: 'latest' + }; + await verify(query, kUnknownUrl); + }); + + it('should resolve `rapid`', async function() { + const query = { + version: 'rapid' + }; + await verify(query, kUnknownUrl); + }); + + it('should resolve `latest-alpha` for macos arm64', async function() { + const query = { + version: 'latest-alpha', + platform: 'macos', + enterprise: true, + arch: 'aarch64' + }; + await verify(query, 'https://downloads.mongodb.com/osx/mongodb-macos-arm64-enterprise-latest.tgz'); + }); + + it('should resolve `latest-alpha` for macos x64', async function() { + const query = { + version: 'latest-alpha', + platform: 'macos', + enterprise: true, + arch: 'x64' + }; + await verify(query, 'https://downloads.mongodb.com/osx/mongodb-macos-x86_64-enterprise-latest.tgz'); + }); + + it('should resolve `latest-alpha` for windows', async function() { + const query = { + version: 'latest-alpha', + platform: 'windows', + enterprise: true, + bits: 64 + } as const; + await verify(query, 'https://downloads.mongodb.com/windows/mongodb-windows-x86_64-enterprise-latest.zip'); + }); + + it('should resolve `latest-alpha` for linux', async function() { + const query = { + version: 'latest-alpha', + platform: 'linux', + distro: 'ubuntu2004', + enterprise: true, + bits: 64 + } as const; + await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-ubuntu2004-latest.tgz'); + }); + }); + + describe('options', function() { + it('should handle empty options', async function() { + await verify({}, kUnknownUrl); + }); + + it('should handle no options at all', async function() { + await verify(undefined, kUnknownUrl); + }); + + it('should handle a version string input', async function() { + await verify('7.0.11', kUnknownUrl); + }); + + it('should use the MONGODB_VERSION environment variable for version', async function() { + process.env.MONGODB_VERSION = '3.0.7'; + const query = { + platform: 'win32', + bits: 32 + } as const; + await verify(query, 'https://fastdl.mongodb.org/win32/mongodb-win32-i386-3.0.7.zip'); + delete process.env.MONGODB_VERSION; + }); + }); + + describe('errors', function() { + it('fails for bad versions', async function() { + const query = { + version: '123.456.789' + }; + await assert.rejects(() => verify(query, kUnknownUrl), /Could not find version matching/); + }); + + it('fails for bad download specifiers', async function() { + const query = { + version: '1.0.0', + enterprise: true + }; + await assert.rejects(() => verify(query, kUnknownUrl), /Could not find download URL for/); + }); + }); + + describe('full.json cache', function() { + let tmpdir, cachePath; + let server, versionListUrl, currentFakeVersion, baseOptions; + + function fakeVersion(version: string) { + return { + versions: [ + { + version: version, + production_release: true, + downloads: [ + { + target: 'linux_x86_64', + edition: 'targeted', + arch: 'x64', + archive: { + url: `${versionListUrl}${version}.tgz` + } + } + ] + } + ] + }; + } + + beforeEach(async function() { + currentFakeVersion = '1.2.1'; + tmpdir = path.join(__dirname, '..', 'tmp-' + Date.now()); + cachePath = path.join(tmpdir, 'mongodb-full-json-cache.gz'); + await fs.mkdir(tmpdir, { recursive: true }); + await clearCache(''); // Clear in-memory cache. + server = http.createServer((req, res) => { + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify(fakeVersion(currentFakeVersion))); + }).listen(0); + await once(server, 'listening'); + versionListUrl = `http://localhost:${server.address().port}/`; + baseOptions = { cachePath, versionListUrl, platform: 'linux', arch: 'x64', distro: 'ubuntu2004' }; + process.umask(0o002); + }); + afterEach(async function() { + await fs.rmdir(tmpdir, { recursive: true }); + await clearCache(''); // Clear in-memory cache. + server.close(); + process.umask(0o022); + }); + + it('stores a cache file with mode 0o644', async function() { + if (process.platform === 'win32') { + return this.skip(); + } + await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); + assert.strictEqual((await fs.stat(cachePath)).mode & 0o777, 0o644); + }); + + it('caches in memory if possible', async function() { + await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); + await fs.stat(cachePath); + await fs.unlink(cachePath); + await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); + await assert.rejects(() => fs.stat(cachePath), /ENOENT/); + }); + + it('reads from disk if in-memory cache is cleared', async function() { + await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); + await fs.stat(cachePath); + await clearCache(''); + await fs.writeFile(cachePath, zlib.gzipSync(JSON.stringify(fakeVersion('1.2.3')))); + await verify({ ...baseOptions }, `${versionListUrl}1.2.3.tgz`); + }); + + it('does not write to disk if requested not to', async function() { + await verify({ ...baseOptions, cacheTimeMs: 0 }, `${versionListUrl}1.2.1.tgz`); + await assert.rejects(() => fs.stat(cachePath), /ENOENT/); + }); + + it('refuses to read the disk cache if permissions are insecure', async function() { + if (process.platform === 'win32') { + return this.skip(); + } + await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); + await fs.stat(cachePath); + await clearCache(''); + await fs.unlink(cachePath); + await fs.writeFile(cachePath, zlib.gzipSync(JSON.stringify(fakeVersion('1.2.3'))), { mode: 0o666 }); + await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); + }); + + it('refuses to read the disk cache if it is outdated', async function() { + await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); + await fs.stat(cachePath); + await clearCache(''); + const twoDaysAgo = new Date().getTime() / 1000 - 2 * 24 * 3600; + await fs.utimes(cachePath, twoDaysAgo, twoDaysAgo); + currentFakeVersion = '1.2.2'; + await verify({ ...baseOptions }, `${versionListUrl}1.2.2.tgz`); + }); + }); +}); diff --git a/packages/download-url/tsconfig.json b/packages/download-url/tsconfig.json new file mode 100644 index 00000000..3e70eef1 --- /dev/null +++ b/packages/download-url/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "downlevelIteration": true, + "sourceMap": true, + "strictNullChecks": false, + "declaration": true, + "removeComments": true, + "target": "es2019", + "lib": ["es2019"], + "outDir": "./lib", + "moduleResolution": "node", + "module": "commonjs" + }, + "include": [ + "./src/**/*" + ], + "exclude": [ + "./src/**/*.spec.*" + ] +} diff --git a/packages/download-url/usage.txt b/packages/download-url/usage.txt new file mode 100644 index 00000000..79ea5616 --- /dev/null +++ b/packages/download-url/usage.txt @@ -0,0 +1,15 @@ +Usage: mongodb-download-url + +Get the URL to download a MongoDB tarball or zip. + +Usage: + mongodb-download-url [options] + +Options: + --version A semver-ish version string [Default: `stable`]. + --platform The operating system [Default: `process.platform`]. + --bits CPU arch [Default: `process.arch`]. + --enterprise Use MongoDB enterprise [Default: `false`]. + --debug Debug build [Default: `false`]. + -h --help Show this screen. + --version Show version. From 5ea1da56633be53c9cf148346bd3083e68d72c30 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Tue, 29 Oct 2024 01:20:30 +0100 Subject: [PATCH 2/3] Move over to a create-workspace version of the package --- package-lock.json | 52 +++++++++++++++++++++++- packages/download-url/.depcheckrc | 8 ++++ packages/download-url/.eslintignore | 2 + packages/download-url/.eslintrc | 15 ------- packages/download-url/.eslintrc.js | 13 ++++++ packages/download-url/.mocharc.js | 1 + packages/download-url/.prettierignore | 3 ++ packages/download-url/.prettierrc.json | 1 + packages/download-url/package.json | 46 +++++++++++++-------- packages/download-url/tsconfig-lint.json | 5 +++ packages/download-url/tsconfig.json | 20 +++------ 11 files changed, 116 insertions(+), 50 deletions(-) create mode 100644 packages/download-url/.depcheckrc create mode 100644 packages/download-url/.eslintignore delete mode 100644 packages/download-url/.eslintrc create mode 100644 packages/download-url/.eslintrc.js create mode 100644 packages/download-url/.mocharc.js create mode 100644 packages/download-url/.prettierignore create mode 100644 packages/download-url/.prettierrc.json create mode 100644 packages/download-url/tsconfig-lint.json diff --git a/package-lock.json b/package-lock.json index 223f23c9..0396aef9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26241,11 +26241,17 @@ "mongodb-download-url": "bin/mongodb-download-url.js" }, "devDependencies": { + "@mongodb-js/eslint-config-devtools": "0.9.10", + "@mongodb-js/mocha-config-devtools": "^1.0.4", + "@mongodb-js/prettier-config-devtools": "^1.0.1", + "@mongodb-js/tsconfig-devtools": "^1.0.2", + "@types/chai": "^4.2.21", "@types/mocha": "^9.1.1", "@types/node": "^17.0.35", "@typescript-eslint/eslint-plugin": "^5.59.0", "@typescript-eslint/parser": "^5.59.0", - "eslint": "^7.22.0", + "depcheck": "^1.4.1", + "eslint": "^7.25.0", "eslint-config-semistandard": "^17.0.0", "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.22.1", @@ -26254,6 +26260,8 @@ "gen-esm-wrapper": "^1.1.1", "mocha": "^8.4.0", "nyc": "^15.1.0", + "prettier": "^2.3.2", + "sinon": "^9.2.3", "ts-node": "^10.9.2", "typescript": "^5.0.4" } @@ -26284,6 +26292,38 @@ "node": ">=14.17" } }, + "packages/download-url2": { + "name": "mongodb-download-url", + "version": "1.5.4", + "extraneous": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.1", + "minimist": "^1.2.3", + "node-fetch": "^2.6.1", + "semver": "^7.1.1" + }, + "bin": { + "mongodb-download-url": "bin/mongodb-download-url.js" + }, + "devDependencies": { + "@types/mocha": "^9.1.1", + "@types/node": "^17.0.35", + "@typescript-eslint/eslint-plugin": "^5.59.0", + "@typescript-eslint/parser": "^5.59.0", + "eslint": "^7.22.0", + "eslint-config-semistandard": "^17.0.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.1.1", + "gen-esm-wrapper": "^1.1.1", + "mocha": "^8.4.0", + "nyc": "^15.1.0", + "ts-node": "^10.9.2", + "typescript": "^5.0.4" + } + }, "packages/ejson-shell-parser": { "version": "2.0.2", "extraneous": true, @@ -43478,12 +43518,18 @@ "mongodb-download-url": { "version": "file:packages/download-url", "requires": { + "@mongodb-js/eslint-config-devtools": "0.9.10", + "@mongodb-js/mocha-config-devtools": "^1.0.4", + "@mongodb-js/prettier-config-devtools": "^1.0.1", + "@mongodb-js/tsconfig-devtools": "^1.0.2", + "@types/chai": "^4.2.21", "@types/mocha": "^9.1.1", "@types/node": "^17.0.35", "@typescript-eslint/eslint-plugin": "^5.59.0", "@typescript-eslint/parser": "^5.59.0", "debug": "^4.1.1", - "eslint": "^7.22.0", + "depcheck": "^1.4.1", + "eslint": "^7.25.0", "eslint-config-semistandard": "^17.0.0", "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.22.1", @@ -43494,7 +43540,9 @@ "mocha": "^8.4.0", "node-fetch": "^2.6.1", "nyc": "^15.1.0", + "prettier": "^2.3.2", "semver": "^7.1.1", + "sinon": "^9.2.3", "ts-node": "^10.9.2", "typescript": "^5.0.4" }, diff --git a/packages/download-url/.depcheckrc b/packages/download-url/.depcheckrc new file mode 100644 index 00000000..8a4a4b63 --- /dev/null +++ b/packages/download-url/.depcheckrc @@ -0,0 +1,8 @@ +ignores: + - '@mongodb-js/prettier-config-devtools' + - '@mongodb-js/tsconfig-devtools' + - '@types/chai' + - '@types/sinon-chai' + - 'sinon' +ignore-patterns: + - 'lib' diff --git a/packages/download-url/.eslintignore b/packages/download-url/.eslintignore new file mode 100644 index 00000000..e46ee694 --- /dev/null +++ b/packages/download-url/.eslintignore @@ -0,0 +1,2 @@ +.nyc-output +lib diff --git a/packages/download-url/.eslintrc b/packages/download-url/.eslintrc deleted file mode 100644 index b25496fd..00000000 --- a/packages/download-url/.eslintrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": [ - "semistandard", - "plugin:promise/recommended", - "plugin:@typescript-eslint/recommended" - ], - "rules": { - "@typescript-eslint/no-explicit-any": 0, - "@typescript-eslint/no-empty-function": 0, - "no-return-assign": 0, - "camelcase": 0, - "no-cond-assign": 0, - "space-before-function-paren": ["error", "never"] - } -} diff --git a/packages/download-url/.eslintrc.js b/packages/download-url/.eslintrc.js new file mode 100644 index 00000000..d9da846b --- /dev/null +++ b/packages/download-url/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + root: true, + extends: ['@mongodb-js/eslint-config-devtools'], + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig-lint.json'], + }, + rules: { + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + }, +}; diff --git a/packages/download-url/.mocharc.js b/packages/download-url/.mocharc.js new file mode 100644 index 00000000..64afeb1f --- /dev/null +++ b/packages/download-url/.mocharc.js @@ -0,0 +1 @@ +module.exports = require('@mongodb-js/mocha-config-devtools'); diff --git a/packages/download-url/.prettierignore b/packages/download-url/.prettierignore new file mode 100644 index 00000000..2a9ac589 --- /dev/null +++ b/packages/download-url/.prettierignore @@ -0,0 +1,3 @@ +.nyc_output +lib +coverage diff --git a/packages/download-url/.prettierrc.json b/packages/download-url/.prettierrc.json new file mode 100644 index 00000000..dfae21d0 --- /dev/null +++ b/packages/download-url/.prettierrc.json @@ -0,0 +1 @@ +"@mongodb-js/prettier-config-devtools" diff --git a/packages/download-url/package.json b/packages/download-url/package.json index a3eb89b5..30003d77 100644 --- a/packages/download-url/package.json +++ b/packages/download-url/package.json @@ -3,12 +3,22 @@ "version": "1.5.4", "description": "Lookup download URLs for MongoDB versions.", "scripts": { - "lint": "eslint src/**/*.ts test/**/*.ts", - "lint-fix": "eslint src/**/*.ts test/**/*.ts --fix", - "test": "npm run lint && npm run build && nyc -r text -r html mocha --colors -r ts-node/register test/*.ts", - "build": "npm run compile-ts && gen-esm-wrapper . ./.esm-wrapper.mjs", - "prepare": "npm run build", - "compile-ts": "tsc -p tsconfig.json" + "bootstrap": "npm run compile", + "prepublishOnly": "npm run compile", + "compile": "tsc -p tsconfig.json && gen-esm-wrapper . ./.esm-wrapper.mjs", + "typecheck": "tsc --noEmit", + "eslint": "eslint", + "prettier": "prettier", + "lint": "npm run eslint . && npm run prettier -- --check .", + "lint-fix": "npm run eslint . -- --fix && npm run prettier -- --write .", + "depcheck": "depcheck", + "check": "npm run typecheck && npm run lint && npm run depcheck", + "check-ci": "npm run check", + "test": "mocha", + "test-cov": "nyc -r text -r html -r lcov mocha --colors -r ts-node/register test/*.ts", + "test-watch": "npm run test -- --watch", + "test-ci": "npm run test-cov", + "reformat": "npm run prettier -- --write ." }, "main": "lib/index.js", "exports": { @@ -35,21 +45,22 @@ "semver": "^7.1.1" }, "devDependencies": { + "@mongodb-js/eslint-config-devtools": "0.9.10", + "@mongodb-js/mocha-config-devtools": "^1.0.4", + "@mongodb-js/prettier-config-devtools": "^1.0.1", + "@mongodb-js/tsconfig-devtools": "^1.0.2", + "@types/chai": "^4.2.21", "@types/mocha": "^9.1.1", "@types/node": "^17.0.35", - "@typescript-eslint/eslint-plugin": "^5.59.0", - "@typescript-eslint/parser": "^5.59.0", - "eslint": "^7.22.0", - "eslint-config-semistandard": "^17.0.0", - "eslint-config-standard": "^17.1.0", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.1.1", + "depcheck": "^1.4.1", + "eslint": "^7.25.0", "gen-esm-wrapper": "^1.1.1", "mocha": "^8.4.0", "nyc": "^15.1.0", - "ts-node": "^10.9.2", - "typescript": "^5.0.4" + "prettier": "^2.3.2", + "sinon": "^9.2.3", + "typescript": "^5.0.4", + "ts-node": "^10.9.2" }, "keywords": [ "mongodb", @@ -62,5 +73,4 @@ "author": "Lucas Hrabovsky (http://imlucas.com)", "license": "Apache-2.0", "homepage": "https://github.com/mongodb-js/devtools-shared/tree/main/packages/download-url" - -} \ No newline at end of file +} diff --git a/packages/download-url/tsconfig-lint.json b/packages/download-url/tsconfig-lint.json new file mode 100644 index 00000000..eda2ec11 --- /dev/null +++ b/packages/download-url/tsconfig-lint.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["**/*"], + "exclude": ["node_modules", "lib"] +} diff --git a/packages/download-url/tsconfig.json b/packages/download-url/tsconfig.json index 3e70eef1..b878cde9 100644 --- a/packages/download-url/tsconfig.json +++ b/packages/download-url/tsconfig.json @@ -1,21 +1,11 @@ { + "extends": "@mongodb-js/tsconfig-devtools/tsconfig.common.json", "compilerOptions": { - "esModuleInterop": true, - "downlevelIteration": true, - "sourceMap": true, - "strictNullChecks": false, - "declaration": true, - "removeComments": true, + "outDir": "./lib", "target": "es2019", "lib": ["es2019"], - "outDir": "./lib", - "moduleResolution": "node", - "module": "commonjs" + "moduleResolution": "node" }, - "include": [ - "./src/**/*" - ], - "exclude": [ - "./src/**/*.spec.*" - ] + "include": ["src/**/*"], + "exclude": ["./src/**/*.spec.*"] } From 32a46f962dd51789793302c9f26e5a5524964ffb Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Tue, 29 Oct 2024 01:20:43 +0100 Subject: [PATCH 3/3] Format, fix eslint issues --- packages/download-url/src/bin.ts | 13 +- packages/download-url/src/index.ts | 131 ++-- packages/download-url/src/linux-distro.ts | 114 ++-- packages/download-url/src/version-list.ts | 49 +- packages/download-url/test/index.test.ts | 717 ++++++++++++++-------- 5 files changed, 668 insertions(+), 356 deletions(-) diff --git a/packages/download-url/src/bin.ts b/packages/download-url/src/bin.ts index c5a2aadf..3be43422 100644 --- a/packages/download-url/src/bin.ts +++ b/packages/download-url/src/bin.ts @@ -1,12 +1,13 @@ import path from 'path'; import fs from 'fs'; import minimist from 'minimist'; +import type { Options } from './index'; import getURL from './index'; /* eslint no-sync:0 no-console:0 */ const usage = fs.readFileSync(path.resolve(__dirname, '../usage.txt'), 'utf8'); const args = minimist(process.argv.slice(2), { - boolean: ['debug'] + boolean: ['debug'], }); args.version = args._[0] || args.version || 'stable'; @@ -15,7 +16,11 @@ if (args.help || args.h) { console.error(usage); process.exitCode = 1; } else { - getURL(args as any) - .then(pkg => console.log(pkg.url)) - .catch(err => { process.nextTick(() => { throw err; }); }); + getURL(args as Options) + .then((pkg) => console.log(pkg.url)) + .catch((err) => { + process.nextTick(() => { + throw err; + }); + }); } diff --git a/packages/download-url/src/index.ts b/packages/download-url/src/index.ts index 70af8f1f..67531f2f 100644 --- a/packages/download-url/src/index.ts +++ b/packages/download-url/src/index.ts @@ -1,13 +1,14 @@ import os from 'os'; import path from 'path'; import semver from 'semver'; -import { getVersion, DownloadInfo, VersionListOpts, clearCache } from './version-list'; +import type { DownloadInfo, VersionListOpts } from './version-list'; +import { getVersion, clearCache } from './version-list'; import { getCurrentLinuxDistro } from './linux-distro'; import { inspect } from 'util'; import _debug from 'debug'; const debug = _debug('mongodb-download-url'); -type PriorityValue = { value: T; priority: number; } +type PriorityValue = { value: T; priority: number }; type ArtifactOptions = { /** @@ -51,7 +52,7 @@ type ArtifactOptions = { /** * @deprecated Use arch instead. */ - bits?: '32' | '64' | 32 | 64 + bits?: '32' | '64' | 32 | 64; }; export type Options = ArtifactOptions & VersionListOpts; @@ -121,7 +122,12 @@ function parseArch(arch: string): string[] { return [arch]; } -async function parseTarget(distro: string | undefined, platform: string, archs: string[], version: string): Promise[]> { +async function parseTarget( + distro: string | undefined, + platform: string, + archs: string[], + version: string +): Promise[]> { if (platform === 'linux') { const results: PriorityValue[] = []; if (distro) { @@ -145,15 +151,17 @@ async function parseTarget(distro: string | undefined, platform: string, archs: let distroResultsErr; try { - results.push(...await getCurrentLinuxDistro()); + results.push(...(await getCurrentLinuxDistro())); } catch (err) { distroResultsErr = err; } - if (distro === undefined && - distroResultsErr && - (version === '*' || - version === 'latest-alpha' || - semver.gte(version, '4.0.0'))) { + if ( + distro === undefined && + distroResultsErr && + (version === '*' || + version === 'latest-alpha' || + semver.gte(version, '4.0.0')) + ) { throw distroResultsErr; } return results; @@ -163,7 +171,7 @@ async function parseTarget(distro: string | undefined, platform: string, archs: if (archs.includes('i686')) { return [ { value: 'windows', priority: 1 }, - { value: 'windows_i686', priority: 10 } + { value: 'windows_i686', priority: 10 }, ]; } else { return [ @@ -171,7 +179,7 @@ async function parseTarget(distro: string | undefined, platform: string, archs: { value: 'windows_x86_64', priority: 10 }, { value: 'windows_x86_64-2008plus', priority: 10 }, { value: 'windows_x86_64-2008plus-ssl', priority: 100 }, - { value: 'windows_x86_64-2012plus', priority: 100 } + { value: 'windows_x86_64-2012plus', priority: 100 }, ]; } } else if (['darwin', 'osx', 'macos'].includes(platform)) { @@ -179,23 +187,23 @@ async function parseTarget(distro: string | undefined, platform: string, archs: { value: 'osx', priority: 1 }, { value: 'osx-ssl', priority: 10 }, { value: 'darwin', priority: 1 }, - { value: 'macos', priority: 1 } + { value: 'macos', priority: 1 }, ]; } return [{ value: platform, priority: 1 }]; } async function resolve(opts: ProcessedOptions): Promise { - let download: DownloadInfo; + let download: DownloadInfo | undefined; if (opts.version === 'latest-alpha' && opts.enterprise) { const targets = opts.target.map(({ value }) => value); const arch = opts.arch.includes('arm64') ? 'arm64' : 'x86_64'; - let url, target; + let url, target: string | undefined; if (targets.includes('macos')) { url = `https://downloads.mongodb.com/osx/mongodb-macos-${arch}-enterprise-latest.tgz`; target = 'macos'; } else if (targets.includes('linux_x86_64')) { - target = maximizer(opts.target, candidate => candidate.priority).value; + target = maximizer(opts.target, (candidate) => candidate.priority)!.value; url = `https://downloads.mongodb.com/linux/mongodb-linux-${arch}-enterprise-${target}-latest.tgz`; } else if (targets.includes('windows_x86_64')) { target = 'windows'; @@ -210,8 +218,8 @@ async function resolve(opts: ProcessedOptions): Promise { url, sha1: '', sha256: '', - debug_symbols: '' - } + debug_symbols: '', + }, }; } } @@ -222,44 +230,59 @@ async function resolve(opts: ProcessedOptions): Promise { if (!version) { throw new Error(`Could not find version matching ${inspect(opts)}`); } - const bestDownload = maximizer(version.downloads.map((candidate: DownloadInfo) => { - if (opts.enterprise) { - if (candidate.edition !== 'enterprise') { - return { value: candidate, priority: 0 }; + const bestDownload = maximizer( + version.downloads.map((candidate: DownloadInfo) => { + if (opts.enterprise) { + if (candidate.edition !== 'enterprise') { + return { value: candidate, priority: 0 }; + } + } else { + if ( + candidate.edition !== 'targeted' && + candidate.edition !== 'base' + ) { + return { value: candidate, priority: 0 }; + } } - } else { - if (candidate.edition !== 'targeted' && candidate.edition !== 'base') { + + if (!candidate.arch || !opts.arch.includes(candidate.arch)) { return { value: candidate, priority: 0 }; } - } - if (!opts.arch.includes(candidate.arch)) { - return { value: candidate, priority: 0 }; - } + const targetPriority = getPriority(opts.target, candidate.target); + return { value: candidate, priority: targetPriority }; + }), + (candidate: PriorityValue) => candidate.priority + ); - const targetPriority = getPriority(opts.target, candidate.target); - return { value: candidate, priority: targetPriority }; - }), (candidate: PriorityValue) => candidate.priority); - if (bestDownload.priority > 0) { + if (bestDownload && bestDownload.priority > 0) { download = bestDownload.value; } } if (!download) { - throw new Error(`Could not find download URL for version ${version?.version} ${inspect(opts)}`); + throw new Error( + `Could not find download URL for version ${version?.version} ${inspect( + opts + )}` + ); } const wantsCryptd = opts.cryptd && download.target; const wantsCryptShared = opts.crypt_shared && download.target; if (wantsCryptShared && !download.crypt_shared && !download.csfle) { - throw new Error(`No crypt_shared library download for version ${version?.version} available ${inspect(opts)}`); + throw new Error( + `No crypt_shared library download for version ${ + version?.version + } available ${inspect(opts)}` + ); } debug('fully resolved', JSON.stringify(opts, null, 2), download); // mongocryptd is contained in the regular enterprise archive, the csfle lib is not let { url } = wantsCryptShared - ? (download.crypt_shared ?? download.csfle) - : ((wantsCryptd ? download.cryptd : null) ?? download.archive); + ? (download.crypt_shared ?? download.csfle)! + : (wantsCryptd ? download.cryptd : null) ?? download.archive; if (wantsCryptd) { // cryptd package on Windows was buggy: https://jira.mongodb.org/browse/BUILD-13653 url = url.replace('mongodb-shell-windows', 'mongodb-cryptd-windows'); @@ -269,24 +292,26 @@ async function resolve(opts: ProcessedOptions): Promise { ...opts, name: 'mongodb', url: url, - arch: download.arch, - distro: download.target, - platform: download.target, - filenamePlatform: download.target, + arch: download.arch!, + distro: download.target!, + platform: download.target!, + filenamePlatform: download.target!, version: version?.version ?? '*', artifact: path.basename(url), debug: false, enterprise: download.edition === 'enterprise', branch: 'master', - bits: ['i386', 'i686'].includes(download.arch) ? '32' : '64', - ext: url.match(/\.([^.]+)$/)?.[1] ?? 'tgz' + bits: ['i386', 'i686'].includes(download.arch!) ? '32' : '64', + ext: url.match(/\.([^.]+)$/)?.[1] ?? 'tgz', }; } -async function options(opts: Options | string = {}): Promise { +async function options( + opts: Options | string = {} +): Promise { if (typeof opts === 'string') { opts = { - version: opts + version: opts, }; } else { opts = { ...opts }; @@ -314,10 +339,15 @@ async function options(opts: Options | string = {}): Promise { +export async function getDownloadURL( + opts?: Options | string +): Promise { const parsedOptions = await options(opts); debug('Building URL for options `%j`', parsedOptions); diff --git a/packages/download-url/src/linux-distro.ts b/packages/download-url/src/linux-distro.ts index 4907a519..81237800 100644 --- a/packages/download-url/src/linux-distro.ts +++ b/packages/download-url/src/linux-distro.ts @@ -5,48 +5,50 @@ import _debug from 'debug'; const debug = _debug('mongodb-download-url:linux-distro'); const execFile = promisify(childProcess.execFile); -type PriorityValue = { value: T; priority: number; } +type PriorityValue = { value: T; priority: number }; let osRelease: string; -export async function getCurrentLinuxDistro(): Promise[]> { +export async function getCurrentLinuxDistro(): Promise< + PriorityValue[] +> { if (process.env.DISTRO_ID) { const distroId = process.env.DISTRO_ID.split('-')[0].split('_')[0]; debug('Using environment-provided linux distro ID', distroId); let match; - if (match = distroId.match(/^ubuntu(\d\d)(\d\d)$/)) { + if ((match = distroId.match(/^ubuntu(\d\d)(\d\d)$/))) { return listDistroIds({ id: 'ubuntu', version: match[1] }); - } else if (match = distroId.match(/^debian([8-9])\d$/)) { + } else if ((match = distroId.match(/^debian([8-9])\d$/))) { return listDistroIds({ id: 'debian', version: match[1] }); - } else if (match = distroId.match(/^debian([1-7]\d)$/)) { + } else if ((match = distroId.match(/^debian([1-7]\d)$/))) { return listDistroIds({ id: 'debian', version: match[1] }); - } else if (match = distroId.match(/^suse(\d+)-?(sp\d+)?$/)) { + } else if ((match = distroId.match(/^suse(\d+)-?(sp\d+)?$/))) { return listDistroIds({ id: 'suse', version: match[1] }); - } else if (match = distroId.match(/^rhel(\d+)$/)) { + } else if ((match = distroId.match(/^rhel(\d+)$/))) { return listDistroIds({ id: 'redhatenterprise', version: match[1] }); } else if (['amazon', 'amzn64', 'amazon1'].includes(distroId)) { return listDistroIds({ id: 'amazon', version: '2018.03' }); - } else if (match = distroId.match(/^amazon([0-9.]+)$/)) { + } else if ((match = distroId.match(/^amazon([0-9.]+)$/))) { return listDistroIds({ id: 'amazon', version: match[1] }); } return [{ value: distroId, priority: 100 }]; } - let osReleaseId: string; + let osReleaseId: string | undefined; try { osRelease ??= await fs.readFile('/etc/os-release', 'utf8'); debug('loaded /etc/os-release'); - } catch (err) { + } catch (err: any) { if (err.code === 'ENOENT') { osRelease = ''; } } if (osRelease) { - const id = osReleaseId = osRelease.match(/^ID="?(.+?)"?$/m)?.[1]; + const id = (osReleaseId = osRelease.match(/^ID="?(.+?)"?$/m)?.[1]); const version = osRelease.match(/^VERSION_ID="?(.+?)"?$/m)?.[1]; const codename = osRelease.match(/^VERSION_CODENAME="?(.+?)"?$/m)?.[1]; if (id && (version || codename)) { debug('got os-release info', { id, version, codename }); - const results = listDistroIds({ id, version, codename }); + const results = listDistroIds({ id, version: version || '', codename }); if (results.length > 0) { return results; } @@ -57,10 +59,20 @@ export async function getCurrentLinuxDistro(): Promise[]> if (results.length > 0) { return results; } - throw new Error(`Could not figure out current Linux distro (${id}, ${osReleaseId})`); + throw new Error( + `Could not figure out current Linux distro (${id}, ${osReleaseId})` + ); } -function listDistroIds({ id, version, codename }: { id: string, version: string, codename?: string }): PriorityValue[] { +function listDistroIds({ + id, + version, + codename, +}: { + id: string; + version: string; + codename?: string; +}): PriorityValue[] { const results: PriorityValue[] = []; switch (id.toLowerCase()) { case 'ubuntu': { @@ -72,20 +84,30 @@ function listDistroIds({ id, version, codename }: { id: string, version: string, if (major >= 20) results.push({ value: 'ubuntu2004', priority: 500 }); if (major >= 22) results.push({ value: 'ubuntu2204', priority: 600 }); if (major >= 24) results.push({ value: 'ubuntu2404', priority: 700 }); - if (major > 24) results.push({ value: 'ubuntu' + version.replace('.', '') + '04', priority: 700 }); + if (major > 24) + results.push({ + value: 'ubuntu' + version.replace('.', '') + '04', + priority: 700, + }); return results; } case 'debian': { if (+version >= 8) results.push({ value: 'debian81', priority: 100 }); if (+version >= 9) results.push({ value: 'debian92', priority: 200 }); if (+version >= 10) results.push({ value: 'debian10', priority: 300 }); - if (+version > 10) results.push({ value: 'debian' + version, priority: 400 }); + if (+version > 10) + results.push({ value: 'debian' + version, priority: 400 }); if (!version) { - if (codename === 'buster') results.push({ value: 'debian10', priority: 100 }); - if (codename === 'bullseye') results.push({ value: 'debian11', priority: 200 }); - if (codename === 'bookworm') results.push({ value: 'debian12', priority: 300 }); - if (codename === 'trixie') results.push({ value: 'debian13', priority: 400 }); - if (codename === 'forky') results.push({ value: 'debian14', priority: 500 }); + if (codename === 'buster') + results.push({ value: 'debian10', priority: 100 }); + if (codename === 'bullseye') + results.push({ value: 'debian11', priority: 200 }); + if (codename === 'bookworm') + results.push({ value: 'debian12', priority: 300 }); + if (codename === 'trixie') + results.push({ value: 'debian13', priority: 400 }); + if (codename === 'forky') + results.push({ value: 'debian14', priority: 500 }); } return results; } @@ -96,9 +118,14 @@ function listDistroIds({ id, version, codename }: { id: string, version: string, case 'amzn64': case 'amazon': if (version.match(/^201[0-9]\./)) { - return [{ value: 'amazon', priority: 100 }, { value: 'amzn64', priority: 100 }]; + return [ + { value: 'amazon', priority: 100 }, + { value: 'amzn64', priority: 100 }, + ]; } else if (version.match(/^\d\d\d\d\./)) { - return [{ value: 'amazon' + version.replace(/\..+$/, ''), priority: 100 }]; + return [ + { value: 'amazon' + version.replace(/\..+$/, ''), priority: 100 }, + ]; } else { return [{ value: 'amazon' + version.replace('.', ''), priority: 100 }]; } @@ -117,29 +144,40 @@ function listDistroIds({ id, version, codename }: { id: string, version: string, want = want * 10 + 9; } const known = [55, 57, 62, 67, 70, 71, 72, 80, 81, 82, 83, 8, 90, 93, 9]; - const allowedVersions = known.filter(v => v > 50 ? v <= want : v * 10 <= want); + const allowedVersions = known.filter((v) => + v > 50 ? v <= want : v * 10 <= want + ); - return allowedVersions.map((v, i) => ({ value: 'rhel' + v, priority: (i + 1) * 100 })); + return allowedVersions.map((v, i) => ({ + value: `rhel${v}`, + priority: (i + 1) * 100, + })); } } return []; } -async function lsbReleaseInfo(): Promise<{ id: string, version: string, codename: string }> { - const [ - id, - version, - codename - ] = await Promise.all([ - (async() => { - return (await execFile('lsb_release', ['-si'], { encoding: 'utf8' })).stdout.trim(); +async function lsbReleaseInfo(): Promise<{ + id: string; + version: string; + codename: string; +}> { + const [id, version, codename] = await Promise.all([ + (async () => { + return ( + await execFile('lsb_release', ['-si'], { encoding: 'utf8' }) + ).stdout.trim(); })(), - (async() => { - return (await execFile('lsb_release', ['-sr'], { encoding: 'utf8' })).stdout.trim(); + (async () => { + return ( + await execFile('lsb_release', ['-sr'], { encoding: 'utf8' }) + ).stdout.trim(); + })(), + (async () => { + return ( + await execFile('lsb_release', ['-sc'], { encoding: 'utf8' }) + ).stdout.trim(); })(), - (async() => { - return (await execFile('lsb_release', ['-sc'], { encoding: 'utf8' })).stdout.trim(); - })() ]); debug('got lsb info', { id, version, codename }); return { id, version, codename }; diff --git a/packages/download-url/src/version-list.ts b/packages/download-url/src/version-list.ts index cf90545f..0e6da941 100644 --- a/packages/download-url/src/version-list.ts +++ b/packages/download-url/src/version-list.ts @@ -77,11 +77,13 @@ function defaultCachePath(): string { let fullJSON: FullJSON | undefined; let fullJSONFetchTime = 0; async function getFullJSON(opts: VersionListOpts): Promise { - const versionListUrl = opts.versionListUrl ?? 'https://downloads.mongodb.org/full.json'; + const versionListUrl = + opts.versionListUrl ?? 'https://downloads.mongodb.org/full.json'; const cachePath = opts.cachePath ?? defaultCachePath(); const cacheTimeMs = opts.cacheTimeMs ?? 24 * 3600 * 1000; let tryWriteCache = cacheTimeMs > 0; - const inMemoryCopyUpToDate = () => fullJSONFetchTime >= new Date().getTime() - cacheTimeMs; + const inMemoryCopyUpToDate = () => + fullJSONFetchTime >= new Date().getTime() - cacheTimeMs; try { if ((!fullJSON || !inMemoryCopyUpToDate()) && cacheTimeMs > 0) { @@ -89,9 +91,14 @@ async function getFullJSON(opts: VersionListOpts): Promise { const fh = await fs.open(cachePath, 'r'); try { const stat = await fh.stat(); - if (process.getuid && (stat.uid !== process.getuid() || (stat.mode & 0o022) !== 0)) { + if ( + process.getuid && + (stat.uid !== process.getuid() || (stat.mode & 0o022) !== 0) + ) { tryWriteCache = false; - debug('cannot use cache because it is not a file or we do not own it'); + debug( + 'cannot use cache because it is not a file or we do not own it' + ); throw new Error(); } if (stat.mtime.getTime() < new Date().getTime() - cacheTimeMs) { @@ -106,12 +113,17 @@ async function getFullJSON(opts: VersionListOpts): Promise { await fh.close(); } } - } catch {} + } catch { + // Ignore errors + } + if (!fullJSON || !inMemoryCopyUpToDate()) { debug('trying to load versions from source', versionListUrl); const response = await fetch(versionListUrl); if (!response.ok) { - throw new Error(`Could not get mongodb versions from ${versionListUrl}: ${response.statusText}`); + throw new Error( + `Could not get mongodb versions from ${versionListUrl}: ${response.statusText}` + ); } fullJSON = await response.json(); fullJSONFetchTime = new Date().getTime(); @@ -120,17 +132,22 @@ async function getFullJSON(opts: VersionListOpts): Promise { await fs.mkdir(path.dirname(cachePath), { recursive: true }); try { const compressed = await gzip(JSON.stringify(fullJSON), { level: 9 }); - await fs.writeFile(partialFilePath, compressed, { mode: 0o644, flag: 'wx' }); + await fs.writeFile(partialFilePath, compressed, { + mode: 0o644, + flag: 'wx', + }); await fs.rename(partialFilePath, cachePath); debug('wrote cache', cachePath); } catch { try { await fs.unlink(partialFilePath); - } catch {} + } catch { + // Ignore errors + } } } } - return fullJSON; + return fullJSON!; } export async function getVersion(opts: VersionListOpts): Promise { @@ -138,12 +155,18 @@ export async function getVersion(opts: VersionListOpts): Promise { let versions = fullJSON.versions; versions = versions.filter((info: VersionInfo) => info.downloads.length > 0); if (opts.allowedTags && !opts.allowedTags.includes('*')) { - versions = versions.filter((info: VersionInfo) => opts.allowedTags.some(tag => !!info[tag])); + versions = versions.filter((info: VersionInfo) => + opts.allowedTags!.some((tag) => !!info[tag as Exclude]) + ); } if (opts.version && opts.version !== '*') { - versions = versions.filter((info: VersionInfo) => semver.satisfies(info.version, opts.version)); + versions = versions.filter((info: VersionInfo) => + semver.satisfies(info.version, opts.version!) + ); } - versions = versions.sort((a: VersionInfo, b: VersionInfo) => semver.rcompare(a.version, b.version)); + versions = versions.sort((a: VersionInfo, b: VersionInfo) => + semver.rcompare(a.version, b.version) + ); return versions[0]; } @@ -154,7 +177,7 @@ export async function clearCache(cachePath?: string): Promise { if (cachePath !== '') { try { await fs.unlink(cachePath ?? defaultCachePath()); - } catch (err) { + } catch (err: any) { if (err.code === 'ENOENT') return; throw err; } diff --git a/packages/download-url/test/index.test.ts b/packages/download-url/test/index.test.ts index cd693519..4baf2d34 100644 --- a/packages/download-url/test/index.test.ts +++ b/packages/download-url/test/index.test.ts @@ -1,15 +1,21 @@ import assert from 'assert'; import fetch from 'node-fetch'; +import type { PathLike } from 'fs'; import { promises as fs } from 'fs'; import path from 'path'; import zlib from 'zlib'; import http from 'http'; import { once } from 'events'; -import resolve, { Options, clearCache } from '../'; +import type { Options } from '../'; +import resolve, { clearCache } from '../'; +import type { AddressInfo } from 'net'; const kUnknownUrl = Symbol('kUnknownUrl'); -async function verify(query: Options | string | undefined, expectedURL: string | typeof kUnknownUrl): Promise { +async function verify( + query: Options | string | undefined, + expectedURL: string | typeof kUnknownUrl +): Promise { const res = await resolve(query); if (expectedURL !== kUnknownUrl) { assert.strictEqual(res.url, expectedURL); @@ -21,13 +27,17 @@ async function verify(query: Options | string | undefined, expectedURL: string | } } -function withFakeDistro(distro) { - let origDistroId; - before(function() { +function withFakeDistro(distro: string) { + let origDistroId: string | undefined; + + // eslint-disable-next-line mocha/no-top-level-hooks + before(function () { origDistroId = process.env.DISTRO_ID; process.env.DISTRO_ID = distro; }); - after(function() { + + // eslint-disable-next-line mocha/no-top-level-hooks + after(function () { if (origDistroId) { process.env.DISTRO_ID = origDistroId; } else { @@ -36,738 +46,921 @@ function withFakeDistro(distro) { }); } -describe('mongodb-download-url', function() { +describe('mongodb-download-url', function () { this.slow(10_000); this.timeout(20_000); - before(async function() { + before(async function () { await clearCache(); }); - describe('linux', function() { - it('should resolve 2.4.14', async function() { + describe('linux', function () { + it('should resolve 2.4.14', async function () { const query = { version: '2.4.14', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.14.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.14.tgz' + ); }); - it('should resolve 2.6.11', async function() { + it('should resolve 2.6.11', async function () { const query = { version: '2.6.11', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz' + ); }); - it('should resolve 3.1.9 enterprise', async function() { + it('should resolve 3.1.9 enterprise', async function () { const query = { version: '3.1.9', platform: 'linux', distro: 'ubuntu1404', enterprise: true, - bits: 64 + bits: 64, } as const; - await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1404-3.1.9.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1404-3.1.9.tgz' + ); }); - it('should resolve 5.0.2 enterprise cryptd-only on Linux', async function() { + it('should resolve 5.0.2 enterprise cryptd-only on Linux', async function () { const query = { version: '5.0.2', platform: 'linux', distro: 'ubuntu2004', enterprise: true, cryptd: true, - bits: 64 + bits: 64, } as const; - await verify(query, 'https://downloads.mongodb.com/linux/mongodb-cryptd-linux-x86_64-enterprise-ubuntu2004-5.0.2.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/linux/mongodb-cryptd-linux-x86_64-enterprise-ubuntu2004-5.0.2.tgz' + ); }); - it('should resolve 5.0.2 enterprise cryptd-only on Windows', async function() { + it('should resolve 5.0.2 enterprise cryptd-only on Windows', async function () { const query = { version: '5.0.2', platform: 'windows', distro: 'windows', enterprise: true, cryptd: true, - bits: 64 + bits: 64, } as const; - await verify(query, 'https://downloads.mongodb.com/windows/mongodb-cryptd-windows-x86_64-enterprise-5.0.2.zip'); + await verify( + query, + 'https://downloads.mongodb.com/windows/mongodb-cryptd-windows-x86_64-enterprise-5.0.2.zip' + ); }); - it('should resolve 6.0.1 enterprise csfle-only on Linux', async function() { + it('should resolve 6.0.1 enterprise csfle-only on Linux', async function () { const query = { version: '6.0.1', platform: 'linux', distro: 'ubuntu2004', enterprise: true, csfle: true, - bits: 64 + bits: 64, } as const; - await verify(query, 'https://downloads.mongodb.com/linux/mongo_crypt_shared_v1-linux-x86_64-enterprise-ubuntu2004-6.0.1.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/linux/mongo_crypt_shared_v1-linux-x86_64-enterprise-ubuntu2004-6.0.1.tgz' + ); }); - it('should resolve 6.0.1 enterprise csfle-only on Windows', async function() { + it('should resolve 6.0.1 enterprise csfle-only on Windows', async function () { const query = { version: '6.0.1', platform: 'windows', distro: 'windows', enterprise: true, csfle: true, - bits: 64 + bits: 64, } as const; - await verify(query, 'https://downloads.mongodb.com/windows/mongo_crypt_shared_v1-windows-x86_64-enterprise-6.0.1.zip'); + await verify( + query, + 'https://downloads.mongodb.com/windows/mongo_crypt_shared_v1-windows-x86_64-enterprise-6.0.1.zip' + ); }); - it('should resolve 3.0.7 (32-bit)', async function() { + it('should resolve 3.0.7 (32-bit)', async function () { const query = { version: '3.0.7', platform: 'linux', - bits: 32 + bits: 32, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-i686-3.0.7.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-i686-3.0.7.tgz' + ); }); - describe('ubuntu 18.04', function() { + describe('ubuntu 18.04', function () { withFakeDistro('ubuntu1804'); - it('should resolve 4.2.0-rc1 with ubuntu-specific url', async function() { + it('should resolve 4.2.0-rc1 with ubuntu-specific url', async function () { const query = { version: '4.2.0-rc1', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.0-rc1.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.0-rc1.tgz' + ); }); - it('should resolve 4.0.0 with ubuntu-specific url and fallback to an older version of ubuntu', async function() { + it('should resolve 4.0.0 with ubuntu-specific url and fallback to an older version of ubuntu', async function () { const query = { version: '4.0.0', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.0.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.0.0.tgz' + ); }); - it('should resolve 3.6.0 with ubuntu-specific url and fallback to an older version of ubuntu', async function() { + it('should resolve 3.6.0 with ubuntu-specific url and fallback to an older version of ubuntu', async function () { const query = { version: '3.6.0', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-3.6.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-3.6.0.tgz' + ); }); - it('should resolve 2.6.11 with generic linux url', async function() { + it('should resolve 2.6.11 with generic linux url', async function () { const query = { version: '2.6.11', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz' + ); }); }); - describe('ubuntu 20.04', function() { + describe('ubuntu 20.04', function () { withFakeDistro('ubuntu2004'); - it('should resolve * with ubuntu-specific url', async function() { + it('should resolve * with ubuntu-specific url', async function () { const query = { version: '*', - platform: 'linux' + platform: 'linux', }; await verify(query, kUnknownUrl); }); - it('should resolve 4.4.4 with ubuntu-specific url', async function() { + it('should resolve 4.4.4 with ubuntu-specific url', async function () { const query = { version: '4.4.4', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2004-4.4.4.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2004-4.4.4.tgz' + ); }); - it('should resolve 4.2.3 with ubuntu-specific url', async function() { + it('should resolve 4.2.3 with ubuntu-specific url', async function () { const query = { version: '4.2.3', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.3.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.3.tgz' + ); }); - it('should resolve 4.4.0 with ubuntu-specific url for arm', async function() { + it('should resolve 4.4.0 with ubuntu-specific url for arm', async function () { const query = { version: '4.4.0', platform: 'linux', - arch: 'arm64' + arch: 'arm64', }; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-aarch64-ubuntu2004-4.4.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-aarch64-ubuntu2004-4.4.0.tgz' + ); }); - it('should resolve 6.2.0 as a continuous release', async function() { + it('should resolve 6.2.0 as a continuous release', async function () { const query = { version: '>= 6.1 <= 6.2.0', platform: 'linux', arch: 'arm64', - allowedTags: ['production_release', 'continuous_release'] + allowedTags: ['production_release', 'continuous_release'], } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-aarch64-ubuntu2004-6.2.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-aarch64-ubuntu2004-6.2.0.tgz' + ); }); }); - describe('sunos', function() { - it('should resolve 3.5.8 with sunos-specific url', async function() { + describe('sunos', function () { + it('should resolve 3.5.8 with sunos-specific url', async function () { const query = { version: '3.5.8', platform: 'sunos', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/sunos5/mongodb-sunos5-x86_64-3.5.8.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/sunos5/mongodb-sunos5-x86_64-3.5.8.tgz' + ); }); }); - describe('suse 12', function() { + describe('suse 12', function () { withFakeDistro('suse12'); - it('should resolve 4.4.0 with suse-specific url', async function() { + it('should resolve 4.4.0 with suse-specific url', async function () { const query = { version: '4.4.0', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-suse12-4.4.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-suse12-4.4.0.tgz' + ); }); }); - describe('suse 15', function() { + describe('suse 15', function () { withFakeDistro('suse15'); - it('should resolve 4.4.0 with suse-specific url', async function() { + it('should resolve 4.4.0 with suse-specific url', async function () { const query = { version: '4.4.0', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-suse15-4.4.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-suse15-4.4.0.tgz' + ); }); }); - describe('suse 15', function() { + describe('suse 15sp4', function () { withFakeDistro('suse15sp4'); - it('should resolve 4.4.0 with suse-specific url', async function() { + it('should resolve 4.4.0 with suse-specific url', async function () { const query = { version: '4.4.0', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-suse15-4.4.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-suse15-4.4.0.tgz' + ); }); }); - describe('RHEL 7.7', function() { + describe('RHEL 7.7', function () { withFakeDistro('rhel77'); - it('should resolve 7.0.14 with RHEL-specific url', async function() { + it('should resolve 7.0.14 with RHEL-specific url', async function () { const query = { version: '7.0.14', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-7.0.14.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-7.0.14.tgz' + ); }); - it('should resolve 4.4.0 with RHEL-specific url', async function() { + it('should resolve 4.4.0 with RHEL-specific url', async function () { const query = { version: '4.4.0', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.0.tgz' + ); }); }); - describe('RHEL 8.3', function() { + describe('RHEL 8.3', function () { withFakeDistro('rhel83'); - it('should resolve 7.0.14 with new schema RHEL-specific url', async function() { + it('should resolve 7.0.14 with new schema RHEL-specific url', async function () { const query = { version: '7.0.14', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel8-7.0.14.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel8-7.0.14.tgz' + ); }); }); - describe('RHEL 8.0', function() { + describe('RHEL 8.0', function () { withFakeDistro('rhel80'); - it('should resolve 6.0.17 with new schema RHEL-specific url', async function() { + it('should resolve 6.0.17 with new schema RHEL-specific url', async function () { const query = { version: '6.0.17', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel8-6.0.17.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel8-6.0.17.tgz' + ); }); - it('should resolve 6.0.16 with old schema RHEL-specific url', async function() { + it('should resolve 6.0.16 with old schema RHEL-specific url', async function () { const query = { version: '6.0.16', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-6.0.16.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-6.0.16.tgz' + ); }); }); - describe('RHEL 5.5', function() { + describe('RHEL 5.5', function () { withFakeDistro('rhel55'); - it('should resolve 3.0.0 with RHEL-specific url', async function() { + it('should resolve 3.0.0 with RHEL-specific url', async function () { const query = { version: '3.0.0', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel55-3.0.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel55-3.0.0.tgz' + ); }); }); - describe('RHEL 7', function() { + describe('RHEL 7', function () { withFakeDistro('rhel7'); - it('should resolve 7.2 with RHEL-specific url', async function() { + it('should resolve 7.2 with RHEL-specific url', async function () { const query = { platform: 'linux', arch: 's390x', enterprise: true, - version: '6.0.19' + version: '6.0.19', } as const; - await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-s390x-enterprise-rhel72-6.0.19.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/linux/mongodb-linux-s390x-enterprise-rhel72-6.0.19.tgz' + ); }); }); - describe('RHEL 8', function() { + describe('RHEL 8', function () { withFakeDistro('rhel8'); - it('should resolve zseries with RHEL8.3-specific url', async function() { + it('should resolve zseries with RHEL8.3-specific url', async function () { const query = { platform: 'linux', arch: 's390x', enterprise: true, - version: '6.0.19' + version: '6.0.19', } as const; // We don't have zseries release tagged as rhel8, so this should fallback to rhel83 as the latest one - await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-s390x-enterprise-rhel83-6.0.19.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/linux/mongodb-linux-s390x-enterprise-rhel83-6.0.19.tgz' + ); }); - it('should resolve x64 with RHEL8-specific url', async function() { + it('should resolve x64 with RHEL8-specific url', async function () { const query = { platform: 'linux', enterprise: true, version: '6.0.19', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-rhel8-6.0.19.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-rhel8-6.0.19.tgz' + ); }); }); - describe('debian 9.2', function() { + describe('debian 9.2', function () { withFakeDistro('debian92'); - it('should resolve 4.4.4 with debian-specific url', async function() { + it('should resolve 4.4.4 with debian-specific url', async function () { const query = { version: '4.4.4', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-4.4.4.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-4.4.4.tgz' + ); }); - it('should resolve 4.0.0 with debian-specific url', async function() { + it('should resolve 4.0.0 with debian-specific url', async function () { const query = { version: '4.0.0', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-4.0.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-4.0.0.tgz' + ); }); - it('should resolve 3.6.0 with debian-specific url', async function() { + it('should resolve 3.6.0 with debian-specific url', async function () { const query = { version: '3.6.0', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian81-3.6.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian81-3.6.0.tgz' + ); }); - it('should resolve 2.6.11 with generic linux url', async function() { + it('should resolve 2.6.11 with generic linux url', async function () { const query = { version: '2.6.11', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz' + ); }); }); - describe('debian 10', function() { + describe('debian 10', function () { withFakeDistro('debian10'); - it('should resolve 4.4.4 with debian-specific url', async function() { + it('should resolve 4.4.4 with debian-specific url', async function () { const query = { version: '4.4.4', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-4.4.4.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-4.4.4.tgz' + ); }); - it('should resolve 4.2.1 with debian-specific url', async function() { + it('should resolve 4.2.1 with debian-specific url', async function () { const query = { version: '4.2.1', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-4.2.1.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-4.2.1.tgz' + ); }); - it('should resolve 4.1.1 with debian-specific url', async function() { + it('should resolve 4.1.1 with debian-specific url', async function () { const query = { version: '4.1.1', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-4.1.1.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian92-4.1.1.tgz' + ); }); - it('should resolve 3.6.0 with debian-specific url', async function() { + it('should resolve 3.6.0 with debian-specific url', async function () { const query = { version: '3.6.0', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian81-3.6.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian81-3.6.0.tgz' + ); }); - it('should resolve 2.6.11 with generic linux url', async function() { + it('should resolve 2.6.11 with generic linux url', async function () { const query = { version: '2.6.11', platform: 'linux', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz' + ); }); }); - describe('rhel 7.1 ppc', function() { + describe('rhel 7.1 ppc', function () { withFakeDistro('rhel71'); - it('should resolve 4.4.5 with rhel-specific url', async function() { + it('should resolve 4.4.5 with rhel-specific url', async function () { const query = { version: '4.4.5', platform: 'linux', arch: 'ppc64', - enterprise: true + enterprise: true, }; - await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-ppc64le-enterprise-rhel71-4.4.5.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/linux/mongodb-linux-ppc64le-enterprise-rhel71-4.4.5.tgz' + ); }); }); }); - describe('windows', function() { - it('should resolve 3.1.9', async function() { + describe('windows', function () { + it('should resolve 3.1.9', async function () { const query = { version: '3.1.9', platform: 'win32', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-3.1.9.zip'); + await verify( + query, + 'https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-3.1.9.zip' + ); }); - it('should resolve 3.1.19 enterprise', async function() { + it('should resolve 3.1.19 enterprise', async function () { const query = { version: '3.1.9', platform: 'win32', enterprise: true, - bits: 64 + bits: 64, } as const; - await verify(query, 'https://downloads.mongodb.com/win32/mongodb-win32-x86_64-enterprise-windows-64-3.1.9.zip'); + await verify( + query, + 'https://downloads.mongodb.com/win32/mongodb-win32-x86_64-enterprise-windows-64-3.1.9.zip' + ); }); - it('should resolve 2.6.11', async function() { + it('should resolve 2.6.11', async function () { const query = { version: '2.6.11', platform: 'win32', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-2.6.11.zip'); + await verify( + query, + 'https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-2.6.11.zip' + ); }); - it('should resolve 3.0.7 (32-bit)', async function() { + it('should resolve 3.0.7 (32-bit)', async function () { const query = { version: '3.0.7', platform: 'win32', - bits: 32 + bits: 32, } as const; - await verify(query, 'https://fastdl.mongodb.org/win32/mongodb-win32-i386-3.0.7.zip'); + await verify( + query, + 'https://fastdl.mongodb.org/win32/mongodb-win32-i386-3.0.7.zip' + ); }); - it('should resolve 4.2.1 (64-bit)', async function() { + it('should resolve 4.2.1 (64-bit)', async function () { const query = { version: '4.2.1', platform: 'win32', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2012plus-4.2.1.zip'); + await verify( + query, + 'https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2012plus-4.2.1.zip' + ); }); - it('should resolve stable (64-bit)', async function() { + it('should resolve stable (64-bit)', async function () { const query = { version: 'stable', platform: 'win32', - bits: 64 + bits: 64, } as const; await verify(query, kUnknownUrl); }); }); - describe('osx', function() { - it('should resolve 3.1.19 enterprise', async function() { + describe('osx', function () { + it('should resolve 3.1.19 enterprise', async function () { const query = { version: '3.1.9', platform: 'osx', enterprise: true, - bits: 64 + bits: 64, } as const; - await verify(query, 'https://downloads.mongodb.com/osx/mongodb-osx-x86_64-enterprise-3.1.9.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/osx/mongodb-osx-x86_64-enterprise-3.1.9.tgz' + ); }); - it('should resolve 3.6.8', async function() { + it('should resolve 3.6.8', async function () { const query = { version: '3.6.8', platform: 'osx', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.6.8.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.6.8.tgz' + ); }); - it('should resolve 4.0.3', async function() { + it('should resolve 4.0.3', async function () { const query = { version: '4.0.3', platform: 'osx', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-4.0.3.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-4.0.3.tgz' + ); }); - it('should resolve 4.1.3', async function() { + it('should resolve 4.1.3', async function () { const query = { version: '4.1.3', platform: 'osx', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-macos-x86_64-4.1.3.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/osx/mongodb-macos-x86_64-4.1.3.tgz' + ); }); - it('should resolve 3.5.13 community', async function() { + it('should resolve 3.5.13 community', async function () { const query = { version: '3.5.13', platform: 'osx', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.5.13.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.5.13.tgz' + ); }); - it('should resolve 3.0.0 without ssl', async function() { + it('should resolve 3.0.0 without ssl', async function () { const query = { version: '3.0.0', platform: 'osx', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-3.0.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-3.0.0.tgz' + ); }); - it('should resolve 2.6.0 without ssl', async function() { + it('should resolve 2.6.0 without ssl', async function () { const query = { version: '2.6.0', platform: 'osx', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-2.6.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-2.6.0.tgz' + ); }); - it('should resolve 3.2.0 with ssl', async function() { + it('should resolve 3.2.0 with ssl', async function () { const query = { version: '3.2.0', platform: 'osx', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.2.0.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.2.0.tgz' + ); }); - it('should resolve 3.6.0-rc3 with ssl', async function() { + it('should resolve 3.6.0-rc3 with ssl', async function () { const query = { version: '3.6.0-rc3', platform: 'osx', - bits: 64 + bits: 64, } as const; - await verify(query, 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.6.0-rc3.tgz'); + await verify( + query, + 'https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.6.0-rc3.tgz' + ); }); }); - describe('version aliases', function() { - it('should resolve `stable`', async function() { + describe('version aliases', function () { + it('should resolve `stable`', async function () { const query = { - version: 'stable' + version: 'stable', }; await verify(query, kUnknownUrl); }); - it('should resolve `unstable`', async function() { + it('should resolve `unstable`', async function () { const query = { - version: 'unstable' + version: 'unstable', }; await verify(query, kUnknownUrl); }); - it('should resolve `latest`', async function() { + it('should resolve `latest`', async function () { const query = { - version: 'latest' + version: 'latest', }; await verify(query, kUnknownUrl); }); - it('should resolve `rapid`', async function() { + it('should resolve `rapid`', async function () { const query = { - version: 'rapid' + version: 'rapid', }; await verify(query, kUnknownUrl); }); - it('should resolve `latest-alpha` for macos arm64', async function() { + it('should resolve `latest-alpha` for macos arm64', async function () { const query = { version: 'latest-alpha', platform: 'macos', enterprise: true, - arch: 'aarch64' + arch: 'aarch64', }; - await verify(query, 'https://downloads.mongodb.com/osx/mongodb-macos-arm64-enterprise-latest.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/osx/mongodb-macos-arm64-enterprise-latest.tgz' + ); }); - it('should resolve `latest-alpha` for macos x64', async function() { + it('should resolve `latest-alpha` for macos x64', async function () { const query = { version: 'latest-alpha', platform: 'macos', enterprise: true, - arch: 'x64' + arch: 'x64', }; - await verify(query, 'https://downloads.mongodb.com/osx/mongodb-macos-x86_64-enterprise-latest.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/osx/mongodb-macos-x86_64-enterprise-latest.tgz' + ); }); - it('should resolve `latest-alpha` for windows', async function() { + it('should resolve `latest-alpha` for windows', async function () { const query = { version: 'latest-alpha', platform: 'windows', enterprise: true, - bits: 64 + bits: 64, } as const; - await verify(query, 'https://downloads.mongodb.com/windows/mongodb-windows-x86_64-enterprise-latest.zip'); + await verify( + query, + 'https://downloads.mongodb.com/windows/mongodb-windows-x86_64-enterprise-latest.zip' + ); }); - it('should resolve `latest-alpha` for linux', async function() { + it('should resolve `latest-alpha` for linux', async function () { const query = { version: 'latest-alpha', platform: 'linux', distro: 'ubuntu2004', enterprise: true, - bits: 64 + bits: 64, } as const; - await verify(query, 'https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-ubuntu2004-latest.tgz'); + await verify( + query, + 'https://downloads.mongodb.com/linux/mongodb-linux-x86_64-enterprise-ubuntu2004-latest.tgz' + ); }); }); - describe('options', function() { - it('should handle empty options', async function() { + describe('options', function () { + it('should handle empty options', async function () { await verify({}, kUnknownUrl); }); - it('should handle no options at all', async function() { + it('should handle no options at all', async function () { await verify(undefined, kUnknownUrl); }); - it('should handle a version string input', async function() { + it('should handle a version string input', async function () { await verify('7.0.11', kUnknownUrl); }); - it('should use the MONGODB_VERSION environment variable for version', async function() { + it('should use the MONGODB_VERSION environment variable for version', async function () { process.env.MONGODB_VERSION = '3.0.7'; const query = { platform: 'win32', - bits: 32 + bits: 32, } as const; - await verify(query, 'https://fastdl.mongodb.org/win32/mongodb-win32-i386-3.0.7.zip'); + await verify( + query, + 'https://fastdl.mongodb.org/win32/mongodb-win32-i386-3.0.7.zip' + ); delete process.env.MONGODB_VERSION; }); }); - describe('errors', function() { - it('fails for bad versions', async function() { + describe('errors', function () { + it('fails for bad versions', async function () { const query = { - version: '123.456.789' + version: '123.456.789', }; - await assert.rejects(() => verify(query, kUnknownUrl), /Could not find version matching/); + await assert.rejects( + () => verify(query, kUnknownUrl), + /Could not find version matching/ + ); }); - it('fails for bad download specifiers', async function() { + it('fails for bad download specifiers', async function () { const query = { version: '1.0.0', - enterprise: true + enterprise: true, }; - await assert.rejects(() => verify(query, kUnknownUrl), /Could not find download URL for/); + await assert.rejects( + () => verify(query, kUnknownUrl), + /Could not find download URL for/ + ); }); }); - describe('full.json cache', function() { - let tmpdir, cachePath; - let server, versionListUrl, currentFakeVersion, baseOptions; + describe('full.json cache', function () { + let tmpdir: PathLike, cachePath: PathLike; + let server: http.Server, + versionListUrl: string, + currentFakeVersion: string, + baseOptions: Options; function fakeVersion(version: string) { return { @@ -781,38 +974,48 @@ describe('mongodb-download-url', function() { edition: 'targeted', arch: 'x64', archive: { - url: `${versionListUrl}${version}.tgz` - } - } - ] - } - ] + url: `${versionListUrl}${version}.tgz`, + }, + }, + ], + }, + ], }; } - beforeEach(async function() { + beforeEach(async function () { currentFakeVersion = '1.2.1'; - tmpdir = path.join(__dirname, '..', 'tmp-' + Date.now()); + tmpdir = path.join(__dirname, '..', `tmp-${Date.now()}`); cachePath = path.join(tmpdir, 'mongodb-full-json-cache.gz'); await fs.mkdir(tmpdir, { recursive: true }); await clearCache(''); // Clear in-memory cache. - server = http.createServer((req, res) => { - res.writeHead(200, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify(fakeVersion(currentFakeVersion))); - }).listen(0); + server = http + .createServer((req, res) => { + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify(fakeVersion(currentFakeVersion))); + }) + .listen(0); await once(server, 'listening'); - versionListUrl = `http://localhost:${server.address().port}/`; - baseOptions = { cachePath, versionListUrl, platform: 'linux', arch: 'x64', distro: 'ubuntu2004' }; + versionListUrl = `http://localhost:${ + (server.address() as AddressInfo).port + }/`; + baseOptions = { + cachePath, + versionListUrl, + platform: 'linux', + arch: 'x64', + distro: 'ubuntu2004', + }; process.umask(0o002); }); - afterEach(async function() { - await fs.rmdir(tmpdir, { recursive: true }); + afterEach(async function () { + await fs.rm(tmpdir, { recursive: true }); await clearCache(''); // Clear in-memory cache. server.close(); process.umask(0o022); }); - it('stores a cache file with mode 0o644', async function() { + it('stores a cache file with mode 0o644', async function () { if (process.platform === 'win32') { return this.skip(); } @@ -820,7 +1023,7 @@ describe('mongodb-download-url', function() { assert.strictEqual((await fs.stat(cachePath)).mode & 0o777, 0o644); }); - it('caches in memory if possible', async function() { + it('caches in memory if possible', async function () { await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); await fs.stat(cachePath); await fs.unlink(cachePath); @@ -828,20 +1031,26 @@ describe('mongodb-download-url', function() { await assert.rejects(() => fs.stat(cachePath), /ENOENT/); }); - it('reads from disk if in-memory cache is cleared', async function() { + it('reads from disk if in-memory cache is cleared', async function () { await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); await fs.stat(cachePath); await clearCache(''); - await fs.writeFile(cachePath, zlib.gzipSync(JSON.stringify(fakeVersion('1.2.3')))); + await fs.writeFile( + cachePath, + zlib.gzipSync(JSON.stringify(fakeVersion('1.2.3'))) + ); await verify({ ...baseOptions }, `${versionListUrl}1.2.3.tgz`); }); - it('does not write to disk if requested not to', async function() { - await verify({ ...baseOptions, cacheTimeMs: 0 }, `${versionListUrl}1.2.1.tgz`); + it('does not write to disk if requested not to', async function () { + await verify( + { ...baseOptions, cacheTimeMs: 0 }, + `${versionListUrl}1.2.1.tgz` + ); await assert.rejects(() => fs.stat(cachePath), /ENOENT/); }); - it('refuses to read the disk cache if permissions are insecure', async function() { + it('refuses to read the disk cache if permissions are insecure', async function () { if (process.platform === 'win32') { return this.skip(); } @@ -849,11 +1058,15 @@ describe('mongodb-download-url', function() { await fs.stat(cachePath); await clearCache(''); await fs.unlink(cachePath); - await fs.writeFile(cachePath, zlib.gzipSync(JSON.stringify(fakeVersion('1.2.3'))), { mode: 0o666 }); + await fs.writeFile( + cachePath, + zlib.gzipSync(JSON.stringify(fakeVersion('1.2.3'))), + { mode: 0o666 } + ); await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); }); - it('refuses to read the disk cache if it is outdated', async function() { + it('refuses to read the disk cache if it is outdated', async function () { await verify({ ...baseOptions }, `${versionListUrl}1.2.1.tgz`); await fs.stat(cachePath); await clearCache('');