├── .gitignore ├── .npmignore ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── SECURITY.md ├── build └── pipeline.yml ├── jsconfig.json ├── lib ├── download.js ├── index.d.ts ├── index.js └── postinstall.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | _node_modules/ 3 | bin/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Postinstall", 11 | "program": "${workspaceFolder}/lib/postinstall.js", 12 | "runtimeVersion": "10.12.0" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.trimTrailingWhitespace": true, 3 | "git.branchProtection": ["main"], 4 | "git.branchProtectionPrompt": "alwaysCommitToNewBranch", 5 | "editor.tabSize": 4 6 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | vscode-ripgrep 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | All rights reserved. 6 | 7 | MIT License 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vscode-ripgrep 2 | 3 | This is an npm module for using [ripgrep](https://github.com/BurntSushi/ripgrep) in a Node project. It's used by VS Code. 4 | 5 | ## How it works 6 | 7 | - Ripgrep is built in [microsoft/ripgrep-prebuilt](https://github.com/microsoft/ripgrep-prebuilt) and published to releases for each tag in that repo. 8 | - In this module's postinstall task, it determines which platform it is being installed on and downloads the correct binary from ripgrep-prebuilt for the platform. 9 | - The path to the ripgrep binary is exported as `rgPath`. 10 | 11 | ### Usage example 12 | 13 | ```js 14 | const { rgPath } = require('vscode-ripgrep'); 15 | 16 | // child_process.spawn(rgPath, ...) 17 | ``` 18 | 19 | ### Dev note 20 | 21 | Runtime dependencies are not allowed in this project. This code runs on postinstall, and any dependencies would only be needed for postinstall, but they would have to be declared as `dependencies`, not `devDependencies`. Then if they were not cleaned up manually, they would end up being included in any project that uses this. I allow `https-proxy-agent` as an exception because we already ship that in VS Code, and `proxy-from-env` because it's very small and much easier to use it than reimplement it. 22 | 23 | ### GitHub API Limit note 24 | 25 | You can produce an API key, set the GITHUB_TOKEN environment var to it, and vscode-ripgrep will use it when downloading from GitHub. This increases your API limit. 26 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /build/pipeline.yml: -------------------------------------------------------------------------------- 1 | name: $(Date:yyyyMMdd)$(Rev:.r) 2 | 3 | trigger: 4 | branches: 5 | include: 6 | - main 7 | pr: none 8 | 9 | resources: 10 | repositories: 11 | - repository: templates 12 | type: github 13 | name: microsoft/vscode-engineering 14 | ref: main 15 | endpoint: Monaco 16 | 17 | parameters: 18 | - name: publishPackage 19 | displayName: 🚀 Publish @vscode/ripgrep 20 | type: boolean 21 | default: false 22 | 23 | extends: 24 | template: azure-pipelines/npm-package/pipeline.yml@templates 25 | parameters: 26 | npmPackages: 27 | - name: ripgrep 28 | 29 | buildPlatforms: 30 | - name: Linux 31 | nodeVersions: 32 | - 18.x 33 | - name: MacOS 34 | nodeVersions: 35 | - 18.x 36 | - name: Windows 37 | nodeVersions: 38 | - 18.x 39 | 40 | buildSteps: 41 | - task: AzureKeyVault@2 42 | displayName: "Azure Key Vault: Get Secrets" 43 | inputs: 44 | azureSubscription: "vscode-oss-build-secrets" 45 | KeyVaultName: "vscode-oss-build-secrets" 46 | SecretsFilter: "github-token-code-oss" 47 | - script: npm i 48 | displayName: Install dependencies 49 | env: 50 | GITHUB_TOKEN: $(github-token-code-oss) 51 | 52 | publishPackage: ${{ parameters.publishPackage }} -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "resolveJsonModule": true, 4 | "lib": [ 5 | "esnext" 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /lib/download.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 'use strict'; 3 | 4 | const path = require('path'); 5 | const fs = require('fs'); 6 | const os = require('os'); 7 | const https = require('https'); 8 | const util = require('util'); 9 | const url = require('url'); 10 | const stream = require('stream'); 11 | const child_process = require('child_process'); 12 | const proxy_from_env = require('proxy-from-env'); 13 | const yauzl = require('yauzl'); // use yauzl ^2.9.2 because vscode already ships with it. 14 | const packageVersion = require('../package.json').version; 15 | const tmpDir = path.join(os.tmpdir(), `vscode-ripgrep-cache-${packageVersion}`); 16 | 17 | const fsUnlink = util.promisify(fs.unlink); 18 | const fsExists = util.promisify(fs.exists); 19 | const fsMkdir = util.promisify(fs.mkdir); 20 | 21 | const isWindows = os.platform() === 'win32'; 22 | 23 | const REPO = 'microsoft/ripgrep-prebuilt'; 24 | const pipelineAsync = util.promisify(stream.pipeline); 25 | 26 | /** 27 | * @param {string} _url 28 | */ 29 | function isGithubUrl(_url) { 30 | return url.parse(_url).hostname === 'api.github.com'; 31 | } 32 | 33 | 34 | /** 35 | * @param {string} _url 36 | * @param {fs.PathLike} dest 37 | * @param {any} opts 38 | */ 39 | function download(_url, dest, opts) { 40 | 41 | const proxy = proxy_from_env.getProxyForUrl(url.parse(_url)); 42 | if (proxy !== '') { 43 | var HttpsProxyAgent = require('https-proxy-agent'); 44 | opts = { 45 | ...opts, 46 | "agent": new HttpsProxyAgent.HttpsProxyAgent(proxy), 47 | proxy 48 | }; 49 | } 50 | 51 | 52 | if (opts.headers && opts.headers.authorization && !isGithubUrl(_url)) { 53 | delete opts.headers.authorization; 54 | } 55 | 56 | return new Promise((resolve, reject) => { 57 | console.log(`Download options: ${JSON.stringify(opts)}`); 58 | const outFile = fs.createWriteStream(dest); 59 | const mergedOpts = { 60 | ...url.parse(_url), 61 | ...opts 62 | }; 63 | https.get(mergedOpts, response => { 64 | console.log('statusCode: ' + response.statusCode); 65 | if (response.statusCode === 302) { 66 | response.resume(); 67 | console.log('Following redirect to: ' + response.headers.location); 68 | return download(response.headers.location, dest, opts) 69 | .then(resolve, reject); 70 | } else if (response.statusCode !== 200) { 71 | reject(new Error('Download failed with ' + response.statusCode)); 72 | return; 73 | } 74 | 75 | response.pipe(outFile); 76 | outFile.on('finish', () => { 77 | resolve(); 78 | }); 79 | }).on('error', async err => { 80 | await fsUnlink(dest); 81 | reject(err); 82 | }); 83 | }); 84 | } 85 | 86 | /** 87 | * @param {string} _url 88 | * @param {any} opts 89 | */ 90 | function get(_url, opts) { 91 | console.log(`GET ${_url}`); 92 | 93 | const proxy = proxy_from_env.getProxyForUrl(url.parse(_url)); 94 | if (proxy !== '') { 95 | var HttpsProxyAgent = require('https-proxy-agent'); 96 | opts = { 97 | ...opts, 98 | "agent": new HttpsProxyAgent.HttpsProxyAgent(proxy) 99 | }; 100 | } 101 | 102 | return new Promise((resolve, reject) => { 103 | let result = ''; 104 | opts = { 105 | ...url.parse(_url), 106 | ...opts 107 | }; 108 | https.get(opts, response => { 109 | if (response.statusCode !== 200) { 110 | reject(new Error('Request failed: ' + response.statusCode)); 111 | } 112 | 113 | response.on('data', d => { 114 | result += d.toString(); 115 | }); 116 | 117 | response.on('end', () => { 118 | resolve(result); 119 | }); 120 | 121 | response.on('error', e => { 122 | reject(e); 123 | }); 124 | }).on('error', e => reject(e)); 125 | }); 126 | } 127 | 128 | /** 129 | * @param {string} repo 130 | * @param {string} tag 131 | */ 132 | function getApiUrl(repo, tag) { 133 | return `https://api.github.com/repos/${repo}/releases/tags/${tag}`; 134 | } 135 | 136 | /** 137 | * @param {{ force: boolean; token: string; version: string; }} opts 138 | * @param {string} assetName 139 | * @param {string} downloadFolder 140 | */ 141 | async function getAssetFromGithubApi(opts, assetName, downloadFolder) { 142 | const assetDownloadPath = path.join(downloadFolder, assetName); 143 | 144 | // We can just use the cached binary 145 | if (!opts.force && await fsExists(assetDownloadPath)) { 146 | console.log('Using cached download: ' + assetDownloadPath); 147 | return assetDownloadPath; 148 | } 149 | 150 | const downloadOpts = { 151 | headers: { 152 | 'user-agent': 'vscode-ripgrep' 153 | } 154 | }; 155 | 156 | if (opts.token) { 157 | downloadOpts.headers.authorization = `token ${opts.token}`; 158 | } 159 | 160 | console.log(`Finding release for ${opts.version}`); 161 | const release = await get(getApiUrl(REPO, opts.version), downloadOpts); 162 | let jsonRelease; 163 | try { 164 | jsonRelease = JSON.parse(release); 165 | } catch (e) { 166 | throw new Error('Malformed API response: ' + e.stack); 167 | } 168 | 169 | if (!jsonRelease.assets) { 170 | throw new Error('Bad API response: ' + JSON.stringify(release)); 171 | } 172 | 173 | const asset = jsonRelease.assets.find(a => a.name === assetName); 174 | if (!asset) { 175 | throw new Error('Asset not found with name: ' + assetName); 176 | } 177 | 178 | console.log(`Downloading from ${asset.url}`); 179 | console.log(`Downloading to ${assetDownloadPath}`); 180 | 181 | downloadOpts.headers.accept = 'application/octet-stream'; 182 | await download(asset.url, assetDownloadPath, downloadOpts); 183 | } 184 | 185 | /** 186 | * @param {string} zipPath 187 | * @param {string} destinationDir 188 | */ 189 | function unzipWindows(zipPath, destinationDir) { 190 | // code from https://stackoverflow.com/questions/63932027/how-to-unzip-to-a-folder-using-yauzl 191 | return new Promise((resolve, reject) => { 192 | try { 193 | // Create folder if not exists 194 | fs.promises.mkdir(path.dirname(destinationDir), { recursive: true }); 195 | 196 | // Same as example we open the zip. 197 | yauzl.open(zipPath, { lazyEntries: true }, (err, zipFile) => { 198 | if (err) { 199 | zipFile.close(); 200 | reject(err); 201 | return; 202 | } 203 | 204 | // This is the key. We start by reading the first entry. 205 | zipFile.readEntry(); 206 | 207 | // Now for every entry, we will write a file or dir 208 | // to disk. Then call zipFile.readEntry() again to 209 | // trigger the next cycle. 210 | zipFile.on('entry', (entry) => { 211 | try { 212 | // Directories 213 | if (/\/$/.test(entry.fileName)) { 214 | // Create the directory then read the next entry. 215 | fs.promises.mkdir(path.join(destinationDir, entry.fileName), { recursive: true }); 216 | zipFile.readEntry(); 217 | } 218 | // Files 219 | else { 220 | // Write the file to disk. 221 | zipFile.openReadStream(entry, (readErr, readStream) => { 222 | if (readErr) { 223 | zipFile.close(); 224 | reject(readErr); 225 | return; 226 | } 227 | 228 | const file = fs.createWriteStream(path.join(destinationDir, entry.fileName)); 229 | readStream.pipe(file); 230 | file.on('finish', () => { 231 | // Wait until the file is finished writing, then read the next entry. 232 | // @ts-ignore: Typing for close() is wrong. 233 | file.close(() => { 234 | zipFile.readEntry(); 235 | }); 236 | 237 | file.on('error', (err) => { 238 | zipFile.close(); 239 | reject(err); 240 | }); 241 | }); 242 | }); 243 | } 244 | } catch (e) { 245 | zipFile.close(); 246 | reject(e); 247 | } 248 | }); 249 | zipFile.on('end', (err) => { 250 | resolve(); 251 | }); 252 | zipFile.on('error', (err) => { 253 | zipFile.close(); 254 | reject(err); 255 | }); 256 | }); 257 | } 258 | catch (e) { 259 | reject(e); 260 | } 261 | }); 262 | } 263 | 264 | /** 265 | * Handle whitespace in filepath as powershell splits path with whitespaces 266 | * @param {string} path 267 | */ 268 | function sanitizePathForPowershell(path) { 269 | path = path.replace(/ /g, '` '); // replace whitespace with "` " as solution provided here https://stackoverflow.com/a/18537344/7374562 270 | return path; 271 | } 272 | 273 | function untar(zipPath, destinationDir) { 274 | return new Promise((resolve, reject) => { 275 | const unzipProc = child_process.spawn('tar', ['xvf', zipPath, '-C', destinationDir], { stdio: 'inherit' }); 276 | unzipProc.on('error', err => { 277 | reject(err); 278 | }); 279 | unzipProc.on('close', code => { 280 | console.log(`tar xvf exited with ${code}`); 281 | if (code !== 0) { 282 | reject(new Error(`tar xvf exited with ${code}`)); 283 | return; 284 | } 285 | 286 | resolve(); 287 | }); 288 | }); 289 | } 290 | 291 | /** 292 | * @param {string} zipPath 293 | * @param {string} destinationDir 294 | */ 295 | async function unzipRipgrep(zipPath, destinationDir) { 296 | if (isWindows) { 297 | await unzipWindows(zipPath, destinationDir); 298 | } else { 299 | await untar(zipPath, destinationDir); 300 | } 301 | 302 | const expectedName = path.join(destinationDir, 'rg'); 303 | if (await fsExists(expectedName)) { 304 | return expectedName; 305 | } 306 | 307 | if (await fsExists(expectedName + '.exe')) { 308 | return expectedName + '.exe'; 309 | } 310 | 311 | throw new Error(`Expecting rg or rg.exe unzipped into ${destinationDir}, didn't find one.`); 312 | } 313 | 314 | module.exports = async opts => { 315 | if (!opts.version) { 316 | return Promise.reject(new Error('Missing version')); 317 | } 318 | 319 | if (!opts.target) { 320 | return Promise.reject(new Error('Missing target')); 321 | } 322 | 323 | const extension = isWindows ? '.zip' : '.tar.gz'; 324 | const assetName = ['ripgrep', opts.version, opts.target].join('-') + extension; 325 | 326 | if (!await fsExists(tmpDir)) { 327 | await fsMkdir(tmpDir); 328 | } 329 | 330 | const assetDownloadPath = path.join(tmpDir, assetName); 331 | try { 332 | await getAssetFromGithubApi(opts, assetName, tmpDir) 333 | } catch (e) { 334 | console.log('Deleting invalid download cache'); 335 | try { 336 | await fsUnlink(assetDownloadPath); 337 | } catch (e) { } 338 | 339 | throw e; 340 | } 341 | 342 | console.log(`Unzipping to ${opts.destDir}`); 343 | try { 344 | const destinationPath = await unzipRipgrep(assetDownloadPath, opts.destDir); 345 | if (!isWindows) { 346 | await util.promisify(fs.chmod)(destinationPath, '755'); 347 | } 348 | } catch (e) { 349 | console.log('Deleting invalid download'); 350 | 351 | try { 352 | await fsUnlink(assetDownloadPath); 353 | } catch (e) { } 354 | 355 | throw e; 356 | } 357 | }; 358 | -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export declare const rgPath: string; -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | module.exports.rgPath = path.join(__dirname, `../bin/rg${process.platform === 'win32' ? '.exe' : ''}`); -------------------------------------------------------------------------------- /lib/postinstall.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 'use strict'; 3 | 4 | const os = require('os'); 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | const util = require('util'); 8 | const child_process = require('child_process'); 9 | 10 | const download = require('./download'); 11 | 12 | const fsExists = util.promisify(fs.exists); 13 | const mkdir = util.promisify(fs.mkdir); 14 | const exec = util.promisify(child_process.exec); 15 | 16 | const forceInstall = process.argv.includes('--force'); 17 | if (forceInstall) { 18 | console.log('--force, ignoring caches'); 19 | } 20 | 21 | const VERSION = 'v13.0.0-10'; 22 | const MULTI_ARCH_LINUX_VERSION = 'v13.0.0-4';// use this for arm-unknown-linux-gnueabihf and powerpc64le-unknown-linux-gnu until we can fix https://github.com/microsoft/ripgrep-prebuilt/issues/24 and https://github.com/microsoft/ripgrep-prebuilt/issues/32 respectively. 23 | const BIN_PATH = path.join(__dirname, '../bin'); 24 | 25 | process.on('unhandledRejection', (reason, promise) => { 26 | console.log('Unhandled rejection: ', promise, 'reason:', reason); 27 | }); 28 | 29 | async function getTarget() { 30 | const arch = process.env.npm_config_arch || os.arch(); 31 | 32 | switch (os.platform()) { 33 | case 'darwin': 34 | return arch === 'arm64' ? 'aarch64-apple-darwin' : 35 | 'x86_64-apple-darwin'; 36 | case 'win32': 37 | return arch === 'x64' ? 'x86_64-pc-windows-msvc' : 38 | arch === 'arm64' ? 'aarch64-pc-windows-msvc' : 39 | 'i686-pc-windows-msvc'; 40 | case 'linux': 41 | return arch === 'x64' ? 'x86_64-unknown-linux-musl' : 42 | arch === 'arm' ? 'arm-unknown-linux-gnueabihf' : 43 | arch === 'armv7l' ? 'arm-unknown-linux-gnueabihf' : 44 | arch === 'arm64' ? 'aarch64-unknown-linux-musl': 45 | arch === 'ppc64' ? 'powerpc64le-unknown-linux-gnu' : 46 | arch === 's390x' ? 's390x-unknown-linux-gnu' : 47 | 'i686-unknown-linux-musl' 48 | default: throw new Error('Unknown platform: ' + os.platform()); 49 | } 50 | } 51 | 52 | /** 53 | * Sleep for a specified number of milliseconds 54 | * @param {number} ms Time to sleep in milliseconds 55 | * @returns {Promise} 56 | */ 57 | function sleep(ms) { 58 | return new Promise(resolve => setTimeout(resolve, ms)); 59 | } 60 | 61 | /** 62 | * Retry a function with exponential backoff 63 | * @param {Function} fn Function to retry 64 | * @param {number} maxRetries Maximum number of retries 65 | * @returns {Promise} 66 | */ 67 | async function retry(fn, maxRetries = 5) { 68 | let retries = 0; 69 | let lastError; 70 | 71 | while (retries < maxRetries) { 72 | try { 73 | return await fn(); 74 | } catch (err) { 75 | lastError = err; 76 | retries++; 77 | 78 | if (retries >= maxRetries) { 79 | break; 80 | } 81 | 82 | const delay = Math.pow(2, retries) * 1000; 83 | console.error(err); 84 | console.log(`Download attempt ${retries} failed, retrying in ${delay/1000} seconds...`); 85 | await sleep(delay); 86 | } 87 | } 88 | 89 | throw lastError; 90 | } 91 | 92 | async function main() { 93 | const binExists = await fsExists(BIN_PATH); 94 | if (!forceInstall && binExists) { 95 | console.log('bin/ folder already exists, exiting'); 96 | process.exit(0); 97 | } 98 | 99 | if (!binExists) { 100 | await mkdir(BIN_PATH); 101 | } 102 | 103 | const target = await getTarget(); 104 | const opts = { 105 | version: target === "arm-unknown-linux-gnueabihf" || target === "powerpc64le-unknown-linux-gnu" || target === "s390x-unknown-linux-gnu" ? MULTI_ARCH_LINUX_VERSION: VERSION, 106 | token: process.env['GITHUB_TOKEN'], 107 | target: await getTarget(), 108 | destDir: BIN_PATH, 109 | force: forceInstall 110 | }; 111 | 112 | try { 113 | await retry(() => download(opts)); 114 | } catch (err) { 115 | console.error(`Downloading ripgrep failed after multiple retries: ${err.stack}`); 116 | process.exit(1); 117 | } 118 | } 119 | 120 | main(); 121 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vscode/ripgrep", 3 | "version": "1.15.10", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@vscode/ripgrep", 9 | "version": "1.15.10", 10 | "hasInstallScript": true, 11 | "license": "MIT", 12 | "dependencies": { 13 | "https-proxy-agent": "^7.0.2", 14 | "proxy-from-env": "^1.1.0", 15 | "yauzl": "^2.9.2" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^20.8.4" 19 | } 20 | }, 21 | "node_modules/@types/node": { 22 | "version": "20.8.4", 23 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.4.tgz", 24 | "integrity": "sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A==", 25 | "dev": true, 26 | "dependencies": { 27 | "undici-types": "~5.25.1" 28 | } 29 | }, 30 | "node_modules/agent-base": { 31 | "version": "7.1.0", 32 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", 33 | "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", 34 | "dependencies": { 35 | "debug": "^4.3.4" 36 | }, 37 | "engines": { 38 | "node": ">= 14" 39 | } 40 | }, 41 | "node_modules/buffer-crc32": { 42 | "version": "0.2.13", 43 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 44 | "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", 45 | "engines": { 46 | "node": "*" 47 | } 48 | }, 49 | "node_modules/debug": { 50 | "version": "4.3.4", 51 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 52 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 53 | "dependencies": { 54 | "ms": "2.1.2" 55 | }, 56 | "engines": { 57 | "node": ">=6.0" 58 | }, 59 | "peerDependenciesMeta": { 60 | "supports-color": { 61 | "optional": true 62 | } 63 | } 64 | }, 65 | "node_modules/fd-slicer": { 66 | "version": "1.1.0", 67 | "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", 68 | "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", 69 | "dependencies": { 70 | "pend": "~1.2.0" 71 | } 72 | }, 73 | "node_modules/https-proxy-agent": { 74 | "version": "7.0.2", 75 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", 76 | "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", 77 | "dependencies": { 78 | "agent-base": "^7.0.2", 79 | "debug": "4" 80 | }, 81 | "engines": { 82 | "node": ">= 14" 83 | } 84 | }, 85 | "node_modules/ms": { 86 | "version": "2.1.2", 87 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 88 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 89 | }, 90 | "node_modules/pend": { 91 | "version": "1.2.0", 92 | "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", 93 | "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" 94 | }, 95 | "node_modules/proxy-from-env": { 96 | "version": "1.1.0", 97 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 98 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 99 | }, 100 | "node_modules/undici-types": { 101 | "version": "5.25.3", 102 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", 103 | "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", 104 | "dev": true 105 | }, 106 | "node_modules/yauzl": { 107 | "version": "2.10.0", 108 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", 109 | "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", 110 | "dependencies": { 111 | "buffer-crc32": "~0.2.3", 112 | "fd-slicer": "~1.1.0" 113 | } 114 | } 115 | }, 116 | "dependencies": { 117 | "@types/node": { 118 | "version": "20.8.4", 119 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.4.tgz", 120 | "integrity": "sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A==", 121 | "dev": true, 122 | "requires": { 123 | "undici-types": "~5.25.1" 124 | } 125 | }, 126 | "agent-base": { 127 | "version": "7.1.0", 128 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", 129 | "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", 130 | "requires": { 131 | "debug": "^4.3.4" 132 | } 133 | }, 134 | "buffer-crc32": { 135 | "version": "0.2.13", 136 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 137 | "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" 138 | }, 139 | "debug": { 140 | "version": "4.3.4", 141 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 142 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 143 | "requires": { 144 | "ms": "2.1.2" 145 | } 146 | }, 147 | "fd-slicer": { 148 | "version": "1.1.0", 149 | "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", 150 | "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", 151 | "requires": { 152 | "pend": "~1.2.0" 153 | } 154 | }, 155 | "https-proxy-agent": { 156 | "version": "7.0.2", 157 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", 158 | "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", 159 | "requires": { 160 | "agent-base": "^7.0.2", 161 | "debug": "4" 162 | } 163 | }, 164 | "ms": { 165 | "version": "2.1.2", 166 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 167 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 168 | }, 169 | "pend": { 170 | "version": "1.2.0", 171 | "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", 172 | "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" 173 | }, 174 | "proxy-from-env": { 175 | "version": "1.1.0", 176 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 177 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 178 | }, 179 | "undici-types": { 180 | "version": "5.25.3", 181 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", 182 | "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", 183 | "dev": true 184 | }, 185 | "yauzl": { 186 | "version": "2.10.0", 187 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", 188 | "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", 189 | "requires": { 190 | "buffer-crc32": "~0.2.3", 191 | "fd-slicer": "~1.1.0" 192 | } 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vscode/ripgrep", 3 | "version": "1.15.11", 4 | "description": "A module for using ripgrep in a Node project", 5 | "main": "lib/index.js", 6 | "typings": "lib/index.d.ts", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/microsoft/vscode-ripgrep" 10 | }, 11 | "scripts": { 12 | "postinstall": "node ./lib/postinstall.js" 13 | }, 14 | "author": "Rob Lourens", 15 | "license": "MIT", 16 | "dependencies": { 17 | "https-proxy-agent": "^7.0.2", 18 | "yauzl": "^2.9.2", 19 | "proxy-from-env": "^1.1.0" 20 | }, 21 | "devDependencies": { 22 | "@types/node": "^20.8.4" 23 | } 24 | } 25 | --------------------------------------------------------------------------------