在Firefox附加目录中选择一个文件

时间:2014-07-23 02:23:34

标签: javascript firefox firefox-addon firefox-addon-sdk

为了简单起见,我将基于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以便执行它?

2 个答案:

答案 0 :(得分:5)

目前只能使用nsIProcess API支持从Firefox运行外部命令。你已经为自己想出了这一点。

打包python脚本。

SDK只会打包某些文件/位置。将python脚本放在data/文件夹中是最简单的,因为这是SDK将所有文件打包的位置之一。

nsIProcess

nsIProcess需要一个可执行文件,该文件实际上需要是一个真实文件(不仅仅是XPI中包含的内容,默认情况下不会解压缩)。

因此我们可能需要处理两种情况:

  1. 文件是一个真实的文件 - 只需执行它。
  2. 文件已打包 - 需要将数据提取/复制到(临时)实际文件中并执行该文件。
  3. 以下代码处理两者。我测试了它,它适用于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)

嘿,我刚刚在sdk上查了一些东西。不要在install.rdf中进行解压缩,因为引用的那些“性能问题”。而只是把东西放在你的数据文件夹中。比这样访问它:

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")