Categories

Archive pour la catégorie ‘General’

Update on installer builders

Yoono took me to WiX. It uses an XML based file format, but doesn’t feature a scripting language ; extension is done through DLLs. A companion project aims to provide a GUI. It doesn’t seem to provide actions for PATH management nor configuration file customization, and this time working around this involves building a DLL… So this won’t do either. Too bad !

What’s worrying me is that altering the PATH or modifying configuration file doesn’t look too exotic to me, yet it’s not supported by any of the free-beer installer builders out there (and I suspect the same for commercial ones). Am I a weirdo, or didn’t anybody actually thought about what an installer would need to do ?

To conclude on this subject, I finally found the bug in the Inno Setup script : I put an extra pair of parentheses in an AfterInstall directive, which like crossing the streams is bad. Aahh, the joys of syntax parsing with the naked eye ! So for now, I’ll stick to Inno Setup which is one of the best *available* solutions.

Someone’s got to be kidding with the installer builders

It’s been a little more than a year now that I build my own Apache setup file, a nice setup compiled with MSVC 7.1, with SSL support, Subversion, PHP and a few other goodies (hint : it used to be a little difficult, but now there is this tutorial).

I won’t write about the stupid laws on cryptographic software and how it’s OK for me to download the source and build it, but not to download the binaries. Woohoo, I’m sure the most determined terrorists are scared shitless about building SSL support by themselves, thus reverting to the usage of low-tech communication means like ROT-13 or pigeons or whatever thing which espace the Echelon program. Because, you know, for the NSA, SSL is hard to break (and now I’m under close scrutiny). No, I won’t talk about that, because today my rant is about installer-building software.

Up until now, the installer for my Batteries Included Apache Server (BIAS) has been built using InnoSetup, which is free. InnoSetup installers are defined in a kind of INI file, with a little language for each kind of item definition (components, tasks, files, registry entries) and higher level scripting through the use of a Pascal scripting engine.

Yeah, a Pascal scripting engine. It’s like the best oxymoron I could give as an example of an oxymoron if I lived in a world only populated by geeks.

Pascal is strongly typed and has one of the worst syntax I’ve ever seen. To be clear, I learned myself Pascal at the age of 11 or so on my Amstrad CPC 6128. Back then, it was fun to switch the CPC to CP/M and launch Borland Turbo Pascal and feel like a big guy (I still have the 3″ disk ! I bought half of it on my own pocket money, it was worth 1000 French Francs which was a LOT to me back then).

Back to the present, Pascal is a pain in the ass, syntax-wise. And I did the obligatory detour by Delphi 1.0 (still got the disks too !) and though it was way better than MSVC or VB at the time, it is no longer, sorry.

I don’t know what kind of mindset you must have to design a strongly typed scripting language with an awkward Pascal syntax, but hey, it’s not mine. You get all the drawbacks, especially no compile time checking, without any single advantage. As Cake put it in their latest album, « Some people like to make life a little tougher than it is« . Even reading Perl is a treat compared to this.

Anyway, it doesn’t matter, since I am using an installer builder. I should not worry too much about writing code, since what I want to do is pretty much standard stuff that doesn’t need programming, right ?

Wrong. Here are two seemingly basic things that require programming : altering the PATH variable and modifying a template configuration file to take into account the installation path the user has chosen. And when I write « programming », I mean « fiddle with the feeble API at my disposal ». Power tools like regular expressions, that have made up for more than one scripting language’s lack API *cough*Javascript*cough* are totally sci-fi here. At the end of the day, a seemingly trivial task becomes a chore, especially since the debug part involves endless edit / build / install / uninstall cycles. I’ve reused some code on the Web for the PATH problem, but I had to write my own for the configuration file customization.

The problem is that I did a bit of refactoring of the installer today, to sort a few problems that accumulated through the months. I don’t know why, but that broke my file customization code. Maybe something is rotten in the callback system ? I’ve got a procedure with half of the code running, and the rest silently failing or not running. No stack trace, no error message, no nothing. That is extremely bothering.

So, sorry, but Innosetup sucks. When a piece of software sucks, there are a few options :

  • Stop bitchin’ and improve the software yourself. Well, Innosetup is written in Delphi, so I’ll pass.
  • Stop bitchin’ and do it yourself, since you seem to know so well how to do it. Well, if I could fix everything that’s wrong in the world, it would be undoubtly a better place, unfortunately I have only a limited amount of time and energy, most of both going right now into this blog entry…
  • Switch to the competition.

