Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CB-14140] Replace shelljs calls with fs-extra & which #21

Merged
merged 3 commits into from
Jun 5, 2018

Conversation

dpogue
Copy link
Member

@dpogue dpogue commented May 15, 2018

Replaces all uses of shelljs with fs-extra for handling directory creation/deletion and file copying. Replaces the single use of shelljs.which with which.

While this doesn't have a huge impact here, fs-extra should give us some more stability in our tests in other projects like cordova-lib, especially around directory deletions on Windows.

The potential concern is that these changes will cause test failures in other modules because they are stubbing methods on fs instead of fs-extra, but my hope would be to update all those other modules as well. I've got a branch of cordova-lib that I've started updating.

@codecov-io
Copy link

codecov-io commented May 15, 2018

Codecov Report

Merging #21 into master will increase coverage by 0.11%.
The diff coverage is 96.15%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #21      +/-   ##
==========================================
+ Coverage   85.51%   85.63%   +0.11%     
==========================================
  Files          19       19              
  Lines        1761     1747      -14     
  Branches      371      367       -4     
==========================================
- Hits         1506     1496      -10     
+ Misses        255      251       -4
Impacted Files Coverage Δ
src/PluginInfo/PluginInfo.js 81.25% <100%> (ø) ⬆️
src/PlatformJson.js 78.18% <100%> (+2.74%) ⬆️
src/PluginManager.js 92.45% <100%> (ø) ⬆️
src/ConfigChanges/ConfigFile.js 89.85% <100%> (ø) ⬆️
src/PluginInfo/PluginInfoProvider.js 85.71% <100%> (ø) ⬆️
src/CordovaCheck.js 87.5% <100%> (ø) ⬆️
src/ConfigParser/ConfigParser.js 76.73% <100%> (ø) ⬆️
src/util/xml-helpers.js 94.94% <100%> (ø) ⬆️
src/FileUpdater.js 86.01% <100%> (-0.92%) ⬇️
src/superspawn.js 69.41% <66.66%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ff3630f...6534c21. Read the comment docs.

@dpogue dpogue force-pushed the fs-extra branch 2 times, most recently from 061db2d to d84c28a Compare May 19, 2018 04:16
@raphinesse
Copy link
Contributor

👍 I thought about proposing the same substitution when working on cordova-create. I definitely prefer this over the shelljs solution.

@dpogue
Copy link
Member Author

dpogue commented May 21, 2018

I have all tests passing here, but we still use shelljs in one spot (superspawn for shell.which).

The potential concern is that these changes will cause test failures in other modules because they are stubbing methods on fs instead of fs-extra, but my hope would be to update all those other modules as well. I've got a branch of cordova-lib that I've started updating.

@raphinesse
Copy link
Contributor

raphinesse commented May 21, 2018

@dpogue Regarding stubbing/mocking: foo.__set__('fs', mockFs); will replace the variable named fs in module foo's top level scope. So it should work regardless of what fs refers to.
Edit: I see, you mean when other modules do stuff like spyOn(require('fs'), ...)

Use this to get rid of shelljs? https://www.npmjs.com/package/which

@dpogue dpogue changed the title WIP: Replace most shelljs calls with fs-extra Replace shelljs calls with fs-extra & which May 22, 2018
@dpogue
Copy link
Member Author

dpogue commented May 22, 2018

This should be ready for review now

Copy link
Contributor

@raphinesse raphinesse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a correct transformation of the existing code to me 👍

I left some suggestions on how to further improve some of the locations you touched. Some might be considered out of the scope of this PR.

