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