Well, for now, the only free competition I’ve found is NSIS, and it sucks too. Yeah, I know, now I’ve got something like 98% of the free installer-builder users in the world against me. So to be a little bit more diplomatic (not that I care, but…), let’s say that according to my metrics, it sucks. Manipulating the PATH variable is not built-in and non trivial. The same goes for in-file string replacement. But the best in yet to come in the form of the scripting language, which is this time a kind of stack-and-registers-based assembly language with macros and functions, something close in spirit to FORTH. Now Pascal Scripting looks like a gentle walk in the park.

There is an obscure HJ-Installer which uses an even more obscure scripting language, and of course a lot of commercial offers. Advanced Installer has my sympathy for using Lua as its scripting language, as it seems using a sane scripting language is not common place on this market.

So, it looks like the market is ready for a free, open-source installer builder, which uses a sane scripting language (like Python, Lua, or heck, even Javascript) and provides a bunch of goodies right in the box. The general objectives of an installer builder are :

  • To be able to build a self-contained executable that does everything needed to install an application, including requesting configuration data from the user and applying them to the application (it includes adding / removing components, specifying password, IP addresses, ports…), and of course things like altering the PATH environment variable and customizing configuration files.
  • To manage the delicate procedure of un-installing the software while letting the user the choice of keeping part of the application (like the configuration files, which are precious in the Apache environment).
  • To do all this while saving the developper a lot of time in writing the installer ; if the developer has to revert to programming to do trivial things like environment variable management or configuration file template instantiation, then he/she might as well not use an installer builder, roll his/her sleeves up and use his/her favorite generic programming language to do so. Except that it’s no trivial to handle the first two points.

That’s it ! Don’t forget my percentage if you don’t get rich following this advice.

Read tabular data from Excel spreadsheets the fast and easy way

I have posted a new recipe on the Python Cookbook. It’s a piece of code I’m using to read tabular data from Excel documents.

And now, for something complety different

At 07:19 this morning, my first child was born ! Her name is Violette, and I’m her greatest fan (I mean, objectively, she’s the cutest thing in the world). I won’t bother you with pictures and things like that, those in the know can contact me directly for that. Carine, thank you for this beautiful child. I love you both !

My first use of XmlHttpRequest (or AJAX if you prefer)

OK now I must confess something : I’m not a client-side guy. Designing web pages is not my thing, and even if I totally understand how HTML works, writing pages that look good and are compatible with each and every browser on the planet is too darn difficult.

In a total breach of my convictions, I’ve decided to give a try to this new AJAX (A.K.A. XmlHttpRequest in a fancy dress) thing. Well, once I’ve finished debugging the various Javascript errors, which is an horrible experience under Internet Explorer but not so bad under Firefox (thanks to the Javascript console), I’ve had a first prototype running. Looking around me to find something more interesting to do with this, I just remembered the Doodlepad application I’ve wrote back in 1995 when I wanted to test that new Java Applet thing. The applet was simple : you drew something in it using the mouse, and everybody connected to the same page could see it appear. So, I’ve decided to do something equivalent in AJAX.

It turns out that you can draw pixels in Javascript, but this is saturday evening, so I didn’t want to go that far for now. Here is something much simpler : a piece of text on a page, you move it, everybody else sees it moving on their page, and vice versa. How fun ! Too bad there is sometimes a bit of flashing on the text…

Comparing Microsoft Word documents stored in a Subversion repository

Update (2005/07/26): the latest version of TortoiseSVN comes with VBScripts for Word and OpenOffice documents comparison.

TortoiseSVN has a nifty feature which allows you to specify a custom diff program, based on the extension of the file which has to be diffed. This gave me the idea of this small Python script, which launches Word in document comparison mode:

# Use the pywin32 extension and Microsoft word to compare two Word documents
# Use this script with TortoiseSVN and extension-specific diff programs
# with a command line like this :
# c:\python24\pythonw.exe c:\path\to\word_diff.py %base %mine
# $Id: word_diff.py 1355 2005-06-30 11:16:59Z nlehuen $

import win32com.client
import sys
import os

