Chris Winters


OpenInteract2::Package - Perform actions on individual packages


 # Programmatically install a package you've downloaded (for the real
 # world, see C<oi2_manage> and/or
 # L<OpenInteract2::Manage::Website::InstallPackage|OpenInteract2::Manage::Website::InstallPackage).
 # You get back a reference to the installed package.
 my $package = OpenInteract2::Package->install(
                         { package_file => '/home/perlguy/',
                           website_dir  => '/home/httpd/mysite' });
 # Create a new skeleton package for development (for the real world,
 # see C<oi2_manage>). You get back a reference to the newly created
 # package.
 my $package = OpenInteract2::Package->create_skeleton(
                         { name       => 'mynewpackage',
                           sample_dir => '/usr/local/src/OpenInteract-2.00/sample/package' });
 # Export package in the given directory for distribution
 my $package = OpenInteract2::Package->new({
                    directory => '/home/cwinters/pkg/mynewpackage' });
 my $export_filename = eval { $package->export };
 if ( $@ ) {
     print "Export failed: $@";
 else {
     print "Exported successfully to file '$export_filename'";
 # Read information about a package distribution
 my $package = OpenInteract2::Package->new({
                    package_file => '/home/cwinters/pkg/' });
 my $config = $package->config;
 print "Package ", $package->name, " ", $package->version, "\n",
       "Author ", join( ", ", @{ $config->author } ), "\n";
 my $files = $package->get_files;
 foreach my $filename ( @{ $files } ) {
     print "   File - $filename\n";
 # Check validity of a package
 my $package = OpenInteract2::Package->new({
                    directory => '/home/cwinters/pkg/mynewpackage' });
 my @status = $package->check;
 foreach my $status ( @status ) {
    print "Action: $status->{action}   OK? $status->{is_ok}\n";
 # Remove package
 my $package = OpenInteract2::Package->new({
                    directory => '/home/cwinters/pkg/mynewpackage' });
 # Get an object representing the changelog of a package and print out
 # the last version, date and message
 my $changes = $package->get_changes;
 my ( $latest_change ) = $changes->latest(1);
 print "$latest_change->{version}  on  $latest_change->{date}\n",


This module defines actions to be performed on individual packages. The first argument for many of the methods that


Class Methods

new( \%params )

Create a new package object. You can specify an archived package (using package_file) and be able to find out information about the package, or you can specify a directory (using directory) of an opened package.

If package_file, directory or a valid package_config are passed in we read the package information immediately.


  • package_file: Specify the package file to explore. An example is, although it's smart to specify the full path with the file.

    If the specified file does not exist we throw an exception.

  • directory: A package directory to explore. It's smart to specify the full path with the directory.

    If the specified directory does not exist we throw an exception.

  • package_config: A OpenInteract2::Config::Package object. We pull the package directory (package_dir property) from it.

  • repository: The OpenInteract2::Repository that this package belongs to.

install( \%params )

Installs the file specified in the parameter filename to the website specified in the parameter website_dir or retrieved from the OpenInteract2::Repository object specified in repository.

If the package already exists in the website repository we first remove its entry (leaving the old directory). We then unpack the given package file into the website, copy over any global files (those in html/ and widget/), and then create an entry in the website repository for the new package.


  • filename: A valid package file.

  • website_dir: Full path to a website we will install the package to.

  • repository: A OpenInteract2::Repository from which we can take the website directory.

Returns: package created from the new directory. Any failures throw an exception.

create_skeleton( \%params )

Creates a new package skeleton in the current directory. This is the recommended way to start developing a new OI2 package, similar to creating a new perl module using h2xs.


  • name: Name of your package. It should be all alphanumberic lower-case with no spaces. If not an exception is thrown.

  • sample_dir: The directory from where we pull our skeleton files from. This is normally in the OpenInteract source distribution directory, although you may elect to copy these files elsewhere so developers can have access.

  • source_dir: You can use this instead of sample_dir as long as the directory 'sample/package' exists underneath. (It should unless you have mucked with the source distribution.)

Returns: package created from the new directory. Any failures throw an exception.

generate_distribution_digest( $package_file )

Creates an MD5 digest of the contents in $package_file. (See Digest::MD5 for what this means.)

parse_full_name( $full_name )

Returns a two-item list of the package name and version found in $full_name.

Object Methods


Returns a string with the package name and version:

 $package->name( 'foo' );
 $package->version( '1.52' );
 print "Name: ", $package->full_name;
 # Name: foo-1.52

get_files( [ $force_read ] )

Reads list of files from package MANIFEST file. These results are cached in the object -- if you want to force a read pass a true value for $force_read.

Returns: arrayref of files in MANIFEST.

export( \%params )

Exports a package to a package distribution file. The name of the file is always:


If a file already exists with that name in the current directory, the process will throw an exception. Similarly, if a directory of the name:


already exists in the current directory an exception will be thrown.

Returns: the full path to the distribution file created.

check( \%params )

Checks the validity of a package. We perform the following checks:

  • Does the changelog exist? (This is not a fatal error, but you will get a virtual raspberry if you do not have one.)

  • Are all the files in MANIFEST in the package directory?

  • Are there any extra files in the package directory that are not in MANIFEST?

  • Are all the configuration INI files (action.ini, spops.ini) parseable?

  • Are all the perl modules includable? (A "perl module" includes any file ending in .pm.)

  • Are all the data files valid Perl data structures? (This includes all files in data/ ending in .dat.)

  • Are the Template Toolkit templates parseable? (This includes all files ending in .tmpl in template/ and all files in widget/.) The implementation of parseability can probably be improved, since we have to ignore certain errors caused by commonly available templates not being available since the template is not deployed in the full OI2 environment.

Returns a list of hashrefs indicating the status of the various package elements. Each hashref includes (at a minimum): 'is_ok', 'message' and 'action'. Some also include 'filename' where appropriate.

remove( [ $repository ] )

Removes a package from its repository. This may fail if you do not have a repository set in the package object or if you do not pass $repository into the method. It may also fail for reasons given in OpenInteract2::Repository.

Returns: array of status hashrefs, with a single member.


Retrieves SPOPS configuration files from the package. You can either specify the files yourself in the package configuration (see OpenInteract2::Config::Package), or this routine will pick up all files that match ^conf/spops.*\.ini$.

Returns: arrayref of relative SPOPS configuration files.


Retrieves action configuration files from the package. You can either specify the files yourself in the package configuration (see OpenInteract2::Config::Package), or this routine will pick up all files that match ^conf/action.*\.ini$.

Returns: arrayref of relative action configuration files.


Retrieves all documentation from the package. This includes all files in doc/.

Returns: arrayref of relative documentation files.


Retrieves message files from the package -- each one specifies i18n keys and values for use in templates and elsewhere. You can either specify the files yourself in the package configuration (see OpenInteract2::Config::Package), or this routine will pick up all files that match ^msg/*\.msg$.

Returns: arrayref of relative message files.


Returns the OpenInteract2::Config::PackageChanges object associated with this package.

find_file( @relative_files )

Finds the a file from the list @relative_files.

Returns: the full path to the first existing filename; if no file is found, undef.

read_file( $relative_file )

Slurps the contents of $relative_file into a variable and returns it. Finds full path to $relative_file using find_file().

Returns: contents of $relative_file; if $relative_file does not exist, returns undef. If there is an error reading $relative_file, throws exception.


name: Name of this package.

version: Version of this package.

package_file: The distribution (zip) file this package was read from.

directory: The directory this package was read from. Hopefully fully-qualified... (TODO: shouldn't it always be?)

repository: The OpenInteract2::Repository associated with this package.

installed_date: Date the package was installed. This is typically stored in the repository associated with the package.

config: The OpenInteract2::Config::Package object associated with this package.


Automatically create objects for HTML pages


In the relevant OI2::Manage class, just run the page scanner after a package has been installed.


For each file copied over to the /html directory, create a 'page' object in the system for it. Note that we might have to hook this up with the system that ensures we do not overwrite certain files. So we might need to either remove it from the _copy_package_files() routine, or add an argument to that routine that lets us pass in a coderef to execute with every item copied over.

ACK -- here is the problem. We do not know if we can even create an $R yet, because (1) the base_page package might not have even been installed yet (when creating a website) and (2) the user has not yet configured the database (etc.)

We can get around this whenever we rewrite Package/PackageRepository/oi_manage, but until then we will tell people to include the relevant data inserts with packages that include HTML documents.

Until then, here is what this might look like :-)

 # Now do the HTML files, but also create records for each of the HTML
 # files in the 'page' table

   my $copied = $class->_copy_package_files( "$info->{website_dir}/html",
                                             $pkg_file_list );
   my @html_locations = map { s/^html//; $_ } @{ $copied };
   foreach my $location ( @html_locations ) {
       my $page = $R->page->fetch( $location, { skip_security => 1 } );
       next if ( $page );
       eval {
           $R->page->new({ location => $location,
                                      ... })
                   ->save({ skip_security => 1 });






Copyright (c) 2002-2004 Chris Winters. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


Chris Winters <>