@@ -196,10 +195,10 @@ describe('config-changes module', function () {

describe('processing of plugins (via process method)', function () {
beforeEach(function () {
shell.cp('-rf', dummyplugin, plugins_dir);
fs.copySync(dummyplugin, path.join(plugins_dir, path.basename(dummyplugin)));
Copy link
Contributor

@raphinesse raphinesse May 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this idiom occurs quite often in this file, I'd add a helper like this

function installPlugin (pluginPath) {
    fs.copySync(pluginPath, path.join(plugins_dir, path.basename(pluginPath)));
}

@@ -31,12 +31,12 @@ describe('findProjectRoot method', function () {
process.chdir(cwd);
});
function removeDir (someDirectory) {
Copy link
Contributor

@raphinesse raphinesse May 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd inline all occurrences of this helper and drop it, since it's now only an alias

Edit: I realize now that the placement of the comment was suboptimal

}
it('Test 001 : should return false if it hits the home directory', function () {
var somedir = path.join(home, 'somedir');
removeDir(somedir);
shell.mkdir(somedir);
fs.ensureDirSync(somedir);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this particular instance, one could use fs.emptyDirSync(somedir) to replace the remove/create idiom

shell.mkdir('-p', path.join(anotherdir, 'www', 'config.xml'));
shell.mkdir('-p', path.join(somedir, 'www'));
shell.mkdir('-p', path.join(somedir, 'config.xml'));
fs.ensureDirSync(anotherdir);
Copy link
Contributor

@raphinesse raphinesse May 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need this because of next line

Again, bad placement of the comment on my part 🙄

shell.mkdir('-p', anotherdir);
shell.mkdir('-p', path.join(somedir, 'www', 'config.xml'));
fs.ensureDirSync(anotherdir);
fs.ensureDirSync(path.join(somedir, 'www', 'config.xml'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the previous version was just a lazy hack. We actually want fs.ensureFileSync on all instances of this. One might might even consider adding a test that asserts that directories are not accepted as config.xml.

} else if (!targetStats.isDirectory() && sourceStats.isDirectory()) {
log('delete ' + targetPath + ' (source is a directory)');
shell.rm('-f', targetFullPath);
if ((targetStats.isDirectory() && !sourceStats.isDirectory()) || (!targetStats.isDirectory() && sourceStats.isDirectory())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Condition is equivalent to targetStats.isDirectory() !== sourceStats.isDirectory().
I'd merge with containing block to targetStats && (targetStats.isDirectory() !== sourceStats.isDirectory())

@@ -37,7 +36,7 @@ PlatformJson.load = function (plugins_dir, platform) {
};

PlatformJson.prototype.save = function () {
shelljs.mkdir('-p', path.dirname(this.filePath));
fs.ensureDirSync(path.dirname(this.filePath));
fs.writeFileSync(this.filePath, JSON.stringify(this.root, null, 2), 'utf-8');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified to:

fs.outputJsonSync(this.filePath, this.root, {spaces: 2})

Encoding defaults to utf-8

@@ -212,7 +211,7 @@ PlatformJson.prototype.generateMetadata = function () {
*/
PlatformJson.prototype.generateAndSaveMetadata = function (destination) {
var meta = this.generateMetadata();
shelljs.mkdir('-p', path.dirname(destination));
fs.ensureDirSync(path.dirname(destination));
fs.writeFileSync(destination, meta, 'utf-8');
Copy link
Contributor

@raphinesse raphinesse May 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, these lines can be replaced by:

fs.outputFileSync(destination, this.generateMetadata());

@dpogue
Copy link
Member Author

dpogue commented May 23, 2018

Thanks for those review comments @raphinesse! Since they all help to make the code easier to read I'll consider them all in scope 😉

I've added another commit addressing them. We'll squash this branch when merging.

@raphinesse
Copy link
Contributor

raphinesse commented May 23, 2018

Did you include the async test handling changes by accident? Since they are completely unrelated, I would consider them out of scope 😉

I'm meaning to say the async test handling changes are fine but should go in a separate PR IMHO.

@dpogue
Copy link
Member Author

dpogue commented May 24, 2018

Fixed the re-spacing JSON output, and pulled out the spec changes for a future PR. Thanks!

@@ -211,8 +210,7 @@ PlatformJson.prototype.generateMetadata = function () {
*/
PlatformJson.prototype.generateAndSaveMetadata = function (destination) {
var meta = this.generateMetadata();
fs.ensureDirSync(path.dirname(destination));
fs.writeFileSync(destination, meta, 'utf-8');
fs.outputJsonSync(destination, meta);
Copy link
Contributor

@raphinesse raphinesse May 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hate to bug you again with this, but it was not about re-spacing JSON output. generateMetadata returns a string containing JS, not JSON. Therefore we need fs.outputFileSync(destination, meta) here (mind the File).

I also wrote a butt-ugly test that will fail with your implementation:

describe('generateAndSaveMetadata method', function () {
    it('should save generated metadata', function () {
        // Needs to use graceful-fs, since that is used by fs-extra
        const spy = spyOn(require('graceful-fs'), 'writeFileSync');

        const dest = require('path').join(__dirname, 'test-destination');
        platformJson.addPluginMetadata(fakePlugin).generateAndSaveMetadata(dest);

        expect(spy).toHaveBeenCalledTimes(1);
        const [file, data] = spy.calls.argsFor(0);
        expect(file).toBe(dest);
        expect(data.indexOf(JSON.stringify(platformJson.root.modules, null, 2))).toBeGreaterThan(0);
        expect(data).toMatch(JSON.stringify(platformJson.root.plugin_metadata, null, 2));
    });
});

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, now I understand! 🤦‍♂️

I've fixed that and added your test to the PlatformJson.spec.js

@brodybits
Copy link
Contributor

Any timeline when this one will be merged?

@dpogue
Copy link
Member Author

dpogue commented May 30, 2018

I'm hoping to do a minor version release of cordova-common with bugfixes before merging this, since this might qualify as a major-version API change.

@dpogue
Copy link
Member Author

dpogue commented Jun 5, 2018

We've done the cordova-common 2.2.3 release, I think we're ready to merge this.
@raphinesse care to do the honours? 🙂

@raphinesse raphinesse merged commit d781ffd into apache:master Jun 5, 2018
@raphinesse
Copy link
Contributor

With the greatest of pleasure 😁

@brodybits brodybits changed the title Replace shelljs calls with fs-extra & which [CB-14140] Replace shelljs calls with fs-extra & which Jun 15, 2018
@brodybits
Copy link
Contributor

Linking this wonderful change which landed in d781ffd to CB-14140 (https://issues.apache.org/jira/browse/CB-14140).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants