简体   繁体   中英

Select A File Within Firefox Add-On Directory

I'm converting an XUL-based Firefox add-on to an SDK based version for simplicity. The XPCOM modules I use in the XUL-based version seem to work but ci.nsIFile is behaving differently.

I can't figure out how to navigate to smartProxy.py which currently sits on the highest level of the directory.

In the XUL version smartProxy.py sits on chrome/bin/smartproxy.py. I use the commands below to execute the program and it works without error.

getExeFile: function() {
    var file = cc["@mozilla.org/file/directory_service;1"].getService(ci.nsIProperties).get("ProfD", ci.nsIFile);
    file.append("smartProxy.py");
    return file;
},

This below is where it's executed which should give a full picture of how the add-on works.

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();
},

How do I go about finding smartProxy.py so that it can be executed?

Running an external command from Firefox right now is only supported with the nsIProcess API. You figured out this bit for yourself already.

Packaging a python script.

The SDK will only package certain files/locations. It would be easiest to just place the python script in the data/ folder, because that is one of the locations the SDK will package all files from.

nsIProcess

nsIProcess needs an executable file, and that file actually needs to be a real file (not just something contained within the XPI, which by default is not unpacked).

So there are two cases we might want to handle:

  1. File is a real file - Just execute it.
  2. File is packaged - Need to extract/copy the data into a (temporary) real file and execute that.

The following code deals with both. I tested and it works for me on OSX (*nix, so should work on Linux or BSDs as well) and Windows, with and without em:unpack (and you should avoid 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);

Running a script

Running a script (as opposed to a full-blown binary) can be tricky. In case of Python eg the *nix OSes needs to be told that there is an interpreter and what this is, which is done by a shebang . On Windows, Python needs to be installed with .py file type registration, which the default installer will do, but not "portable" versions".

Hey man I just looked up some stuff on sdk. Don't do the unpacking in the install.rdf because of those "performance issues" that are cited. Instead just put the thing in your data folder. Than access it like this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM