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"

 

Comments are closed.