installer: further moves of zebra configuration files
[koha_fer] / Makefile.PL
index 7671fda..5438aee 100644 (file)
 # See http://www.koha.org/wiki/?page=KohaInstaller
 #
 
+use strict;
+use warnings;
 use ExtUtils::MakeMaker;
 use POSIX;
 use File::Spec;
 
+my $DEBUG = 0;
 die "perl 5.6.1 or later required" unless ($] >= 5.006001);
 
 # Hash up directory structure & files beginning with the directory we were called from (should be the base of koha)...
@@ -79,11 +82,6 @@ Hash of perl modules and versions required.
 
 Hash of file mappings
 
-=head2 CONFIGURE
-
-Maybe use prompt() here in future to get configuration values 
-interactively at installation time.
-
 =head2 PL_FILES
 
 This is a hash of PL scripts to run after installation and
@@ -108,8 +106,8 @@ contents will be copied to the installation target directory.
 its target overrides the parent's target for that subdirectory.
 
 =item The value of each map entry may either be a scalar containing 
-one target or a reference to an array of targets, in which case
-the directory or file is copied to each target.
+one target or a reference to a hash containing 'target' and 'trimdir'
+keys.
 
 =item Any files at the top level of the source tree that are
 not included in the map will not be installed.
@@ -121,7 +119,7 @@ current organization of the source tree, but (FIXME) it
 would be better to reorganize the source tree to better
 match the installation system, to allow adding new directories
 without having to adjust Makefile.PL each time.  The idea
-is to make the C<%target_map> hash as minimal as possible.
+is to make the C<$target_map> hash as minimal as possible.
 
 =back
 
@@ -168,6 +166,43 @@ Directory for Koha configuration files.
 
 Directory for Zebra configuration files.
 
+=item ZEBRA_LOCK_DIR
+
+Directory for Zebra's lock files.
+
+=item ZEBRA_DATA_DIR
+
+Directory for Zebra's data files.
+
+=item ZEBRA_RUN_DIR
+
+Directory for Zebra's UNIX-domain sockets.
+
+=item EXAMPLE_DIR
+
+Directory for example configuration files.  This directory
+exists primarily to make it easier to change the
+MARC format or language of the active Zebra
+indexes.
+
+=item SCRIPT_DIR
+
+Directory for command-line scripts and daemons.
+
+=item MAN_DIR
+
+Directory for man pages created from POD -- will mostly
+contain information of interest to Koha developers.
+
+=item DOC_DIR
+
+Directory for Koha documentation accessed from the 
+command-line, e.g., READMEs.
+
+=item LOG_DIR
+
+Directory for Apache and Zebra logs produced by Koha.
+
 =item NONE
 
 This is a dummy target used to explicitly state
@@ -180,49 +215,72 @@ production installation.
 
 =cut
 
