I have compiled numerous bits of code a quick hacks which I am making available here for anybody who is interested. The code is unmaintained, but I will endeavor to provide any help I can as time permits. All this code was created to complete a specific task and may be written very poorly with little to no documentation.

These are all released under the GPL license

perl code snippets

Backing up Linux/Cygwin with rsync and perl

rsync is a very powerful tool, but not always the most intuitive. Here is a perl script that I use to backup all of my relevant files (under both linux and cygwin) to a remote backup machine. All that is needed is ssh, rsync and perl.


Using Par::Packer (pp) with Gtk2 on Windows

Well I haven't completely got it working, but it is darn close. I ended up switching to WxWidgets, which will work with some coaxing. Most of this kludge is based on bug reports from Marc Lehmann. Thanks Marc!

First off, we need to create a list of all the Gtk2 files that aren't picked up automatically by pp. I use this script to create the list and run pp. Note that I am running the script under cygwin, but I want to use the ActiveState Perl to run pp so we end up with a native Windows app. (BTW, I tried our Strawberry Perl, but it had issues with some of the dependencies due to a lack of pkgconfig.)

#!/bin/sh

# ppkludge - Automatically package the Gtk2 dependencies with pp
# This is a tweaked version of a script written by Marc Lehmann. Thanks
# for sharing this solution; I would have never figured this out!
#
# The original can be found at: http://data.plan9.de/ppwin
# Here is Marc Lehmann's original comment:
#  Convert a gtk2-perl program to a standalone .exe, including all 
# libraries and runtime files required for running as well as required 
# datafiles. I _literaly_ sold my soul to the devil and paid with blood 
# for this. Microsoft die die die die die die die die die die die die

GTK2="/cygdrive/c/Progra~1/Common~1/Gtk/2.0"

(
   cat <<EOF
c:\Perl\site\lib\auto\Cairo\Cairo.dll;root/Cairo.dll
c:\Perl\site\lib\auto\Glib\Glib.dll;root/Glib.dll
c:\Perl\site\lib\auto\Gtk2\Gtk2.dll;root/Gtk2.dll
# Here down, needed for systems w/o gtk
`cygpath -w $GTK2/etc`;root/etc
`cygpath -w $GTK2/lib/pango`;root/lib/pango
`cygpath -w $GTK2/lib/gtk-2.0`;root/lib/gtk-2.0
`cygpath -w $GTK2/share/themes/MS-Windows/gtk-2.0`;root/share/themes/MS-Windows/gtk-2.0
EOF

   cd "$GTK2/bin" || exit
   for dll in *.dll; do
      echo "`cygpath -w $GTK2/bin/$dll`;root/$dll"
   done
) >addlist

trap "/cygwin/bin/rm addlist" 0

PATH=/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/perl/bin
/cygdrive/c/perl/bin/perl /perl/bin/pp -o test.exe -I lib -A addlist test.pl

This will add the required file to the par/exe archive under the root/ directory. Now when you start your script, you need to unzip these files into the par cache directory. Use the following package, PAR::Kludge, in you script to do so.

package PAR::Kludge;

# This is a package implementing the fix discovered by Marc Lehmann. Thanks
# for sharing this solution; I would have never figured this out!
# The original can be found at: http://txt.schmorp.de/2629b6fdba568e7cda3ed953cbaf8613.txt

use strict;
use warnings;

our $VERSION = '0.30';

BEGIN {
    my $dbg; for(@ARGV){ $dbg++ if /^-d|^--debug/;}

    print "Running kludge\n" if $dbg;
    if (%PAR::LibCache) {
        print "kludging\n" if $dbg;
        @INC = grep ref, @INC; # weed out all paths except pars loader refs

            while (my ($filename, $zip) = each %PAR::LibCache) {
                for ($zip->memberNames) {
                    next unless m!^root/(.*)!;
                    print "zip: $_\n" if $dbg;
                    $zip->extractMember ($_, "$ENV{PAR_TEMP}/$1")
                        unless -e "$ENV{PAR_TEMP}/$1";
                }
            }

        # if ($^O eq "MSWin32") {
        #   $ENV{GTK_RC_FILES} = "$ENV{PAR_TEMP}/share/themes/MS-Windows/gtk-2.0/gtkrc";
        # }

        print "Inc:\n", join("\n",@INC),"\n" if $dbg;
        print "Temp:\n", $ENV{PAR_TEMP},"\n" if $dbg;
        print "Path:\n", $ENV{PATH},"\n" if $dbg;

        # print "Chdir to $ENV{PAR_TEMP}\n" if $dbg;
        # chdir $ENV{PAR_TEMP} if $ENV{PAR_TEMP};
        # use lib "$ENV{PAR_TEMP}/inc/lib";
    }
}

1;

All this is all well and good, but it doesn't actually work. I use glade to design the interface and Gtk2::GladeXML to render it. The packaged app will work fine until you try to hook up the events with the $gui->signal_autoconnect_from_package($self). Leave that command out and you have a beautifully packaged app (that doesn't do anything). Add the line and kplow!

The included script and PAR::Kludge packages can downloaded here. If anyone figures out how to get this working, please let me know!


Using Par::Packer (pp) with WxWidgets on Windows

After spending a considerable amount of time trying to package a Gtk2 app with pp, I decided to try a different gui toolkit, and was successful packaging a Wx app.

Again, most of this kludge is based on bug reports from Marc Lehmann regarding Gtk. Thanks Marc!

First off, we need to create a list of all the Wx files that aren't picked up automatically by pp. I use this script to create the list and run pp. Note that I am running the script under cygwin, but I want to use the ActiveState Perl to run pp so we end up with a native Windows app. (BTW, I tried our Strawberry Perl, but it had issues with some of the dependencies due to a lack of pkgconfig.)