try:
    # Get the absolute paths for the arguments
    # Word requires absolute paths.
    p1 = os.path.abspath(sys.argv[1])
    p2 = os.path.abspath(sys.argv[2])
    print "Comparing %s to %s..."%(p1,p2)

    # Open Word
    word = win32com.client.Dispatch("Word.Application")

    # Open the first document
    destination = word.Documents.Open(p2)
    # Hide it
    destination.Windows[0].Visible=0

    # Compare to the second document
    compare = destination.Compare(p1)

    # Show the comparison result
    word.ActiveDocument.Windows[0].Visible = 1

    # Mark the comparison document as saved to prevent the annoying
    # "Save as" dialog from appearing.
    word.ActiveDocument.Saved = 1

    # Close the first document
    destination.Close()
except:
    # In case of an exception, display it and wait for user input.
    import traceback
    traceback.print_exc()
    raw_input()

Very simple, but the precise sequence of COM calls to perform (showing which document, closing which document, should we open the first and compare to the second or conversely, etc.) needed a few minutes of work. This may be more naturally implemented in VBScript on top of the Windows Scripting Host, but I prefer coding in Python.

The new PythonReference implementation

Here is the new PythonReference implementation, based on what I’ve learned from Scott Meyers’ Effective C++.

class PythonReference {
public:
    explicit PythonReference() : ref(Py_None) {
        Py_INCREF(ref);
    }

    explicit PythonReference(PyObject *object, int borrow=1) : ref(object) {
        if(ref==NULL) {
            throw TSTException("Cannot reference NULL");
        }
        if(borrow) {
            Py_INCREF(ref);
        }
    }

    PythonReference(const PythonReference& that) : ref(that.ref) {
        Py_INCREF(ref);
    }

    PythonReference& operator= (const PythonReference& that) {
        PyObject* old = ref;

        if((this->ref = that.ref) != old) {
            Py_INCREF(ref);
            Py_DECREF(old);
        }

        return *this;
    }

    ~PythonReference() {
        Py_DECREF(ref);
    }

    int operator==(const PythonReference& that) {
        return (ref==that.ref);
    }

    int operator!=(const PythonReference& that) {
        return (ref!=that.ref);
    }

    PyObject* get() {
        return ref;
    }

    PyObject* lend() {
        Py_INCREF(ref);
        return ref;
    }

private:
    PyObject* ref;
};

Effective programming in C++

OK, so up until recently I had the nerve to write on my resumé that I had an advanced knowledge in C++. Well, the bad news is that it’s not totally true, since each time I read an item from Effective C++, I make a loud « Duh ! » and learn another bunch of things I’d rather not know about C++. The good news is that I think pretty much everybody will have the same reaction. The baseline is that you cannot write effective C++ code if you don’t read this book. Period.

C++ is so tricky and ugly that it is becoming beautiful in its weird own way. We should all be grateful that simpler languages have appeared and thrived, like Java, C# or even better, D (well, D is not in the thriving lot yet, but I truly hope so). Still, sometimes, you have to write C++ if you want some really portable, low-level (by which I mean total control on the implementation), fast code.

A unexpected side-effect of this book is that it’s choke-full of interview questions, should you want to hire a C++ specialist. I think I’ll use some on my next interview, even if the person is not a C++ specialist, just to scare him/her :-) .

The most obvious side-effect is that I’m refactoring the C++ part of pytst. I have integrated the PythonReference class from my previous post, but I had to make a few modifications to follow the advice of Effective C++.

La Constitution Martienne / the Constitution of Mars

En français ici / in english here.

IronPython is back !

Jim Hugunin released IronPython 0.7

Quoting his mail :

All of the details for making this release came together just in time for my PyCon keynote this morning, and I have just gotten back from the conference and had a chance to send mail to this list.

This is the release that I should have made about 2 months after IronPython 0.6 and joining MS. I’m sorry that it took so long and that I haven’t been able to really participate in this list during all this time.

The good news is that IronPython is back moving forward full steam ahead. Please come download the 0.7 release from the above URL and let us know how it works for you. Many of the bugs that you reported on this list should be already fixed and the site above has a nice bug tracking tool for you to tell us about any that we forgot. We’re going to be driving hard now to the right IronPython 1.0. We’ll be producing frequent releases to get there, but we need your help in providing the feedback to help us make the right decisions so that IronPython 1.0 will really address your needs.

It would be great if people could join the online forum at the above url for discussing IronPython; however, I’m going to keep this mailing list open for a while for those who prefer it.