Building simplicidade.org: notes, projects, and occasional rants

Fat scripts

Recently we installed HipChat at the office, and I want to write a small script to send messages to it. To make it easier for others to use I wanted to distributed it as a single standalone script, no dependencies.

I wrote the script, x-hipchat, with all the bells and whistles I felt were important, and then turned to the process of pack it into a single no-dependencies script. The simplest method I could find is App::fatten.

For best results, you should create a configuration file somewhere, and use the --config-path to point to it. In fact, if you don’t create it, you keep getting “ERROR 412: Profile ‘your-script-name’ not found in configuration file”. In the configuration file, the section name is the base name of your script. My config file looks like this:

[profile=x-hipchat]
overwrite=1
exclude_core=1

The first attempts ran fine, but the fat script failed to find JSON::backportedPP and later HTTP::Tiny. And if I manually included them with include=MODULE on my config file (oh, there is a bug in 0.13, if put a single include statement, it borks - issue open), HTTP::Tiny will die later on, I’m guessing because some of the internal modules that HTTP::Tiny could not be found.

I tried to use trace_method=prereqscanner_lite_recurse configuration option and fatten found more modules, but too many to include, and some were Core, which caused problems with a different version of perl.

The final solution for this was to install with perlbrew a older version of perl (I choose 5.10.1), and create a perlbrew lib just for packing:

perlbrew install -j 4 perl-5.10.1
perlbrew lib create [email protected]
perlbrew use [email protected]
cpanm App::fatten Module::CoreList

(we force Module::CoreList because App::tracepm requires a more recent version that she declares.)

This gives me a sufficiently old perl that lacks most of the more recent core modules, and will force them into the script. This actually helped, but I still got “599 Internal Exception” from HTTP::Tiny.

I switched to trace_method=require that actually runs your code. This is much better because a lot of modules are only loaded later, when needed. Here App::fatten could make my life easier. My script requires parameters but I could not find a way of pass them. A command line option to give extra parameters to the program would be nice. Fortunately I had environment variables for most options, so I used those.

Eventually I found the culprit: HipChat API is HTTPS-only, and HTTP::Tiny and perl in general require XS modules to use HTTPS, and XS modules cannot be fat packed.

So I could not create a standalone script for this because of my HTTPS dependency. Oh well…

I think this is a good example for me to dust up my Go knowledge…