Skip to content

Commit fcf6cfa

Browse files
author
Sebastian McKenzie
committed
Merge branch 'torifat-feature/update'
2 parents 0c17423 + b6f3aec commit fcf6cfa

File tree

6 files changed

+215
-4
lines changed

6 files changed

+215
-4
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"detect-indent": "^4.0.0",
1818
"diff": "^2.2.1",
1919
"ini": "^1.3.4",
20+
"inquirer": "^1.2.2",
2021
"invariant": "^2.2.0",
2122
"is-builtin-module": "^1.0.0",
2223
"is-ci": "^1.0.9",

src/cli/aliases.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export default ({
2828
rm: 'remove',
2929
show: 'info',
3030
uninstall: 'remove',
31-
update: 'upgrade',
31+
udpate: 'upgrade',
3232
verison: 'version',
3333
view: 'info',
3434
}: { [key: string]: ?string });

src/cli/commands/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import * as upgrade from './upgrade.js'; export {upgrade};
3131
import * as version from './version.js'; export {version};
3232
import * as versions from './versions.js'; export {versions};
3333
import * as why from './why.js'; export {why};
34+
import * as upgradeInteractive from './upgrade-interactive.js'; export {upgradeInteractive};
3435

3536
import buildUseless from './_useless.js';
3637

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/* @flow */
2+
3+
import type {Reporter} from '../../reporters/index.js';
4+
import type Config from '../../config.js';
5+
import inquirer from 'inquirer';
6+
import repeat from 'repeating';
7+
import {MessageError} from '../../errors.js';
8+
import PackageRequest from '../../package-request.js';
9+
import {Add} from './add.js';
10+
import {Install} from './install.js';
11+
import Lockfile from '../../lockfile/wrapper.js';
12+
13+
export const requireLockfile = true;
14+
15+
export function setFlags(commander: Object) {
16+
// TODO: support some flags that install command has
17+
commander.usage('update');
18+
}
19+
20+
type Dependency = {
21+
name: string,
22+
current: string,
23+
wanted: string,
24+
latest: string,
25+
hint: ?string
26+
};
27+
28+
type InquirerResponses<K, T> = {[key: K]: Array<T>};
29+
30+
// Prompt user with Inquirer
31+
async function prompt(choices): Promise<Array<Dependency>> {
32+
const answers: InquirerResponses<'packages', Dependency> = await inquirer.prompt([{
33+
name: 'packages',
34+
type: 'checkbox',
35+
message: 'Choose which packages to update.',
36+
choices,
37+
// Couldn't make it work, I guess I'm missing something here
38+
// $FlowFixMe: https://github.com/facebook/flow/blob/f41e66e27b227235750792c34f5a80f38bde6320/lib/node.js#L1197
39+
pageSize: process.stdout.rows - 2,
40+
validate: (answer) => !!answer.length || 'You must choose at least one package.',
41+
}]);
42+
return answers.packages;
43+
}
44+
45+
export async function run(
46+
config: Config,
47+
reporter: Reporter,
48+
flags: Object,
49+
args: Array<string>,
50+
): Promise<void> {
51+
const lockfile = await Lockfile.fromDirectory(config.cwd);
52+
const install = new Install(flags, config, reporter, lockfile);
53+
const [deps] = await install.fetchRequestFromCwd();
54+
55+
const allDeps = (await Promise.all(deps.map(async ({pattern, hint}): Promise<Dependency> => {
56+
const locked = lockfile.getLocked(pattern);
57+
if (!locked) {
58+
throw new MessageError(reporter.lang('lockfileOutdated'));
59+
}
60+
61+
const {name, version: current} = locked;
62+
let latest = '';
63+
let wanted = '';
64+
65+
const normalized = PackageRequest.normalizePattern(pattern);
66+
67+
if (PackageRequest.getExoticResolver(pattern) ||
68+
PackageRequest.getExoticResolver(normalized.range)) {
69+
latest = wanted = 'exotic';
70+
} else {
71+
({latest, wanted} = await config.registries[locked.registry].checkOutdated(config, name, normalized.range));
72+
}
73+
74+
return ({name, current, wanted, latest, hint});
75+
})));
76+
77+
const isDepOld = ({latest, current}) => latest !== current;
78+
const isDepExpected = ({current, wanted}) => current === wanted;
79+
80+
const outdatedDeps = allDeps
81+
.filter(isDepOld)
82+
.sort((depA, depB) => {
83+
if (isDepExpected(depA) && !isDepExpected(depB)) {
84+
return 1;
85+
}
86+
return -1;
87+
});
88+
89+
const getNameFromHint = (hint) => hint ? `${hint}Dependencies` : 'dependencies';
90+
91+
const maxLengthArr = {name: 0, current: 0, latest: 0};
92+
outdatedDeps.forEach((dep) =>
93+
['name', 'current', 'latest'].forEach((key) => {
94+
maxLengthArr[key] = Math.max(maxLengthArr[key], dep[key].length);
95+
}),
96+
);
97+
98+
// Depends on maxLengthArr
99+
const addPadding = (dep) => (key) =>
100+
`${dep[key]}${repeat(' ', maxLengthArr[key] - dep[key].length)}`;
101+
102+
const colorizeName = ({current, wanted}) =>
103+
(current === wanted) ? reporter.format.yellow : reporter.format.red;
104+
105+
const makeRow = (dep) => {
106+
const padding = addPadding(dep);
107+
const name = colorizeName(dep)(padding('name'));
108+
const current = reporter.format.blue(padding('current'));
109+
const latest = reporter.format.green(padding('latest'));
110+
return `${name} ${current}${latest}`;
111+
};
112+
113+
const groupedDeps = outdatedDeps.reduce((acc, dep) => {
114+
const {hint, name, latest} = dep;
115+
const key = getNameFromHint(hint);
116+
const xs = acc[key] || [];
117+
acc[key] = xs.concat({
118+
name: makeRow(dep),
119+
value: dep,
120+
short: `${name}@${latest}`,
121+
});
122+
return acc;
123+
}, {});
124+
125+
const flatten = (xs) => xs.reduce(
126+
(ys, y) => ys.concat(Array.isArray(y) ? flatten(y) : y), [],
127+
);
128+
129+
const choices = Object.keys(groupedDeps).map((key) => [
130+
new inquirer.Separator(reporter.format.bold.underline.green(key)),
131+
groupedDeps[key],
132+
new inquirer.Separator(' '),
133+
]);
134+
135+
const answers = await prompt(flatten(choices));
136+
137+
const getName = ({name}) => name;
138+
const isHint = (x) => ({hint}) => hint === x;
139+
140+
await [null, 'dev', 'optional', 'peer'].reduce(async (promise, hint) => {
141+
// Wait for previous promise to resolve
142+
await promise;
143+
// Reset dependency flags
144+
flags.dev = hint === 'dev';
145+
flags.peer = hint === 'peer';
146+
flags.optional = hint === 'optional';
147+
148+
const deps = answers.filter(isHint(hint)).map(getName);
149+
if (deps.length) {
150+
reporter.info(reporter.lang('updateInstalling', getNameFromHint(hint)));
151+
const add = new Add(deps, flags, config, reporter, lockfile);
152+
return await add.init();
153+
}
154+
return Promise.resolve();
155+
}, Promise.resolve());
156+
}

src/reporters/lang/en.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,11 @@ const messages = {
210210
cantRequestOffline: 'Can\'t make a request in offline mode',
211211
requestManagerNotSetupHAR: 'RequestManager was not setup to capture HAR files',
212212
requestError: 'Request $0 returned a $1',
213-
214213
tarballNotInNetworkOrCache: '$0: Tarball is not in network and can not be located in cache ($1)',
215214
fetchBadHash: 'Bad hash. Expected $0 but got $1 ',
216215
fetchErrorCorrupt: '$0. Mirror tarball appears to be corrupt. You can resolve this by running:\n\n $ rm -rf $1\n $ yarn install',
217216
errorDecompressingTarball: '$0. Error decompressing $1, it appears to be corrupt.',
217+
updateInstalling: 'Installing $0...',
218218
};
219219

220220
export type LanguageKeys = $Keys<typeof messages>;

yarn.lock

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,7 @@ [email protected]:
14411441
version "0.0.1"
14421442
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
14431443

1444-
concat-stream@^1.4.6:
1444+
concat-stream@^1.4.6, concat-stream@^1.4.7:
14451445
version "1.5.2"
14461446
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266"
14471447
dependencies:
@@ -2006,6 +2006,14 @@ extend@^3.0.0, extend@~3.0.0:
20062006
version "3.0.0"
20072007
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
20082008

2009+
external-editor@^1.1.0:
2010+
version "1.1.0"
2011+
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.0.tgz#c7fe15954b09af852b89aaec82a2707a0dc5597a"
2012+
dependencies:
2013+
extend "^3.0.0"
2014+
spawn-sync "^1.0.15"
2015+
temp "^0.8.3"
2016+
20092017
extglob@^0.3.1:
20102018
version "0.3.2"
20112019
resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
@@ -2612,6 +2620,25 @@ ini@^1.3.4, ini@~1.3.0:
26122620
version "1.3.4"
26132621
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
26142622

2623+
inquirer:
2624+
version "1.2.2"
2625+
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.2.tgz#f725c1316f0020e7f3d538c8c5ad0c2732c1c451"
2626+
dependencies:
2627+
ansi-escapes "^1.1.0"
2628+
chalk "^1.0.0"
2629+
cli-cursor "^1.0.1"
2630+
cli-width "^2.0.0"
2631+
external-editor "^1.1.0"
2632+
figures "^1.3.5"
2633+
lodash "^4.3.0"
2634+
mute-stream "0.0.6"
2635+
pinkie-promise "^2.0.0"
2636+
run-async "^2.2.0"
2637+
rx "^4.1.0"
2638+
string-width "^1.0.1"
2639+
strip-ansi "^3.0.0"
2640+
through "^2.3.6"
2641+
26152642
inquirer@^0.12.0:
26162643
version "0.12.0"
26172644
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
@@ -2766,6 +2793,10 @@ is-primitive@^2.0.0:
27662793
version "2.0.0"
27672794
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
27682795

2796+
is-promise@^2.1.0:
2797+
version "2.1.0"
2798+
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
2799+
27692800
is-property@^1.0.0:
27702801
version "1.0.2"
27712802
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
@@ -3668,7 +3699,7 @@ multipipe@^0.1.2:
36683699
dependencies:
36693700
duplexer2 "0.0.2"
36703701

3671-
mute-stream@~0.0.4:
3702+
mute-stream@~0.0.4, [email protected]:
36723703
version "0.0.6"
36733704
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db"
36743705

@@ -3903,6 +3934,10 @@ os-locale@^1.4.0:
39033934
dependencies:
39043935
lcid "^1.0.0"
39053936

3937+
os-shim@^0.1.2:
3938+
version "0.1.3"
3939+
resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917"
3940+
39063941
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
39073942
version "1.0.2"
39083943
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@@ -4431,10 +4466,21 @@ run-async@^0.1.0:
44314466
dependencies:
44324467
once "^1.3.0"
44334468

4469+
run-async@^2.2.0:
4470+
version "2.2.0"
4471+
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.2.0.tgz#8783abd83c7bb86f41ee0602fc82404b3bd6e8b9"
4472+
dependencies:
4473+
is-promise "^2.1.0"
4474+
pinkie-promise "^2.0.0"
4475+
44344476
rx-lite@^3.1.2:
44354477
version "3.1.2"
44364478
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
44374479

4480+
rx@^4.1.0:
4481+
version "4.1.0"
4482+
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
4483+
44384484
sane@~1.4.1:
44394485
version "1.4.1"
44404486
resolved "https://registry.yarnpkg.com/sane/-/sane-1.4.1.tgz#88f763d74040f5f0c256b6163db399bf110ac715"
@@ -4560,6 +4606,13 @@ sparkles@^1.0.0:
45604606
version "1.0.0"
45614607
resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3"
45624608

4609+
spawn-sync@^1.0.15:
4610+
version "1.0.15"
4611+
resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476"
4612+
dependencies:
4613+
concat-stream "^1.4.7"
4614+
os-shim "^0.1.2"
4615+
45634616
spdx-correct@~1.0.0:
45644617
version "1.0.2"
45654618
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"

0 commit comments

Comments
 (0)