#!/bin/sh

# ppkludge - Automatically package the Wx dependencies with pp

WX="/cygdrive/c/Perl/site/lib/auto/Wx"
MODS=""

(
 cat <<EOF
icons/test.bmp;root/icons/test.bmp
templates;root/templates
EOF

        cd "$WX" || exit
        for dll in *.dll; do
                echo "`cygpath -w $WX/$dll`;root/$dll"
        done

) >addlist

cdir=`pwd`
cd "$WX" || exit
for dir in *; do
        if [ -d $dir ] ; then
                MODS="$MODS -M Wx::$dir"
        fi
done
cd $cdir || exit

trap "/bin/rm addlist" 0

# unset BASH_ENV CLASSPATH COLORFGBG GTK_BASEPATH HOME INFOPATH INPUTRC KAPSRES PKG_CONFIG_PATH
PATH=/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/perl/bin
/cygdrive/c/perl/bin/perl /perl/bin/pp --gui -o test.exe -I lib $MODS -A addlist test.pl

This will add the required files to the par/exe archive under the root/ directory. Now when you start your script, you need to unzip these files into the par cache directory. Use the following package, PAR::Kludge, in you script to do so.

package PAR::Kludge;

# This is a package implementing the fix discovered by Marc Lehmann. Thanks
# for sharing this solution; I would have never figured this out!
# The original can be found at: http://txt.schmorp.de/2629b6fdba568e7cda3ed953cbaf8613.txt

use strict;
use warnings;

our $VERSION = '0.30';

BEGIN {
    my $dbg; for(@ARGV){ $dbg++ if /^-d|^--debug/;}

    print "Running kludge\n" if $dbg;
    if (%PAR::LibCache) {
        print "kludging\n" if $dbg;
        @INC = grep ref, @INC; # weed out all paths except pars loader refs

            while (my ($filename, $zip) = each %PAR::LibCache) {
                for ($zip->memberNames) {
                    next unless m!^root/(.*)!;
                    print "zip: $_\n" if $dbg;
                    $zip->extractMember ($_, "$ENV{PAR_TEMP}/$1")
                        unless -e "$ENV{PAR_TEMP}/$1";
                }
            }

        print "Inc:\n", join("\n",@INC),"\n" if $dbg;
        print "Temp:\n", $ENV{PAR_TEMP},"\n" if $dbg;
        print "Path:\n", $ENV{PATH},"\n" if $dbg;

        # print "Chdir to $ENV{PAR_TEMP}\n" if $dbg;
        # chdir $ENV{PAR_TEMP} if $ENV{PAR_TEMP};
        # use lib "$ENV{PAR_TEMP}/inc/lib";
    }
}

1;

The included script and PAR::Kludge packages can downloaded here. Hopefully this save someone else a bunch of time!


Lossless Rotation of JPEGs

Found a very interesting tool to do lossless rotation and exif editing of JPEG files. Checkout jpegtran. This version is apparently a patched verion of the JPEG software from IJG.

  jpegtran -copy all -rotate 90 1.jpg

There is also a related tool, jhead, which can pull all sorts of interesting stuff out of JPEGs. This will extract a thumbnail which most cameras already imbed in photos:

  jhead -st "thumbnails\&i" *.jpg

And finally, another tool and script which can automagically rotate files based on the orientation info in the header.


Local CPAN (mini-cpan)

Found a nice module/script to keep a local copy of the cpan repository for those times when we aren't connected to the internet.

Used cpanp to get CPAN::Mini

minicpan -r ftp://ftp.ibiblio.org/pub/languages/perl/CPAN/ -l CPAN/

From cpan use this to add the local repository. (This is a pain to do with cpanplus

o conf urllist unshift file:///home/mgrimes/CPAN/

CPANPLUS with Local CPAN

In followup to the not about how to create a local cpan repository, I figured out how to get cpanplus to use this respository. Not nearly as simple as with cpan, but once it is setup, it is a breeze. The following script does all the work.

#!/usr/bin/env perl

use strict;
use warnings;

my $local = {
                path   => '/home/mgrimes/CPAN',
                scheme => 'file',
                host   => '',
            };

use vars '$VERSION';

use CPANPLUS;
use CPANPLUS::Shell qw[Default];
use CPANPLUS::Backend;

$VERSION = CPANPLUS->VERSION;

# my $cb = new CPANPLUS::Backend;
my $shell = CPANPLUS::Shell->new;
my $conf = $shell->backend->configure_object;

my $hosts = [ $local ];
$conf->set_conf('hosts' => $hosts);

### if we're given a command, run it; otherwise, open a shell.
if (@ARGV) {
    ### take the command line arguments as a command
    my $input = "@ARGV";
    ### if they said "--help", fix it up to work.
    $input = 'h' if $input =~ /^\s*--?h(?:elp)?\s*$/i;
    ### strip the leading dash
    $input =~ s/^\s*-//;
    ### pass the command line to the shell
    $shell->dispatch_on_input(input => $input, noninteractive => 1);
} else {
    ### open a shell for the user
    $shell->shell();
}

Perl Tk on Cygwin

Getting Perl/Tk running under cygwin seems to be a constant pain. Until the recent perl release which went to a site/5.8 directory for modules, this was something that I went through every time I upgraded perl. I think I found the secret though. Apparently they dropped cygwin support in Tk804. You need to get Tk800.025 from cpan. Make test still reports a few errors, but the installation works for me.


Main

outlook

cygwin

perl

spam

vba

websites

excel

applescript

mac