mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-23 19:26:33 +00:00
Convert window-network-drives.js to typescript
Change-type: patch
This commit is contained in:
parent
255fae3a90
commit
b266a72726
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 balena.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const Bluebird = require('bluebird')
|
||||
const cp = require('child_process')
|
||||
const fs = require('fs')
|
||||
const _ = require('lodash')
|
||||
const os = require('os')
|
||||
const Path = require('path')
|
||||
const process = require('process')
|
||||
const { promisify } = require('util')
|
||||
|
||||
const { tmpFileDisposer } = require('../../../shared/utils')
|
||||
|
||||
const readFileAsync = promisify(fs.readFile)
|
||||
|
||||
const execAsync = promisify(cp.exec)
|
||||
|
||||
/**
|
||||
* @summary Returns wmic's output for network drives
|
||||
* @function
|
||||
*
|
||||
* @returns {Promise<String>}
|
||||
*
|
||||
* @example
|
||||
* const output = await getWmicNetworkDrivesOutput()
|
||||
*/
|
||||
exports.getWmicNetworkDrivesOutput = async () => {
|
||||
// Exported for tests.
|
||||
// When trying to read wmic's stdout directly from node, it is encoded with the current
|
||||
// console codepage (depending on the computer).
|
||||
// Decoding this would require getting this codepage somehow and using iconv as node
|
||||
// doesn't know how to read cp850 directly for example.
|
||||
// We could also use wmic's "/output:" switch but it doesn't work when the filename
|
||||
// contains a space and the os temp dir may contain spaces ("D:\Windows Temp Files" for example).
|
||||
// So we just redirect to a file and read it afterwards as we know it will be ucs2 encoded.
|
||||
const options = {
|
||||
|
||||
// Close the file once it's created
|
||||
discardDescriptor: true,
|
||||
|
||||
// Wmic fails with "Invalid global switch" when the "/output:" switch filename contains a dash ("-")
|
||||
prefix: 'tmp'
|
||||
}
|
||||
return Bluebird.using(tmpFileDisposer(options), async ({ path }) => {
|
||||
const command = [
|
||||
Path.join(process.env.SystemRoot, 'System32', 'Wbem', 'wmic'),
|
||||
'path',
|
||||
'Win32_LogicalDisk',
|
||||
'Where',
|
||||
'DriveType="4"',
|
||||
'get',
|
||||
'DeviceID,ProviderName',
|
||||
'>',
|
||||
`"${path}"`
|
||||
]
|
||||
await execAsync(command.join(' '), { windowsHide: true })
|
||||
return readFileAsync(path, 'ucs2')
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary returns a Map of drive letter -> network locations on Windows
|
||||
* @function
|
||||
*
|
||||
* @returns {Promise<Map<String, String>>} - 'Z:' -> '\\\\192.168.0.1\\Public'
|
||||
*
|
||||
* @example
|
||||
* getWindowsNetworkDrives()
|
||||
* .then(console.log);
|
||||
*/
|
||||
const getWindowsNetworkDrives = async () => {
|
||||
const result = await exports.getWmicNetworkDrivesOutput()
|
||||
const couples = _.chain(result)
|
||||
.split('\n')
|
||||
|
||||
// Remove header line
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
.slice(1)
|
||||
|
||||
// Remove extra spaces / tabs / carriage returns
|
||||
.invokeMap(String.prototype.trim)
|
||||
|
||||
// Filter out empty lines
|
||||
.compact()
|
||||
.map((str) => {
|
||||
const colonPosition = str.indexOf(':')
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
if (colonPosition === -1) {
|
||||
throw new Error(`Can't parse wmic output: ${result}`)
|
||||
}
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
return [ str.slice(0, colonPosition + 1), _.trim(str.slice(colonPosition + 1)) ]
|
||||
})
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
.filter((couple) => couple[1].length > 0)
|
||||
.value()
|
||||
return new Map(couples)
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Replaces network drive letter with network drive location in the provided filePath on Windows
|
||||
* @function
|
||||
*
|
||||
* @param {String} filePath - file path
|
||||
*
|
||||
* @returns {String} - updated file path
|
||||
*
|
||||
* @example
|
||||
* replaceWindowsNetworkDriveLetter('Z:\\some-file')
|
||||
* .then(console.log);
|
||||
*/
|
||||
exports.replaceWindowsNetworkDriveLetter = async (filePath) => {
|
||||
let result = filePath
|
||||
if (os.platform() === 'win32') {
|
||||
const matches = /^([A-Z]+:)\\(.*)$/.exec(filePath)
|
||||
if (matches !== null) {
|
||||
const [ , drive, relativePath ] = matches
|
||||
const drives = await getWindowsNetworkDrives()
|
||||
const location = drives.get(drive)
|
||||
// eslint-disable-next-line no-undefined
|
||||
if (location !== undefined) {
|
||||
result = `${location}\\${relativePath}`
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
115
lib/gui/app/os/windows-network-drives.ts
Executable file
115
lib/gui/app/os/windows-network-drives.ts
Executable file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2019 balena.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { using } from 'bluebird';
|
||||
import { exec } from 'child_process';
|
||||
import { readFile } from 'fs';
|
||||
import { chain, trim } from 'lodash';
|
||||
import { platform } from 'os';
|
||||
import { join } from 'path';
|
||||
import { env } from 'process';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import { tmpFileDisposer } from '../../../shared/utils';
|
||||
|
||||
const readFileAsync = promisify(readFile);
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
/**
|
||||
* @summary Returns wmic's output for network drives
|
||||
*/
|
||||
export async function getWmicNetworkDrivesOutput(): Promise<string> {
|
||||
// Exported for tests.
|
||||
// When trying to read wmic's stdout directly from node, it is encoded with the current
|
||||
// console codepage (depending on the computer).
|
||||
// Decoding this would require getting this codepage somehow and using iconv as node
|
||||
// doesn't know how to read cp850 directly for example.
|
||||
// We could also use wmic's "/output:" switch but it doesn't work when the filename
|
||||
// contains a space and the os temp dir may contain spaces ("D:\Windows Temp Files" for example).
|
||||
// So we just redirect to a file and read it afterwards as we know it will be ucs2 encoded.
|
||||
const options = {
|
||||
// Close the file once it's created
|
||||
discardDescriptor: true,
|
||||
// Wmic fails with "Invalid global switch" when the "/output:" switch filename contains a dash ("-")
|
||||
prefix: 'tmp',
|
||||
};
|
||||
return using(tmpFileDisposer(options), async ({ path }) => {
|
||||
const command = [
|
||||
join(env.SystemRoot as string, 'System32', 'Wbem', 'wmic'),
|
||||
'path',
|
||||
'Win32_LogicalDisk',
|
||||
'Where',
|
||||
'DriveType="4"',
|
||||
'get',
|
||||
'DeviceID,ProviderName',
|
||||
'>',
|
||||
`"${path}"`,
|
||||
];
|
||||
await execAsync(command.join(' '), { windowsHide: true });
|
||||
return readFileAsync(path, 'ucs2');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary returns a Map of drive letter -> network locations on Windows: 'Z:' -> '\\\\192.168.0.1\\Public'
|
||||
*/
|
||||
async function getWindowsNetworkDrives(): Promise<Map<string, string>> {
|
||||
// Use getWindowsNetworkDrives from "exports." so it can be mocked in tests
|
||||
const result = await exports.getWmicNetworkDrivesOutput();
|
||||
const couples: Array<[string, string]> = chain(result)
|
||||
.split('\n')
|
||||
// Remove header line
|
||||
.slice(1)
|
||||
// Remove extra spaces / tabs / carriage returns
|
||||
.invokeMap(String.prototype.trim)
|
||||
// Filter out empty lines
|
||||
.compact()
|
||||
.map((str: string): [string, string] => {
|
||||
const colonPosition = str.indexOf(':');
|
||||
if (colonPosition === -1) {
|
||||
throw new Error(`Can't parse wmic output: ${result}`);
|
||||
}
|
||||
return [
|
||||
str.slice(0, colonPosition + 1),
|
||||
trim(str.slice(colonPosition + 1)),
|
||||
];
|
||||
})
|
||||
.filter(couple => couple[1].length > 0)
|
||||
.value();
|
||||
return new Map(couples);
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Replaces network drive letter with network drive location in the provided filePath on Windows
|
||||
*/
|
||||
export async function replaceWindowsNetworkDriveLetter(
|
||||
filePath: string,
|
||||
): Promise<string> {
|
||||
let result = filePath;
|
||||
if (platform() === 'win32') {
|
||||
const matches = /^([A-Z]+:)\\(.*)$/.exec(filePath);
|
||||
if (matches !== null) {
|
||||
const [, drive, relativePath] = matches;
|
||||
const drives = await getWindowsNetworkDrives();
|
||||
const location = drives.get(drive);
|
||||
if (location !== undefined) {
|
||||
result = `${location}\\${relativePath}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
20
npm-shrinkwrap.json
generated
20
npm-shrinkwrap.json
generated
@ -1193,9 +1193,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "6.14.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.9.tgz",
|
||||
"integrity": "sha512-leP/gxHunuazPdZaCvsCefPQxinqUDsCxCR5xaDUrY2MkYxQRFZZwU5e7GojyYsGB7QVtCi7iVEl/hoFXQYc+w=="
|
||||
"version": "12.12.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.24.tgz",
|
||||
"integrity": "sha512-1Ciqv9pqwVtW6FsIUKSZNB82E5Cu1I2bBTj1xuIHXLe/1zYLl3956Nbhg2MzSYHVfl9/rmanjbQIb7LibfCnug=="
|
||||
},
|
||||
"@types/normalize-package-data": {
|
||||
"version": "2.4.0",
|
||||
@ -6054,6 +6054,13 @@
|
||||
"unzip-stream": "^0.3.0",
|
||||
"xxhash": "^0.3.0",
|
||||
"yauzl": "^2.9.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "6.14.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.9.tgz",
|
||||
"integrity": "sha512-leP/gxHunuazPdZaCvsCefPQxinqUDsCxCR5xaDUrY2MkYxQRFZZwU5e7GojyYsGB7QVtCi7iVEl/hoFXQYc+w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"event-emitter": {
|
||||
@ -10037,6 +10044,13 @@
|
||||
"@types/node": "^6.0.112",
|
||||
"@types/usb": "^1.5.1",
|
||||
"debug": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "6.14.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.9.tgz",
|
||||
"integrity": "sha512-leP/gxHunuazPdZaCvsCefPQxinqUDsCxCR5xaDUrY2MkYxQRFZZwU5e7GojyYsGB7QVtCi7iVEl/hoFXQYc+w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-releases": {
|
||||
|
@ -94,6 +94,7 @@
|
||||
"@babel/plugin-proposal-function-bind": "^7.2.0",
|
||||
"@babel/preset-env": "^7.6.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@types/node": "^12.12.24",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"babel-loader": "^8.0.4",
|
||||
"chalk": "^1.1.3",
|
||||
|
@ -22,6 +22,7 @@ const m = require('mochainon')
|
||||
const { env } = require('process')
|
||||
const { promisify } = require('util')
|
||||
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const wnd = require('../../../lib/gui/app/os/windows-network-drives')
|
||||
|
||||
const readFileAsync = promisify(readFile)
|
||||
|
Loading…
x
Reference in New Issue
Block a user