-my %target_map = (
-  'about.pl'                  => 'INTRANET_CGI_DIR',
-  'acqui'                     => 'INTRANET_CGI_DIR',
-  'admin'                     => 'INTRANET_CGI_DIR',
-  'authorities'               => 'INTRANET_CGI_DIR',
-  'C4'                        => 'PERL_MODULE_DIR',
-  'catalogue'                 => 'INTRANET_CGI_DIR',
-  'cataloguing'               => 'INTRANET_CGI_DIR',
-  'changelanguage.pl'         => [ 'INTRANET_CGI_DIR', 'OPAC_CGI_DIR' ],
-  'check_sysprefs.pl'         => 'NONE',
-  'circ'                      => 'INTRANET_CGI_DIR',
-  'edithelp.pl'               => 'INTRANET_CGI_DIR',
-  'etc'                       => 'KOHA_CONF_DIR',
-  'etc/zebradb'               => 'ZEBRA_CONF_DIR',
-  'installer-CPAN.pl'         => 'NONE',
-  'installer'                 => 'INTRANET_CGI_DIR',
-  'koha-tmpl'                 => 'NONE',
-  'koha-tmpl/intranet-tmpl'   => 'INTRANET_TMPL_DIR',
-  'koha-tmpl/opac-tmpl'       => 'OPAC_TMPL_DIR',
-  'koha-version.pl'           => 'INTRANET_CGI_DIR', # FIXME this may need to be in OPAC_CGI_DIR as well, with an update to C4::Context
-  'labels'                    => 'INTRANET_CGI_DIR',
-  'mainpage.pl'               => 'INTRANET_CGI_DIR',
-  'Makefile.PL'               => 'NONE',
-  'MANIFEST.SKIP'             => 'NONE',
-  'members'                   => 'INTRANET_CGI_DIR',
-  'misc'                      => 'NONE', # FIXME deal with a little later
-  'opac'                      => 'OPAC_CGI_DIR',
-  'README.txt'                => 'NONE',
-  'reports'                   => 'INTRANET_CGI_DIR',
-  'reserve'                   => 'INTRANET_CGI_DIR',
-  'reviews'                   => 'INTRANET_CGI_DIR',
-  'rewrite-config.PL'         => 'NONE',
-  'reviews'                   => 'INTRANET_CGI_DIR',
-  'rss'                       => 'NONE', # FIXME deal with a little later
-  'serials'                   => 'INTRANET_CGI_DIR',
-  'sms'                       => 'INTRANET_CGI_DIR',
-  'suggestion'                => 'INTRANET_CGI_DIR',
-  'svc'                       => 'INTRANET_CGI_DIR',
-  't'                         => 'NONE',
-  'tmp'                       => 'NONE', # FIXME deal with later
-  'tools'                     => 'INTRANET_CGI_DIR',
-  'virtualshelves'            => 'INTRANET_CGI_DIR',
-);
+my $target_map = {
+  './about.pl'                  => 'INTRANET_CGI_DIR',
+  './acqui'                     => 'INTRANET_CGI_DIR',
+  './admin'                     => 'INTRANET_CGI_DIR',
+  './authorities'               => 'INTRANET_CGI_DIR',
+  './C4'                        => 'PERL_MODULE_DIR',
+  './C4/SIP/t'                  => 'NONE',
+  './C4/SIP/koha_test'          => 'NONE',
+  './C4/tests'                  => 'NONE',
+  './catalogue'                 => 'INTRANET_CGI_DIR',
+  './cataloguing'               => 'INTRANET_CGI_DIR',
+  './changelanguage.pl'         => 'INTRANET_CGI_DIR',
+  './check_sysprefs.pl'         => 'NONE',
+  './circ'                      => 'INTRANET_CGI_DIR',
+  './edithelp.pl'               => 'INTRANET_CGI_DIR',
+  './etc'                       => { target => 'KOHA_CONF_DIR', trimdir => -1 },
+  './etc/zebradb'               => { target => 'ZEBRA_CONF_DIR', trimdir => -1 },
+  './help.pl'                   => 'NONE', # FIXME
+  './installer-CPAN.pl'         => 'NONE',
+  './installer'                 => 'INTRANET_CGI_DIR',
+  './koha-tmpl/errors'          => {target => 'INTRANET_CGI_DIR', trimdir => 2},
+  './koha-tmpl/intranet-tmpl'   => {target => 'INTRANET_TMPL_DIR', trimdir => -1},
+  './koha-tmpl/opac-tmpl'       => {target => 'OPAC_TMPL_DIR', trimdir => -1},
+  './kohaversion.pl'            => 'INTRANET_CGI_DIR', # FIXME this may need to be in OPAC_CGI_DIR as well, with an update to C4::Context
+  './labels'                    => 'INTRANET_CGI_DIR',
+  './mainpage.pl'               => 'INTRANET_CGI_DIR',
+  './Makefile.PL'               => 'NONE',
+  './MANIFEST.SKIP'             => 'NONE',
+  './members'                   => 'INTRANET_CGI_DIR',
+  './misc'                      => { target => 'SCRIPT_DIR', trimdir => -1 }, 
+  './misc/info'                 => { target => 'DOC_DIR', trimdir => 2 },
+  './misc/release notes'        => { target => 'DOC_DIR', trimdir => 2 },
+  './misc/translator'           => { target => 'EXAMPLE_DIR', trimdir => 2 }, 
+  './misc/installer_devel_notes' => 'NONE',
+  './opac'                      => 'OPAC_CGI_DIR',
+  './README.txt'                => 'NONE',
+  './reports'                   => 'INTRANET_CGI_DIR',
+  './reserve'                   => 'INTRANET_CGI_DIR',
+  './reviews'                   => 'INTRANET_CGI_DIR',
+  './rewrite-config.PL'         => 'NONE',
+  './reviews'                   => 'INTRANET_CGI_DIR',
+  './rss'                       => 'NONE', # FIXME deal with a little later
+  './serials'                   => 'INTRANET_CGI_DIR',
+  './skel'                      => 'NONE',
+  './skel/var/run/koha/zebradb' => { target => 'ZEBRA_RUN_DIR', trimdir => -1 },
+  './skel/var/lock/koha/zebradb/authorities' => { target => 'ZEBRA_LOCK_DIR', trimdir => 6 },
+  './skel/var/lib/koha/zebradb/authorities/key'  => { target => 'ZEBRA_DATA_DIR', trimdir => 6 },
+  './skel/var/lib/koha/zebradb/authorities/register'  => { target => 'ZEBRA_DATA_DIR', trimdir => 6 },
+  './skel/var/lib/koha/zebradb/authorities/shadow'  => { target => 'ZEBRA_DATA_DIR', trimdir => 6 },
+  './skel/var/lib/koha/zebradb/authorities/tmp'  => { target => 'ZEBRA_DATA_DIR', trimdir => 6 },
+  './skel/var/lock/koha/zebradb/biblios' => { target => 'ZEBRA_LOCK_DIR', trimdir => 6 },
+  './skel/var/lib/koha/zebradb/biblios/key'  => { target => 'ZEBRA_DATA_DIR', trimdir => 6 },
+  './skel/var/lib/koha/zebradb/biblios/register'  => { target => 'ZEBRA_DATA_DIR', trimdir => 6 },
+  './skel/var/lib/koha/zebradb/biblios/shadow'  => { target => 'ZEBRA_DATA_DIR', trimdir => 6 },
+  './skel/var/lib/koha/zebradb/biblios/tmp'  => { target => 'ZEBRA_DATA_DIR', trimdir => 6 },
+  './sms'                       => 'INTRANET_CGI_DIR',
+  './suggestion'                => 'INTRANET_CGI_DIR',
+  './svc'                       => 'INTRANET_CGI_DIR',
+  './t'                         => 'NONE',
+  './tmp'                       => 'NONE', # FIXME deal with later
+  './tools'                     => 'INTRANET_CGI_DIR',
+  './virtualshelves'            => 'INTRANET_CGI_DIR',
+  # ignore files and directories created by the install itself
+  './pm_to_blib'                => 'NONE',
+  './blib'                      => 'NONE',
+};
 
 =head1 CONFIGURATION OPTIONS
 
