Skip to content

Commit ff115a5

Browse files
committed
Use a completely separate adapter for yarn
1 parent 324be12 commit ff115a5

8 files changed

Lines changed: 694 additions & 488 deletions

File tree

lib/dependency-manager-adapters/npm.js

Lines changed: 18 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,12 @@ module.exports = class {
1111
configKey = 'npm';
1212
packageJSON = 'package.json';
1313
packageLock = 'package-lock.json';
14-
useYarnCommand = false;
15-
yarnLock = 'yarn.lock';
1614

1715
constructor(options) {
1816
this.buildManagerOptions = options.buildManagerOptions;
1917
this.cwd = options.cwd;
2018
this.managerOptions = options.managerOptions;
2119
this.run = options.run || require('../utils/run');
22-
this.useYarnCommand = options.useYarnCommand ?? false;
2320

2421
this.backup = new Backup({ cwd: this.cwd });
2522
}
@@ -45,7 +42,7 @@ module.exports = class {
4542
name: dep,
4643
versionExpected: deps[dep],
4744
versionSeen: this._findCurrentVersionOf(dep),
48-
packageManager: this.useYarnCommand ? 'yarn' : 'npm',
45+
packageManager: 'npm',
4946
};
5047
});
5148

@@ -63,18 +60,16 @@ module.exports = class {
6360
}
6461

