kopia lustrzana https://github.com/c9/core
Merge pull request +15340 from c9/process-list
backport preview changes from v4pull/198/merge
commit
11ab9610b9
|
@ -192,7 +192,7 @@ define(function(require, exports, module) {
|
|||
var panels = navigation && navigation.$ext && navigation.$ext.children;
|
||||
if (panels) {
|
||||
for (var i = 0; i < panels.length; i++) {
|
||||
if (panels[i].name == panel) {
|
||||
if (panels[i].name == panel || panels[i].name == "preferences." + panel) {
|
||||
panel = panels[i].hostPlugin;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -64,27 +64,8 @@ define(function(require, exports, module) {
|
|||
if (!options.hideButton) {
|
||||
var submenu = new ui.menu({
|
||||
"onprop.visible": function(e) {
|
||||
var tab = tabs.focussedTab;
|
||||
var isKnown = false;
|
||||
|
||||
if (tab && tab.path) {
|
||||
var path = tab.path;
|
||||
for (var name in previewers) {
|
||||
if (previewers[name].matcher(path)) {
|
||||
isKnown = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
liveMenuItem.setAttribute("caption", isKnown
|
||||
? "Live Preview File (" + basename(path) + ")"
|
||||
: "Raw Content of " + basename(path)
|
||||
);
|
||||
liveMenuItem.enable();
|
||||
}
|
||||
else {
|
||||
liveMenuItem.disable();
|
||||
}
|
||||
if (e.value)
|
||||
updatePreviewMenu(e, submenu);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -99,7 +80,7 @@ define(function(require, exports, module) {
|
|||
|
||||
menus.addItemByPath("Tools/Preview/", submenu, 1000, handle);
|
||||
liveMenuItem = new ui.item({
|
||||
onclick: function(e) { commands.exec("preview", { newTab: e && e.button == 1 }); }
|
||||
onclick: function(e) { commands.exec("preview", null, { newTab: e && e.button == 1 }); }
|
||||
});
|
||||
menus.addItemByPath("Tools/Preview/Live Preview Files",
|
||||
liveMenuItem, 100, handle);
|
||||
|
@ -111,6 +92,14 @@ define(function(require, exports, module) {
|
|||
});
|
||||
}
|
||||
}), 200, handle);
|
||||
menus.addItemByPath("Tools/Preview/~", new ui.divider({}), 2000, handle);
|
||||
menus.addItemByPath("Tools/Preview/~", new ui.divider({}), 4000, handle);
|
||||
menus.addItemByPath("Tools/Preview/Configure Preview URL...", new ui.item({
|
||||
onclick: function(e) { commands.exec("openpreferences", null, {panel: "project", section: "Run & Debug"}); }
|
||||
}), 4200, handle);
|
||||
menus.addItemByPath("Tools/Preview/Show Active Servers...", new ui.item({
|
||||
onclick: function(e) { commands.exec("showprocesslist", null, { mode: "lsof" }); }
|
||||
}), 4300, handle);
|
||||
}
|
||||
|
||||
settings.on("read", function(e) {
|
||||
|
@ -122,18 +111,18 @@ define(function(require, exports, module) {
|
|||
}, handle);
|
||||
|
||||
// Context menu for tree
|
||||
var itemCtxTreePreview = new ui.item({
|
||||
match: "file",
|
||||
caption: "Preview",
|
||||
isAvailable: function() {
|
||||
return tree.selectedNode && !tree.selectedNode.isFolder
|
||||
&& (options.local || util.normalizePath(tree.selectedNode.path).charAt(0) != "~");
|
||||
},
|
||||
onclick: function() {
|
||||
openPreview(tree.selected);
|
||||
}
|
||||
});
|
||||
tree.getElement("mnuCtxTree", function(mnuCtxTree) {
|
||||
var itemCtxTreePreview = new ui.item({
|
||||
match: "file",
|
||||
caption: "Preview",
|
||||
isAvailable: function() {
|
||||
return tree.selectedNode && !tree.selectedNode.isFolder
|
||||
&& (options.local || util.normalizePath(tree.selectedNode.path).charAt(0) != "~");
|
||||
},
|
||||
onclick: function() {
|
||||
openPreview(tree.selected);
|
||||
}
|
||||
});
|
||||
ui.insertByIndex(mnuCtxTree, itemCtxTreePreview, 160, handle);
|
||||
});
|
||||
|
||||
|
@ -163,70 +152,30 @@ define(function(require, exports, module) {
|
|||
var nodes = tab.pane.group;
|
||||
if (!nodes)
|
||||
pane = tab.pane.hsplit(true);
|
||||
else {
|
||||
else
|
||||
pane = nodes[nodes.indexOf(tab.pane) === 0 ? 1 : 0];
|
||||
}
|
||||
}
|
||||
|
||||
return pane;
|
||||
}
|
||||
|
||||
if (args.server) {
|
||||
var hostname = c9.hostname || "localhost:8080";
|
||||
var openInNewTab = args.newTab;
|
||||
path = args.url;
|
||||
|
||||
var cb = function(err, stderr, stdout) {
|
||||
if (err && err.code != 1)
|
||||
showError("Could not check if server is running.");
|
||||
else if (stderr || !stdout || !stdout.length) {
|
||||
|
||||
// Check for project run config
|
||||
var json = settings.getJson("project/run/configs") || {};
|
||||
for (var name in json) {
|
||||
if (json[name]["default"]) {
|
||||
commands.exec("run", null, {
|
||||
callback: function(proc) {
|
||||
proc.on("started", function() {
|
||||
setTimeout(done, 1000);
|
||||
});
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
warnNoServer(hostname);
|
||||
}
|
||||
|
||||
done();
|
||||
};
|
||||
if (!path)
|
||||
path = "https://$C9_HOSTNAME";
|
||||
|
||||
function done() {
|
||||
var path = (options.local ? "http" : "https")
|
||||
+ "://" + hostname;
|
||||
if (args.newTab)
|
||||
return util.openNewWindow(path);
|
||||
|
||||
// Open Pane
|
||||
pane = findPane();
|
||||
|
||||
// Open Preview
|
||||
openPreview(path, pane, args && args.active);
|
||||
}
|
||||
path = expandUrl(path);
|
||||
|
||||
if (args.nocheck)
|
||||
done();
|
||||
else if (options.local) {
|
||||
proc.execFile("lsof", {
|
||||
args: ["-i", ":8080"]
|
||||
}, cb);
|
||||
}
|
||||
else {
|
||||
proc.execFile("nc", {
|
||||
args: ["-zv", hostname, "80"]
|
||||
}, cb);
|
||||
}
|
||||
if (window.location.protocol == "https:" && !path.startsWith("https:"))
|
||||
openInNewTab = true;
|
||||
|
||||
return;
|
||||
if (openInNewTab)
|
||||
return util.openNewWindow(path);
|
||||
|
||||
pane = findPane();
|
||||
return openPreview(path, pane, args && args.active);
|
||||
}
|
||||
else if (args.path) {
|
||||
path = args.path;
|
||||
|
@ -284,6 +233,20 @@ define(function(require, exports, module) {
|
|||
var key = commands.getHotkey("reloadpreview");
|
||||
if (commands.platform == "mac")
|
||||
key = apf.hotkeys.toMacNotation(key);
|
||||
|
||||
prefs.add({
|
||||
"Project": {
|
||||
position: 100,
|
||||
"Run & Debug": {
|
||||
position: 300,
|
||||
"Preview URL": {
|
||||
type: "textbox",
|
||||
path: "project/preview/@url"
|
||||
},
|
||||
}
|
||||
}
|
||||
}, handle);
|
||||
|
||||
prefs.add({
|
||||
"Run": {
|
||||
position: 600,
|
||||
|
@ -312,7 +275,7 @@ define(function(require, exports, module) {
|
|||
{ caption: "Only on " + key, value: "false" },
|
||||
{ caption: "Always", value: "true" },
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}, handle);
|
||||
|
@ -357,6 +320,13 @@ define(function(require, exports, module) {
|
|||
return pane;
|
||||
}
|
||||
|
||||
function expandUrl(url) {
|
||||
var hostname = c9.hostname;
|
||||
if (!c9.hosted && !hostname)
|
||||
hostname = window.location.hostname;
|
||||
return url.replace(/\$C9_HOSTNAME\b/, hostname);
|
||||
}
|
||||
|
||||
function registerPlugin(plugin, matcher) {
|
||||
previewers[plugin.name] = {
|
||||
plugin: plugin,
|
||||
|
@ -409,6 +379,73 @@ define(function(require, exports, module) {
|
|||
+ "and change the hostname in the location bar.");
|
||||
}
|
||||
|
||||
function updatePreviewMenu(e, submenu) {
|
||||
var tab = tabs.focussedTab;
|
||||
var isKnown = false;
|
||||
var title = "Live Preview File";
|
||||
if (tab && tab.path) {
|
||||
var path = tab.path;
|
||||
for (var name in previewers) {
|
||||
if (previewers[name].matcher(path)) {
|
||||
isKnown = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isKnown) {
|
||||
title = "Raw Content of " + basename(path);
|
||||
isKnown = true;
|
||||
}
|
||||
else {
|
||||
title += " (" + basename(path) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
liveMenuItem.setAttribute("caption", title);
|
||||
if (isKnown)
|
||||
liveMenuItem.enable();
|
||||
else
|
||||
liveMenuItem.disable();
|
||||
// user configured elements
|
||||
var url = settings.get("project/preview/@url");
|
||||
if (!Array.isArray(url)) url = [url];
|
||||
var added = false;
|
||||
var index = 0;
|
||||
var children = submenu.childNodes;
|
||||
while (children[index] && children[index].localName != "divider") {
|
||||
index++;
|
||||
}
|
||||
var appMenu = children[index - 1];
|
||||
var firstDivider = children[index];
|
||||
index++;
|
||||
for (var i = 0; i < url.length; i++) {
|
||||
if (typeof url[i] != "string" || !url[i]) continue;
|
||||
var oldNode = children[index];
|
||||
if (!oldNode || oldNode.localName != "item") {
|
||||
oldNode = submenu.insertBefore(new ui.item({
|
||||
onclick: openUrl
|
||||
}), oldNode);
|
||||
}
|
||||
oldNode.value = url[i];
|
||||
var caption = "Open " + expandUrl(url[i]);
|
||||
oldNode.setAttribute("caption", caption);
|
||||
added = true;
|
||||
index++;
|
||||
}
|
||||
while(index < children.length - 3)
|
||||
submenu.removeChild(children[index]);
|
||||
|
||||
appMenu.setAttribute("visible", !added);
|
||||
firstDivider.setAttribute("visible", added);
|
||||
|
||||
function openUrl(e) {
|
||||
commands.exec("preview", null, {
|
||||
newTab: e.button == 1,
|
||||
url: e.currentTarget.value,
|
||||
server: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The preview handle, responsible for managing preview plugins.
|
||||
* This is the object you get when you request the preview
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(function(require, exports, module) {
|
||||
main.consumes = [
|
||||
"ui", "layout", "commands", "Dialog", "proc", "util", "menus"
|
||||
"ui", "layout", "commands", "Dialog", "proc", "util", "menus", "dialog.error"
|
||||
];
|
||||
main.provides = ["processlist"];
|
||||
return main;
|
||||
|
@ -15,6 +15,7 @@ define(function(require, exports, module) {
|
|||
var proc = imports.proc;
|
||||
var util = imports.util;
|
||||
var menus = imports.menus;
|
||||
var showError = imports["dialog.error"].show;
|
||||
|
||||
var search = require("../c9.ide.navigate/search");
|
||||
var Tree = require("ace_tree/tree");
|
||||
|
@ -47,6 +48,8 @@ define(function(require, exports, module) {
|
|||
var INTERVAL = 5000;
|
||||
var model, datagrid, btnKill, btnForceKill, tbFilter, timer;
|
||||
|
||||
var mode = "ps";
|
||||
|
||||
var loaded = false;
|
||||
function load() {
|
||||
if (loaded) return false;
|
||||
|
@ -55,8 +58,8 @@ define(function(require, exports, module) {
|
|||
commands.addCommand({
|
||||
name: "showprocesslist",
|
||||
bindKey: { mac: "Command-Option-P", win: "Ctrl-Alt-P" },
|
||||
exec: function() {
|
||||
plugin.show();
|
||||
exec: function(editor, args) {
|
||||
plugin.show(args.mode || "ps");
|
||||
}
|
||||
}, plugin);
|
||||
|
||||
|
@ -82,10 +85,11 @@ define(function(require, exports, module) {
|
|||
model.$sortNodes = true;
|
||||
|
||||
model.$sorted = true;
|
||||
model.columns = [{
|
||||
model.columnsPs = [{
|
||||
caption: "Process Name",
|
||||
value: "name",
|
||||
width: "100%"
|
||||
width: "100%",
|
||||
type: "tree",
|
||||
}, {
|
||||
caption: "CPU",
|
||||
// value: "cpu",
|
||||
|
@ -99,7 +103,7 @@ define(function(require, exports, module) {
|
|||
}, {
|
||||
caption: "Process Time",
|
||||
value: "ptime",
|
||||
width: "100",
|
||||
width: "50",
|
||||
}, {
|
||||
caption: "PID",
|
||||
value: "pid",
|
||||
|
@ -110,6 +114,30 @@ define(function(require, exports, module) {
|
|||
width: "80",
|
||||
}];
|
||||
|
||||
model.columnsLsof = [{
|
||||
caption: "Address",
|
||||
value: "address",
|
||||
width: "100%",
|
||||
}, {
|
||||
caption: "Process Name",
|
||||
value: "command",
|
||||
width: "80",
|
||||
}, {
|
||||
caption: "Status",
|
||||
value: "status",
|
||||
width: "50",
|
||||
}, {
|
||||
caption: "PID",
|
||||
value: "pid",
|
||||
width: "50",
|
||||
}, {
|
||||
caption: "Type",
|
||||
value: "type",
|
||||
width: "50",
|
||||
}];
|
||||
|
||||
model.columns = model.columnsPs;
|
||||
|
||||
var datagridDiv = pNode.appendChild(document.createElement("div"));
|
||||
datagrid = new Tree(datagridDiv);
|
||||
datagrid.renderer.setTheme({ cssClass: "blackdg" });
|
||||
|
@ -148,50 +176,112 @@ define(function(require, exports, module) {
|
|||
applyFilter();
|
||||
});
|
||||
|
||||
updateProcessList();
|
||||
update();
|
||||
|
||||
emit("draw");
|
||||
}
|
||||
|
||||
/***** Methods *****/
|
||||
|
||||
function update() {
|
||||
if (mode == "ps")
|
||||
updateProcessList();
|
||||
else
|
||||
updateServerList();
|
||||
}
|
||||
|
||||
function updateProcessList() {
|
||||
var sel = datagrid.selection.getSelectedNodes();
|
||||
|
||||
proc.execFile("ps", { args: ["auxc"]}, function(err, stdout, stderr) {
|
||||
setModel(null, model.columnsPs);
|
||||
proc.execFile("ps", { args: ["axh", "-ouser,pid:1,ppid:1,pcpu:1,pmem:1,time:1,command:1"] }, function(err, stdout, stderr) {
|
||||
if (err) return;
|
||||
var hiddenRegex = /^\[kthreadd|/
|
||||
|
||||
var lines = stdout.substr(0, stdout.length - 1).split("\n"); lines.shift();
|
||||
var oldNodes = model.pidMap;
|
||||
if (!oldNodes || oldNodes.mode != mode)
|
||||
oldNodes = { mode: mode };
|
||||
var pidMap = model.pidMap = { mode: mode };
|
||||
|
||||
var lines = stdout.substr(0, stdout.length - 1).split("\n");
|
||||
var json = lines.map(function(line) {
|
||||
var item = line.split(/\s+/);
|
||||
var name = item.splice(10).join(" ");
|
||||
return {
|
||||
name: name,
|
||||
cpu: item[2],
|
||||
mem: item[3],
|
||||
ptime: item[9],
|
||||
pid: item[1],
|
||||
user: item[0]
|
||||
};
|
||||
var name = item.slice(6).join(" ");
|
||||
var pid = item[1];
|
||||
var node = oldNodes[pid] || { pid: pid, isOpen: hiddenRegex.test(name) };
|
||||
pidMap[pid] = node;
|
||||
|
||||
node.cpu = item[3];
|
||||
node.mem = item[4];
|
||||
node.ppid = item[2];
|
||||
node.name = name;
|
||||
node.user = item[0];
|
||||
node.ptime = item[5];
|
||||
|
||||
node.items = node.children = null;
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
var root = [];
|
||||
json.forEach(function(node) {
|
||||
var parent = pidMap[node.ppid];
|
||||
if (!parent) return root.push(node);
|
||||
if (!parent.items) parent.items = [];
|
||||
parent.items.push(node);
|
||||
});
|
||||
json = root;
|
||||
|
||||
setModel(json, model.columnsPs);
|
||||
});
|
||||
}
|
||||
|
||||
function updateServerList() {
|
||||
setModel(null, model.columnsLsof);
|
||||
proc.execFile("bash", { args: ["-c",
|
||||
"sudo -n lsof -P -i -F pcnTtu || lsof -P -i -F pcnTtu"
|
||||
]}, function(err, stdout, stderr) {
|
||||
if (err) return;
|
||||
var json = [];
|
||||
var node;
|
||||
var oldNodes = model.pidMap;
|
||||
if (!oldNodes || oldNodes.mode != mode)
|
||||
oldNodes = { mode: mode };
|
||||
model.pidMap = { mode: mode };
|
||||
stdout.split("\n").forEach(function(part) {
|
||||
if (part[0] == "p") {
|
||||
if (node) json.push(node);
|
||||
var pid = part.slice(1);
|
||||
node = oldNodes[pid] || { pid: pid };
|
||||
model.pidMap[pid] = node;
|
||||
}
|
||||
if (part[0] == "c")
|
||||
node.command = part.slice(1);
|
||||
if (part[0] == "n")
|
||||
node.address = part.slice(1);
|
||||
if (part[0] == "T" && /^TST=/.test(part))
|
||||
node.status = part.slice(4);
|
||||
if (part[0] == "t")
|
||||
node.type = part.slice(1);
|
||||
if (part[0] == "u")
|
||||
node.uid = parseInt(part.slice(1), 10);
|
||||
});
|
||||
if (node) json.push(node);
|
||||
|
||||
setModel(json, model.columnsLsof);
|
||||
});
|
||||
}
|
||||
|
||||
function setModel(json, columns) {
|
||||
if (model.columns != columns) {
|
||||
model.columns = columns;
|
||||
datagrid.setDataProvider(model);
|
||||
if (!json) json = [];
|
||||
}
|
||||
if (json) {
|
||||
model.cachedRoot = json;
|
||||
model.setRoot(json);
|
||||
|
||||
if (model.keyword)
|
||||
applyFilter();
|
||||
|
||||
if (sel) {
|
||||
var nodes = [];
|
||||
var pids = sel.map(function(n) { return n.pid; });
|
||||
|
||||
model.root.items.forEach(function(item) {
|
||||
if (pids.indexOf(item.pid) > -1)
|
||||
nodes.push(item);
|
||||
});
|
||||
datagrid.selection.setSelection(nodes);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (model.keyword)
|
||||
applyFilter();
|
||||
}
|
||||
|
||||
function forceKill() {
|
||||
|
@ -201,22 +291,21 @@ define(function(require, exports, module) {
|
|||
function kill(force) {
|
||||
var nodes = datagrid.selection.getSelectedNodes();
|
||||
if (!nodes.length) return;
|
||||
|
||||
var button = force ? btnForceKill : btnKill;
|
||||
|
||||
async.each(nodes, function(row, next) {
|
||||
if (!/^\d+$/.test(row.pid)) return next();
|
||||
button.disable();
|
||||
|
||||
var args = [];
|
||||
if (force) args.push("-9");
|
||||
args.push(row.pid);
|
||||
|
||||
proc.execFile("kill", { args: args }, function(err, stdout, stderr) {
|
||||
var args = (force ? "" : "-9 ") + row.pid;
|
||||
proc.execFile("bash", {
|
||||
args: ["-c", "sudo -n kill " + args + " || kill " + args]
|
||||
}, function(err, stdout, stderr) {
|
||||
next(err);
|
||||
});
|
||||
}, function(err) {
|
||||
button.enable();
|
||||
if (!err) updateProcessList();
|
||||
if (err) return showError(err);
|
||||
update();
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -235,29 +324,33 @@ define(function(require, exports, module) {
|
|||
}
|
||||
}
|
||||
|
||||
function show(reset, options) {
|
||||
function show(mode, options) {
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
setMode(mode);
|
||||
return plugin.queue(function() {
|
||||
// if (reset || current == -1) {
|
||||
// path = [startPage];
|
||||
// current = 0;
|
||||
// activate(startPage);
|
||||
// }
|
||||
|
||||
}, true);
|
||||
}
|
||||
|
||||
function setMode(val) {
|
||||
if ((val == "ps" || val == "lsof") && mode != val) {
|
||||
mode = val;
|
||||
if (timer) update();
|
||||
}
|
||||
}
|
||||
|
||||
/***** Lifecycle *****/
|
||||
|
||||
plugin.on("show", function() {
|
||||
timer = setInterval(function() {
|
||||
updateProcessList();
|
||||
update();
|
||||
}, INTERVAL);
|
||||
update();
|
||||
});
|
||||
plugin.on("hide", function() {
|
||||
clearInterval(timer);
|
||||
timer = clearInterval(timer);
|
||||
});
|
||||
plugin.on("draw", function(options) {
|
||||
draw(options);
|
||||
|
|
Ładowanie…
Reference in New Issue