Writing software, the wrong way

Wednesday, April 16, 2008

Nearing the final release

I got disabling updates working for Firefox, though it is terrible hack since I couldn't find a policy to disable IE updates. A google search didn't help, and most of them pointed to third party tools to disable updating to IE7 from Windows Update. So I had to manually create a registry key to disable browser updates (ironically enough, I unconsciously put it in the Internet Explorer branch of the registry).

There are still so many things to do, most of it cosmetic. For example, the code is still a mess. I have my doubts about fixing it entirely, but I can certainly comment.

So here is what is left to do, at minimum, where I stand :
  1. Document on the wiki how to implement a new policy
  2. Use javascript components whenever possible
And then I can finally say that I am done, and anything else is just frosting :)

Sunday, April 6, 2008

Overcomplicated

While doing some test cases for the javascript wrapper around registry keys, I found a major flaw in an assumption I was making about keys that made me rethink my code. While I made some things simplier, it was still a pain to get something. Here is a progression of how things used to be and how things are right now.

Declare the service :
let service = Cc["@shacknet.nu/winregistry;1"]
.getService(Ci.nsIWindowsRegistryService);


Oldest way :
let key = service.getKey(
Ci.nsIWindowsRegistryService.ROOT_KEY_LOCAL_MACHINE,
"Software\\Mozilla\\Firefox\\Crash Reporter\\EmailMe");
let answer = key.getValue();
key.close();


Older way :
let key = service.getKey(
"Software\\Mozilla\\Firefox\\Crash Reporter",
"EmailMe");
let answer = key.getValue();
key.close();


New and simplier :
let answer = service.getKey(
"Software\\Mozilla\\Firefox\\Crash Reporter",
"EmailMe");


I figure, this will work for 100% of the use cases right now. I was gonna get complicated with making another, more complete, interface for getting attributes of keys (ie. what was the root, path, and key name). But this early in the process, especially without requirements, I don't care about it :)

Thursday, April 3, 2008

Mystery unravelled!

A bit of my last release failed. Mainly because my javascript component was failing in an odd place. I couldn't figure out why, and so xpcshell tests never got complete.

I went back to the problem today. Firing up venkman and the javascript shell, I started to play around with it some more. I manually tested (grumble) both components independently and they both worked. But they didn't work together. I couldn't get one to return an instance of the other, and it was bothering me.

Walking through the javascript in venkman, It got all the way to the return value and throws the exception there.

if (regkey.hasValue(value) == false)
return null;

key.init(regkey, relPath, value);

return key; /* Always failing here */
},

Looking at the terminal, I noticed a strange assertion coming up after the code fails. I asked in #developers, and even sdwilsh (a very knowledgeable and promising character that interned last year) took a stab at it and couldn't find anything obvious. I started losing hope of ever getting this blasted thing working. Looking up the assertion didn't help, and neither did a NS_ENSURE_TRUE warning that were both being fired after the code failing.

I finally had it. It couldn't be the .js file. It had to be something more. But what else is there except the idl interface? I looked, examining each line. Then I noticed something very, very, wrong.

void getKey(in unsigned long root, in string path);

The return value was void. I must have just put void there first because I didn't know what I wanted to call the other interface. I promptly change it to :

nsIWindowsRegistryKey getKey(in unsigned long root, in string path);

And it starts to work in the javascript shell, which is absolutely a relief. Now I can start seeing if tests work.

Tuesday, April 1, 2008

Dynamic Javascript

For the next release, I want to start cleaning up the code base. I've started with grouppolicy's browser.xul (which overlay's Firefox's browser.xul) because this is a file that confuses me quite a bit. I also found out why it's seemingly so confusing.

The problem is this: Say I have a function called multiply that lives in another file :
function multiply(a,b) {
...
}

Without changing multiply's function internals, how do I change the logic? You might consider making a multiply2(a,b) and copy and pasting code and substituting your own logic, but the catch is you can't change any of the functions that call multiply() either!

It's sorta the same dilemma that we have. There are functions in Firefox's browser.xul that we don't want to change, but we want to add bits of logic jammed into the middle that would, for example, prevent a user from ctrl+click a link to open it in a new tab when tabs are disabled via a policy.

Overlays offer one solution. You can declare your own multiply(a,b) function and it would overwrite the one in Firefox's. However, I don't like this approach because you have to copy and paste code. And when you do that, you're responsible for keeping it current.

Another solution to wrap around the function. Let's expand our multiply function :
function multiply(a, b) {
var rv = 0, i;
// If we go over 999, just give up silently because we're evil
if (b < 1000) {
for (i = 0; i < b; ++i) {
rv += a;
}
}
return rv;
}

And let's say you wanted to change 1000 to 500. One solution is to wrap the function. Something like :
var _multiply = multiply;
function multiply(a, b) {
if (b < 500) return _multiply(a,b);
return 0;
}

Now the real multiply doesn't get called unless the second factor is less than 500. This is the approach I'm using to solve my problem. However, there is sometimes duplicate code that you just can't get around.

A third option, which is quite innovative, is something I found someone doing on an addon. It uses eval(), which is risky but gets the job done in this situation.
eval(multiply.toString().replace("1000", "500"));
I'll leave that for you to figure out. But it works!

Yay, bedtime!