From 18d3c005826eedecd38d267b201269bafe6ac86c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Mon, 5 Sep 2022 18:11:12 +0200 Subject: [PATCH] fix(cli): do not throw error when extracting examples in Node 18+ (#40182) `create-next-app` currently cannot extract examples/git repos in Node 18+, because of an issue with `node-tar` (https://github.com/npm/node-tar/issues/321). The files are extracted, but an error is thrown that the stream has been prematurely closed. To prevent `create-next-app` from not being able to finish, ~for now, we can swallow this error, and hopefully `node-tar` will be patched soon.~ we can save the tar in the `tmp` folder and extract it from there as suggested: https://github.com/vercel/next.js/pull/40182#pullrequestreview-1095216714 I cannot reproduce this on earlier Node.js versions. More context: https://github.com/vercel/next.js/issues/39321#issuecomment-1235642058 Fixes #39321 ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples) --- packages/create-next-app/helpers/examples.ts | 50 +++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/packages/create-next-app/helpers/examples.ts b/packages/create-next-app/helpers/examples.ts index 44af47b2acff..64a7635cf1d1 100644 --- a/packages/create-next-app/helpers/examples.ts +++ b/packages/create-next-app/helpers/examples.ts @@ -3,6 +3,9 @@ import got from 'got' import tar from 'tar' import { Stream } from 'stream' import { promisify } from 'util' +import { join } from 'path' +import { tmpdir } from 'os' +import { createWriteStream } from 'fs' const pipeline = promisify(Stream.pipeline) @@ -79,31 +82,44 @@ export function existsInRepo(nameOrUrl: string): Promise { } } -export function downloadAndExtractRepo( +async function downloadTar(url: string) { + const tempFile = join(tmpdir(), `next.js-cra-example.temp-${Date.now()}`) + await pipeline(got.stream(url), createWriteStream(tempFile)) + return tempFile +} + +export async function downloadAndExtractRepo( root: string, { username, name, branch, filePath }: RepoInfo -): Promise { - return pipeline( - got.stream( - `https://codeload.github.com/${username}/${name}/tar.gz/${branch}` - ), - tar.extract( - { cwd: root, strip: filePath ? filePath.split('/').length + 1 : 1 }, - [`${name}-${branch.replace(/\//g, '-')}${filePath ? `/${filePath}` : ''}`] - ) +) { + const tempFile = await downloadTar( + `https://codeload.github.com/${username}/${name}/tar.gz/${branch}` ) + + await tar.x({ + file: tempFile, + cwd: root, + strip: filePath ? filePath.split('/').length + 1 : 1, + filter: (p) => + p.startsWith( + `${name}-${branch.replace(/\//g, '-')}${filePath ? `/${filePath}` : ''}` + ), + }) } -export function downloadAndExtractExample( - root: string, - name: string -): Promise { +export async function downloadAndExtractExample(root: string, name: string) { if (name === '__internal-testing-retry') { throw new Error('This is an internal example for testing the CLI.') } - return pipeline( - got.stream('https://codeload.github.com/vercel/next.js/tar.gz/canary'), - tar.extract({ cwd: root, strip: 3 }, [`next.js-canary/examples/${name}`]) + const tempFile = await downloadTar( + 'https://codeload.github.com/vercel/next.js/tar.gz/canary' ) + + await tar.x({ + file: tempFile, + cwd: root, + strip: 3, + filter: (p) => p.includes(`next.js-canary/examples/${name}`), + }) }