fix(GUI): duplicate drives in Windows (#790)

If a drive contains multiple partitions that Windows recognises and
mounts, then `drivelist` will incorrectly display separate drive objects
for each partition, causing `ngRepeat` to complain in the drive selector
component.

The issue was fixed by grouping the mountpoints of all recognised
partitions in a single drive object, as we do with the other supported
operating systems.

After the fix, `drivelist` also removed its `name` property (since its
now always equal to `device`), so some extra logic to compute an
appropriate display name for the drive has been introduced to
`DriveScannerService`.

Fixes: https://github.com/resin-io/etcher/issues/720
See: https://github.com/resin-io-modules/drivelist/pull/100
Change-Type: patch
Changelog-Entry: Fix duplicate drives in Windows.
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
Juan Cruz Viotti 2016-10-31 01:18:58 -04:00 committed by GitHub
parent a6624cc344
commit bc985f08a9
4 changed files with 189 additions and 40 deletions

View File

@ -21,6 +21,7 @@
*/
const Rx = require('rx');
const os = require('os');
const _ = require('lodash');
const angular = require('angular');
const EventEmitter = require('events').EventEmitter;
@ -40,6 +41,18 @@ driveScanner.factory('DriveScannerService', (SettingsModel) => {
return Rx.Observable.fromNodeCallback(drivelist.list)();
})
.map((drives) => {
// Calculate an appropriate "display name"
drives = _.map(drives, (drive) => {
drive.name = drive.device;
if (os.platform() === 'win32' && drive.mountpoint) {
drive.name = drive.mountpoint;
}
return drive;
});
if (SettingsModel.get('unsafeMode')) {
return drives;
}

56
npm-shrinkwrap.json generated
View File

@ -1153,14 +1153,14 @@
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz"
},
"drivelist": {
"version": "3.3.4",
"from": "drivelist@3.3.4",
"resolved": "https://registry.npmjs.org/drivelist/-/drivelist-3.3.4.tgz",
"version": "4.0.0",
"from": "drivelist@4.0.0",
"resolved": "https://registry.npmjs.org/drivelist/-/drivelist-4.0.0.tgz",
"dependencies": {
"lodash": {
"version": "3.10.1",
"from": "lodash@>=3.0.1 <4.0.0",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
"version": "4.16.4",
"from": "lodash@>=4.16.4 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.4.tgz"
}
}
},
@ -3568,6 +3568,40 @@
}
}
},
"module-deps": {
"version": "4.0.8",
"from": "module-deps@>=4.0.8 <5.0.0",
"resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.0.8.tgz",
"dependencies": {
"isarray": {
"version": "1.0.0",
"from": "isarray@~1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
},
"readable-stream": {
"version": "2.1.5",
"from": "readable-stream@^2.0.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz"
},
"through2": {
"version": "2.0.1",
"from": "through2@^2.0.0",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz",
"dependencies": {
"readable-stream": {
"version": "2.0.6",
"from": "readable-stream@>=2.0.0 <2.1.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz"
}
}
},
"xtend": {
"version": "4.0.1",
"from": "xtend@^4.0.0",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
}
}
},
"moment": {
"version": "2.13.0",
"from": "moment@>=2.8.0 <3.0.0",
@ -4304,6 +4338,11 @@
"from": "bluebird@>=2.9.34 <3.0.0",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz"
},
"drivelist": {
"version": "3.3.4",
"from": "drivelist@>=3.1.0 <4.0.0",
"resolved": "https://registry.npmjs.org/drivelist/-/drivelist-3.3.4.tgz"
},
"lodash": {
"version": "3.10.1",
"from": "lodash@>=3.10.0 <4.0.0",
@ -4906,6 +4945,11 @@
"from": "timers-browserify@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz"
},
"tmp": {
"version": "0.0.28",
"from": "tmp@0.0.28",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz"
},
"tn1150": {
"version": "0.1.0",
"from": "tn1150@>=0.1.0 <0.2.0",

View File

@ -66,7 +66,7 @@
"bluebird": "^3.0.5",
"bootstrap-sass": "^3.3.5",
"chalk": "^1.1.3",
"drivelist": "^3.3.4",
"drivelist": "^4.0.0",
"electron-is-running-in-asar": "^1.0.0",
"etcher-image-stream": "^5.1.0",
"etcher-image-write": "^8.1.3",

View File

@ -1,6 +1,7 @@
'use strict';
const m = require('mochainon');
const os = require('os');
const angular = require('angular');
const drivelist = require('drivelist');
require('angular-mocks');
@ -73,42 +74,29 @@ describe('Browser: DriveScanner', function() {
});
describe('given available drives', function() {
describe('given linux', function() {
beforeEach(function() {
this.drivesListStub = m.sinon.stub(drivelist, 'list');
this.drivesListStub.yields(null, [
{
device: '/dev/sda',
description: 'WDC WD10JPVX-75J',
size: '931.5G',
mountpoint: '/',
system: true
},
{
device: '/dev/sdb',
description: 'Foo',
size: '14G',
mountpoint: '/mnt/foo',
system: false
},
{
device: '/dev/sdc',
description: 'Bar',
size: '14G',
mountpoint: '/mnt/bar',
system: false
}
]);
this.osPlatformStub = m.sinon.stub(os, 'platform');
this.osPlatformStub.returns('linux');
});
afterEach(function() {
this.drivesListStub.restore();
this.osPlatformStub.restore();
});
it('should emit the non removable drives', function(done) {
DriveScannerService.on('drives', function(drives) {
m.chai.expect(drives).to.deep.equal([
describe('given available drives', function() {
beforeEach(function() {
this.drivesListStub = m.sinon.stub(drivelist, 'list');
this.drivesListStub.yields(null, [
{
device: '/dev/sda',
description: 'WDC WD10JPVX-75J',
size: '931.5G',
mountpoint: '/',
system: true
},
{
device: '/dev/sdb',
description: 'Foo',
@ -124,12 +112,116 @@ describe('Browser: DriveScanner', function() {
system: false
}
]);
DriveScannerService.stop();
done();
});
DriveScannerService.start();
afterEach(function() {
this.drivesListStub.restore();
});
it('should emit the non removable drives', function(done) {
DriveScannerService.on('drives', function(drives) {
m.chai.expect(drives).to.deep.equal([
{
device: '/dev/sdb',
name: '/dev/sdb',
description: 'Foo',
size: '14G',
mountpoint: '/mnt/foo',
system: false
},
{
device: '/dev/sdc',
name: '/dev/sdc',
description: 'Bar',
size: '14G',
mountpoint: '/mnt/bar',
system: false
}
]);
DriveScannerService.stop();
done();
});
DriveScannerService.start();
});
});
});
describe('given windows', function() {
beforeEach(function() {
this.osPlatformStub = m.sinon.stub(os, 'platform');
this.osPlatformStub.returns('win32');
});
afterEach(function() {
this.osPlatformStub.restore();
});
describe('given available drives', function() {
beforeEach(function() {
this.drivesListStub = m.sinon.stub(drivelist, 'list');
this.drivesListStub.yields(null, [
{
device: '\\\\.\\PHYSICALDRIVE1',
description: 'WDC WD10JPVX-75J',
size: '931.5G',
mountpoint: 'C:',
system: true
},
{
device: '\\\\.\\PHYSICALDRIVE2',
description: 'Foo',
size: '14G',
mountpoint: null,
system: false
},
{
device: '\\\\.\\PHYSICALDRIVE3',
description: 'Bar',
size: '14G',
mountpoint: 'F:',
system: false
}
]);
});
afterEach(function() {
this.drivesListStub.restore();
});
it('should emit the non removable drives', function(done) {
DriveScannerService.on('drives', function(drives) {
m.chai.expect(drives).to.deep.equal([
{
device: '\\\\.\\PHYSICALDRIVE2',
name: '\\\\.\\PHYSICALDRIVE2',
description: 'Foo',
size: '14G',
mountpoint: null,
system: false
},
{
device: '\\\\.\\PHYSICALDRIVE3',
name: 'F:',
description: 'Bar',
size: '14G',
mountpoint: 'F:',
system: false
}
]);
DriveScannerService.stop();
done();
});
DriveScannerService.start();
});
});
});