… or living without perlbrew.

There are several advantages to building perl locally, my top five being

  1. Ensure you are using unthreaded perl
  2. Control where (this version of) perl is installed (with short paths)
  3. Customise the @INC path (with fewer components, simplifying debugging)
  4. Easily switch to test releases under different versions
  5. Stop pondering if you are getting best performance

These notes give a reliable route to getting what you always wanted (if what you always wanted was a customised perl). If all you want is a default build of perl redirect yourself to Perl README where you will find things are even simpler (even if you want to customise where perl is installed). These notes are for people who want to customise more than that (eg @INC), especially if they want to do that on more than one machine or for more than one version of perl.

The notes assume you’re on linux and using bash as your shell, but I’m confident it won’t be difficult to translate them to your environment. I have used them to build v5.12.4—v5.17.4 on different (linux) architectures without troubles (but it didn’t work on v5.10.1 and below). The sneaky bit is it helps if you have a couple of files from here.

where “x86-64” is replaced by the arch identifier for perl (that one is for amd64). The most reliable way to produce it if you don’t have one is to

./Configure -es -Dprefix=/opt/perl/5.16.1

and manually answer each question. (You won’t have to do this again, unless new options are added in a future version of perl.) Then save the resulting Policy.sh to a filename like above and edit the file till it’s exactly what you want, then proceed as below.

A quick alternative to answering all those questions is to run it on ‘auto’ and then edit the resulting Policy.sh.

./Configure -des -Dprefix=/opt/perl/5.16.1
rm -f config.sh
vi Policy.sh
./Configure -des -Dprefix=/opt/perl/5.16.1

Grab the wget line from Get Perl and unpack the archive into /opt/perl/build.

apt-get install build-essential
cd /opt/perl/build/perl-5.16.1
cp /tmp/Policy.sh_x86-64_5.16.1 Policy.sh
./Configure -des -Dprefix=/opt/perl/5.16.1
diff /tmp/Policy.sh_x86-64_5.16.1 Policy.sh

If the paths in that diff are the same then you’re safe to proceed. But sometimes Configure fails to pick up Policy and the diff shows the paths still disagree. In that case

rm -f config.sh

then repeat the cp line and the lines that follow it.

Once the diff shows no disagreement about configuration, you’re safe to proceed.

make && make test && make install
env -i /opt/perl/5.16.1/bin/perl -V

Then create an env var file

mkdir -p /etc/perl
vi /etc/perl/perl.env

with the contents

p=/opt/perl/5.16.1
export PERL_MB_OPT="--install_base $p"
export PERL_MM_OPT="INSTALL_BASE=$p"
if ! which perl5.16.1; then
  if [ "$(id -u)" -eq 0 ]; then
    PATH=/usr/local/sbin:/usr/local/bin:$p/bin:/usr/sbin:/usr/bin:/sbin:/bin
  else
    PATH=/usr/local/bin:$p/bin:/usr/bin:/bin
  fi
  export PATH
fi

That works nicely in an environment where you have one ‘active’ perl at a time, and you only need to edit that file at upgrade time. If you test against multiple versions of perl, you’ll want to call that file /etc/perl/perl-5.16.1.env.

(That file is quite naive because it assumes perl is the only ‘special’ package on your box. You might want to use PATH=$p/bin:$PATH or something smarter.)

Then install a corresponding cpanm.

. /etc/perl/perl.env
which cpan
cpan App::cpanminus

Scripts then optionally pick up this new perl via

. /etc/perl/perl.env

which you should test with

which perl
perl -V

You might want to edit your profile so that all new interactive shells automatically include perl.env. (I choose not to do that.)

At the head of scripts that should use this perl, you can use

#!/opt/perl/5.16.1/bin/perl

or probably better (more conventional and requiring less maintenance but relies on your PATH being set correctly)

#!/usr/bin/env perl

Once you’re happy with your new perl you might want to save disk space by deleting the .tar.gz file and doing make clean inside the build dir. You’ll certainly want to preserve your Polic.sh for posterity.

A couple of warnings:

  • That /etc/perl/perl.env assumes you only have one instance of each version. If you have two instances, eg one threaded, one non-threaded, the if-clause will need to be made smarter.
  • Watch out for $HOME/.cpan or $HOME/.cpanm growing overly big. It’s not something you want to include accidentally in your backups.
  • I don’t follow the convention of having a redundant ‘perl5’ dir at the end of each path. My horrible workaround is to install with cpanm as usual and then run my unperl5 script which moves the contents of lib/perl5 to lib. If you don’t want to use that, the simpler option is to build perl with “/perl5” appended to each non-core library path. (eg /usr/local/lib/site_perl/perl5)
