Make “cfx run” work in cygwin
I want to create an add-on for Firefox (as my diploma thesis). I did it before manually by simply creating the required files structure on my filesystem and then zipping all the stuff into XPI package. But things change. The structure of add-ons changed, they got restart-less and we (the elderly ones.. I’m mid twenties BTW ;) can start learning our $h17 from scratch. Moreover devs from Mozilla created some super cool tool cfx.
Ok. So I installed the Add-on SDK (i.e. the cfx tool)… reated the addon using cfx init, and put some stuff into it.
And did:
$ cfx run Using binary at 'C:\Program Files (x86)/Mozilla Firefox/firefox.exe'. Using profile at '/tmp/tmpvylRQ6.mozrunner'. Error: argument -profile requires a path <-- this is actually firefox error output
As you can see cfx uses windows path for the execution file and linux path (internal cygwin path) for the temporary profile directory. It’s no wonder firefox doesn’t know what the heck is it. The program hangs in there, so when you press Ctrl+C to kill it, you get some more info.
Traceback (most recent call last): File "/usr/local/bin/cfx", line 33, in <module> cuddlefish.run() File "/cygdrive/c/Program Files/addon-sdk-1.16/python-lib/cuddlefish/__init__.py", line 925, in run pkgdir=options.pkgdir) File "/cygdrive/c/Program Files/addon-sdk-1.16/python-lib/cuddlefish/runner.py", line 747, in run_app runner.stop() File "/cygdrive/c/Program Files/addon-sdk-1.16/python-lib/mozrunner/__init__.py", line 567, in stop self.kill() File "/cygdrive/c/Program Files/addon-sdk-1.16/python-lib/mozrunner/__init__.py", line 553, in kill for pid in get_pids(name, self.process_handler.pid): File "/cygdrive/c/Program Files/addon-sdk-1.16/python-lib/mozrunner/__init__.py", line 73, in get_pids import wpk File "/cygdrive/c/Program Files/addon-sdk-1.16/python-lib/mozrunner/wpk.py", line 5, in <module> from ctypes import sizeof, windll, addressof, c_wchar, create_unicode_buffer ImportError: cannot import name windll
So that’s where cfx is living. In a python library called cuddlefish.
So what’s the deal
I’d like to point cfx into my existing devel profile. Since it sleeps in AppData I’ll just use the –profiledir parameter of cfx rigt?
$ cfx run --profiledir "/cygdrive/c/Users/kub1x/AppData/Roaming/Mozilla/Firefox/Profiles/d859hbtr.selectowl/" Using binary at 'C:\Program Files (x86)/Mozilla Firefox/firefox.exe'. Using profile at '/cygdrive/c/Users/kub1x/AppData/Roaming/Mozilla/Firefox/Profiles/d859hbtr.selectowl'. Error: argument -profile requires a path
Same problem. how about converting it into windows path.. I’ll use cygpath tool for that:
$ cygpath.exe -w /cygdrive/c/Users/kub1x/AppData/Roaming/Mozilla/Firefox/Profiles/d859hbtr.selectowl/ C:\Users\kub1x\AppData\Roaming\Mozilla\Firefox\Profiles\d859hbtr.selectowl\
$ cfx run --profiledir "`cygpath -w /cygdrive/c/Users/kub1x/AppData/Roaming/Mozilla/Firefox/Profiles/d859hbtr.selectowl/`" Traceback (most recent call last): File "/usr/local/bin/cfx", line 33, in <module> cuddlefish.run() File "/cygdrive/c/Program Files/addon-sdk-1.16/python-lib/cuddlefish/__init__.py", line 925, in run pkgdir=options.pkgdir) File "/cygdrive/c/Program Files/addon-sdk-1.16/python-lib/cuddlefish/runner.py", line 562, in run_app preferences=preferences) File "/cygdrive/c/Program Files/addon-sdk-1.16/python-lib/mozrunner/__init__.py", line 185, in __init__ self.install_addon(addon) File "/cygdrive/c/Program Files/addon-sdk-1.16/python-lib/mozrunner/__init__.py", line 212, in install_addon os.makedirs(extensions_path) File "/usr/lib/python2.7/os.py", line 150, in makedirs makedirs(head, mode) File "/usr/lib/python2.7/os.py", line 157, in makedirs mkdir(name, mode) OSError: [Errno 2] No such file or directory: '/cygdrive/c/Users/kub1x/school/fel/diplomka/sowl/C:\\Users\\kub1x\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\d859hbtr.selectowl\\'
Allright so somebody is trying to touch that directory, not just pass the path to firefox. Well of course, cfx must install my addon into that dir. So we’ll have to find the spot, were the command line call is performed and translate the path ourselves, yaaay. Also I’m still wondering why Firefox path is in windows format and the profiledir path is not.
I used the output “Using profile at” to get a little closer to where we’re touching the profile path.
addon-sdk-1.16/python-lib$ grep -iR "Using profile at" * cuddlefish/runner.py:697: print >>sys.stderr, "Using profile at '%s'." % profile.profile Binary file cuddlefish/runner.pyc matches
HC SVNT DRACONES
Following is just the list of spots that I’ve visited (filename:line number). The deduction itself is kinda art of reverse redaing the code I’d say. I tried to put the mindflow there too…
cuddlefish/runner.py:697 <-- found with grep cuddlefish/runner.py:560 <-- instantiating profile_class.. where does it come from? cuddlefish/runner.py:452 <-- ah here.. it's the mozrunner.FirefoxProfille class $ grep -R FirefoxProfile * cuddlefish/runner.py:452: profile_class = mozrunner.FirefoxProfile Binary file cuddlefish/runner.pyc matches mozrunner/__init__.py:315:class FirefoxProfile(Profile): mozrunner/__init__.py:573: profile_class = FirefoxProfile mozrunner/__init__.py:610: profile_class = FirefoxProfile Binary file mozrunner/__init__.pyc matches mozrunner/__init__.py:315 <-- FirefoxProfile has Profile as a parent mozrunner/__init__.py:158 <-- browsing a bit the Profile class.. it is the one who's handling all the stuff with profile, but who's using it mozrunner/__init__.py:371 <-- down lower there is the Runner class... mozrunner/__init__.py:495 <-- and here we're home the command method that creates the command to be executed
I had to educate myself a bit on how to call external program from python (in my case cygpath). Here is the resulting method with the added bit highlighted:
@property
def command(self):
"""Returns the command list to run."""
cmd = [self.binary, '-profile', self.profile.profile]
# In cygwin we're working with unix style directories, but we'd better
# translate them for Firefox tu get there too.
if sys.platform == 'cygwin':
win_profile_path = subprocess.Popen('cygpath.exe -w "%s"' % self.profile.profile, shell=True, stdout=subprocess.PIPE).stdout.read();
cmd = [self.binary, '-profile', win_profile_path]
# On i386 OS X machines, i386+x86_64 universal binaries need to be told
# to run as i386 binaries. If we're not running a i386+x86_64 universal
# binary, then this command modification is harmless.
if sys.platform == 'darwin':
if hasattr(platform, 'architecture') and platform.architecture()[0] == '32bit':
cmd = ['arch', '-i386'] + cmd
return cmd
$ cfx run --profiledir "/cygdrive/c/Users/kub1x/AppData/Roaming/Mozilla/Firefox/Profiles/d859hbtr.selectowl/" Using binary at 'C:\Program Files (x86)/Mozilla Firefox/firefox.exe'. Using profile at '/cygdrive/c/Users/kub1x/AppData/Roaming/Mozilla/Firefox/Profiles/d859hbtr.selectowl'. -- cygpathed: C:\Users\kub1x\AppData\Roaming\Mozilla\Firefox\Profiles\d859hbtr.selectowl -- running: C:\Program Files (x86)/Mozilla Firefox/firefox.exe -profile C:\Users\kub1x\AppData\Roaming\Mozilla\Firefox\Profiles\d859hbtr.selectowl
For now I got stuck in here. While passing the correct path I still can’t access the profile. It works, when I run it manually. Will follow next time =j
/cygdrive/c/Program\ Files\ \(x86\)/Mozilla\ Firefox/firefox.exe -no-remote -profile "C:\Users\kub1x\AppData\Roaming\Mozilla\Firefox\Profiles\d859hbtr.selectowl"