-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'torifat-feature/update'
- Loading branch information
Showing
6 changed files
with
215 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/* @flow */ | ||
|
||
import type {Reporter} from '../../reporters/index.js'; | ||
import type Config from '../../config.js'; | ||
import inquirer from 'inquirer'; | ||
import repeat from 'repeating'; | ||
import {MessageError} from '../../errors.js'; | ||
import PackageRequest from '../../package-request.js'; | ||
import {Add} from './add.js'; | ||
import {Install} from './install.js'; | ||
import Lockfile from '../../lockfile/wrapper.js'; | ||
|
||
export const requireLockfile = true; | ||
|
||
export function setFlags(commander: Object) { | ||
// TODO: support some flags that install command has | ||
commander.usage('update'); | ||
} | ||
|
||
type Dependency = { | ||
name: string, | ||
current: string, | ||
wanted: string, | ||
latest: string, | ||
hint: ?string | ||
}; | ||
|
||
type InquirerResponses<K, T> = {[key: K]: Array<T>}; | ||
|
||
// Prompt user with Inquirer | ||
async function prompt(choices): Promise<Array<Dependency>> { | ||
const answers: InquirerResponses<'packages', Dependency> = await inquirer.prompt([{ | ||
name: 'packages', | ||
type: 'checkbox', | ||
message: 'Choose which packages to update.', | ||
choices, | ||
// Couldn't make it work, I guess I'm missing something here | ||
// $FlowFixMe: https://github.com/facebook/flow/blob/f41e66e27b227235750792c34f5a80f38bde6320/lib/node.js#L1197 | ||
pageSize: process.stdout.rows - 2, | ||
validate: (answer) => !!answer.length || 'You must choose at least one package.', | ||
}]); | ||
return answers.packages; | ||
} | ||
|
||
export async function run( | ||
config: Config, | ||
reporter: Reporter, | ||
flags: Object, | ||
args: Array<string>, | ||
): Promise<void> { | ||
const lockfile = await Lockfile.fromDirectory(config.cwd); | ||
const install = new Install(flags, config, reporter, lockfile); | ||
const [deps] = await install.fetchRequestFromCwd(); | ||
|
||
const allDeps = (await Promise.all(deps.map(async ({pattern, hint}): Promise<Dependency> => { | ||
const locked = lockfile.getLocked(pattern); | ||
if (!locked) { | ||
throw new MessageError(reporter.lang('lockfileOutdated')); | ||
} | ||
|
||
const {name, version: current} = locked; | ||
let latest = ''; | ||
let wanted = ''; | ||
|
||
const normalized = PackageRequest.normalizePattern(pattern); | ||
|
||
if (PackageRequest.getExoticResolver(pattern) || | ||
PackageRequest.getExoticResolver(normalized.range)) { | ||
latest = wanted = 'exotic'; | ||
} else { | ||
({latest, wanted} = await config.registries[locked.registry].checkOutdated(config, name, normalized.range)); | ||
} | ||
|
||
return ({name, current, wanted, latest, hint}); | ||
}))); | ||
|
||
const isDepOld = ({latest, current}) => latest !== current; | ||
const isDepExpected = ({current, wanted}) => current === wanted; | ||
|
||
const outdatedDeps = allDeps | ||
.filter(isDepOld) | ||
.sort((depA, depB) => { | ||
if (isDepExpected(depA) && !isDepExpected(depB)) { | ||
return 1; | ||
} | ||
return -1; | ||
}); | ||
|
||
const getNameFromHint = (hint) => hint ? `${hint}Dependencies` : 'dependencies'; | ||
|
||
const maxLengthArr = {name: 0, current: 0, latest: 0}; | ||
outdatedDeps.forEach((dep) => | ||
['name', 'current', 'latest'].forEach((key) => { | ||
maxLengthArr[key] = Math.max(maxLengthArr[key], dep[key].length); | ||
}), | ||
); | ||
|
||
// Depends on maxLengthArr | ||
const addPadding = (dep) => (key) => | ||
`${dep[key]}${repeat(' ', maxLengthArr[key] - dep[key].length)}`; | ||
|
||
const colorizeName = ({current, wanted}) => | ||
(current === wanted) ? reporter.format.yellow : reporter.format.red; | ||
|
||
const makeRow = (dep) => { | ||
const padding = addPadding(dep); | ||
const name = colorizeName(dep)(padding('name')); | ||
const current = reporter.format.blue(padding('current')); | ||
const latest = reporter.format.green(padding('latest')); | ||
return `${name} ${current} ❯ ${latest}`; | ||
}; | ||
|
||
const groupedDeps = outdatedDeps.reduce((acc, dep) => { | ||
const {hint, name, latest} = dep; | ||
const key = getNameFromHint(hint); | ||
const xs = acc[key] || []; | ||
acc[key] = xs.concat({ | ||
name: makeRow(dep), | ||
value: dep, | ||
short: `${name}@${latest}`, | ||
}); | ||
return acc; | ||
}, {}); | ||
|
||
const flatten = (xs) => xs.reduce( | ||
(ys, y) => ys.concat(Array.isArray(y) ? flatten(y) : y), [], | ||
); | ||
|
||
const choices = Object.keys(groupedDeps).map((key) => [ | ||
new inquirer.Separator(reporter.format.bold.underline.green(key)), | ||
groupedDeps[key], | ||
new inquirer.Separator(' '), | ||
]); | ||
|
||
const answers = await prompt(flatten(choices)); | ||
|
||
const getName = ({name}) => name; | ||
const isHint = (x) => ({hint}) => hint === x; | ||
|
||
await [null, 'dev', 'optional', 'peer'].reduce(async (promise, hint) => { | ||
// Wait for previous promise to resolve | ||
await promise; | ||
// Reset dependency flags | ||
flags.dev = hint === 'dev'; | ||
flags.peer = hint === 'peer'; | ||
flags.optional = hint === 'optional'; | ||
|
||
const deps = answers.filter(isHint(hint)).map(getName); | ||
if (deps.length) { | ||
reporter.info(reporter.lang('updateInstalling', getNameFromHint(hint))); | ||
const add = new Add(deps, flags, config, reporter, lockfile); | ||
return await add.init(); | ||
} | ||
return Promise.resolve(); | ||
}, Promise.resolve()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1441,7 +1441,7 @@ [email protected]: | |
version "0.0.1" | ||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" | ||
|
||
concat-stream@^1.4.6: | ||
concat-stream@^1.4.6, concat-stream@^1.4.7: | ||
version "1.5.2" | ||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" | ||
dependencies: | ||
|
@@ -2006,6 +2006,14 @@ extend@^3.0.0, extend@~3.0.0: | |
version "3.0.0" | ||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" | ||
|
||
external-editor@^1.1.0: | ||
version "1.1.0" | ||
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.0.tgz#c7fe15954b09af852b89aaec82a2707a0dc5597a" | ||
dependencies: | ||
extend "^3.0.0" | ||
spawn-sync "^1.0.15" | ||
temp "^0.8.3" | ||
|
||
extglob@^0.3.1: | ||
version "0.3.2" | ||
resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" | ||
|
@@ -2612,6 +2620,25 @@ ini@^1.3.4, ini@~1.3.0: | |
version "1.3.4" | ||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" | ||
|
||
inquirer: | ||
version "1.2.2" | ||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.2.tgz#f725c1316f0020e7f3d538c8c5ad0c2732c1c451" | ||
dependencies: | ||
ansi-escapes "^1.1.0" | ||
chalk "^1.0.0" | ||
cli-cursor "^1.0.1" | ||
cli-width "^2.0.0" | ||
external-editor "^1.1.0" | ||
figures "^1.3.5" | ||
lodash "^4.3.0" | ||
mute-stream "0.0.6" | ||
pinkie-promise "^2.0.0" | ||
run-async "^2.2.0" | ||
rx "^4.1.0" | ||
string-width "^1.0.1" | ||
strip-ansi "^3.0.0" | ||
through "^2.3.6" | ||
|
||
inquirer@^0.12.0: | ||
version "0.12.0" | ||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" | ||
|
@@ -2766,6 +2793,10 @@ is-primitive@^2.0.0: | |
version "2.0.0" | ||
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" | ||
|
||
is-promise@^2.1.0: | ||
version "2.1.0" | ||
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" | ||
|
||
is-property@^1.0.0: | ||
version "1.0.2" | ||
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" | ||
|
@@ -3668,7 +3699,7 @@ multipipe@^0.1.2: | |
dependencies: | ||
duplexer2 "0.0.2" | ||
|
||
mute-stream@~0.0.4: | ||
mute-stream@~0.0.4, [email protected]: | ||
version "0.0.6" | ||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" | ||
|
||
|
@@ -3903,6 +3934,10 @@ os-locale@^1.4.0: | |
dependencies: | ||
lcid "^1.0.0" | ||
|
||
os-shim@^0.1.2: | ||
version "0.1.3" | ||
resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" | ||
|
||
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: | ||
version "1.0.2" | ||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" | ||
|
@@ -4431,10 +4466,21 @@ run-async@^0.1.0: | |
dependencies: | ||
once "^1.3.0" | ||
|
||
run-async@^2.2.0: | ||
version "2.2.0" | ||
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.2.0.tgz#8783abd83c7bb86f41ee0602fc82404b3bd6e8b9" | ||
dependencies: | ||
is-promise "^2.1.0" | ||
pinkie-promise "^2.0.0" | ||
|
||
rx-lite@^3.1.2: | ||
version "3.1.2" | ||
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" | ||
|
||
rx@^4.1.0: | ||
version "4.1.0" | ||
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" | ||
|
||
sane@~1.4.1: | ||
version "1.4.1" | ||
resolved "https://registry.yarnpkg.com/sane/-/sane-1.4.1.tgz#88f763d74040f5f0c256b6163db399bf110ac715" | ||
|
@@ -4560,6 +4606,13 @@ sparkles@^1.0.0: | |
version "1.0.0" | ||
resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" | ||
|
||
spawn-sync@^1.0.15: | ||
version "1.0.15" | ||
resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" | ||
dependencies: | ||
concat-stream "^1.4.7" | ||
os-shim "^0.1.2" | ||
|
||
spdx-correct@~1.0.0: | ||
version "1.0.2" | ||
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" | ||
|