mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-20 09:35:38 -05:00
Merge from master
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
</head>
|
||||
|
||||
<body aria-label="">
|
||||
<div id="process-list"></div>
|
||||
<table id="process-list" aria-live="polite"></table>
|
||||
</body>
|
||||
|
||||
<!-- Startup via processExplorer.js -->
|
||||
|
||||
@@ -3,182 +3,11 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const remote = require('electron').remote;
|
||||
const bootstrapWindow = require('../../../../bootstrap-window');
|
||||
|
||||
function assign(destination, source) {
|
||||
return Object.keys(source)
|
||||
.reduce(function (r, key) { r[key] = source[key]; return r; }, destination);
|
||||
}
|
||||
|
||||
function parseURLQueryArgs() {
|
||||
const search = window.location.search || '';
|
||||
|
||||
return search.split(/[?&]/)
|
||||
.filter(function (param) { return !!param; })
|
||||
.map(function (param) { return param.split('='); })
|
||||
.filter(function (param) { return param.length === 2; })
|
||||
.reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {});
|
||||
}
|
||||
|
||||
function uriFromPath(_path) {
|
||||
var pathName = path.resolve(_path).replace(/\\/g, '/');
|
||||
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
|
||||
pathName = '/' + pathName;
|
||||
}
|
||||
|
||||
return encodeURI('file://' + pathName);
|
||||
}
|
||||
|
||||
function readFile(file) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c()));
|
||||
|
||||
function main() {
|
||||
const args = parseURLQueryArgs();
|
||||
const configuration = JSON.parse(args['config'] || '{}') || {};
|
||||
|
||||
assign(process.env, configuration.userEnv);
|
||||
|
||||
//#region Add support for using node_modules.asar
|
||||
(function () {
|
||||
const path = require('path');
|
||||
const Module = require('module');
|
||||
let NODE_MODULES_PATH = path.join(configuration.appRoot, 'node_modules');
|
||||
if (/[a-z]\:/.test(NODE_MODULES_PATH)) {
|
||||
// Make drive letter uppercase
|
||||
NODE_MODULES_PATH = NODE_MODULES_PATH.charAt(0).toUpperCase() + NODE_MODULES_PATH.substr(1);
|
||||
}
|
||||
const NODE_MODULES_ASAR_PATH = NODE_MODULES_PATH + '.asar';
|
||||
|
||||
const originalResolveLookupPaths = Module._resolveLookupPaths;
|
||||
Module._resolveLookupPaths = function (request, parent, newReturn) {
|
||||
const result = originalResolveLookupPaths(request, parent, newReturn);
|
||||
|
||||
const paths = newReturn ? result : result[1];
|
||||
for (let i = 0, len = paths.length; i < len; i++) {
|
||||
if (paths[i] === NODE_MODULES_PATH) {
|
||||
paths.splice(i, 0, NODE_MODULES_ASAR_PATH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
//#endregion
|
||||
|
||||
// Get the nls configuration into the process.env as early as possible.
|
||||
var nlsConfig = { availableLanguages: {} };
|
||||
const config = process.env['VSCODE_NLS_CONFIG'];
|
||||
if (config) {
|
||||
process.env['VSCODE_NLS_CONFIG'] = config;
|
||||
try {
|
||||
nlsConfig = JSON.parse(config);
|
||||
} catch (e) { /*noop*/ }
|
||||
}
|
||||
|
||||
if (nlsConfig._resolvedLanguagePackCoreLocation) {
|
||||
let bundles = Object.create(null);
|
||||
nlsConfig.loadBundle = function(bundle, language, cb) {
|
||||
let result = bundles[bundle];
|
||||
if (result) {
|
||||
cb(undefined, result);
|
||||
return;
|
||||
}
|
||||
let bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, bundle.replace(/\//g, '!') + '.nls.json');
|
||||
readFile(bundleFile).then(function (content) {
|
||||
let json = JSON.parse(content);
|
||||
bundles[bundle] = json;
|
||||
cb(undefined, json);
|
||||
}).catch((error) => {
|
||||
try {
|
||||
if (nlsConfig._corruptedFile) {
|
||||
writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); });
|
||||
}
|
||||
} finally {
|
||||
cb(error, undefined);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
var locale = nlsConfig.availableLanguages['*'] || 'en';
|
||||
if (locale === 'zh-tw') {
|
||||
locale = 'zh-Hant';
|
||||
} else if (locale === 'zh-cn') {
|
||||
locale = 'zh-Hans';
|
||||
}
|
||||
|
||||
window.document.documentElement.setAttribute('lang', locale);
|
||||
|
||||
const extractKey = function (e) {
|
||||
return [
|
||||
e.ctrlKey ? 'ctrl-' : '',
|
||||
e.metaKey ? 'meta-' : '',
|
||||
e.altKey ? 'alt-' : '',
|
||||
e.shiftKey ? 'shift-' : '',
|
||||
e.keyCode
|
||||
].join('');
|
||||
};
|
||||
|
||||
const TOGGLE_DEV_TOOLS_KB = (process.platform === 'darwin' ? 'meta-alt-73' : 'ctrl-shift-73'); // mac: Cmd-Alt-I, rest: Ctrl-Shift-I
|
||||
const RELOAD_KB = (process.platform === 'darwin' ? 'meta-82' : 'ctrl-82'); // mac: Cmd-R, rest: Ctrl-R
|
||||
|
||||
window.addEventListener('keydown', function (e) {
|
||||
const key = extractKey(e);
|
||||
if (key === TOGGLE_DEV_TOOLS_KB) {
|
||||
remote.getCurrentWebContents().toggleDevTools();
|
||||
} else if (key === RELOAD_KB) {
|
||||
remote.getCurrentWindow().reload();
|
||||
}
|
||||
});
|
||||
|
||||
// Load the loader
|
||||
const loaderFilename = configuration.appRoot + '/out/vs/loader.js';
|
||||
const loaderSource = fs.readFileSync(loaderFilename);
|
||||
require('vm').runInThisContext(loaderSource, { filename: loaderFilename });
|
||||
var define = global.define;
|
||||
global.define = undefined;
|
||||
|
||||
window.nodeRequire = require.__$__nodeRequire;
|
||||
|
||||
define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
|
||||
|
||||
window.MonacoEnvironment = {};
|
||||
const rootUrl = uriFromPath(configuration.appRoot) + '/out';
|
||||
|
||||
require.config({
|
||||
baseUrl: rootUrl,
|
||||
'vs/nls': nlsConfig,
|
||||
nodeCachedDataDir: configuration.nodeCachedDataDir,
|
||||
nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
|
||||
});
|
||||
|
||||
if (nlsConfig.pseudo) {
|
||||
require(['vs/nls'], function (nlsPlugin) {
|
||||
nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
|
||||
});
|
||||
}
|
||||
|
||||
require([
|
||||
'vs/code/electron-browser/processExplorer/processExplorerMain'
|
||||
], function (processExplorer) {
|
||||
processExplorer.startup(configuration.data);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
bootstrapWindow.load(['vs/code/electron-browser/processExplorer/processExplorerMain'], function (processExplorer, configuration) {
|
||||
processExplorer.startup(configuration.data);
|
||||
}, { forceEnableDeveloperKeybindings: true });
|
||||
@@ -3,11 +3,9 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./media/processExplorer';
|
||||
import { listProcesses, ProcessItem } from 'vs/base/node/ps';
|
||||
import { remote, webFrame, ipcRenderer, clipboard } from 'electron';
|
||||
import { webFrame, ipcRenderer, clipboard } from 'electron';
|
||||
import { repeat } from 'vs/base/common/strings';
|
||||
import { totalmem } from 'os';
|
||||
import product from 'vs/platform/node/product';
|
||||
@@ -15,10 +13,15 @@ import { localize } from 'vs/nls';
|
||||
import { ProcessExplorerStyles, ProcessExplorerData } from 'vs/platform/issue/common/issue';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu';
|
||||
import { popup } from 'vs/base/parts/contextmenu/electron-browser/contextmenu';
|
||||
|
||||
let processList: any[];
|
||||
let mapPidToWindowTitle = new Map<number, string>();
|
||||
|
||||
const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/;
|
||||
const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/;
|
||||
|
||||
function getProcessList(rootProcess: ProcessItem) {
|
||||
const processes: any[] = [];
|
||||
|
||||
@@ -62,6 +65,40 @@ function getProcessItem(processes: any[], item: ProcessItem, indent: number): vo
|
||||
}
|
||||
}
|
||||
|
||||
function isDebuggable(cmd: string): boolean {
|
||||
const matches = DEBUG_FLAGS_PATTERN.exec(cmd);
|
||||
return (matches && matches.length >= 2) || cmd.indexOf('node ') >= 0 || cmd.indexOf('node.exe') >= 0;
|
||||
}
|
||||
|
||||
function attachTo(item: ProcessItem) {
|
||||
const config: any = {
|
||||
type: 'node',
|
||||
request: 'attach',
|
||||
name: `process ${item.pid}`
|
||||
};
|
||||
|
||||
let matches = DEBUG_FLAGS_PATTERN.exec(item.cmd);
|
||||
if (matches && matches.length >= 2) {
|
||||
// attach via port
|
||||
if (matches.length === 4 && matches[3]) {
|
||||
config.port = parseInt(matches[3]);
|
||||
}
|
||||
config.protocol = matches[1] === 'debug' ? 'legacy' : 'inspector';
|
||||
} else {
|
||||
// no port -> try to attach via pid (send SIGUSR1)
|
||||
config.processId = String(item.pid);
|
||||
}
|
||||
|
||||
// a debug-port=n or inspect-port=n overrides the port
|
||||
matches = DEBUG_PORT_PATTERN.exec(item.cmd);
|
||||
if (matches && matches.length === 3) {
|
||||
// override port
|
||||
config.port = parseInt(matches[2]);
|
||||
}
|
||||
|
||||
ipcRenderer.send('vscode:workbenchCommand', { id: 'workbench.action.debug.start', from: 'processExplorer', args: [config] });
|
||||
}
|
||||
|
||||
function getProcessIdWithHighestProperty(processList, propertyName: string) {
|
||||
let max = 0;
|
||||
let maxProcessId;
|
||||
@@ -77,16 +114,24 @@ function getProcessIdWithHighestProperty(processList, propertyName: string) {
|
||||
|
||||
function updateProcessInfo(processList): void {
|
||||
const target = document.getElementById('process-list');
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
const highestCPUProcess = getProcessIdWithHighestProperty(processList, 'cpu');
|
||||
const highestMemoryProcess = getProcessIdWithHighestProperty(processList, 'memory');
|
||||
|
||||
let tableHtml = `
|
||||
<tr>
|
||||
<th class="cpu">${localize('cpu', "CPU %")}</th>
|
||||
<th class="memory">${localize('memory', "Memory (MB)")}</th>
|
||||
<th class="pid">${localize('pid', "pid")}</th>
|
||||
<th class="nameLabel">${localize('name', "Name")}</th>
|
||||
</tr>`;
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="cpu">${localize('cpu', "CPU %")}</th>
|
||||
<th scope="col" class="memory">${localize('memory', "Memory (MB)")}</th>
|
||||
<th scope="col" class="pid">${localize('pid', "pid")}</th>
|
||||
<th scope="col" class="nameLabel">${localize('name', "Name")}</th>
|
||||
</tr>
|
||||
</thead>`;
|
||||
|
||||
tableHtml += `<tbody>`;
|
||||
|
||||
processList.forEach(p => {
|
||||
const cpuClass = p.pid === highestCPUProcess ? 'highest' : '';
|
||||
@@ -101,7 +146,9 @@ function updateProcessInfo(processList): void {
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
target.innerHTML = `<table>${tableHtml}</table>`;
|
||||
tableHtml += `</tbody>`;
|
||||
|
||||
target.innerHTML = tableHtml;
|
||||
}
|
||||
|
||||
function applyStyles(styles: ProcessExplorerStyles): void {
|
||||
@@ -121,7 +168,9 @@ function applyStyles(styles: ProcessExplorerStyles): void {
|
||||
}
|
||||
|
||||
styleTag.innerHTML = content.join('\n');
|
||||
document.head.appendChild(styleTag);
|
||||
if (document.head) {
|
||||
document.head.appendChild(styleTag);
|
||||
}
|
||||
document.body.style.color = styles.color;
|
||||
}
|
||||
|
||||
@@ -137,29 +186,29 @@ function applyZoom(zoomLevel: number): void {
|
||||
function showContextMenu(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const menu = new remote.Menu();
|
||||
const items: IContextMenuItem[] = [];
|
||||
|
||||
const pid = parseInt(e.currentTarget.id);
|
||||
if (pid && typeof pid === 'number') {
|
||||
menu.append(new remote.MenuItem({
|
||||
items.push({
|
||||
label: localize('killProcess', "Kill Process"),
|
||||
click() {
|
||||
process.kill(pid, 'SIGTERM');
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
menu.append(new remote.MenuItem({
|
||||
items.push({
|
||||
label: localize('forceKillProcess', "Force Kill Process"),
|
||||
click() {
|
||||
process.kill(pid, 'SIGKILL');
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
menu.append(new remote.MenuItem({
|
||||
items.push({
|
||||
type: 'separator'
|
||||
}));
|
||||
});
|
||||
|
||||
menu.append(new remote.MenuItem({
|
||||
items.push({
|
||||
label: localize('copy', "Copy"),
|
||||
click() {
|
||||
const row = document.getElementById(pid.toString());
|
||||
@@ -167,9 +216,9 @@ function showContextMenu(e) {
|
||||
clipboard.writeText(row.innerText);
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
menu.append(new remote.MenuItem({
|
||||
items.push({
|
||||
label: localize('copyAll', "Copy All"),
|
||||
click() {
|
||||
const processList = document.getElementById('process-list');
|
||||
@@ -177,9 +226,23 @@ function showContextMenu(e) {
|
||||
clipboard.writeText(processList.innerText);
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
const item = processList.filter(process => process.pid === pid)[0];
|
||||
if (item && isDebuggable(item.cmd)) {
|
||||
items.push({
|
||||
type: 'separator'
|
||||
});
|
||||
|
||||
items.push({
|
||||
label: localize('debug', "Debug"),
|
||||
click() {
|
||||
attachTo(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
menu.append(new remote.MenuItem({
|
||||
items.push({
|
||||
label: localize('copyAll', "Copy All"),
|
||||
click() {
|
||||
const processList = document.getElementById('process-list');
|
||||
@@ -187,10 +250,10 @@ function showContextMenu(e) {
|
||||
clipboard.writeText(processList.innerText);
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
menu.popup({ window: remote.getCurrentWindow() });
|
||||
popup(items);
|
||||
}
|
||||
|
||||
export function startup(data: ProcessExplorerData): void {
|
||||
@@ -198,7 +261,7 @@ export function startup(data: ProcessExplorerData): void {
|
||||
applyZoom(data.zoomLevel);
|
||||
|
||||
// Map window process pids to titles, annotate process names with this when rendering to distinguish between them
|
||||
ipcRenderer.on('windowsInfoResponse', (event, windows) => {
|
||||
ipcRenderer.on('vscode:windowsInfoResponse', (event, windows) => {
|
||||
mapPidToWindowTitle = new Map<number, string>();
|
||||
windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title));
|
||||
});
|
||||
@@ -206,7 +269,7 @@ export function startup(data: ProcessExplorerData): void {
|
||||
setInterval(() => {
|
||||
ipcRenderer.send('windowsInfoRequest');
|
||||
|
||||
listProcesses(remote.process.pid).then(processes => {
|
||||
listProcesses(data.pid).then(processes => {
|
||||
processList = getProcessList(processes);
|
||||
updateProcessInfo(processList);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user