Activar warnings en Perl

Por defecto los warnings están desactivados en Perl. Si nuestro código no se comporta correctamente no veremos estas advertencias de manera temprana y podríamos encontrarnos con problemas graves a futuro.

Los warnings se pueden activar de varias formas, estas son algunas de ellas:

Con el pragma warnings en un bloque de código

El indicar use warnings; activa los warnings hasta el final del bloque o bien hasta que se indique no warnings;

No afecta a los módulos incluidos (con use, require o do)

Esta es la forma recomendada. Provee más control de los warnings porque se puede activar donde y cuando se desee.

Con el parámetro -w o -W en el shebang del script

En la primer línea del script (shebang) se agrega uno de los 2 parámetros:

#!/usr/bin/perl -w

Con -w se activan los warnings en todo el código del script y módulos incluidos, excepto donde se utilice el pragma warnings (que tiene precedencia)

Con -W se activan los warnings en todo el código del script y módulos incluidos sin excepción.

Con la variable $^W = 1

Con ambos parámetros -w y -W, la variable Perl $^W se establece en 1. De la misma manera, podemos hacer esto directamente en el código:

$^W = 1;

Activa los warnings hasta el final del script y los módulos que se incluyan (solo con require o do), excepto donde se utilice el pragma warnings (que tiene precedencia)

Anuncios

Límites de fecha en timelocal de Perl

Una forma de validar una fecha en Perl es mediante la función timelocal del módulo Time::Local. El problemas es que en versiones de Perl menores a 5.12, las fechas que soporta están limitadas. En la documentación se indica “from Dec 1901 to Jan 2038”. Quise probar realmente estos límites y ahora les muestro un ejemplo práctico en Perl 5.8

Creamos un script con el siguiente código y lo llamamos test_timelocal.pl

#!/usr/bin/perl

use strict;

use Time::Local;

my ($fecha) = @ARGV;
$fecha =~ /^(\d{4})-(\d{2})-(\d{2})$/;
my ( $a, $m, $d ) = ($1,$2,$3);

my $time = undef;

eval {
      $time = timelocal(0,0,0,$d,--$m,$a); #se indica la cantidad de meses desde Enero (0..11)
};
if ( $@ ) { print "Fecha no definida"; }
else      { print $time; }

El mismo acepta como único parámetro una fecha. Obtendremos como resultado la cantidad de segundos desde el epoch del sistema.

Procedemos entonces a ejecutar desde la línea de comandos el script, intentando encontrar las fechas límite:

perl test_timelocal.pl 1901-12-16
-> Fecha no definida

perl test_timelocal.pl 1901-12-17
-> -2023488000

perl test_timelocal.pl 2038-01-16
-> 2147223600

perl test_timelocal.pl 2038-01-17
-> Fecha no definida

Comprobado empíricamente, en este caso las fechas soportadas por timelocal son aquellas que se encuentren en el rango desde 17/12/1901 al 16/01/2038, para versiones de Perl menores a 5.12

 

Basado en:

http://perldoc.perl.org/Time/Local.html#Limits-of-time_t

Ejecutar scripts CGI con código Perl desde Apache en Windows

Los scripts CGI comienzan con una línea llamada “shebang” denominada así por los caracteres #!  (cuyo número mágico en ASCII es 23 21) los cuales indican que el archivo es un script ejecutable (por las funciones de tipo “exec”). En la misma se indica el intérprete que se utilizará para procesar el código. Por lo general, el intérprete ignora la línea debido a que comienza con el caracter #, utilizado para comentarios en muchos lenguajes.

Una vez que Apache esté configurado para utilizar scripts CGI, utilizará esta línea para poder procesar correctamente los CGIs cuando se los soliciten (la utiliza efectivamente para lanzar el intérprete asociado al script).

El formato de la línea shebang es:

#!/<PATH_ABSOLUTO>/<INTERPRETE>

donde indicamos el PATH_ABSOLUTO y el INTERPRETE que corresponda.

La línea del shebang típica de los scripts Perl en sistemas con Linux es:

#!/usr/bin/perl

Para mantenerla en sistemas Windows, lo que les recomiendo es:

  1. Determinar la unidad en que están los archivos del sitio asociado al VirtualHost
    • Si los archivos están en C:\www\site\, la unidad es C:
  2. Crear el directorio “usr” en esta unidad y dentro de éste, crear el directorio “bin”
  3. Buscar el el archivo “perl.exe” dentro directorio donde hayan instalado Perl
  4. Copiar “perl.exe” desde su ubicación original a la ruta recientemente creada