@@ -266,14 +324,22 @@ indexed by Zebra.
 my %config_defaults = (
   'INSTALL_MODE'      => 'standard',
   'INSTALL_BASE'      => '/usr/share/koha',
+  'DB_TYPE'           => 'mysql',
+  'DB_HOST'           => 'localhost',
+  'DB_NAME'           => 'koha',    
+  'DB_USER'           => 'kohaadmin',
+  'DB_PASS'           => 'katikoan',
   'INSTALL_ZEBRA'     => 'yes',
   'ZEBRA_MARC_FORMAT' => 'marc21',
   'ZEBRA_LANGUAGE'    => 'en',
+  'ZEBRA_USER'        => 'kohauser',
+  'ZEBRA_PASS'        => 'zebrastripes',
 );
 
 # valid values for certain configuration options
 my %valid_config_values = (
   'INSTALL_MODE'  => { 'standard' => 1, 'single' => 1, 'dev' => 1 },
+  'DB_TYPE' => { 'mysql' => 1, 'Pg' => 1 },
   'INSTALL_ZEBRA' => { 'yes' => 1, 'no' => 1 },
   'ZEBRA_MARC_FORMAT' => { 'marc21' => 1, 'unimarc' => 1 }, # FIXME should generate from contents of distributation
   'ZEBRA_LANGUAGE'    => { 'en' => 1, 'fr' => 1 }, # FIXME should generate from contents of distribution
@@ -281,6 +347,9 @@ my %valid_config_values = (
 
 my %config = get_configuration(\%config_defaults, \%valid_config_values);
 my %target_directories = get_target_directories(\%config);
+display_configuration(\%config, \%target_directories);
+my $file_map = {};
+get_file_map($target_map, $dirtree, $file_map);
 
 WriteMakefile(
     NAME => 'koha',
@@ -346,11 +415,11 @@ WriteMakefile(
         },
 
        # File tree mapping
-#      PM => map_tree(),
-       PM => unhashdir($dirtree),
+       PM => $file_map,
 
-       # disable tests
-       'test' => {TESTS => 't/dummy.t'},
+    # Man pages generated from POD
+    INSTALLMAN1DIR => File::Spec->catdir($target_directories{'MAN_DIR'}, 'man1'),
+    INSTALLMAN3DIR => File::Spec->catdir($target_directories{'MAN_DIR'}, 'man3'),
 
 #   CONFIGURE => sub {
 #     # Ask for options with prompt($question,$default) calls here?
@@ -359,11 +428,11 @@ WriteMakefile(
 
    PL_FILES => { # generator => target(s)
       'rewrite-config.PL' => [
-         '$(PREFIX)/share/koha/etc/koha-conf.xml',
-         '$(PREFIX)/share/koha/etc/koha-httpd.conf',
-         '$(PREFIX)/share/koha/etc/zebradb/etc/passwd',
-         '$(PREFIX)/share/koha/etc/zebradb/zebra-biblios.cfg',
-         '$(PREFIX)/share/koha/etc/zebradb/zebra-authorities.cfg'
+         'blib/KOHA_CONF_DIR/koha-conf.xml',
+         'blib/KOHA_CONF_DIR/koha-httpd.conf',
+         'blib/ZEBRA_CONF_DIR/etc/passwd',
+         'blib/ZEBRA_CONF_DIR/zebra-biblios.cfg',
+         'blib/ZEBRA_CONF_DIR/zebra-authorities.cfg'
          ]
    }
 #     'opac/getfromintranet.PL' => ['$(INST_LIBDIR)/opac/cgi-bin/detail.pl','$(INST_LIBDIR)/opac/cgi-bin/moredetail.pl','$(INST_LIBDIR)/opac/cgi-bin/search.pl','$(INST_LIBDIR)/opac/cgi-bin/subjectsearch.pl','$(INST_LIBDIR)/opac/cgi-bin/logout.pl'],
@@ -395,7 +464,7 @@ sub hashdir{
     opendir my $dh, $dir or die $!;
     my $tree = {}->{$dir} = {};
     while( my $file = readdir($dh) ) {
-        next if $file =~ m/^\.{1,2}/;
+        next if $file =~ m/^\.{1,2}/ and $file !~ /^\.htaccess/; # .htaccess is a special case
         my $path = $dir .'/' . $file;
         $tree->{$file} = hashdir($path), next if -d $path;
         push @{$tree->{'.'}}, $file;
@@ -403,49 +472,121 @@ sub hashdir{
     return $tree;
 }
 
-=head2 unhashdir
-
-This function unhashes the hash of hashes generated by hashdir().
-This directory unhashing routine is the personal work of Chris Nighswonger (fbcit).
-Modified here to build koha makefile. It lists all files and where to install each one.
-It then returns a hash reference suitable for the PM variable above.
-
-=cut
-
-sub unhashdir{
-       my $dirhash = shift;
-       my $dirlevel = shift;
-       my $toplevel = $dirlevel;
-       for my $k1 ( sort keys %$dirhash ) {
-               if ($k1 ne '.' && $k1 ne '') {
-                       $dirlevel = ( $dirlevel ? $dirlevel . '/' . $k1 : $k1 );
-                       &unhashdir($dirhash->{ $k1 }, $dirlevel);
-                       $dirlevel = $toplevel;
-               }
-               elsif ( $k1 eq '.' ) {
-                       foreach $file ( @{$dirhash->{ $k1 }} ) {
-#                              TODO: There are some hacks here that may be able to be improved... -fbcit
-                               if ( $file =~ /^./ ) { next; } # skip hidden files and directories.
+=head2 get_file_map 
 
-                               elsif ( $file =~ /\.pm/ && $dirlevel =~ /C4/ ) { $result{ ($dirlevel ? $dirlevel . '/' . $file : $file) } = '$(INST_LIBDIR)/' . ($dirlevel ? $dirlevel . '/' . $file : $file); } # C4/*.pm is copied to perl's lib namespace.
+This function combines the target_map and file hash to
+map each source file to its destination relative to
+the set of installation targets.
 
-                               elsif ( $dirlevel !~ /koha-tmpl/ && $dirlevel =~ /(installer|errors)/ ) { $result{ ($dirlevel ? $dirlevel . '/' . $file : $file) } = '$(PREFIX)/lib/cgi-bin/koha/' . ($dirlevel ? $dirlevel . '/' . $file : $file); } # error templates are copied to $(PREFIX)/lib/cgi-bin/koha/
+Output will be a hash mapping from each source file
+to its destination value, like this:
 
-                               elsif ( $dirlevel =~ /koha-tmpl/ && $dirlevel !~ /errors/ ) { $result{ ($dirlevel ? $dirlevel . '/' . $file : $file) } = '$(INST_LIBDIR)/koha/templates/' . ($dirlevel ? $dirlevel . '/' . $file : $file); } # error templates are copied to $(INST_LIBDIR)/koha/templates/
+'mainpage.pl' => '$(INTRANET_CGI_DIR)/mainpage.pl'
 
-                               elsif ( $dirlevel =~ /(misc|rss)/ ) { $result{ ($dirlevel ? $dirlevel . '/' . $file : $file) } = '$(INST_LIBDIR)/koha/' . ($dirlevel ? $dirlevel . '/' . $file : $file); } # misc & rss are copied to koha,
-
-#                              elsif ( $dirlevel =~ /(intranet-tmpl|opac-tmpl)/ ) { $result{ ($dirlevel ? $dirlevel . '/' . $file : $file) } = '$(INST_LIBDIR)/koha/templates/' . ($dirlevel ? $dirlevel . '/' . $file : $file); } # Templates are copied to koha/templates,
-
-                               elsif ( $file !~ /\.pl/ && $dirlevel =~ /etc/ ) { $result{ ($dirlevel ? $dirlevel . '/' . $file : $file) } = '$(PREFIX)/share/koha/' . ($dirlevel ? $dirlevel . '/' . $file : $file); } # Misc etc to koha/etc
+=cut
 
-                               elsif ( $file =~ /\.pl/ ) { $result{ ($dirlevel ? $dirlevel . '/' . $file : $file) } = '$(PREFIX)/lib/cgi-bin/koha/' . ($dirlevel ? $dirlevel . '/' . $file : $file); } # CGIs are copied to $(PREFIX)/lib/cgi-bin/koha/ print $result{ ($dirlevel ? $dirlevel . '/' . $file : $file)},"\n\n"; 
+sub get_file_map {
+    my $target_map = shift;
+    my $dirtree = shift;
+    my $file_map = shift;
+    my $curr_path = @_ ? shift : ['.'];
+
+    # Traverse the directory tree.
+    # For each file or directory, identify the
+    # most specific match in the target_map
+    foreach my $dir (sort keys %{ $dirtree }) {
+        if ($dir eq '.') {
+            # deal with files in directory
+            foreach my $file (sort @{ $dirtree->{$dir} }) {
+                my $targetdir = undef;
+                my $matchlevel = undef;
+                # first, see if there is a match on this specific
+                # file in the target map
+                my $filepath = join("/", @$curr_path, $file);
+                if (exists $target_map->{$filepath}) {
+                    $targetdir = $target_map->{$filepath};
+                    $matchlevel = scalar(@$curr_path) + 1;
+                } else {
+                    # no match on the specific file; look for
+                    # a directory match
+                    for (my $i = scalar(@$curr_path) - 1; $i >= 0; $i--)  {
+                        my $dirpath = join("/", @$curr_path[0..$i]);
+                        if (exists $target_map->{$dirpath}) {
+                            $targetdir = $target_map->{$dirpath};
+                            $matchlevel = $i + 1;
+                            last;
+                        }
+                    }
+                }
+                if (defined $targetdir) {
+                     _add_to_file_map($file_map, $targetdir, $curr_path, $file, $matchlevel);
+                } else {
+                    my $path = join("/", @$curr_path);
+                    print "failed to map: $path/$file\n" if $DEBUG;
+                }
+            }
+        } else {
+            # dealing with subdirectory
+            push @$curr_path, $dir;
+            get_file_map($target_map, $dirtree->{$dir}, $file_map, $curr_path);
+            pop @$curr_path;
+        }
+    }
+}
 
-                       }
-                       next;
-               }
-       }
-       return \%result;
+sub _add_to_file_map {
+    my $file_map = shift;
+    my $targetdir = shift;
+    my $curr_path = shift;
+    my $file = shift;
+    my $matchlevel = shift;
+    my $dest_path = @_ ? shift : $curr_path;
+
+    # The target can be one of the following:
+    # 1. scalar representing target symbol
+    # 2. hash ref containing target and trimdir keys
+    #
+    # Consequently, this routine traverses this structure,
+    # calling itself recursively, until it deals with
+    # all of the scalar target symbols.
+    if (ref $targetdir eq 'HASH') {
+        my $subtarget = $targetdir->{target};
+        if (exists $targetdir->{trimdir}) {
+            # if we get here, we've specified that
+            # rather than installing the file to
+            # $(TARGET)/matching/dirs/subdirs/file,
+            # we want to install it to
+            # $(TARGET)/subdirs/file
+            #
+            # Note that this the only place where
+            # $matchlevel is used.
+            my @new_dest_path = @$dest_path;
+            if ($targetdir->{trimdir} == -1)  {
+                splice @new_dest_path, 0, $matchlevel;
+            } else {
+                splice @new_dest_path, 0, $targetdir->{trimdir};
+            }
+            _add_to_file_map($file_map, $subtarget, $curr_path, $file, $matchlevel, \@new_dest_path);
+        } else {
+            # actually getting here means that the
+            # target was unnecessarily listed
+            # as a hash, but we'll forgive that
+            _add_to_file_map($file_map, $subtarget, $curr_path, $file, $matchlevel);
+        }
+    } elsif ($targetdir ne 'NONE' and $targetdir ne '') {
+        my $source = File::Spec->catfile(@$curr_path, $file);
+        my $destination = File::Spec->catfile('blib', $targetdir, @$dest_path, $file);
+        #print "$source => $destination\n"; # DEBUG
+        # quote spaces in file names
+        # FIXME: this is of questionable portability and
+        # probably depends on user's make recognizing this
+        # quoting syntax -- probably better to remove
+        # spaces and shell metacharacters from all file names
+        $source =~ s/ /\\ /g;
+        $destination =~ s/ /\\ /g;
+       
+        $file_map->{$source} = $destination;
+    }
 }
 
 =head2 get_configuration_options
@@ -515,6 +656,48 @@ component of the directory path, which will be used
 as the package name in the FHS layout.);
     }
     $config{'INSTALL_BASE'} = _get_value('INSTALL_BASE', $msg, $install_base_default, $valid_values);
+    $config{'INSTALL_BASE'} = File::Spec->rel2abs($config{'INSTALL_BASE'});
+
+    $msg = q(
+Please specify which database engine you will use
+to store data in Koha.  The choices are MySQL and
+PostgreSQL; please note that at the moment
+PostgreSQL support is highly experimental.
+
+DBMS to use);
+    $msg .= _add_valid_values_disp('DB_TYPE', $valid_values);
+    $config{'DB_TYPE'} = _get_value('DB_TYPE', $msg, $defaults->{'DB_TYPE'}, $valid_values);
+
+    $msg = q(
+Please specify the name or address of your 
+database server.  Note that the database 
+does not have to exist at this point, it
+can be created after running 'make install'
+and before you try using Koha for the first time.
+
+Database server);
+    $config{'DB_HOST'} = _get_value('DB_HOST', $msg, $defaults->{'DB_HOST'}, $valid_values);
+
+    $msg = q(
+Please specify the port used to connect to the
+DMBS);
+    my $db_port_default = $config{'DB_TYPE'} eq 'mysql' ? '3306' : '5432';
+    $config{'DB_PORT'} = _get_value('DB_PORT', $msg, $db_port_default, $valid_values);
+
+    $msg = q(
+Please specify the name of the database to be
+used by Koha);
+    $config{'DB_NAME'} = _get_value('DB_NAME', $msg, $defaults->{'DB_NAME'}, $valid_values);
+
+    $msg = q(
+Please specify the user that owns the database to be
+used by Koha);
+    $config{'DB_USER'} = _get_value('DB_USER', $msg, $defaults->{'DB_USER'}, $valid_values);
+
+    $msg = q(
+Please specify the password of the user that owns the 
+database to be used by Koha);
+    $config{'DB_PASS'} = _get_value('DB_PASS', $msg, $defaults->{'DB_PASS'}, $valid_values);
 
     $msg = q(
 Koha can use the Zebra search engine for high-performance
@@ -547,6 +730,15 @@ records.
 Please specify the primary language of the MARC records);
         $msg .= _add_valid_values_disp('ZEBRA_LANGUAGE', $valid_values);
         $config{'ZEBRA_LANGUAGE'} = _get_value('ZEBRA_LANGUAGE', $msg, $defaults->{'ZEBRA_LANGUAGE'}, $valid_values);
+
+        $msg = q(
+Please specify Zebra database user);
+        $config{'ZEBRA_USER'} = _get_value('ZEBRA_USER', $msg, $defaults->{'ZEBRA_USER'}, $valid_values);
+
+        $msg = q(
+Please specify the Zebra database password);
+        $config{'ZEBRA_PASS'} = _get_value('ZEBRA_PASS', $msg, $defaults->{'ZEBRA_PASS'}, $valid_values);
+
     }
     return %config;
 }
@@ -599,13 +791,12 @@ sub get_target_directories {
 
     my %dirmap = ();
     if ($mode eq 'single') {
-        # mode is standard, i.e., 'fhs'
         $dirmap{'INTRANET_CGI_DIR'} = File::Spec->catdir(@basedir, $package, 'intranet', 'cgi-bin');
-        $dirmap{'INTRANET_TMPL_DIR'} = File::Spec->catdir(@basedir, $package, 'intranet', 'templates');
-        $dirmap{'INTRANET_WWW_DIR'} = File::Spec->catdir(@basedir, $package, 'intranet', 'www');
+        $dirmap{'INTRANET_TMPL_DIR'} = File::Spec->catdir(@basedir, $package, 'intranet', 'htdocs', 'intranet-tmpl');
+        $dirmap{'INTRANET_WWW_DIR'} = File::Spec->catdir(@basedir, $package, 'intranet', 'htdocs');
         $dirmap{'OPAC_CGI_DIR'} = File::Spec->catdir(@basedir, $package, 'opac', 'cgi-bin');
-        $dirmap{'OPAC_TMPL_DIR'} = File::Spec->catdir(@basedir, $package, 'opac', 'templates');
-        $dirmap{'OPAC_WWW_DIR'} = File::Spec->catdir(@basedir, $package, 'opac', 'www');
+        $dirmap{'OPAC_TMPL_DIR'} = File::Spec->catdir(@basedir, $package, 'opac', 'htdocs', 'opac-tmpl');
+        $dirmap{'OPAC_WWW_DIR'} = File::Spec->catdir(@basedir, $package, 'opac', 'htdocs');
         $dirmap{'PERL_MODULE_DIR'} = File::Spec->catdir(@basedir, $package, 'lib');
         $dirmap{'KOHA_CONF_DIR'} = File::Spec->catdir(@basedir, $package, 'etc');
         $dirmap{'ZEBRA_CONF_DIR'} = File::Spec->catdir(@basedir, $package, 'etc', 'zebradb');
@@ -616,6 +807,7 @@ sub get_target_directories {
         $dirmap{'ZEBRA_LOCK_DIR'} = File::Spec->catdir(@basedir, $package, 'var', 'lock', 'zebradb');
         $dirmap{'LOG_DIR'} =  File::Spec->catdir(@basedir, $package, 'var', 'log');
         $dirmap{'ZEBRA_DATA_DIR'} =  File::Spec->catdir(@basedir, $package, 'var', 'lib', 'zebradb');
+        $dirmap{'ZEBRA_RUN_DIR'} =  File::Spec->catdir(@basedir, $package, 'var', 'run', 'zebradb');
     } elsif ($mode eq 'dev') {
         my $curdir = File::Spec->rel2abs(File::Spec->curdir());
         $dirmap{'INTRANET_CGI_DIR'} = File::Spec->catdir($curdir);
@@ -634,14 +826,15 @@ sub get_target_directories {
         $dirmap{'ZEBRA_LOCK_DIR'} = File::Spec->catdir(@basedir, $package, 'var', 'lock', 'zebradb');
         $dirmap{'LOG_DIR'} =  File::Spec->catdir(@basedir, $package, 'var', 'log');
         $dirmap{'ZEBRA_DATA_DIR'} =  File::Spec->catdir(@basedir, $package, 'var', 'lib', 'zebradb');
+        $dirmap{'ZEBRA_RUN_DIR'} =  File::Spec->catdir(@basedir, $package, 'var', 'run', 'zebradb');
     } else {
         # mode is standard, i.e., 'fhs'
         $dirmap{'INTRANET_CGI_DIR'} = File::Spec->catdir(@basedir, $package, 'intranet', 'cgi-bin');
-        $dirmap{'INTRANET_TMPL_DIR'} = File::Spec->catdir(@basedir, $package, 'intranet', 'templates');
-        $dirmap{'INTRANET_WWW_DIR'} = File::Spec->catdir(@basedir, $package, 'intranet', 'www');
+        $dirmap{'INTRANET_TMPL_DIR'} = File::Spec->catdir(@basedir, $package, 'intranet', 'htdocs', 'intranet-tmpl');
+        $dirmap{'INTRANET_WWW_DIR'} = File::Spec->catdir(@basedir, $package, 'intranet', 'htdocs');
         $dirmap{'OPAC_CGI_DIR'} = File::Spec->catdir(@basedir, $package, 'opac', 'cgi-bin');
-        $dirmap{'OPAC_TMPL_DIR'} = File::Spec->catdir(@basedir, $package, 'opac', 'templates');
-        $dirmap{'OPAC_WWW_DIR'} = File::Spec->catdir(@basedir, $package, 'opac', 'www');
+        $dirmap{'OPAC_TMPL_DIR'} = File::Spec->catdir(@basedir, $package, 'opac', 'htdocs', 'opac-tmpl');
+        $dirmap{'OPAC_WWW_DIR'} = File::Spec->catdir(@basedir, $package, 'opac', 'htdocs');
         $dirmap{'PERL_MODULE_DIR'} = File::Spec->catdir(@basedir, $package, 'lib');
         $dirmap{'KOHA_CONF_DIR'} = File::Spec->catdir(File::Spec->rootdir(), 'etc', $package);
         $dirmap{'ZEBRA_CONF_DIR'} = File::Spec->catdir(File::Spec->rootdir(), 'etc', $package, 'zebradb');
@@ -652,19 +845,92 @@ sub get_target_directories {
         $dirmap{'ZEBRA_LOCK_DIR'} = File::Spec->catdir(File::Spec->rootdir(), 'var', 'lock', $package, 'zebradb');
         $dirmap{'LOG_DIR'} =  File::Spec->catdir(File::Spec->rootdir(), 'var', 'log', $package);
         $dirmap{'ZEBRA_DATA_DIR'} =  File::Spec->catdir(File::Spec->rootdir(), 'var', 'lib', $package, 'zebradb');
+        $dirmap{'ZEBRA_RUN_DIR'} =  File::Spec->catdir(File::Spec->rootdir(), 'var', 'run', $package, 'zebradb');
     }
 
-    foreach my $key (sort keys %dirmap) {
-        print sprintf("%-25.25s%s\n", $key, $dirmap{$key});
-    }
+    _get_argv_overrides(\%dirmap);
+
     return %dirmap;
 }
 
-#package MY;
-#sub install {
-    #warn "\n\n\noverride\n\n\n";
-    #return "";
-#}
+sub _get_argv_overrides {
+    my $dirmap = shift;
+    
+    my @new_argv = ();
+    for (my $i = 0; $i <= $#ARGV; $i++) {
+        if ($ARGV[$i] =~ /^([^=]+)=([^=]+)$/ and exists $dirmap->{$1}) {
+            $dirmap->{$1} = $2;
+        } else {
+            push @new_argv, $ARGV[$i];
+        }
+    }
+    @ARGV = @new_argv;
+}
+
+sub display_configuration {
+    my $config = shift;
+    my $dirmap = shift;
+    print "\n\nKoha will be installed with the following configuration parameters:\n\n";
+    foreach my $key (sort keys %$config) {
+        print sprintf("%-25.25s%s\n", $key, $config->{$key});
+    }
+
+    print "\nand in the following directories:\n\n";
+    foreach my $key (sort keys %$dirmap) {
+        print sprintf("%-25.25s%s\n", $key, $dirmap->{$key});
+    }
+    print "\n\nTo change any configuration setting, please run\n";
+    print "perl Makefile.PL again.  To override one of the target\n";
+    print "directories, you can do so on the command line like this:\n";
+    print "\nperl Makefile.PL PERL_MODULE_DIR=/usr/share/perl/5.8\n\n";
+}
+
+package MY;
+
+sub test {
+    my $self = shift;
+    my $test = $self->SUPER::test(@_);
+    $test =~ s!\$\(INST_LIB\)!blib/PERL_MODULE_DIR!g;
+    return $test;
+}
+
+sub install {
+    my $self = shift;
+    my $install = ""; 
+    # NOTE: we're *not* doing this: my $install = $self->SUPER::install(@_);
+    # This means that we're completely overriding EU::MM's default
+    # installation and uninstallation targets.
+    foreach my $key (sort keys %target_directories) {
+        $install .= qq(
+KOHA_INST_$key = blib/$key
+KOHA_DEST_$key = $target_directories{$key}
+);
+    }
+
+    $install .= qq(
+install :: all install_koha
+\t\$(NOECHO) \$(NOOP)
+);
+    $install .= "install_koha ::\n";      
+    $install .= "\t\$(NOECHO) umask 022; \$(MOD_INSTALL) \\\n";
+    foreach my $key (sort keys %target_directories) {
+        $install .= "\t\t\$(KOHA_INST_$key) \$(KOHA_DEST_$key) \\\n";
+    }
+    $install .= "\t\t\$(INST_MAN1DIR) \$(DESTINSTALLMAN1DIR) \\\n";
+    $install .= "\t\t\$(INST_MAN3DIR) \$(DESTINSTALLMAN3DIR)\n";
+    return $install;
+}
+
+sub postamble {
+    # put directory mappings into Makefile
+    # so that Make will export as environment
+    # variables -- this is for the use of
+    # rewrite-confg.PL
+    my $env = join("\n", map { "export __${_}__ = $target_directories{$_}" } keys %target_directories); 
+    $env .= "\n\n";
+    $env .= join("\n", map { "export __${_}__ = $config{$_}" } keys %config);
+    return "$env\n";
+}
 
 __END__
 
@@ -678,4 +944,5 @@ ExtUtils::MakeMaker(3)
 MJ Ray mjr at phonecoop.coop
 
 =cut
-
+FIXME: Zebra lang/MARC mapping
+FIXME: deal with .htaccess