<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>CPAN &#8211; Johnny Morano&#039;s Tech Articles</title>
	<atom:link href="https://jmorano.moretrix.com/tag/cpan/feed/" rel="self" type="application/rss+xml" />
	<link>https://jmorano.moretrix.com</link>
	<description>Ramblings of an old-fashioned space cowboy</description>
	<lastBuildDate>Wed, 20 Apr 2022 07:18:55 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.6.2</generator>

<image>
	<url>https://jmorano.moretrix.com/wp-content/uploads/2022/04/cropped-jmorano_emblem-32x32.png</url>
	<title>CPAN &#8211; Johnny Morano&#039;s Tech Articles</title>
	<link>https://jmorano.moretrix.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Monitor running processes with Perl</title>
		<link>https://jmorano.moretrix.com/2014/05/monitor-running-processes-with-perl/</link>
					<comments>https://jmorano.moretrix.com/2014/05/monitor-running-processes-with-perl/#comments</comments>
		
		<dc:creator><![CDATA[Johnny Morano]]></dc:creator>
		<pubDate>Thu, 15 May 2014 12:33:22 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[CPAN]]></category>
		<category><![CDATA[Dev]]></category>
		<category><![CDATA[SysAdmin]]></category>
		<guid isPermaLink="false">http://jmorano.moretrix.com/?p=1081</guid>

					<description><![CDATA[Update: This article is updated thanks to Colin Keith his excellent comment. I was extremely inspired by it&#8230;]]></description>
										<content:encoded><![CDATA[
<p><strong>Update:</strong> This article is updated thanks to Colin Keith his excellent comment. I was extremely inspired by it</p>



<p>Maintaining a large number of servers cannot be done without proper programming skills. Each good system administrator must therefor make sure he knows how to automate his daily works.</p>



<p>Although many many programming languages exist, most persons will only write code in one. I happen to like Perl.</p>



<p>In this next blog post, I am going to show how to create a script which can be deployed on all the Linux servers you need to maintain and need to check for certain running services.</p>



<p>Of course, a tool as Nagios together with NRPE and a configured event-handler could also be used, but lately I was often in the situation that the &#8216;nrpe daemon&#8217; crashed, Nagios was spewing a lot of errors and the event-handler&#8230; well, since nrpe was down, the event-handler of course couldn&#8217;t connect or do anything. So why rely on a remote triggered action, when a simple script could be used.</p>



<p>The following script will check a default list of services and can additionally load or overwrite these services. A regular expression can be used to check for running processes, and of course, a startup command needs to be defined. And that is all the script will and should do.</p>



<p>The script uses three CPAN modules:</p>



<ul class="wp-block-list"><li><a title="Proc::ProcessTable" href="http://search.cpan.org/~jwb/Proc-ProcessTable-0.50/ProcessTable.pm">Proc::ProcessTable</a></li><li><a title="YAML" href="http://search.cpan.org/~ingy/YAML-0.90/lib/YAML.pm">YAML</a></li><li><a title="File::Slurp" href="http://search.cpan.org/~uri/File-Slurp-9999.19/lib/File/Slurp.pm">File::Slurp</a></li></ul>



<p>The first one will be used to get a full listing of all running processes and the second one will provide us a means for using configuration files.</p>



<p>So let&#8217;s start our script:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">#!/usr/bin/env perl 
use strict; use warnings;
use utf8;

use Proc::ProcessTable;
use YAML qw/LoadFile/;
use File::Slurp;

# Default set of processes to watch
my %default_services = (
    'NRPE' =&amp;gt; {
        'cmd'     =&amp;gt; '/etc/init.d/nagios-nrpe-server restart',
        're'      =&amp;gt; '/usr/sbin/nrpe -c /etc/nagios/nrpe.cfg -d',
	'pidfile' =&amp;gt; '/var/tmp/nagios-nrpe-server.pid',
    },
    'Freshclam' =&amp;gt; {
        'cmd'     =&amp;gt; '/etc/init.d/clamav-freshclam restart',
        're'      =&amp;gt; '/usr/bin/freshclam -d --quiet',
	'pidfile' =&amp;gt; '/var/tmp/clamav-freshclam.pid',
    },
    'Syslog-NG' =&amp;gt; {
        'cmd'     =&amp;gt; '/etc/init.d/syslog-ng restart',
        're'      =&amp;gt; '/usr/sbin/syslog-ng -p /var/run/syslog-ng.pid',
	'pidfile' =&amp;gt; '/var/run/syslog-ng.pid',     
    },
    'VMToolsD' =&amp;gt; {
        'cmd'     =&amp;gt; '/etc/init.d/vmware-tools restart',
        're'      =&amp;gt; '/usr/sbin/vmtoolsd',
	'pidfile' =&amp;gt; '/var/tmp/vmtoolsd.pid',
    },
    'Munin-Node' =&amp;gt; {
        'cmd'     =&amp;gt; '/etc/init.d/munin-node restart',
        're'      =&amp;gt; '/usr/sbin/munin-node',
	'pidfile' =&amp;gt; '/var/tmp/munin-node.pid',
    },
);

my (%services) = (%default_services);
</pre>



<p>Until now, no rocket science. We load the required modules, we defined our default services that need to be checked.</p>



<p>Next part, check if there is a configuration file on disk. The script looks for a hard-coded path &#8221;/etc/default/watchdog.yaml&#8221;:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Check if there is a local config file and if yes, load them in the services hash
if( -f '/etc/default/watchdog.yaml' ){
    my $local_config = LoadFile '/etc/default/watchdog.yaml';

    %services = (%default_services, %{ $local_config->{services} });
}
</pre>



<p>The last Perl statement actually allows to overwrite one or more (or even all) the default defined services.</p>



<p>Now let&#8217;s see if these processes are actually running. The following code was hugely inspired by Colin Keith&#8217;s comment below. I have combined his examples together with my code.</p>



<p>Let&#8217;s first have a look at the code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Get current process table
my $processes = Proc::ProcessTable-&amp;gt;new;
my %procs; 
my %matched_procs;
foreach my $p (@{ $processes }){
    $procs{ $p-&amp;gt;{pid} } = $p-&amp;gt;{cmndline};
    foreach my $s (keys %services){
        if($p-&amp;gt;{cmndline} =~ m#$services{$s}-&amp;gt;{re}#){
            $matched_procs{$s}++;
            last;
        }
    }
}

# Search the process table for not running services
foreach my $service ( keys %services ) {
    if(exists($services{$service}-&amp;gt;{pidfile}) &amp;amp;&amp;amp; -f $services{$service}-&amp;gt;{pidfile} ) {
        my $pid = read_file( glob($services{$service}-&amp;gt;{pidfile}) );
 
        # If we get a pid ensure that it is running, and that we can signal it
        $pid &amp;amp;&amp;amp; exists($procs{$pid}) &amp;amp;&amp;amp; kill(0, $pid) &amp;amp;&amp;amp; next;  
        
        # Remove the stale PID file because no running process for this PID file
        unlink( $services{$service}-&amp;gt;{pidfile} );
    }
    else {
        # check if the configured process regex matches
        if( exists($matched_procs{$service}) ){
            # process is running but has no PID file
            next;
        }
    }
	
    # Execute the service command
    system( $services{$service}-&amp;gt;{'cmd'} );

    # Check the exit code of the service command
    if ($? == -1) {
        print "Failed to restart '$service' with '$services{$service}-&amp;gt;{cmd}': $!\n";
    }
    elsif ($? &amp;amp; 127) {
        printf "Restart of '$service' died with signal %d, %s coredump\n", ($? &amp;amp; 127),  ($? &amp;amp; 128) ? 'with':'without';
    }
    else {
        printf "Process '$service' successfully restarted, exit status:  %d\n", $? &amp;gt;&amp;gt; 8;
    }
}
</pre>



<p>Lines 2 retrieves the current process list. We will save that information in two hashes with a little less information, because we actually only need the PID and the actual &#8216;command line&#8217; of each process.</p>



<p>At line 16 we will start looping through the processes we have defined in the <code>%services</code> hash.<br />Inspired by Colins post, we will check if the process&#8217; PID file is still there and if one is configured. If it still exists, we will then verify if the PID stored in the PID file, exists in the process list, which we have stored in <code>%procs</code>. This happens in lines 18-21.<br />At line 21, if the process is still running and the PID matches, we will check the next service to check (<code>&amp;&amp; next</code> part)<br />If the process is not running anymore but the PID file was still in the defined path, then it will be removed at line 24.</p>



<p>Otherwise, if no PID file was found or no PID file was configured, we will check the process list with the regular expression defined for that process. We have already created a hash, <code>%matched_procs</code> between lines 7 and 10, which we will use for this checking. If the process exists in the hash, we will skip and check the next process to be checked.</p>



<p>Now, if there was no PID file or the PID file was removed at line 24, the process will be started again. This happens at line 35.<br />I&#8217;ve executed it with the &#8216;system&#8217; function since I want to have the output of this command directly in STDOUT. And of course, the last thing to do is to check if the process started up correctly or not by checking its exit code.</p>



<p>Now save that script to for instance &#8216;watchdog.pl&#8217; and configure it in a cron job.<br />Example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">*/5 * * * * root /usr/local/bin/watchdog.pl
</pre>



<p>And here&#8217;s an example of the configuration file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">services:
    Exim-Mailserver:
        cmd: /etc/init.d/exim4 restart
        re: /usr/sbin/exim4 -bd -q30m
    Ossec-Agent:
        cmd: /etc/init.d/ossec restart
        re: !!perl/regexp '(?:ossec-agentd|ossec-logcollector|ossec-syscheckd)'

</pre>



<p>Link to script source code: <a href="https://github.com/insani4c/perl_tools/tree/master/watchdog" target="_blank" rel="noopener">https://github.com/insani4c/perl_tools/tree/master/watchdog</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://jmorano.moretrix.com/2014/05/monitor-running-processes-with-perl/feed/</wfw:commentRss>
			<slash:comments>15</slash:comments>
		
		
			</item>
		<item>
		<title>A simple TCP server written in Perl</title>
		<link>https://jmorano.moretrix.com/2013/09/simple-tcp-server-written-perl/</link>
					<comments>https://jmorano.moretrix.com/2013/09/simple-tcp-server-written-perl/#comments</comments>
		
		<dc:creator><![CDATA[Johnny Morano]]></dc:creator>
		<pubDate>Tue, 17 Sep 2013 12:47:04 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[CPAN]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[TCP]]></category>
		<guid isPermaLink="false">http://jmorano.moretrix.com/?p=997</guid>

					<description><![CDATA[The below example is a very simple TCP server script written in Perl, which uses the AnyEvent module.It&#8230;]]></description>
										<content:encoded><![CDATA[
<p>The below example is a very simple TCP server script written in Perl, which uses the <a href="http://software.schmorp.de/pkg/AnyEvent.html" target="_blank" rel="noopener">AnyEvent</a> module.<br />It will create a separate process for each connections and has the ability to return data to the parent process.<br />The below example allows 15 child processes to be created, which results in 15 simultaneous client connections.</p>



<p>The script itself is pretty straight-forward: it creates a server object using <em>IO::Socket::INET</em> and attaches that socket to an <em>AnyEvent</em> IO eventloop. Furthermore, upon every connection, it will call the subroutine <em>fork_call</em> (which is in the <em>AnyEvent::Util</em> module) to open up a client socket.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> 
#!/usr/bin/env perl 
use strict;
use warnings;
use utf8;

use IO::Socket::INET;
use AnyEvent;
use AnyEvent::Util;
$AnyEvent::Util::MAX_FORKS = 15;

my $handled = 0;
$|++;

my $server = IO::Socket::INET->new(
    'Proto'     => 'tcp',
    'LocalAddr' => 'localhost',
    'LocalPort' => 1234,
    'Listen'    => SOMAXCONN,
    'Reuse'     => 1,
) or die "can't setup server: $!\n";
print "Listening on localhost:1234\n";

my $cv = AnyEvent->condvar;
my $w; $w = AnyEvent->io(
        fh   => \*{ $server }, 
        poll => 'r', 
        cb   => sub { 
                   $handled++;
                   $cv->begin; 
                   fork_call &amp;handle_connections, 
                             $server->accept, 
                             sub { 
                               my ($client) = @_ ;
                               print " - Client $client closed\n"
                             } 
                    }
);
$cv->recv;

#
# Subroutines
# 
sub handle_connections {
    my ($client) =  @_;

    my $host = $client->peerhost;
    print "[Accepted connection from $host]\n";

    print $client "Hi, you're client #$handled\n";
    chomp ( my $input = &lt;$client> );
    my $output = reverse $input;
    print $client $output, "\n";
    print $client "Bye, bye.\n";

    $cv->end;
    return $host;
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://jmorano.moretrix.com/2013/09/simple-tcp-server-written-perl/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Generate thumbnails with Perl and Image Magick</title>
		<link>https://jmorano.moretrix.com/2011/04/generate-thumbnails-with-perl-and-image-magick/</link>
					<comments>https://jmorano.moretrix.com/2011/04/generate-thumbnails-with-perl-and-image-magick/#respond</comments>
		
		<dc:creator><![CDATA[insaniac]]></dc:creator>
		<pubDate>Tue, 19 Apr 2011 15:05:28 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Media]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Photo]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[CPAN]]></category>
		<guid isPermaLink="false">http://jmorano.moretrix.com/?p=581</guid>

					<description><![CDATA[Putting photos on a website has always been a pain. There were always a few steps you had&#8230;]]></description>
										<content:encoded><![CDATA[<p>Putting photos on a website has always been a pain. There were always a few steps you had to do, before they could be seen on your webpage. Of course, nowadays there are services like <a href="http://www.flickr.com/">Flickr</a>, <a href="http://picasa.google.com/">Picassa</a>, <a href="http://www.panoramio.com/">Panoramio</a>, <a href="http://www.facebook.com/">Facebook</a> &#8230; but you still have to go through quite some steps before you pictures are online.</p>
<p>One thing you don&#8217;t have to do with those online services like Flickr etc. is generating smaller sizes of your photos, also called thumbnails. But if you maintain your own website, you will have to downsize them on your own.<br />
Being a programmer, I&#8217;m the happiest when I&#8217;m the laziest. So, in case of websites and photos, I don&#8217;t want to create the zillion of thumbnails that I need on my page.<br />
Zillion? Isn&#8217;t that a little bit exajurated? Well, mostly you will need more  than one thumbnail for every picture you will upload:<br />
&#8211; one thumbnail is needed for on the thumbnail page<br />
&#8211; one smaller thumbnail is needed for a small thumbnail preview bar<br />
&#8211; one even smaller thumbnail is needed for marking the photo on a <a href="http://maps.google.com/">Google Map</a><br />
&#8211; one smaller sized photo is needed for previewing it on the website<br />
&#8211; and finally the original image is also put available for download on the site</p>
<p>We&#8217;ll need at least 4 extra images for every photo. Okay, I could generate all those thumbs at home and then upload them all together, but that is wasting bandwidth and time and we know how precious they both are.<br />
<span id="more-581"></span><br />
Being a programmer in my professional life, I have the deviation to automate everything I know or do, with a Perl script. And this situation is again perfect for such a script.</p>
<p>First of all, the following code will make heavy use of the <a href="http://search.cpan.org/~jcristy/PerlMagick-6.67/Magick.pm.in">Image::Magick</a> Perl module, which can be downloaded from either <a href="http://search.cpan.org/">CPAN</a> or your distro&#8217;s repositry.</p>
<p>The several steps of manipulating the original image, were actually inspired by the following two links:<br />
&#8211; <a href="http://www.imagemagick.org/Usage/thumbnails/#glass_bubble">http://www.imagemagick.org/Usage/thumbnails/#glass_bubble</a><br />
&#8211; <a href="http://stackoverflow.com/questions/3973392/facebook-like-resizing-of-images-using-imagemagick">http://stackoverflow.com/questions/3973392/facebook-like-resizing-of-images-using-imagemagick</a></p>
<p>The second link explains how to resize and crop, the first link explains how create neat thumbnails using rounded corners, lighting effects and more. Now, both links give examples using the command line Image Magick tools. I&#8217;ve seen a lot of code which will call these command line tools instead of using the Image::Magick module. That is of course, NOT the way.</p>
<p>On with creating our thumbnails! First, the image needs to be resized:</p>
<pre class="brush:perl">
my $img = 'image.png';
my $magick = new Image::Magick;
$magick->Read($img);
my ($width, $height) = $magick->Get('width', 'height');

$magick->Resize(geometry => int($width/2).'x'.int($height/2));
$magick->Resize(geometry => '180x');
$magick->Resize(geometry => 'x180<');
   
my($nwidth, $nheight) = $magick->Get('width', 'height');
my $xpos = int(( $nwidth - 120 ) / 2) - 60;
my $ypos = int(( $nheight - 120 ) / 2) - 60;
$magick->Crop(geometry => "120x120+$xpos+$ypos", gravity => 'Center');
</pre>
<p>The above code will generate a thumbnail which are 120px by 120px big (or small), using a cropped field out of the 180px by 180px scaled image. The position of the cropped field is somewhat in the middle of the image, where usually the object of the photo can be found.</p>
<p>Next we&#8217;ll add some effects to our downsized image. We&#8217;ll do this by cloning the resized Image Magick object, that was created in the code above:</p>
<pre class="brush:perl">
my $thumb_mask = $magick->Clone();
</pre>
<p>Once the object has been cloned, we can start by adding effects to the new object:</p>
<pre class="brush:perl">
$thumb_mask->Set('alpha' => 'Off');
$thumb_mask->Colorize( fill => 'white', opacity => '100%' );

$thumb_mask->Draw( fill => 'black',
                   primitive => 'polygon',
                   points => '0,0 0,15 15,0');
$thumb_mask->Draw( fill => 'white',
                       primitive => 'circle',
                       points => '15,15 15,0');
my $new_2 = $thumb_mask->Clone();
$new_2->Flip();
$thumb_mask->Composite( compose => 'Multiply', 'image' => $new_2 );

my $new_3 = $thumb_mask->Clone();
$new_3->Flop();
$thumb_mask->Composite( compose => 'Multiply', 'image' => $new_3 );

$thumb_mask->Set('background' => 'Gray50');
$thumb_mask->Set('alpha' => 'Shape');

$thumb_mask->Raise(raise => 'True', geometry => '4x4');
</pre>
<p>By now we should have a rounded gray icon, based on the size of the thumbnail we&#8217;ve created above.</p>
<p>Next we will create some lighting and shading effects so that the thumbnail will look more like a button.</p>
<pre class="brush:perl">
my $thumb_lighting = $thumb_mask->Clone();
$thumb_lighting->Set('bordercolor' => 'None');
$thumb_lighting->Set('border'      => '1x1');
$thumb_lighting->Set('alpha'       => 'Extract');
$thumb_lighting->Blur('geometry'       => '0x10');
$thumb_lighting->Shade(geometry => '80x40');
$thumb_lighting->Set('alpha'       => 'On');
$thumb_lighting->Set('background'  => 'Gray50');
$thumb_lighting->Set('alpha'       => 'Background');
$thumb_lighting->AutoLevel(channel => 'alpha');
$thumb_lighting->[-1]->Function(function => 'polynomial', parameters => [3.5, -5.05, 2.05, 0.3]);

my $new_4 = $thumb_lighting->Clone();
$new_4->Set(alpha => 'Extract');
$new_4->Blur(geometry => '0x2');

$thumb_lighting->Composite(compose => 'Multiply', image => $new_4);
$thumb_lighting->Chop(geometry => '1x1');
</pre>
<p>Finally, all that rests is putting all the images togehter and saving the file to disk:</p>
<pre class="brush:perl">
$magick->Set('alpha' => 'On');
$magick->Composite(compose => 'HardLight', image => $thumb_lighting);
$magick->Set('alpha' => 'Copy');
$magick->Composite(compose => 'CopyOpacity', image => $thumb_mask);
$magick->Write('thumbnail.png');
</pre>
<p>Important to know is, since creating rounded corner will add some transparency to the original image, the newly created thumbnail must be save as either a GIF or PNG image, while those are the only two image formats which support transparency in images.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://jmorano.moretrix.com/2011/04/generate-thumbnails-with-perl-and-image-magick/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Updating custom CPAN modules on Debian</title>
		<link>https://jmorano.moretrix.com/2011/03/updating-custom-cpan-modules-on-debian/</link>
					<comments>https://jmorano.moretrix.com/2011/03/updating-custom-cpan-modules-on-debian/#respond</comments>
		
		<dc:creator><![CDATA[insaniac]]></dc:creator>
		<pubDate>Thu, 10 Mar 2011 12:23:12 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[CPAN]]></category>
		<category><![CDATA[Dev]]></category>
		<category><![CDATA[SysAdmin]]></category>
		<guid isPermaLink="false">http://jmorano.moretrix.com/?p=544</guid>

					<description><![CDATA[On Debian based distributions, a handy tool called dh-make-perl can be installed to ease the installation of CPAN&#8230;]]></description>
										<content:encoded><![CDATA[<p>On Debian based distributions, a handy tool called <a href="http://search.cpan.org/~dam/DhMakePerl-0.72/dh-make-perl">dh-make-perl</a> can be installed to ease the installation of <a href="http://search.cpan.org/">CPAN</a> Perl modules on the system.<br />
This tool will create a <a href="http://www.debian.org/">Debian</a> package of the <a href="http://search.cpan.org/">CPAN</a> module, and can also install this package automatically. The advantage of this procedure is that when the CPAN module is picked by the Debian Perl Group for maintenance, an updated Debian will be installable through apt-get.</p>
<p>Of course, most people don&#8217;t want to wait on a group of other people to update a piece of software.<br />
<span id="more-544"></span><br />
I wrote this script to make my life a little bit easier, but it contains no rocket science. I&#8217;ve written it in <a href="http://www.perl.org/">Perl</a> but it could have been just as easily written in <strong>Bash</strong>. But <strong>Perl</strong> is much cooler than <strong>Bash</strong>, and being cool is all that matters!</p>
<p>The script actually uses some command line tools, that should be installed. <strong>apt-cache</strong> and <strong>egrep</strong> are installed by default on Debian(-based) systems, <strong>dh-make-perl</strong> must be installed separately.</p>
<pre class="brush:shell">
apt-get install dh-make-perl
</pre>
<p>Once <strong>dh-make-perl</strong> is installed, check out the man page for its options and arguments.</p>
<p>What are the steps required in the script:</p>
<ul>
<li>get a list of Perl packages</li>
<li>filter out packages installed by dh-make-perl</li>
<li>check if we really need to upgrade</li>
<li>create new packages out of the CPAN versions</li>
<li>optionally display the required packages</li>
</ul>
<p>Packages created by <strong>dh-make-perl</strong> can be filtered out based on the package description. dh-make-perl adds &#8216;<em>&#8230;automagically extracted from the module by dh-make-perl</em>&#8216; to the package description when creating a Debian package.</p>
<p>It is possible that the package building of the CPAN module fails because the required modules or packages are missing. This information will be displayed when the scripts finishes. You will have to install this missing requirements and relaunch the script afterwards.</p>
<p>When build the Debian with <strong>dh-make-perl</strong>, the option &#8216;<strong>&#8211;recursive</strong>&#8216; will be used. This will also create Debian packages of required modules defined by the CPAN module.</p>
<p>When all these packages have been created, installed them with the <strong>dpkg</strong> command:</p>
<pre class="brush:shell">
# dpkg -i $(ls -rt *.dpkg)
</pre>
<p>I&#8217;ve used the <strong>$(ls -rt *.dpkg)</strong> syntax because the packages will be in the order like they have been built.</p>
<p><strong>The script:</strong></p>
<pre class="brush:perl">
#!/usr/bin/perl
# $Author: insaniac $
# $Id: upgrade_cpan_pkgs.pl 24 2011-03-10 13:54:32Z insaniac $
use strict; use warnings;
use Cwd;
use CPAN;

my $cwd = getcwd;
my ($script) = ($0 =~ /([^/]+)$/);
open my $LOG, '>', "$cwd/${script}_log" or die "KAK for [$cwd/$0_log]: $!n";

my %needed_pkgs;
foreach my $pkg (`apt-cache pkgnames | egrep '\-perl$'`){
    chomp($pkg);
    my $info = `apt-cache show $pkg`;
    if($info =~ m/automagically extracted from the module by dh-make-perl/ms){
        my ($cpan_pkg) = ( $pkg =~ m/^lib(.*?)-perl$/);
        $cpan_pkg =~ s/[_-]/::/g;
        my ($installed_version) = ( $info =~ m/Version:s+(.*?)-[0-9.]+$/m );
        my ($cpan_version) = CPAN::Shell->expand('Module', "/$cpan_pkg/");
        
        next unless ref $cpan_version;
        $cpan_version = $cpan_version->cpan_version;

        if($installed_version eq $cpan_version){
            print "- Package $cpan_pkg does not require updating (current version: $installed_version| CPAN version: $cpan_version)n";
            next;
        }


        print "- Building $cpan_pkg (outdated! installed version: $installed_version|CPAN version: $cpan_version)n";
        print $LOG "- Building $cpan_pkg (outdated! installed version: $installed_version|CPAN version: $cpan_version)n";
        print $LOG "="x80, "n";
        
        my $pkg_upgrade_info = `dh-make-perl --recursive --build --cpan $cpan_pkg`;
        print $LOG $pkg_upgrade_info;

        my ($need_deb_pkgs) = ($pkg_upgrade_info =~ m/Needs the following debian packages:s+(.*)$/ms);
        my ($need_build_deb_pkgs) = ($pkg_upgrade_info =~ m/Needs the following debian packages during building:s+(.*)$/ms);
        print $LOG "need_deb_pkgs: $need_deb_pkgsn"                if $need_deb_pkgs;
        print $LOG "need_build_deb_pkgs: $need_build_deb_pkgsn"    if $need_build_deb_pkgs;

        map { defined $_ && $needed_pkgs{$_}++ } split( /s*,s*/, $need_deb_pkgs )       if defined $need_deb_pkgs;
        map { defined $_ && $needed_pkgs{$_}++ } split( /s*,s*/, $need_build_deb_pkgs ) if defined $need_build_deb_pkgs;

        print $LOG "="x80, "n";
    }
}

print "Needed packages:n";
print "- $_: $needed_pkgs{$_} timesn" foreach keys %needed_pkgs;
print "n";
close $LOG;
</pre>
<p>Some output produced by the script:</p>
<pre class="brush:shell">
$ perl ~/cheese_code/trunk/upgrade_cpan_pkgs.pl 2>&1|tee upgrade.log
CPAN: Storable loaded ok (v2.20)
Going to read '/home/insaniac/.cpan/Metadata'
  Database was generated on Sat, 05 Mar 2011 22:27:24 GMT
- Package geo::ip::pureperl does not require updating (current version: 1.25| CPAN version: 1.25)
- Package html::fromansi does not require updating (current version: 2.03| CPAN version: 2.03)
- Package net::google::calendar does not require updating (current version: 1.0| CPAN version: 1.0)
- Building poe::component::server::httpserver (outdated! installed version: 0.9.2|CPAN version: 0.009002)
Using cached Contents from Thu Mar 10 14:38:42 2011
**********
WARNING: a package named
              'libpoe-component-server-httpserver-perl'
         is already available in APT repositories
Maintainer: Johnny Morano <insaniac@moretrix.com>
Description: serve HTTP requests
- Package poe::filter::log::iptables does not require updating (current version: 0.02| CPAN version: 0.02)
- Package uri::imaps does not require updating (current version: 1.01| CPAN version: 1.01)
- Building class::accessor::chained (outdated! installed version: 0.01.1~debian|CPAN version: 0.01)
Using cached Contents from Thu Mar 10 14:38:42 2011
**********
WARNING: a package named
              'libclass-accessor-chained-perl'
         is already available in APT repositories
Maintainer: James Bromberger <jeb@debian.org>
Description: make chained accessors
- Package www::google::contacts does not require updating (current version: 0.28| CPAN version: 0.28)
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://jmorano.moretrix.com/2011/03/updating-custom-cpan-modules-on-debian/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