De esta manera logramos el objetivo deseado porque Windows entiende que:

  • /usr/bin/ es lo mismo que C:\usr\bin\ o D:\usr\bin\ dependiendo de la unidad
  • perl es lo mismo que perl.exe debido a que es el único ejecutable con ese nombre en ese directorio
Alternativamente, podríamos cambiar la línea para que apunte a la ubicación donde está instalado Perl en Windows. Esta opción tiene algunas contras en ciertas situaciones que obligarán a cambiarla con frecuencia:
  • Se pueden estar desarrollando los scripts del mismo sistema en computadoras con Windows y Linux
  • Perl puede estar instalado en distintas ubicaciones en cada computadora
  • Podemos tener varios checkouts del código en distintas unidades dentro de la misma computadora

Configurar Apache para utilizar scripts CGI

Para poder invocar scripts CGI desde el navegador, es necesario configurar Apache de manera que lo permita. Para ello debemos seguir este sencillo instructivo:

Agregar Handler de CGI

Abrir en un editor de textos el archivo de configuración conf\httpd.conf ubicado dentro del directorio de instalación de Apache

Quitar el comentario de la línea (sólo borrando el # inicial) y guardar

#AddHandler cgi-script .cgi

Indicar la ejecución de CGIs en un VirtualHost

A partir de un VirtualHost que hayamos definido, según la versión de Apache:

  • Versión 2.0.x: En el mismo archivo de configuración (httpd.conf)
  • Versión 2.2.x: En el mismo archivo de configuración conf\extra\httpd-vhosts.conf

Agregar “+ExecCGI” a la cláusula Options dentro de Directory, manteniendo las preexistentes:

<VirtualHost *:80>
    ...
DocumentRoot SITE_PATH

    <Directory SITE_PATH>
        Options +ExecCGI +Indexes
    ...
    </Directory>
ServerName DOMINIO_LOCAL

    ...
</VirtualHost>

Adicionalmente sería conveniente agregar “index.cgi” a la cláusula DirectoryIndex del VirtualHost.

Reiniciar Apache

Procedemos a reiniciar el servicio de Apache para que tome la nueva configuración.

Probar el funcionamiento de CGI

Vamos a hacer la prueba ejecutando scripts CGI con Perl, por lo que requerimos que se encuentre instalado en el sistema. Tal vez tengamos que hacer unos ajustes adicionales para poder ejecutar scripts CGI con código Perl desde Apache en Windows.

En el directorio SITE_PATH correspondiente al VirtualHost, creamos un archivo llamado index.cgi con el siguiente contenido:

#!/usr/bin/perl

print "Content-type: text/html\n\n";

print "<h2>Configuraste correctamente apache para ejecutar scripts CGI con Perl</h2>";

Finalmente, abrimos un navegador y accedemos a la url DOMINIO_LOCAL del VirtualHost. Deberíamos ver el texto “Configuraste correctamente Apache para ejecutar scripts CGI con Perl“.

Quitar un módulo de Perl

Si utilizamos PPM para administrar módulos de Perl tenemos todas las herramientas allí mismo, incluso la posibilidad de quitar un módulo. Pero en el caso de que hayamos usado CPAN esa opción no está disponible. Podemos borrar manualmente los archivos pero puede quedarnos algún resto olvidado.

Estuve buscando alternativas hasta que encontré un script que se encarga de ellos, invocándolo con un módulo como argumento. Su funcionamiento se basa en el módulo ExtUtils de Perl. El mismo borra todos los archivos asociados y los directorios vacíos.

Creen un archivo con el nombre remove_module.pl, copien el siguiente código dentro y guárdenlo en un directorio conocido:

# remove_module.pl from PerlTricks.com

use ExtUtils::Installed;
use ExtUtils::Packlist;

# Exit unless a module name was passed
die ("Error: no Module::Name passed as an argument. E.G.\n\t perl $0 Module::Name\n") unless $#ARGV == 0;

my $module = shift @ARGV;

my $installed_modules = ExtUtils::Installed->new;

# iterate through and try to delete every file associated with the module
foreach my $file ($installed_modules->files($module)) {
    print "removing $file\n";
    unlink $file or warn "could not remove $file: $!\n";
}

# delete the module packfile
my $packfile = $installed_modules->packlist($module)->packlist_file;
print "removing $packfile\n";
unlink $packfile or warn "could not remove $packfile: $!\n";

# delete the module directories if they are empty
foreach my $dir (sort($installed_modules->directory_tree($module))) {
    print("removing $dir\n");
    rmdir $dir or warn "could not remove $dir: $!\n";
}

Aclaraciones:

El método directory_tree() trae todos los directorios contenidos en las rutas donde existan archivos del módulo (incluyendo el directorio raíz ej: c:\) y luego intenta borrarlos. No se preocupen porque solamente lo hará si están vacíos.

Si bien existe otro método, directories(), que trae solamente los directorios del módulo, esta limitado a aquellos de mayor nivel de profundidad

 

Entonces si lo que deseamos es quitar el módulo DBass, abrimos una línea de comandos y nos ubicamos en el directorio donde guardamos el script y ejecutamos mediante:

perl remove_module.pl DBass

removing C:/Perl/site/lib/DBass.pm
removing C:/Perl/html/site/lib/DBass.html
removing C:/Perl/site/lib/auto/DBass/.packlist
removing C:/
could not remove C:/: Directory not empty
removing C:/Perl
could not remove C:/Perl: Directory not empty
removing C:/Perl/html
could not remove C:/Perl/html: Directory not empty
removing C:/Perl/html/site
could not remove C:/Perl/html/site: Directory not empty
removing C:/Perl/html/site/lib
could not remove C:/Perl/html/site/lib: Directory not empty
removing C:/Perl/site
could not remove C:/Perl/site: Directory not empty
removing C:/Perl/site/lib
could not remove C:/Perl/site/lib: Directory not empty

Basado en:

http://perltricks.com/article/3/2013/3/27/How-to-cleanly-uninstall-a-Perl-module

Administrar módulos de Perl mediante PPM

Una forma de administrar los módulos de Perl pudiendo consultarlos, agregarlos, actualizarlos y quitarlos de nuestra instalación de Perl es mediante PPM (Perl Package Manager) de ActiveState. Alternativamente podemos administrarlos mediante CPAN.

PPM está disponible en 2 modos:

PPM – Interfaz gráfica

Para iniciar la interfaz gráfica podemos ir a Inicio > Perl Package Manager o bien desde  desde una consola lanzar:

ppm

En la ventana que se abre podremos buscar módulos a partir de su nombre (cambiando “::” por “-“) en las vistas de Todos, Instalables y Actualizables.

Una vez encontrado el módulo deseado, lo marcamos mediante el icono con el signo + o directamente presionando la tecla +. Análogamente, para quitarlo usamos el icono con el signo – o la tecla -.

Cuando terminamos de indicar todos los cambios a realizar, los ejecutamos con el icono de la flecha verde hacia la derecha (Ctrl + Enter)

Tendremos que confirmarlos junto con las dependencias a instalar/actualizar que los módulos seleccionados necesiten.

PPM – Consola

Para iniciar PPM en modo consola, abrimos una y tipeamos:

ppm-shell

Esto nos ubicará en el shell:

ppm>

Podemos realizar varias acciones, hasta salir mediante el comando exit o quit.

Consultar los paquetes instalados

ppm> list [ --matching <PATRON> ]

ppm> query <PATRON>

Ejemplo:

ppm> list --matching DBD

┌────────────┬─────────┬───────┬─────────┬──────┐
│ name       │ version │ files │ size    │ area │
├────────────┼─────────┼───────┼─────────┼──────┤
│ DBD-CSV    │ 0.38    │     3 │   31 KB │ perl │
│ DBD-ODBC   │ 1.31    │     9 │  329 KB │ perl │
│ DBD-Oracle │ 1.58    │    22 │  636 KB │ perl │
│ DBD-Pg     │ 2.19.3  │     8 │ 2035 KB │ perl │
│ DBD-SQLite │ 1.37    │     9 │ 6205 KB │ perl │
│ DBD-mysql  │ 4.022   │    13 │ 2963 KB │ site │
└────────────┴─────────┴───────┴─────────┴──────┘
 (6 packages installed matching 'dbd')

Listar archivos de un paquete instalado

ppm> files <PAQUETE>

Ejemplo:

ppm> files Archive::Tar

C:/Perl/html/bin/ptar.html
C:/Perl/html/bin/ptardiff.html
C:/Perl/html/bin/ptargrep.html
C:/Perl/html/site/lib/Archive/Tar.html
C:/Perl/html/site/lib/Archive/Tar/File.html
.......

Instalar un paquete o módulo

ppm> install <PAQUETE>|<MODULO>

Actualizar un paquete o módulo

ppm upgrade <PAQUETE>|<MODULO>

ppm update <PAQUETE>|<MODULO>

Ejemplo:

ppm> upgrade Archive::Zip

Downloading Archive-Zip-1.37...done
Unpacking Archive-Zip-1.37...done
Generating HTML for Archive-Zip-1.37...done
Updating files in site area...done
19 files installed

Borrar un paquete

ppm> remove <PAQUETE>

ppm> uninstall <PAQUETE>

Buscar paquetes en los repositorios

ppm search <PATRON>

El formato de salida depende de la cantidad de paquetes que se encuentren con el patrón. Si hay uno solo, se muestra la descripción del mismo. Si son pocos, se muestra información resumida de cada uno. Si son muchos, se listan el nombre y versión por cada línea.

Ejemplo:

ppm> search DBD-

1: AnyEvent-DBD-Pg 0.03
2: Bundle-DBD-PO 2.10
3: DBD-ADO 2.99
4: DBD-AnyData 0.110
...
30: DBD-iPod 0.01
31: DBD-mysql 4.022
32: DBD-mysqlPP 0.07

ppm> s *temp

1: Bundle-Latemp
A bundle to install external CPAN modules used by
Version: v0.2.4
Released: 2014-01-26

2: File-MkTemp
Make temporary filename from template
Version: 1.0.6
Released: 2000-02-23

3: File-Temp
return name and handle of a temporary file safely
Version: 0.2304
Released: 2013-10-10

...

ppm> describe 3

3: File-Temp
return name and handle of a temporary file safely
Version: 0.2304
Released: 2013-10-10
Author: David Golden <dagolden@cpan.org>
Provide: File::Temp version 0.2304
Require: Carp
Require: Carp::Heavy
Require: Cwd
Require: Exporter version 5.57 or better
Require: Fcntl version 1.03 or better
Require: File::Path version 2.06 or better
...
Require: strict
Require: vars
Repo: ActiveState Package Repository
Link: http://ppm4.activestate.com/MSWin32-x64/5.16/1603/D/DA/DAGOLDEN/File-Te
mp-0.2304.ppmx
CPAN: http://search.cpan.org/dist/File-Temp-0.2304/
Installed: 0.22 (perl)

Listar dependencias de un paquete

ppm> tree <PAQUETE>

Muestra las dependencias recursivamente del paquete indicado.

Ejemplo:

ppm> tree Scalar::Util

package Scalar-List-Utils-1.39
needs Test::More (v0.98 installed in perl area)
package Test-Simple-1.001003 provide Test::More
needs Scalar::Util 1.13 or better (v1.27 installed in perl area)
needs Test::Harness 2.03 or better (v3.26 installed in perl area)
package Scalar-List-Utils-1.39 provide Scalar::Util
package Test-Harness-3.32 provide Test::Harness
(no dependencies)

 

TIP ADICIONAL

Todos los comandos mencionados se pueden ejecutar directamente desde la consola sin ingresar a PPM, de la siguiente manera:

ppm <COMANDO> <ARGUMENTO>

Ejemplo:

ppm search File::Temp

Administrar módulos de Perl mediante CPAN

Una forma de consultar los módulos disponibles y agregarlos a nuestra instalación de Perl es mediante CPAN (Comprehensive Perl Archive Network). Alternativamente podemos administrarlos mediante PPM.

Accedemos a la línea de comandos y lanzamos CPAN mediante:

  • En Linux (con un superusuario)
    • perl -MCPAN -e shell
  • En Windows
    • perl -MCPAN -e "shell"

Si es la primera vez que lo hacemos nos indicará si deseamos hacer la configuración automática (lo que recomiendo) y nos ubicará en el shell:

cpan>

Podemos realizar varias acciones, hasta salir mediante el comando q.

Consultar la información de un módulo

cpan> i <MODULO>

nos indica si el módulo, existe la versión en CPAN (CPAN_VERSION) y si está instalado, el archivo (INST_FILE) y la versión (INST_VERSION)

Por ejemplo:

cpan> i Archive::Zip
Strange distribution name [Archive::Zip]
Module id = Archive::Zip
CPAN_USERID PHRED (Fred Moyer <fred@redhotpenguin.com>)
CPAN_VERSION 1.37
CPAN_FILE P/PH/PHRED/Archive-Zip-1.37.tar.gz
MANPAGE Archive::Zip - Provide an interface to ZIP archive files.
INST_FILE /usr/share/perl5/Archive/Zip.pm
INST_VERSION 1.18

Instalar o actualizar un módulo

cpan> install <MODULO>

instala el módulo indicado, o lo actualiza si tenemos una versión menor. Considerar que instala o actualiza el paquete completo que contiene al módulo!

Por ejemplo:

cpan> install Archive::Zip