6562
_runYarnCheck(ui) {
66-
if (!this.useYarnCommand) {
67-
try {
68-
if (fs.statSync(path.join(this.cwd, this.yarnLock)).isFile()) {
69-
ui.writeLine(
70-
chalk.yellow(
71-
"Detected a yarn.lock file. Add `packageManager: 'yarn'` to your `config/ember-try.js` configuration file if you want to use Yarn to install npm dependencies.",
72-
),
73-
);
74-
}
75-
} catch (e) {
76-
// If no yarn.lock is found, no need to warn.
63+
try {
64+
if (fs.statSync(path.join(this.cwd, 'yarn.lock')).isFile()) {
65+
ui.writeLine(
66+
chalk.yellow(
67+
"Detected a yarn.lock file. Add `packageManager: 'yarn'` to your `config/ember-try.js` configuration file if you want to use Yarn to install npm dependencies.",
68+
),
69+
);
7770
}
71+
} catch {
72+
// If no yarn.lock is found, no need to warn.
7873
}
7974
}
8075

@@ -89,7 +84,6 @@ module.exports = class {
8984

9085
async _install(depSet) {
9186
let mgrOptions = this.managerOptions || [];
92-
let cmd = this.useYarnCommand ? 'yarn' : 'npm';
9387

9488
// buildManagerOptions overrides all default
9589
if (typeof this.buildManagerOptions === 'function') {
@@ -98,24 +92,13 @@ module.exports = class {
9892
if (!Array.isArray(mgrOptions)) {
9993
throw new Error('buildManagerOptions must return an array of options');
10094
}
101-
} else {
102-
if (this.useYarnCommand) {
103-
if (mgrOptions.indexOf('--no-lockfile') === -1) {
104-
mgrOptions = mgrOptions.concat(['--no-lockfile']);
105-
}
106-
// npm warns on incompatible engines
107-
// yarn errors, not a good experience
108-
if (mgrOptions.indexOf('--ignore-engines') === -1) {
109-
mgrOptions = mgrOptions.concat(['--ignore-engines']);
110-
}
111-
} else if (mgrOptions.indexOf('--no-package-lock') === -1) {
112-
mgrOptions = mgrOptions.concat(['--no-package-lock']);
113-
}
95+
} else if (mgrOptions.indexOf('--no-package-lock') === -1) {
96+
mgrOptions = mgrOptions.concat(['--no-package-lock']);
11497
}
11598

116-
debug('Run npm/yarn install with options %s', mgrOptions);
99+
debug('Run npm install with options %s', mgrOptions);
117100

118-
await this.run(cmd, [].concat(['install'], mgrOptions), { cwd: this.cwd });
101+
await this.run('npm', [].concat(['install'], mgrOptions), { cwd: this.cwd });
119102
}
120103

121104
applyDependencySet(depSet) {
@@ -140,12 +123,7 @@ module.exports = class {
140123
this._overridePackageJSONDependencies(packageJSON, depSet, 'devDependencies');
141124
this._overridePackageJSONDependencies(packageJSON, depSet, 'peerDependencies');
142125
this._overridePackageJSONDependencies(packageJSON, depSet, 'ember');
143-
144-
if (this.useYarnCommand) {
145-
this._overridePackageJSONDependencies(packageJSON, depSet, 'resolutions');
146-
} else {
147-
this._overridePackageJSONDependencies(packageJSON, depSet, 'overrides');
148-
}
126+
this._overridePackageJSONDependencies(packageJSON, depSet, 'overrides');
149127

150128
return packageJSON;
151129
}
@@ -169,10 +147,7 @@ module.exports = class {
169147
packageJSON[kindOfDependency][packageName] = version;
170148

171149
// in npm we need to always add an override if the version is a pre-release
172-
if (
173-
!this.useYarnCommand &&
174-
(semver.prerelease(version) || /^https*:\/\/.*\.tg*z/.test(version))
175-
) {
150+
if (semver.prerelease(version) || /^https*:\/\/.*\.tg*z/.test(version)) {
176151
if (!packageJSON.overrides) {
177152
packageJSON.overrides = {};
178153
}
@@ -184,12 +159,12 @@ module.exports = class {
184159
}
185160

186161
async _restoreOriginalDependencies() {
187-
await this.backup.restoreFiles([this.packageJSON, this.packageLock, this.yarnLock]);
162+
await this.backup.restoreFiles([this.packageJSON, this.packageLock]);
188163
await this.backup.cleanUp();
189164
await this._install();
190165
}
191166

192167
async _backupOriginalDependencies() {
193-
await this.backup.addFiles([this.packageJSON, this.packageLock, this.yarnLock]);
168+
await this.backup.addFiles([this.packageJSON, this.packageLock]);
194169
}
195170
};

lib/dependency-manager-adapters/workspace.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const path = require('path');
55
const debug = require('debug')('ember-try:dependency-manager-adapter:workspaces');
66
const walkSync = require('walk-sync');
77

8-
const NpmAdapter = require('./npm');
8+
const YarnAdapter = require('./yarn');
99

1010
module.exports = class {
1111
packageJSON = 'package.json';
@@ -15,9 +15,8 @@ module.exports = class {
1515
this.cwd = options.cwd;
1616
this.managerOptions = options.managerOptions;
1717
this.run = options.run || require('../utils/run');
18-
this.useYarnCommand = options.useYarnCommand ?? false;
1918

20-
if (!this.useYarnCommand) {
19+
if (options.packageManager !== 'yarn') {
2120
throw new Error(
2221
'workspaces are currently only supported by Yarn, you must set `packageManager` to `yarn`',
2322
);
@@ -47,11 +46,10 @@ module.exports = class {
4746
});
4847

4948
this._packageAdapters = workspacePaths.map((workspacePath) => {
50-
return new NpmAdapter({
49+
return new YarnAdapter({
5150
cwd: workspacePath,
5251
run: this.run,
5352
managerOptions: this.managerOptions,
54-
useYarnCommand: true,
5553
buildManagerOptions: this.buildManagerOptions,
5654
});
5755
});
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
'use strict';
2+
3+
const fs = require('fs-extra');
4+
const path = require('path');
5+
const debug = require('debug')('ember-try:dependency-manager-adapter:yarn');
6+
const Backup = require('../utils/backup');
7+
8+
module.exports = class {
9+
configKey = 'npm'; // Still use `npm` for now!
10+
packageJSON = 'package.json';
11+
yarnLock = 'yarn.lock';
12+
13+
constructor(options) {
14+
this.buildManagerOptions = options.buildManagerOptions;
15+
this.cwd = options.cwd;
16+
this.managerOptions = options.managerOptions;
17+
this.run = options.run || require('../utils/run');
18+
19+
this.backup = new Backup({ cwd: this.cwd });
20+
}
21+
22+
async setup(options) {
23+
if (!options) {
24+
options = {};
25+
}
26+
27+
return await this._backupOriginalDependencies();
28+
}
29+
30+
async changeToDependencySet(depSet) {
31+
this.applyDependencySet(depSet);
32+
33+
await this._install(depSet);
34+
35+
let deps = Object.assign({}, depSet.dependencies, depSet.devDependencies);
36+
let currentDeps = Object.keys(deps).map((dep) => {
37+
return {
38+
name: dep,
39+
versionExpected: deps[dep],
40+
versionSeen: this._findCurrentVersionOf(dep),
41+
packageManager: 'yarn',
42+
};
43+
});
44+
45+
debug('Switched to dependencies: \n', currentDeps);
46+
47+
return currentDeps;
48+
}
49+
50+
async cleanup() {
51+
try {
52+
await this._restoreOriginalDependencies();
53+
} catch (e) {
54+
console.log('Error cleaning up npm scenario:', e); // eslint-disable-line no-console
55+
}
56+
}
57+
58+
_findCurrentVersionOf(packageName) {
59+
let filename = path.join(this.cwd, 'node_modules', packageName, this.packageJSON);
60+
if (fs.existsSync(filename)) {
61+
return JSON.parse(fs.readFileSync(filename)).version;
62+
} else {
63+
return null;
64+
}
65+
}
66+
67+
async _install(depSet) {
68+
let mgrOptions = this.managerOptions || [];
69+
70+
// buildManagerOptions overrides all default
71+
if (typeof this.buildManagerOptions === 'function') {
72+
mgrOptions = this.buildManagerOptions(depSet);
73+
74+
if (!Array.isArray(mgrOptions)) {
75+
throw new Error('buildManagerOptions must return an array of options');
76+
}
77+
} else {
78+
if (mgrOptions.indexOf('--no-lockfile') === -1) {
79+
mgrOptions = mgrOptions.concat(['--no-lockfile']);
80+
}
81+
82+
// yarn errors on incompatible engines, not a good experience
83+
if (mgrOptions.indexOf('--ignore-engines') === -1) {
84+
mgrOptions = mgrOptions.concat(['--ignore-engines']);
85+
}
86+
}
87+
88+
debug('Run yarn install with options %s', mgrOptions);
89+
90+
await this.run('yarn', [].concat(['install'], mgrOptions), { cwd: this.cwd });
91+
}
92+
93+
applyDependencySet(depSet) {
94+
debug('Changing to dependency set: %s', JSON.stringify(depSet));
95+
96+
if (!depSet) {
97+
return;
98+
}
99+
100+
let backupPackageJSON = this.backup.pathForFile(this.packageJSON);
101+
let packageJSONFile = path.join(this.cwd, this.packageJSON);
102+
let packageJSON = JSON.parse(fs.readFileSync(backupPackageJSON));
103+
let newPackageJSON = this._packageJSONForDependencySet(packageJSON, depSet);
104+
105+
debug('Write package.json with: \n', JSON.stringify(newPackageJSON));
106+
107+
fs.writeFileSync(packageJSONFile, JSON.stringify(newPackageJSON, null, 2));
108+
}
109+
110+
_packageJSONForDependencySet(packageJSON, depSet) {
111+
this._overridePackageJSONDependencies(packageJSON, depSet, 'dependencies');
112+
this._overridePackageJSONDependencies(packageJSON, depSet, 'devDependencies');
113+
this._overridePackageJSONDependencies(packageJSON, depSet, 'peerDependencies');
114+
this._overridePackageJSONDependencies(packageJSON, depSet, 'ember');
115+
this._overridePackageJSONDependencies(packageJSON, depSet, 'resolutions');
116+
117+
return packageJSON;
118+
}
119+
120+
_overridePackageJSONDependencies(packageJSON, depSet, kindOfDependency) {
121+
if (!depSet[kindOfDependency]) {
122+
return;
123+
}
124+
125+
let packageNames = Object.keys(depSet[kindOfDependency]);
126+
127+
packageNames.forEach((packageName) => {
128+
if (!packageJSON[kindOfDependency]) {
129+
packageJSON[kindOfDependency] = {};
130+
}
131+
132+
let version = depSet[kindOfDependency][packageName];
133+
if (version === null) {
134+
delete packageJSON[kindOfDependency][packageName];
135+
} else {
136+
packageJSON[kindOfDependency][packageName] = version;
137+
}
138+
});
139+
}
140+
141+
async _restoreOriginalDependencies() {
142+
await this.backup.restoreFiles([this.packageJSON, this.yarnLock]);
143+
await this.backup.cleanUp();
144+
await this._install();
145+
}
146+
147+
async _backupOriginalDependencies() {
148+
await this.backup.addFiles([this.packageJSON, this.yarnLock]);
149+
}
150+
};

lib/utils/dependency-manager-adapter-factory.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const NpmAdapter = require('../dependency-manager-adapters/npm');
44
const PnpmAdapter = require('../dependency-manager-adapters/pnpm');
55
const WorkspaceAdapter = require('../dependency-manager-adapters/workspace');
6+
const YarnAdapter = require('../dependency-manager-adapters/yarn');
67

78
module.exports = {
89
generateFromConfig(config, root) {
@@ -23,7 +24,7 @@ module.exports = {
2324
new WorkspaceAdapter({
2425
cwd: root,
2526
managerOptions: config.npmOptions,
26-
useYarnCommand: config.packageManager === 'yarn',
27+
packageManager: config.packageManager,
2728
buildManagerOptions: config.buildManagerOptions,
2829
}),
2930
);
@@ -35,12 +36,19 @@ module.exports = {
3536
buildManagerOptions: config.buildManagerOptions,
3637
}),
3738
);
39+
} else if (config.packageManager === 'yarn') {
40+
adapters.push(
41+
new YarnAdapter({
42+
cwd: root,
43+
managerOptions: config.npmOptions,
44+
buildManagerOptions: config.buildManagerOptions,
45+
}),
46+
);
3847
} else if (hasNpm) {
3948
adapters.push(
4049
new NpmAdapter({
4150
cwd: root,
4251
managerOptions: config.npmOptions,
43-
useYarnCommand: config.packageManager === 'yarn',
4452
buildManagerOptions: config.buildManagerOptions,
4553
}),
4654
);

0 commit comments

Comments
 (0)