Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine the extension's directory

I need to get the path of the extension installed directory from JavaScript.

My goal is to write to a JSON file within the extension directory from a Firefox extension. In order to do that, I need to determine the directory in which the extension is installed within the Firefox profile.

I use this code:

function writeToFile()
{
    var id  = "plugin@uua";// The extension's id from install.rdf(i.e. <em:id>)
    var ext = Components.classes["@mozilla.org/extensions/manager;1"]
                        .getService(Components.interfaces.nsIExtensionManager)
                        .getInstallLocation(id)
                        .getItemLocation(id);
    var file = Components.classes["@mozilla.org/file/local;1"]
                         .createInstance(Components.interfaces.nsILocalFile);
    file.initWithPath(ext.path); 
    file.append("config.json");     
    var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]   
                             .createInstance(Components.interfaces.nsIFileOutputStream);
    foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0); 
    var data = '[ {"id" : "2"} ]';
    foStream.write(data, data.length);
    foStream.close();

It throws the following error:

TypeError:Components.classes['@mozilla.org/extensions/manager;1'] is undefined.

I essentially need to get the path of the extension automatically from JavaScript. I double checked the ID of my extension and I also tried writing to files from other extensions with no luck.


Thanks very much for your replies. It didn't let me solve my problem instantly anyway but it forced me to reading Mozilla documentation. I finally got a hang of how it works. Thanks again.

Solution to the question above:

    Components.utils.import("resource://gre/modules/AddonManager.jsm");
    Components.utils.import("resource://gre/modules/FileUtils.jsm");
    AddonManager.getAddonByID("plugin_id", function(addon) {

    var uri = addon.getResourceURI("config.json");
    var file = Components.classes["@mozilla.org/file/local;1"]
                         .createInstance(Components.interfaces.nsILocalFile);
    var stringUri = uri.asciiSpec;
    stringUri = stringUri.replace(new RegExp(/\//g), '\\');
    stringUri = stringUri.slice(8);
    alert(stringUri);
    file.initWithPath(stringUri);
    alert(addon.hasResource("config.json"));

    var stream = FileUtils.openFileOutputStream(file,
                                                FileUtils.MODE_WRONLY 
                                                | FileUtils.MODE_CREATE 
                                                | FileUtils.MODE_TRUNCATE);
    stream.write(dataToWrite, dataToWrite.length);
    stream.close();
like image 407
Jessica Stansfield Avatar asked Nov 05 '22 02:11

Jessica Stansfield


1 Answers

Starting with Firefox 4 you should be using the Add-on Manager API:

Components.utils.import("resource://gre/modules/AddonManager.jsm");

AddonManager.getAddonByID(id, function(addon)
{
  var uri = addon.getResourceURI("config.json");
  if (uri instanceof Components.interfaces.nsIFileURL)
    writeToFile(uri.file);
});

Note that the new API is asynchronous, fetching the data about an extension can take time. Also, you would need to specify <em:unpack>true</em:unpack> flag in your install.rdf, otherwise your extension will not be unpacked upon installation (for performance reasons) and there will be no file on disk corresponding to config.json (it will rather be a location inside the packed XPI file). There is another issue with writing to the extension directory: all the files there will be replaced when the extension is updated. A better idea might be writing to a file in the profile directory, then you won't need to sacrifice performance.

Writing to a file can be simplified using FileUtils.jsm:

Components.utils.import("resource://gre/modules/FileUtils.jsm");

var stream = FileOutputStream.openFileOutputStream(file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
stream.write(data, data.length);
stream.close();
like image 113
Wladimir Palant Avatar answered Nov 09 '22 11:11

Wladimir Palant