Skip to content
This repository has been archived by the owner on Sep 1, 2022. It is now read-only.

Commit

Permalink
fix(install): update targz lib to fix crash extracting versions (#951)
Browse files Browse the repository at this point in the history
* chore: update dev dependencies

* chore: update webpack to v5
  • Loading branch information
Noah authored Mar 13, 2021
1 parent 467d146 commit 79e8a6e
Show file tree
Hide file tree
Showing 7 changed files with 932 additions and 1,962 deletions.
18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@
"regenerator-runtime": "^0.13.7",
"request": "^2.88.2",
"semver": "^7.3.4",
"targz": "^1.0.1"
"tar-fs": "^2.1.1"
},
"devDependencies": {
"@babel/core": "^7.13.1",
"@babel/preset-env": "^7.12.11",
"@babel/core": "^7.13.10",
"@babel/preset-env": "^7.13.10",
"@tophat/eslint-config": "^0.7.0",
"all-contributors-cli": "^6.20.0",
"babel-eslint": "^10.1.0",
Expand All @@ -70,15 +70,17 @@
"jest-mock-props": "^1.9.0",
"lint-staged": "^10.5.4",
"lodash-webpack-plugin": "^0.11.6",
"madge": "^4.0.0",
"marked": "^2.0.0",
"madge": "^4.0.2",
"marked": "^2.0.1",
"memfs": "^3.2.0",
"prettier": "^2.2.1",
"raw-loader": "^4.0.2",
"typescript": "^4.1.3",
"webpack": "^4.44.2",
"webpack-cli": "^4.3.1",
"terser-webpack-plugin": "^5.1.1",
"typescript": "^4.2.3",
"webpack": "^5.25.0",
"webpack-cli": "^4.5.0",
"webpack-compiler-plugin": "^1.1.5",
"webpack-sources": "^2.2.0",
"yarn-deduplicate": "^3.1.0",
"zip-webpack-plugin": "^4.0.1"
},
Expand Down
42 changes: 15 additions & 27 deletions src/commands/install.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import fs from 'fs'
import path from 'path'

import targz from 'targz'

import { YARN_RELEASE_TAGS_URL } from 'util/constants'
import { LATEST, STABLE } from 'util/alias'
import { downloadFile, getDownloadPath } from 'util/download'
Expand All @@ -15,6 +13,7 @@ import {
} from 'util/utils'
import { getSplitVersionAndArgs, resolveVersion } from 'util/version'
import { VerificationError, verifySignature } from 'util/verification'
import { extract } from 'util/extract'

const isVersionInstalled = (version, rootPath) => {
const versionPath = getExtractionPath(version, rootPath)
Expand All @@ -39,30 +38,20 @@ const extractYarn = async (version, rootPath) => {
const tmpPath = `${destPath}.tar.gz.tmp`
const srcPath = getDownloadPath(version, rootPath)

return new Promise((resolve, reject) => {
targz.decompress(
{
src: srcPath,
dest: tmpPath,
},
err => {
if (err) {
return reject(err)
}
log(`Finished extracting yarn version ${version}`)
const [pkgDir] = fs.readdirSync(tmpPath)
if (!pkgDir) {
const errorMessage = 'Unable to locate extracted package'
return reject(new Error(errorMessage))
}
const pkgPath = path.resolve(tmpPath, pkgDir)
fs.renameSync(pkgPath, destPath)
fs.unlinkSync(srcPath)
fs.rmdirSync(tmpPath)
return resolve(destPath)
},
)
})
await extract({ src: srcPath, dest: tmpPath })

log(`Finished extracting yarn version ${version}`)
const [pkgDir] = fs.readdirSync(tmpPath)
if (!pkgDir) {
const errorMessage = 'Unable to locate extracted package'
throw new Error(errorMessage)
}

const pkgPath = path.resolve(tmpPath, pkgDir)
fs.renameSync(pkgPath, destPath)
fs.unlinkSync(srcPath)
fs.rmdirSync(tmpPath)
return destPath
}

const logVerifyNotice = extraMessage => {
Expand Down Expand Up @@ -120,7 +109,6 @@ Please retry with the next available version`)
throw e
}
}

log('Extracting...')
await extractYarn(version, rootPath)
log('Installation successful')
Expand Down
23 changes: 23 additions & 0 deletions src/util/extract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import zlib from 'zlib'
import fs from 'fs'

import tar from 'tar-fs'

export const extract = async ({ src, dest }) =>
await new Promise((resolve, reject) => {
fs.createReadStream(src)
.on('error', reject)
.pipe(
zlib
.createGunzip({})
.on('error', () =>
reject(new Error('Unable to decompress.')),
),
)
.pipe(
tar
.extract(dest, {})
.on('error', () => reject(new Error('Unable to extract.')))
.on('finish', () => resolve(dest)),
)
})
14 changes: 7 additions & 7 deletions src/yvm.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ if (!process.argv.includes('exec')) {
argParser.version(yvmInstalledVersion() || messageNoYvm)
argParser
.command('*', '', { noHelp: true, isDefault: true })
.action(invalidCommand => {
.action(async invalidCommand => {
if (!process.argv.includes('help')) {
log(`Invalid command: ${invalidCommand}`)
}
Expand Down Expand Up @@ -59,7 +59,7 @@ argParser
argParser
.command('use [version]')
.description(messageOptionalVersion`Activate specified Yarn version`)
.action(() => log(messageSourceYvm))
.action(async () => log(messageSourceYvm))

argParser
.command('exec [version] [args...]')
Expand Down Expand Up @@ -105,7 +105,7 @@ argParser
argParser
.command('deactivate')
.description('Undo effects of `yvm` on current shell')
.action(() => log(messageSourceYvm))
.action(async () => log(messageSourceYvm))

const aliasAction = async () => {
const [, , , nameOrPattern, maybeVersion] = process.argv
Expand Down Expand Up @@ -135,7 +135,7 @@ argParser
argParser
.command('unload')
.description('Unload `yvm` from shell')
.action(() => log(messageSourceYvm))
.action(async () => log(messageSourceYvm))

argParser
.command('which [version]')
Expand All @@ -149,7 +149,7 @@ argParser
argParser
.command('update-self')
.description('Updates yvm to the latest version')
.action(() => log(messageSourceYvm))
.action(async () => log(messageSourceYvm))

argParser
.command('configure-shell', '', { noHelp: true })
Expand Down Expand Up @@ -200,7 +200,7 @@ argParser
argParser
.command('version')
.description(signPosting`--version`)
.action(() => {
.action(async () => {
const version = yvmInstalledVersion()
log.capturable(version || messageNoYvm)
process.exit(version ? 0 : 1)
Expand All @@ -227,4 +227,4 @@ argParser
process.exit(await getDefaultVersion())
})

argParser.parse(process.argv)
argParser.parseAsync(process.argv, { from: 'node' })
20 changes: 11 additions & 9 deletions test/commands/install.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import targz from 'targz'
import fs from 'fs-extra'

import * as extractUtils from 'util/extract'
import { resolveStable } from 'util/alias'
import { YARN_RELEASE_TAGS_URL } from 'util/constants'
import * as download from 'util/download'
Expand Down Expand Up @@ -200,26 +200,28 @@ describe('yvm install', () => {
it('Logs error on failed targz decompress', async () => {
const version = '1.7.0'
const mockError = new Error('mock error')
jest.spyOn(targz, 'decompress').mockImplementationOnce((_, callback) =>
callback(mockError),
)
jest.spyOn(extractUtils, 'extract').mockImplementationOnce(() => {
throw mockError
})
expect(await install({ version })).toBe(1)
expect(log.default).toHaveBeenLastCalledWith(mockError.message)
expect(log.info).toHaveBeenLastCalledWith(mockError.stack)
targz.decompress.mockRestore()
extractUtils.extract.mockRestore()
})

it('Handles error if extracted archive does not contain yarn dist', async () => {
const version = '1.7.0'
const expectedErrorMessage = 'Unable to locate extracted package'
jest.spyOn(targz, 'decompress').mockImplementationOnce(
({ dest }, callback) => {

const origExtract = extractUtils.extract
jest.spyOn(extractUtils, 'extract').mockImplementationOnce(
async (...params) => {
const dest = await origExtract(...params)
fs.emptyDirSync(dest)
callback()
},
)
expect(await install({ version })).toBe(1)
expect(log.default).toHaveBeenLastCalledWith(expectedErrorMessage)
targz.decompress.mockRestore()
extractUtils.extract.mockRestore()
})
})
14 changes: 14 additions & 0 deletions webpack/webpack.config.prod.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const ZipFilesPlugin = require('zip-webpack-plugin')
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')

const { config, constants } = require('./webpack.config.base')

Expand All @@ -12,4 +13,17 @@ module.exports = Object.assign(config, {
path: constants.paths.artifacts,
}),
],
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
format: {
comments: /^\*\*?!|@preserve|@license|@cc_on/i,
},
},
extractComments: true,
}),
],
},
})
Loading

0 comments on commit 79e8a6e

Please sign in to comment.