Random Musings

2006-2-26

Perl cross-platform compatibility

Filed under: — PugMajere @ 6:05 pm

Anyone that knows me knows that my generally preferred language is Perl. (I’ll wait for the jeering to die down.)
Generally, this isn’t a bad thing, as Perl is remarkably cross-platform compatible. Unfortunately, Windows is an utter disaster in terms of compatibility with Unix based systems.

Working on a few Git (Introduction) related tools, such as a replacement for “cvs annotate”/”svn blame”, we’ve learned that the current best practices for doing safe pipe opens aren’t very compatible.

For example, to call a program like “ls”, you might do something like this:

open(PIPE, “-|”, “ls”);

while(<PIPE>) { do_something($_); }

close(PIPE);

Unfortunately, that fails on Perl 5.6, and on ActiveState (Any version, I believe.)

So on Perl 5.6, the solution is to instead do the two steps by hand:

my $pid = open my $kid, “-|”;

defined $pid or die “Cannot fork: $!”;

unless ($pid) {

exec “ls”;

die “Cannot exec ls: $!”;

}

while(< $kid>) { do_something($_) }

close($kid);

But this fails on ActiveState, because ActiveState doesn’t handle the forked pipe open well (ok, at all). ActiveState doesn’t appear to have a good solution for this, at all, so at this point, we’re forced to fall back on something like backquotes (“) or the easier to read qx(). (qx() is just an alternate form of backquotes, that gives you some control of how interpolation happens.

The problem with using qx() is that it is a backquote form, so it return a list of lines, not a filehandle. Since that’s a very different way to do things, and potentially a big performance hit on systems that don’t need the qx() work arounds, I forced myself to find a way to just hide the complexity:

sub open_pipe {
if ($^O eq ‘##INSERT_ACTIVESTATE_STRING_HERE##’) {
return open_pipe_activestate(@_);
} else {
return open_pipe_normal(@_);
}
}

sub open_pipe_activestate {
tie *fh, “Git::ActiveStatePipe”, @_;
return *fh;
}

sub open_pipe_normal {
my (@execlist) = @_;

my $pid = open my $kid, “-|”;
defined $pid or die “Cannot fork: $!”;

unless ($pid) {
exec @execlist;
die “Cannot exec @execlist: $!”;
}

return $kid;
}

package Git::ActiveStatePipe;
use strict;

sub TIEHANDLE {
my ($class, @params) = @_;
my $cmdline = join ” “, @params;
my @data = qx{$cmdline};
bless { i => 0, data => \@data }, $class;
}

sub READLINE {
my $self = shift;
if ($self->{i} >= scalar @{$self->{data}}) {
return undef;
}
return $self->{’data’}->[ $self->{i}++ ];
}

sub CLOSE {
my $self = shift;
delete $self->{data};
delete $self->{i};
}

sub EOF {
my $self = shift;
return ($self->{i} >= scalar @{$self->{data}});
}

It should, hopefully, be fairly obvious what is going on there.

For a normal system, we use the Perl 5.6 compatible method, and return a filehandle that works normally.

For an ActiveState system, we tie a glob to a special object that provides some very basic emulation of a filehandle, and internally, calls qx() and indexes across an array returning the data.

So, that’s how “git annotate” is going to be cross-platform compatible, at least, as of today, that is my plan.

Thanks to Randal Schwartz (merlyn) for providing part of the inspiration for this, and the rest of the people on the Git list that helped hash out various approaches to this that didn’t quite seem as clean or as nice as this one, in the long run.

I think this method keeps all the security advantages of the argument list forms, while actually still managing to work on crippled systems, so I’m fairly pleased with it.

2006-2-17

Yaird support for module options

Filed under: — PugMajere @ 12:33 am

I recently was given a Dell Latitude 610 to use for work. So of course I’m running Debian on it. Tonight, I decided to play a DVD, and realized I had never tried to use the DVD player.

Turns out that with SATA drives, you need to give the module option atapi_enabled=1 to make it work. To get this option into the initrd, I had to create a file named /etc/modprobe.d/local as follows:

options libata atapi_enabled=1

and then recreate the initrd with:

mkinitrd.yaird -o /boot/initrd.img-2.6.15-rc5-686 2.6.15-rc5-686

update-grub

and now I’m watching Kill Bill 2.

2006-2-6

Switching to a UTF-8 based system

Filed under: — PugMajere @ 12:33 am

On Friday, I started switching my work machines over to a default locale of en_US.utf8, so diff would work correctly on UTF-8 text files containing Korean.

At home, I read my work email (typically) via mutt, which I leave running in a screen session.  It turns out that this change means I need to switch basically everything at home over, as well.  Well, I’ll leave that for a rainy day, but for the time being, I’ve started up a few shells (urxvt) with LANG=en_US.utf8 instead, so things will work in the meantime.

I should have done this a long time ago, to be honest, but I guess I’m still a little bit worried about how widespread support for this is.

Powered by WordPress