Advertisements

A nice example of Mojolicious code as a proxy service. This is thanks to xaka at gist.


use Mojo::UserAgent;
use Mojo::Server::Daemon;

my $ua = Mojo::UserAgent->new;
my $daemon = Mojo::Server::Daemon->new(
  listen => ['https://*:443']
)->unsubscribe('request');
$daemon->on(request => sub {
  my ($daemon, $tx) = @_;

  my $req = $tx->req->clone;
  $req->url->scheme("https")->host("10.3.199.40");

  $ua->start(Mojo::Transaction::HTTP->new(req => $req) => sub {
    my ($ua, $proxy_tx) = @_;
    $tx->res($proxy_tx->res)->resume;
  });
});
$daemon->run;

It can be a little fiddly to get the USB interface built on a debian box, but This Worked For Me(TM):

apt-get install libusb-1.0-0-dev libusb-1.0-0=2:1.0.8-2

Then install the appropriate perl interface; in my case:

cpanm -l /opt/perl Inline::C Device::USB::PCSensor::HidTEMPer

Node is currently one of those rare packages that are easier to build from source rather than from deb binaries.

apt-get update
apt-get install build-essential g++
cd /usr/local/src
tar xzf /tmp/node-v0.8.2.tar.gz
cd node-v0.8.2
./configure --without-ssl
make -j4
make install

will put node in /usr/local/{bin,lib,include,share/man}.

cd /tmp
tar xzf /tmp/cloudhead-less.js-v1.0-558-g5974b9e.tar.gz
mv /tmp/cloudhead-less.js-5974b9e /usr/local/lib/node_modules/lessjs
cd /usr/local/bin
ln -s ../lib/node_modules/lessjs/bin/lessc

will make the less compiler available in /usr/local/bin.

Now you can

lessc less/mybootstrap.less css/mybootstrap.css

and

lessc -x less/mybootstrap.less css/mybootstrap.min.css

In HTML, if you want to render a block of code, respecting white-space, but without any hyperlinking or other HTML, it’s easy; just use code. Secondly, if you want to have hyperlinks within your code then there are several options, including placing each line within a li of a list. Thirdly, if you want to render it with intelligent syntax highlighting, there are syntax highlighters from Google and others. But what if you want to combine the first two? Have a code block that respects white-space like indents and line-breaks but also includes HTML? Here we look at one solution.

CSS

div.code-linkable {
  background-color: #f7f7f7;
  border-radius: 4px;
  color: #44443c;
}
.code-linkable > ol {
  font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
  list-style-type: none;
  padding: 7px;
  text-shadow: none;
}
.code-linkable > ol > li {
  white-space: pre-wrap;
}

HTML

<div class="code-linkable">
  <ol>
    <li>SELECT</li>
    <li>  iOrderId</li>
    <li>FROM</pre>
    <li>  <a href="/schema_browser?schema=Orders&table=tOrder">
        Orders.tOrder</a>
    <li>WHERE</li>
    <li>  fGross &gt; 100.00</li>
  </ol>
</div>

As you can see with the greater-than symbol, a disadvantage is that everything ambiguous must be html-ified. If you want a distinct background colour for the code block, do that in a wrapping div since list items have varying lengths (widths).

You have a schema containing lots of MyISAM tables that may possibly be stale due to code no longer updating them. You can rank them by date of most recent update.

mysql -D PriceComparison -NBe"show table status like '%'" \
| \
cut -f1,2,11,12 \
| \
sort -k 5,6

I omitted a grep MyISAM because the InnoDB tables will be grouped together with NULL dates so aren’t a problem. The sneaky problem to avoid is that sort sees a datetime field as being two fields. To sort the list by creation date you would use sort -k 3,4.

You’re tailing a file in the usual way

tail -n 80 -f log/production.log

but the writing process (or maybe logrotated) swaps it for a new file. Now your tail is left looking at the old version, which is stale. You could ctrl+c and restart the tail but that is tedious. The answer is to specify you want tail to follow the name of the file rather than the file descriptor. Now when a new file is swapped-in as a replacement, tail continues the way you always wanted.

tail -n 80 --follow=name log/production.log