Bug 3301 - Speed up rebuild_zebra script
[koha.git] / misc / migration_tools / rebuild_zebra.pl
1 #!/usr/bin/perl
2
3 use strict;
4
5 use C4::Context;
6 use Getopt::Long;
7 use File::Temp qw/ tempdir /;
8 use File::Path;
9 use C4::Biblio;
10 use C4::AuthoritiesMarc;
11
12
13 # script that checks zebradir structure & create directories & mandatory files if needed
14 #
15 #
16
17 $|=1; # flushes output
18
19 my $directory;
20 my $nosanitize;
21 my $skip_export;
22 my $keep_export;
23 my $reset;
24 my $biblios;
25 my $authorities;
26 my $noxml;
27 my $noshadow;
28 my $do_munge;
29 my $want_help;
30 my $as_xml;
31 my $process_zebraqueue;
32 my $do_not_clear_zebraqueue;
33 my $verbose_logging;
34 my $zebraidx_log_opt = " -v none,fatal,warn ";
35 my $result = GetOptions(
36     'd:s'           => \$directory,
37     'reset'         => \$reset,
38     's'             => \$skip_export,
39     'k'             => \$keep_export,
40     'nosanitize'    => \$nosanitize,
41     'b'             => \$biblios,
42     'noxml'         => \$noxml,
43     'w'             => \$noshadow,
44     'munge-config'  => \$do_munge,
45     'a'             => \$authorities,
46     'h|help'        => \$want_help,
47         'x'                             => \$as_xml,
48     'y'             => \$do_not_clear_zebraqueue,
49     'z'             => \$process_zebraqueue,
50     'v'             => \$verbose_logging,
51 );
52
53
54 if (not $result or $want_help) {
55     print_usage();
56     exit 0;
57 }
58
59 if (not $biblios and not $authorities) {
60     my $msg = "Must specify -b or -a to reindex bibs or authorities\n";
61     $msg   .= "Please do '$0 --help' to see usage.\n";
62     die $msg;
63 }
64
65 if ($authorities and $as_xml) {
66     my $msg = "Cannot specify both -a and -x\n";
67     $msg   .= "Please do '$0 --help' to see usage.\n";
68     die $msg;
69 }
70
71 if ( !$as_xml and $nosanitize ) {
72     my $msg = "Cannot specify both -no_xml and -nosanitize\n";
73     $msg   .= "Please do '$0 --help' to see usage.\n";
74     die $msg;
75 }
76
77 if ($process_zebraqueue and ($skip_export or $reset)) {
78     my $msg = "Cannot specify -r or -s if -z is specified\n";
79     $msg   .= "Please do '$0 --help' to see usage.\n";
80     die $msg;
81 }
82
83 if ($process_zebraqueue and $do_not_clear_zebraqueue) {
84     my $msg = "Cannot specify both -y and -z\n";
85     $msg   .= "Please do '$0 --help' to see usage.\n";
86     die $msg;
87 }
88
89 if ($noshadow) {
90     $noshadow = ' -n ';
91 }
92
93 #  -v is for verbose, which seems backwards here because of how logging is set
94 #    on the CLI of zebraidx.  It works this way.  The default is to not log much
95 if ($verbose_logging) {
96     $zebraidx_log_opt = '';
97 }
98
99 my $use_tempdir = 0;
100 unless ($directory) {
101     $use_tempdir = 1;
102     $directory = tempdir(CLEANUP => ($keep_export ? 0 : 1));
103
104
105
106 my $biblioserverdir = C4::Context->zebraconfig('biblioserver')->{directory};
107 my $authorityserverdir = C4::Context->zebraconfig('authorityserver')->{directory};
108
109 my $kohadir = C4::Context->config('intranetdir');
110 my $dbh = C4::Context->dbh;
111 my ($biblionumbertagfield,$biblionumbertagsubfield) = &GetMarcFromKohaField("biblio.biblionumber","");
112 my ($biblioitemnumbertagfield,$biblioitemnumbertagsubfield) = &GetMarcFromKohaField("biblioitems.biblioitemnumber","");
113
114 if ( $verbose_logging ) {
115     print "Zebra configuration information\n";
116     print "================================\n";
117     print "Zebra biblio directory      = $biblioserverdir\n";
118     print "Zebra authorities directory = $authorityserverdir\n";
119     print "Koha directory              = $kohadir\n";
120     print "BIBLIONUMBER in :     $biblionumbertagfield\$$biblionumbertagsubfield\n";
121     print "BIBLIOITEMNUMBER in : $biblioitemnumbertagfield\$$biblioitemnumbertagsubfield\n";
122     print "================================\n";
123 }
124
125 if ($do_munge) {
126     munge_config();
127 }
128
129 if ($authorities) {
130     index_records('authority', $directory, $skip_export, $process_zebraqueue, $as_xml, $noxml, $nosanitize, $do_not_clear_zebraqueue, $verbose_logging, $zebraidx_log_opt);
131 } else {
132     print "skipping authorities\n" if ( $verbose_logging );
133 }
134
135 if ($biblios) {
136     index_records('biblio', $directory, $skip_export, $process_zebraqueue, $as_xml, $noxml, $nosanitize, $do_not_clear_zebraqueue, $verbose_logging, $zebraidx_log_opt);
137 } else {
138     print "skipping biblios\n" if ( $verbose_logging );
139 }
140
141
142 if ( $verbose_logging ) {
143     print "====================\n";
144     print "CLEANING\n";
145     print "====================\n";
146 }
147 if ($keep_export) {
148     print "NOTHING cleaned : the export $directory has been kept.\n";
149     print "You can re-run this script with the -s ";
150     if ($use_tempdir) {
151         print " and -d $directory parameters";
152     } else {
153         print "parameter";
154     }
155     print "\n";
156     print "if you just want to rebuild zebra after changing the record.abs\n";
157     print "or another zebra config file\n";
158 } else {
159     unless ($use_tempdir) {
160         # if we're using a temporary directory
161         # created by File::Temp, it will be removed
162         # automatically.
163         rmtree($directory, 0, 1);
164         print "directory $directory deleted\n";
165     }
166 }
167
168 sub index_records {
169     my ($record_type, $directory, $skip_export, $process_zebraqueue, $as_xml, $noxml, $nosanitize, $do_not_clear_zebraqueue, $verbose_logging, $zebraidx_log_opt) = @_;
170
171     my $num_records_exported = 0;
172     my $num_records_deleted = 0;
173     if ($skip_export && $verbose_logging) {
174         print "====================\n";
175         print "SKIPPING $record_type export\n";
176         print "====================\n";
177     } else {
178         if ( $verbose_logging ) {
179             print "====================\n";
180             print "exporting $record_type\n";
181             print "====================\n";
182         }
183         mkdir "$directory" unless (-d $directory);
184         mkdir "$directory/$record_type" unless (-d "$directory/$record_type");
185         if ($process_zebraqueue) {
186             my $entries = select_zebraqueue_records($record_type, 'deleted');
187             mkdir "$directory/del_$record_type" unless (-d "$directory/del_$record_type");
188             $num_records_deleted = generate_deleted_marc_records($record_type, $entries, "$directory/del_$record_type", $as_xml);
189             mark_zebraqueue_batch_done($entries);
190             $entries = select_zebraqueue_records($record_type, 'updated');
191             mkdir "$directory/upd_$record_type" unless (-d "$directory/upd_$record_type");
192             $num_records_exported = export_marc_records_from_list($record_type, 
193                                                                   $entries, "$directory/upd_$record_type", $as_xml, $noxml);
194             mark_zebraqueue_batch_done($entries);
195         } else {
196             my $sth = select_all_records($record_type);
197             $num_records_exported = export_marc_records_from_sth($record_type, $sth, "$directory/$record_type", $as_xml, $noxml, $nosanitize);
198             unless ($do_not_clear_zebraqueue) {
199                 mark_all_zebraqueue_done($record_type);
200             }
201         }
202     }
203     
204     #
205     # and reindexing everything
206     #
207     if ( $verbose_logging ) {
208         print "====================\n";
209         print "REINDEXING zebra\n";
210         print "====================\n";
211     }
212         my $record_fmt = ($as_xml) ? 'marcxml' : 'iso2709' ;
213     if ($process_zebraqueue) {
214         do_indexing($record_type, 'delete', "$directory/del_$record_type", $reset, $noshadow, $record_fmt, $zebraidx_log_opt) 
215             if $num_records_deleted;
216         do_indexing($record_type, 'update', "$directory/upd_$record_type", $reset, $noshadow, $record_fmt, $zebraidx_log_opt)
217             if $num_records_exported;
218     } else {
219         do_indexing($record_type, 'update', "$directory/$record_type", $reset, $noshadow, $record_fmt, $zebraidx_log_opt)
220             if ($num_records_exported or $skip_export);
221     }
222 }
223
224 sub select_zebraqueue_records {
225     my ($record_type, $update_type) = @_;
226
227     my $server = ($record_type eq 'biblio') ? 'biblioserver' : 'authorityserver';
228     my $op = ($update_type eq 'deleted') ? 'recordDelete' : 'specialUpdate';
229
230     my $sth = $dbh->prepare("SELECT id, biblio_auth_number 
231                              FROM zebraqueue
232                              WHERE server = ?
233                              AND   operation = ?
234                              AND   done = 0
235                              ORDER BY id DESC");
236     $sth->execute($server, $op);
237     my $entries = $sth->fetchall_arrayref({});
238 }
239
240 sub mark_all_zebraqueue_done {
241     my ($record_type) = @_;
242
243     my $server = ($record_type eq 'biblio') ? 'biblioserver' : 'authorityserver';
244
245     my $sth = $dbh->prepare("UPDATE zebraqueue SET done = 1
246                              WHERE server = ?
247                              AND done = 0");
248     $sth->execute($server);
249 }
250
251 sub mark_zebraqueue_batch_done {
252     my ($entries) = @_;
253
254     $dbh->{AutoCommit} = 0;
255     my $sth = $dbh->prepare("UPDATE zebraqueue SET done = 1 WHERE id = ?");
256     $dbh->commit();
257     foreach my $id (map { $_->{id} } @$entries) {
258         $sth->execute($id);
259     }
260     $dbh->{AutoCommit} = 1;
261 }
262
263 sub select_all_records {
264     my $record_type = shift;
265     return ($record_type eq 'biblio') ? select_all_biblios() : select_all_authorities();
266 }
267
268 sub select_all_authorities {
269     my $sth = $dbh->prepare("SELECT authid FROM auth_header");
270     $sth->execute();
271     return $sth;
272 }
273
274 sub select_all_biblios {
275     my $sth = $dbh->prepare("SELECT biblionumber FROM biblioitems ORDER BY biblionumber");
276     $sth->execute();
277     return $sth;
278 }
279
280 sub export_marc_records_from_sth {
281     my ($record_type, $sth, $directory, $as_xml, $noxml, $nosanitize) = @_;
282
283     my $num_exported = 0;
284     open (OUT, ">:utf8 ", "$directory/exported_records") or die $!;
285     my $i = 0;
286     while (my ($record_number) = $sth->fetchrow_array) {
287         print "." if ( $verbose_logging );
288         print "\r$i" unless ($i++ %100 or !$verbose_logging);
289         if ( $nosanitize ) {
290             my $marcxml = $record_type eq 'biblio'
291                           ? GetXmlBiblio( $record_number )
292                           : GetAuthorityXML( $record_number );
293             if ( $marcxml ) {
294                 print OUT $marcxml if $marcxml;
295                 $num_exported++;
296             }
297             next;
298         }
299         my ($marc) = get_corrected_marc_record($record_type, $record_number, $noxml);
300         if (defined $marc) {
301             # FIXME - when more than one record is exported and $as_xml is true,
302             # the output file is not valid XML - it's just multiple <record> elements
303             # strung together with no single root element.  zebraidx doesn't seem
304             # to care, though, at least if you're using the GRS-1 filter.  It does
305             # care if you're using the DOM filter, which requires valid XML file(s).
306             print OUT ($as_xml) ? $marc->as_xml_record() : $marc->as_usmarc();
307             $num_exported++;
308         }
309     }
310     print "\nRecords exported: $num_exported\n" if ( $verbose_logging );
311     close OUT;
312     return $num_exported;
313 }
314
315 sub export_marc_records_from_list {
316     my ($record_type, $entries, $directory, $as_xml, $noxml) = @_;
317
318     my $num_exported = 0;
319     open (OUT, ">:utf8 ", "$directory/exported_records") or die $!;
320     my $i = 0;
321     my %found = ();
322     foreach my $record_number ( map { $_->{biblio_auth_number} }
323                                 grep { !$found{ $_->{biblio_auth_number} }++ }
324                                 @$entries ) {
325         print "." if ( $verbose_logging );
326         print "\r$i" unless ($i++ %100 or !$verbose_logging);
327         my ($marc) = get_corrected_marc_record($record_type, $record_number, $noxml);
328         if (defined $marc) {
329             # FIXME - when more than one record is exported and $as_xml is true,
330             # the output file is not valid XML - it's just multiple <record> elements
331             # strung together with no single root element.  zebraidx doesn't seem
332             # to care, though, at least if you're using the GRS-1 filter.  It does
333             # care if you're using the DOM filter, which requires valid XML file(s).
334             print OUT ($as_xml) ? $marc->as_xml_record() : $marc->as_usmarc();
335             $num_exported++;
336         }
337     }
338     print "\nRecords exported: $num_exported\n" if ( $verbose_logging );
339     close OUT;
340     return $num_exported;
341 }
342
343 sub generate_deleted_marc_records {
344     my ($record_type, $entries, $directory, $as_xml) = @_;
345
346     my $num_exported = 0;
347     open (OUT, ">:utf8 ", "$directory/exported_records") or die $!;
348     my $i = 0;
349     foreach my $record_number (map { $_->{biblio_auth_number} } @$entries ) {
350         print "\r$i" unless ($i++ %100 or !$verbose_logging);
351         print "." if ( $verbose_logging );
352
353         my $marc = MARC::Record->new();
354         if ($record_type eq 'biblio') {
355             fix_biblio_ids($marc, $record_number, $record_number);
356         } else {
357             fix_authority_id($marc, $record_number);
358         }
359         if (C4::Context->preference("marcflavour") eq "UNIMARC") {
360             fix_unimarc_100($marc);
361         }
362
363         print OUT ($as_xml) ? $marc->as_xml_record() : $marc->as_usmarc();
364         $num_exported++;
365     }
366     print "\nRecords exported: $num_exported\n" if ( $verbose_logging );
367     close OUT;
368     return $num_exported;
369     
370
371 }
372
373 sub get_corrected_marc_record {
374     my ($record_type, $record_number, $noxml) = @_;
375
376     my $marc = get_raw_marc_record($record_type, $record_number, $noxml); 
377
378     if (defined $marc) {
379         fix_leader($marc);
380         if ($record_type eq 'biblio') {
381             my $succeeded = fix_biblio_ids($marc, $record_number);
382             return unless $succeeded;
383         } else {
384             fix_authority_id($marc, $record_number);
385         }
386         if (C4::Context->preference("marcflavour") eq "UNIMARC") {
387             fix_unimarc_100($marc);
388         }
389     }
390
391     return $marc;
392 }
393
394 sub get_raw_marc_record {
395     my ($record_type, $record_number, $noxml) = @_;
396   
397     my $marc; 
398     if ($record_type eq 'biblio') {
399         if ($noxml) {
400             my $fetch_sth = $dbh->prepare_cached("SELECT marc FROM biblioitems WHERE biblionumber = ?");
401             $fetch_sth->execute($record_number);
402             if (my ($blob) = $fetch_sth->fetchrow_array) {
403                 $marc = MARC::Record->new_from_usmarc($blob);
404                 $fetch_sth->finish();
405             } else {
406                 return; # failure to find a bib is not a problem -
407                         # a delete could have been done before
408                         # trying to process a record update
409             }
410         } else {
411             eval { $marc = GetMarcBiblio($record_number); };
412             if ($@) {
413                 # here we do warn since catching an exception
414                 # means that the bib was found but failed
415                 # to be parsed
416                 warn "error retrieving biblio $record_number";
417                 return;
418             }
419         }
420     } else {
421         eval { $marc = GetAuthority($record_number); };
422         if ($@) {
423             warn "error retrieving authority $record_number";
424             return;
425         }
426     }
427     return $marc;
428 }
429
430 sub fix_leader {
431     # FIXME - this routine is suspect
432     # It blanks the Leader/00-05 and Leader/12-16 to
433     # force them to be recalculated correct when
434     # the $marc->as_usmarc() or $marc->as_xml() is called.
435     # But why is this necessary?  It would be a serious bug
436     # in MARC::Record (definitely) and MARC::File::XML (arguably) 
437     # if they are emitting incorrect leader values.
438     my $marc = shift;
439
440     my $leader = $marc->leader;
441     substr($leader,  0, 5) = '     ';
442     substr($leader, 10, 7) = '22     ';
443     $marc->leader(substr($leader, 0, 24));
444 }
445
446 sub fix_biblio_ids {
447     # FIXME - it is essential to ensure that the biblionumber is present,
448     #         otherwise, Zebra will choke on the record.  However, this
449     #         logic belongs in the relevant C4::Biblio APIs.
450     my $marc = shift;
451     my $biblionumber = shift;
452     my $biblioitemnumber;
453     if (@_) {
454         $biblioitemnumber = shift;
455     } else {    
456         my $sth = $dbh->prepare(
457             "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
458         $sth->execute($biblionumber);
459         ($biblioitemnumber) = $sth->fetchrow_array;
460         $sth->finish;
461         unless ($biblioitemnumber) {
462             warn "failed to get biblioitemnumber for biblio $biblionumber";
463             return 0;
464         }
465     }
466
467     # FIXME - this is cheating on two levels
468     # 1. C4::Biblio::_koha_marc_update_bib_ids is meant to be an internal function
469     # 2. Making sure that the biblionumber and biblioitemnumber are correct and
470     #    present in the MARC::Record object ought to be part of GetMarcBiblio.
471     #
472     # On the other hand, this better for now than what rebuild_zebra.pl used to
473     # do, which was duplicate the code for inserting the biblionumber 
474     # and biblioitemnumber
475     C4::Biblio::_koha_marc_update_bib_ids($marc, '', $biblionumber, $biblioitemnumber);
476
477     return 1;
478 }
479
480 sub fix_authority_id {
481     # FIXME - as with fix_biblio_ids, the authid must be present
482     #         for Zebra's sake.  However, this really belongs
483     #         in C4::AuthoritiesMarc.
484     my ($marc, $authid) = @_;
485     unless ($marc->field('001') and $marc->field('001')->data() eq $authid){
486         $marc->delete_field($marc->field('001'));
487         $marc->insert_fields_ordered(MARC::Field->new('001',$authid));
488     }
489 }
490
491 sub fix_unimarc_100 {
492     # FIXME - again, if this is necessary, it belongs in C4::AuthoritiesMarc.
493     my $marc = shift;
494
495     my $string;
496     if ( length($marc->subfield( 100, "a" )) == 35 ) {
497         $string = $marc->subfield( 100, "a" );
498         my $f100 = $marc->field(100);
499         $marc->delete_field($f100);
500     }
501     else {
502         $string = POSIX::strftime( "%Y%m%d", localtime );
503         $string =~ s/\-//g;
504         $string = sprintf( "%-*s", 35, $string );
505     }
506     substr( $string, 22, 6, "frey50" );
507     unless ( length($marc->subfield( 100, "a" )) == 35 ) {
508         $marc->delete_field($marc->field(100));
509         $marc->insert_grouped_field(MARC::Field->new( 100, "", "", "a" => $string ));
510     }
511 }
512
513 sub do_indexing {
514     my ($record_type, $op, $record_dir, $reset_index, $noshadow, $record_format, $zebraidx_log_opt) = @_;
515
516     my $zebra_server  = ($record_type eq 'biblio') ? 'biblioserver' : 'authorityserver';
517     my $zebra_db_name = ($record_type eq 'biblio') ? 'biblios' : 'authorities';
518     my $zebra_config  = C4::Context->zebraconfig($zebra_server)->{'config'};
519     my $zebra_db_dir  = C4::Context->zebraconfig($zebra_server)->{'directory'};
520
521     system("zebraidx -c $zebra_config $zebraidx_log_opt -g $record_format -d $zebra_db_name init") if $reset_index;
522     system("zebraidx -c $zebra_config $zebraidx_log_opt $noshadow -g $record_format -d $zebra_db_name $op $record_dir");
523     system("zebraidx -c $zebra_config $zebraidx_log_opt -g $record_format -d $zebra_db_name commit") unless $noshadow;
524
525 }
526
527 sub print_usage {
528     print <<_USAGE_;
529 $0: reindex MARC bibs and/or authorities in Zebra.
530
531 Use this batch job to reindex all biblio or authority
532 records in your Koha database.  This job is useful
533 only if you are using Zebra; if you are using the 'NoZebra'
534 mode, this job should not be used.
535
536 Parameters:
537     -b                      index bibliographic records
538
539     -a                      index authority records
540
541     -z                      select only updated and deleted
542                             records marked in the zebraqueue
543                             table.  Cannot be used with -r
544                             or -s.
545
546     -r                      clear Zebra index before
547                             adding records to index
548
549     -d                      Temporary directory for indexing.
550                             If not specified, one is automatically
551                             created.  The export directory
552                             is automatically deleted unless
553                             you supply the -k switch.
554
555     -k                      Do not delete export directory.
556
557     -s                      Skip export.  Used if you have
558                             already exported the records 
559                             in a previous run.
560
561     -noxml                  index from ISO MARC blob
562                             instead of MARC XML.  This
563                             option is recommended only
564                             for advanced user.
565
566     -x                      export and index as xml instead of is02709 (biblios only).
567                             use this if you might have records > 99,999 chars,
568                                                         
569     -nosanitize             export biblio/authority records directly from DB marcxml
570                             field without sanitizing records. It speed up
571                             dump process but could fail if DB contains badly
572                             encoded records. Works only with -x,
573
574     -w                      skip shadow indexing for this batch
575
576     -y                      do NOT clear zebraqueue after indexing; normally,
577                             after doing batch indexing, zebraqueue should be
578                             marked done for the affected record type(s) so that
579                             a running zebraqueue_daemon doesn't try to reindex
580                             the same records - specify -y to override this.  
581                             Cannot be used with -z.
582
583     -v                      increase the amount of logging.  Normally only 
584                             warnings and errors from the indexing are shown.
585
586     -munge-config           Deprecated option to try
587                             to fix Zebra config files.
588     --help or -h            show this message.
589 _USAGE_
590 }
591
592 # FIXME: the following routines are deprecated and 
593 # will be removed once it is determined whether
594 # a script to fix Zebra configuration files is 
595 # actually needed.
596 sub munge_config {
597 #
598 # creating zebra-biblios.cfg depending on system
599 #
600
601 # getting zebraidx directory
602 my $zebraidxdir;
603 foreach (qw(/usr/local/bin/zebraidx
604         /opt/bin/zebraidx
605         /usr/bin/zebraidx
606         )) {
607     if ( -f $_ ) {
608         $zebraidxdir=$_;
609     }
610 }
611
612 unless ($zebraidxdir) {
613     print qq|
614     ERROR: could not find zebraidx directory
615     ERROR: Either zebra is not installed,
616     ERROR: or it's in a directory I don't checked.
617     ERROR: do a which zebraidx and edit this file to add the result you get
618 |;
619     exit;
620 }
621 $zebraidxdir =~ s/\/bin\/.*//;
622 print "Info : zebra is in $zebraidxdir \n";
623
624 # getting modules directory
625 my $modulesdir;
626 foreach (qw(/usr/local/lib/idzebra-2.0/modules/mod-grs-xml.so
627             /usr/local/lib/idzebra/modules/mod-grs-xml.so
628             /usr/lib/idzebra/modules/mod-grs-xml.so
629             /usr/lib/idzebra-2.0/modules/mod-grs-xml.so
630         )) {
631     if ( -f $_ ) {
632         $modulesdir=$_;
633     }
634 }
635
636 unless ($modulesdir) {
637     print qq|
638     ERROR: could not find mod-grs-xml.so directory
639     ERROR: Either zebra is not properly compiled (libxml2 is not setup and you don t have mod-grs-xml.so,
640     ERROR: or it's in a directory I don't checked.
641     ERROR: find where mod-grs-xml.so is and edit this file to add the result you get
642 |;
643     exit;
644 }
645 $modulesdir =~ s/\/modules\/.*//;
646 print "Info: zebra modules dir : $modulesdir\n";
647
648 # getting tab directory
649 my $tabdir;
650 foreach (qw(/usr/local/share/idzebra/tab/explain.att
651             /usr/local/share/idzebra-2.0/tab/explain.att
652             /usr/share/idzebra/tab/explain.att
653             /usr/share/idzebra-2.0/tab/explain.att
654         )) {
655     if ( -f $_ ) {
656         $tabdir=$_;
657     }
658 }
659
660 unless ($tabdir) {
661     print qq|
662     ERROR: could not find explain.att directory
663     ERROR: Either zebra is not properly compiled,
664     ERROR: or it's in a directory I don't checked.
665     ERROR: find where explain.att is and edit this file to add the result you get
666 |;
667     exit;
668 }
669 $tabdir =~ s/\/tab\/.*//;
670 print "Info: tab dir : $tabdir\n";
671
672 #
673 # AUTHORITIES creating directory structure
674 #
675 my $created_dir_or_file = 0;
676 if ($authorities) {
677     if ( $verbose_logging ) {
678         print "====================\n";
679         print "checking directories & files for authorities\n";
680         print "====================\n";
681     }
682     unless (-d "$authorityserverdir") {
683         system("mkdir -p $authorityserverdir");
684         print "Info: created $authorityserverdir\n";
685         $created_dir_or_file++;
686     }
687     unless (-d "$authorityserverdir/lock") {
688         mkdir "$authorityserverdir/lock";
689         print "Info: created $authorityserverdir/lock\n";
690         $created_dir_or_file++;
691     }
692     unless (-d "$authorityserverdir/register") {
693         mkdir "$authorityserverdir/register";
694         print "Info: created $authorityserverdir/register\n";
695         $created_dir_or_file++;
696     }
697     unless (-d "$authorityserverdir/shadow") {
698         mkdir "$authorityserverdir/shadow";
699         print "Info: created $authorityserverdir/shadow\n";
700         $created_dir_or_file++;
701     }
702     unless (-d "$authorityserverdir/tab") {
703         mkdir "$authorityserverdir/tab";
704         print "Info: created $authorityserverdir/tab\n";
705         $created_dir_or_file++;
706     }
707     unless (-d "$authorityserverdir/key") {
708         mkdir "$authorityserverdir/key";
709         print "Info: created $authorityserverdir/key\n";
710         $created_dir_or_file++;
711     }
712     
713     unless (-d "$authorityserverdir/etc") {
714         mkdir "$authorityserverdir/etc";
715         print "Info: created $authorityserverdir/etc\n";
716         $created_dir_or_file++;
717     }
718     
719     #
720     # AUTHORITIES : copying mandatory files
721     #
722     # the record model, depending on marc flavour
723     unless (-f "$authorityserverdir/tab/record.abs") {
724         if (C4::Context->preference("marcflavour") eq "UNIMARC") {
725             system("cp -f $kohadir/etc/zebradb/marc_defs/unimarc/authorities/record.abs $authorityserverdir/tab/record.abs");
726             print "Info: copied record.abs for UNIMARC\n";
727         } else {
728             system("cp -f $kohadir/etc/zebradb/marc_defs/marc21/authorities/record.abs $authorityserverdir/tab/record.abs");
729             print "Info: copied record.abs for USMARC\n";
730         }
731         $created_dir_or_file++;
732     }
733     unless (-f "$authorityserverdir/tab/sort-string-utf.chr") {
734         system("cp -f $kohadir/etc/zebradb/lang_defs/fr/sort-string-utf.chr $authorityserverdir/tab/sort-string-utf.chr");
735         print "Info: copied sort-string-utf.chr\n";
736         $created_dir_or_file++;
737     }
738     unless (-f "$authorityserverdir/tab/word-phrase-utf.chr") {
739         system("cp -f $kohadir/etc/zebradb/lang_defs/fr/sort-string-utf.chr $authorityserverdir/tab/word-phrase-utf.chr");
740         print "Info: copied word-phase-utf.chr\n";
741         $created_dir_or_file++;
742     }
743     unless (-f "$authorityserverdir/tab/auth1.att") {
744         system("cp -f $kohadir/etc/zebradb/authorities/etc/bib1.att $authorityserverdir/tab/auth1.att");
745         print "Info: copied auth1.att\n";
746         $created_dir_or_file++;
747     }
748     unless (-f "$authorityserverdir/tab/default.idx") {
749         system("cp -f $kohadir/etc/zebradb/etc/default.idx $authorityserverdir/tab/default.idx");
750         print "Info: copied default.idx\n";
751         $created_dir_or_file++;
752     }
753     
754     unless (-f "$authorityserverdir/etc/ccl.properties") {
755 #         system("cp -f $kohadir/etc/zebradb/ccl.properties ".C4::Context->zebraconfig('authorityserver')->{ccl2rpn});
756         system("cp -f $kohadir/etc/zebradb/ccl.properties $authorityserverdir/etc/ccl.properties");
757         print "Info: copied ccl.properties\n";
758         $created_dir_or_file++;
759     }
760     unless (-f "$authorityserverdir/etc/pqf.properties") {
761 #         system("cp -f $kohadir/etc/zebradb/pqf.properties ".C4::Context->zebraconfig('authorityserver')->{ccl2rpn});
762         system("cp -f $kohadir/etc/zebradb/pqf.properties $authorityserverdir/etc/pqf.properties");
763         print "Info: copied pqf.properties\n";
764         $created_dir_or_file++;
765     }
766     
767     #
768     # AUTHORITIES : copying mandatory files
769     #
770     unless (-f C4::Context->zebraconfig('authorityserver')->{config}) {
771     open ZD,">:utf8 ",C4::Context->zebraconfig('authorityserver')->{config};
772     print ZD "
773 # generated by KOHA/misc/migration_tools/rebuild_zebra.pl 
774 profilePath:\${srcdir:-.}:$authorityserverdir/tab/:$tabdir/tab/:\${srcdir:-.}/tab/
775
776 encoding: UTF-8
777 # Files that describe the attribute sets supported.
778 attset: auth1.att
779 attset: explain.att
780 attset: gils.att
781
782 modulePath:$modulesdir/modules/
783 # Specify record type
784 iso2709.recordType:grs.marcxml.record
785 recordType:grs.xml
786 recordId: (auth1,Local-Number)
787 storeKeys:1
788 storeData:1
789
790
791 # Lock File Area
792 lockDir: $authorityserverdir/lock
793 perm.anonymous:r
794 perm.kohaadmin:rw
795 register: $authorityserverdir/register:4G
796 shadow: $authorityserverdir/shadow:4G
797
798 # Temp File area for result sets
799 setTmpDir: $authorityserverdir/tmp
800
801 # Temp File area for index program
802 keyTmpDir: $authorityserverdir/key
803
804 # Approx. Memory usage during indexing
805 memMax: 40M
806 rank:rank-1
807     ";
808         print "Info: creating zebra-authorities.cfg\n";
809         $created_dir_or_file++;
810     }
811     
812     if ($created_dir_or_file) {
813         print "Info: created : $created_dir_or_file directories & files\n";
814     } else {
815         print "Info: file & directories OK\n";
816     }
817     
818 }
819 if ($biblios) {
820     if ( $verbose_logging ) {
821         print "====================\n";
822         print "checking directories & files for biblios\n";
823         print "====================\n";
824     }
825
826     #
827     # BIBLIOS : creating directory structure
828     #
829     unless (-d "$biblioserverdir") {
830         system("mkdir -p $biblioserverdir");
831         print "Info: created $biblioserverdir\n";
832         $created_dir_or_file++;
833     }
834     unless (-d "$biblioserverdir/lock") {
835         mkdir "$biblioserverdir/lock";
836         print "Info: created $biblioserverdir/lock\n";
837         $created_dir_or_file++;
838     }
839     unless (-d "$biblioserverdir/register") {
840         mkdir "$biblioserverdir/register";
841         print "Info: created $biblioserverdir/register\n";
842         $created_dir_or_file++;
843     }
844     unless (-d "$biblioserverdir/shadow") {
845         mkdir "$biblioserverdir/shadow";
846         print "Info: created $biblioserverdir/shadow\n";
847         $created_dir_or_file++;
848     }
849     unless (-d "$biblioserverdir/tab") {
850         mkdir "$biblioserverdir/tab";
851         print "Info: created $biblioserverdir/tab\n";
852         $created_dir_or_file++;
853     }
854     unless (-d "$biblioserverdir/key") {
855         mkdir "$biblioserverdir/key";
856         print "Info: created $biblioserverdir/key\n";
857         $created_dir_or_file++;
858     }
859     unless (-d "$biblioserverdir/etc") {
860         mkdir "$biblioserverdir/etc";
861         print "Info: created $biblioserverdir/etc\n";
862         $created_dir_or_file++;
863     }
864     
865     #
866     # BIBLIOS : copying mandatory files
867     #
868     # the record model, depending on marc flavour
869     unless (-f "$biblioserverdir/tab/record.abs") {
870         if (C4::Context->preference("marcflavour") eq "UNIMARC") {
871             system("cp -f $kohadir/etc/zebradb/marc_defs/unimarc/biblios/record.abs $biblioserverdir/tab/record.abs");
872             print "Info: copied record.abs for UNIMARC\n";
873         } else {
874             system("cp -f $kohadir/etc/zebradb/marc_defs/marc21/biblios/record.abs $biblioserverdir/tab/record.abs");
875             print "Info: copied record.abs for USMARC\n";
876         }
877         $created_dir_or_file++;
878     }
879     unless (-f "$biblioserverdir/tab/sort-string-utf.chr") {
880         system("cp -f $kohadir/etc/zebradb/lang_defs/fr/sort-string-utf.chr $biblioserverdir/tab/sort-string-utf.chr");
881         print "Info: copied sort-string-utf.chr\n";
882         $created_dir_or_file++;
883     }
884     unless (-f "$biblioserverdir/tab/word-phrase-utf.chr") {
885         system("cp -f $kohadir/etc/zebradb/lang_defs/fr/sort-string-utf.chr $biblioserverdir/tab/word-phrase-utf.chr");
886         print "Info: copied word-phase-utf.chr\n";
887         $created_dir_or_file++;
888     }
889     unless (-f "$biblioserverdir/tab/bib1.att") {
890         system("cp -f $kohadir/etc/zebradb/biblios/etc/bib1.att $biblioserverdir/tab/bib1.att");
891         print "Info: copied bib1.att\n";
892         $created_dir_or_file++;
893     }
894     unless (-f "$biblioserverdir/tab/default.idx") {
895         system("cp -f $kohadir/etc/zebradb/etc/default.idx $biblioserverdir/tab/default.idx");
896         print "Info: copied default.idx\n";
897         $created_dir_or_file++;
898     }
899     unless (-f "$biblioserverdir/etc/ccl.properties") {
900 #         system("cp -f $kohadir/etc/zebradb/ccl.properties ".C4::Context->zebraconfig('biblioserver')->{ccl2rpn});
901         system("cp -f $kohadir/etc/zebradb/ccl.properties $biblioserverdir/etc/ccl.properties");
902         print "Info: copied ccl.properties\n";
903         $created_dir_or_file++;
904     }
905     unless (-f "$biblioserverdir/etc/pqf.properties") {
906 #         system("cp -f $kohadir/etc/zebradb/pqf.properties ".C4::Context->zebraconfig('biblioserver')->{ccl2rpn});
907         system("cp -f $kohadir/etc/zebradb/pqf.properties $biblioserverdir/etc/pqf.properties");
908         print "Info: copied pqf.properties\n";
909         $created_dir_or_file++;
910     }
911     
912     #
913     # BIBLIOS : copying mandatory files
914     #
915     unless (-f C4::Context->zebraconfig('biblioserver')->{config}) {
916     open ZD,">:utf8 ",C4::Context->zebraconfig('biblioserver')->{config};
917     print ZD "
918 # generated by KOHA/misc/migrtion_tools/rebuild_zebra.pl 
919 profilePath:\${srcdir:-.}:$biblioserverdir/tab/:$tabdir/tab/:\${srcdir:-.}/tab/
920
921 encoding: UTF-8
922 # Files that describe the attribute sets supported.
923 attset:bib1.att
924 attset:explain.att
925 attset:gils.att
926
927 modulePath:$modulesdir/modules/
928 # Specify record type
929 iso2709.recordType:grs.marcxml.record
930 recordType:grs.xml
931 recordId: (bib1,Local-Number)
932 storeKeys:1
933 storeData:1
934
935
936 # Lock File Area
937 lockDir: $biblioserverdir/lock
938 perm.anonymous:r
939 perm.kohaadmin:rw
940 register: $biblioserverdir/register:4G
941 shadow: $biblioserverdir/shadow:4G
942
943 # Temp File area for result sets
944 setTmpDir: $biblioserverdir/tmp
945
946 # Temp File area for index program
947 keyTmpDir: $biblioserverdir/key
948
949 # Approx. Memory usage during indexing
950 memMax: 40M
951 rank:rank-1
952     ";
953         print "Info: creating zebra-biblios.cfg\n";
954         $created_dir_or_file++;
955     }
956     
957     if ($created_dir_or_file) {
958         print "Info: created : $created_dir_or_file directories & files\n";
959     } else {
960         print "Info: file & directories OK\n";
961     }
962     
963 }
964 }