为了简单起见,我将基于XUL的Firefox插件转换为基于SDK的版本。我在基于XUL的版本中使用的XPCOM模块似乎有效但ci.nsIFile的行为却不同。
我无法弄清楚如何导航到目前位于目录最高级别的smartProxy.py。
在XUL版本中,smartProxy.py位于chrome / bin / smartproxy.py上。我使用下面的命令来执行程序,它可以正常工作。
getExeFile: function() {
var file = cc["@mozilla.org/file/directory_service;1"].getService(ci.nsIProperties).get("ProfD", ci.nsIFile);
file.append("smartProxy.py");
return file;
},
下面是它执行的地方,应该可以全面了解附加组件的工作原理。
start: function() {
if (this.process && this.process.isRunning)
return;
this.process = cc["@mozilla.org/process/util;1"].createInstance(ci.nsIProcess);
this.process.init(this.getExeFile());
this.process.runAsync([], 0, this.processObserver);
this.setProxy();
this.executeObservers();
},
如何查找smartProxy.py以便执行它?
答案 0 :(得分:5)
目前只能使用nsIProcess
API支持从Firefox运行外部命令。你已经为自己想出了这一点。
SDK只会打包某些文件/位置。将python脚本放在data/
文件夹中是最简单的,因为这是SDK将所有文件打包的位置之一。
nsIProcess
需要一个可执行文件,该文件实际上需要是一个真实文件(不仅仅是XPI中包含的内容,默认情况下不会解压缩)。
因此我们可能需要处理两种情况:
以下代码处理两者。我测试了它,它适用于OSX(* nix,因此也适用于Linux或BSD)和Windows,有和没有em:unpack(你应该避免em:unpack)。
const self = require("sdk/self");
const {Cc, Ci, Cu} = require("chrome");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
const ChromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIChromeRegistry);
const ResProtoHandler = Services.io.getProtocolHandler("resource").
QueryInterface(Ci.nsIResProtocolHandler);
function copyToTemp(uri, callback) {
// Based on https://stackoverflow.com/a/24850643/484441
let file = Services.dirsvc.get("TmpD", Ci.nsIFile);
file.append(self.name + "_" + uri.spec.replace(/^.+\//, ""));
file.createUnique(Ci.nsIFile, 0o0700);
NetUtil.asyncFetch(uri, function(istream) {
let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream);
ostream.init(file, -1, -1, Ci.nsIFileOutputStream.DEFER_OPEN);
NetUtil.asyncCopy(istream, ostream, function(result) {
callback && callback(file, result);
});
});
}
function runProcessAndThen(file, callback) {
console.log("running", file.path);
let proc = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
try {
// Set executable bit on unix
file.permissions = file.permissions | 0o0500;
}
catch (ex) {
// Might throw?!
}
proc.init(file);
proc.runAsync([], 0, callback);
}
function runFromURIWithPotentialCopy(uri, callback) {
if (!uri.spec) {
uri = Services.io.newURI(uri, null, null);
}
if (uri.scheme === "resource") {
// Need to resolve futher. Strip one layer of indirection and recursively
// call ourselves.
uri = Services.io.newURI(ResProtoHandler.resolveURI(uri), null, null);
return runFromURIWithPotentialCopy(uri, callback);
}
if (uri.scheme === "chrome") {
// Need to resolve futher. Strip one layer of indirection and recursively
// call ourselves.
return runFromURIWithPotentialCopy(ChromeRegistry.convertChromeURL(uri), callback);
}
if (uri instanceof Ci.nsIFileURL) {
// A plain file we can execute directly.
return runProcessAndThen(uri.file, callback);
}
if (uri instanceof Ci.nsIJARURI) {
// A packaged file (in an XPI most likely).
// Need to copy the data into some plain file and run the result.
return copyToTemp(uri, function(f) {
runProcessAndThen(f, function() {
try {
// Clean up after ourselves.
f.remove(false);
}
catch (ex) {
console.error("Failed to remove tmp file again", ex);
}
callback.apply(null, arguments);
});
});
}
throw new Error("Cannot handle URI");
}
function afterRun(subject, topic, data) {
console.log(subject, topic, data);
}
function runFileFromDataDirectory(name, callback) {
try {
runFromURIWithPotentialCopy(self.data.url(name), callback);
}
catch (ex) {
console.error(ex);
}
}
runFileFromDataDirectory("test.py", afterRun);
运行脚本(而不是完整的二进制文件)可能很棘手。在Python的情况下,例如* nix操作系统需要被告知有一个解释器,这是什么,由shebang完成。
在Windows上,Python需要安装.py
文件类型注册,默认安装程序将执行此操作,但不是" portable"版本"
答案 1 :(得分:2)
https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/self
var self = require("sdk/self");
var py = self.data.url("my-panel-content.html")