Merge remote-tracking branch 'kc/new/bug_5616' into kcmaster
[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;
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) {
100     $zebraidx_log_opt = '';
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' );
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                     my @itemsrecord;
327                     foreach my $item (@items){
328                         my $record = Item2Marc($item, $record_number);                        
329                         push @itemsrecord, $record->field($itemtag);
330                     }
331                     $record->insert_fields_ordered(@itemsrecord);
332                     my $itemsxml=$record->as_xml_record();
333                     my $searchstring = '<record>\n';
334                     my $index = index($itemsxml, '<record>\n', 0);
335                     $itemsxml = substr($itemsxml, $index + length($searchstring));
336                     $searchstring = '</record>';
337                     $marcxml = substr($marcxml, 0, index($marcxml, $searchstring));
338                     $marcxml .= $itemsxml;
339                 }
340             }
341             if ( $marcxml ) {
342                 print OUT $marcxml if $marcxml;
343                 $num_exported++;
344             }
345             next;
346         }
347         my ($marc) = get_corrected_marc_record($record_type, $record_number, $noxml);
348         if (defined $marc) {
349             # FIXME - when more than one record is exported and $as_xml is true,
350             # the output file is not valid XML - it's just multiple <record> elements
351             # strung together with no single root element.  zebraidx doesn't seem
352             # to care, though, at least if you're using the GRS-1 filter.  It does
353             # care if you're using the DOM filter, which requires valid XML file(s).
354             eval {
355                 print OUT ($as_xml) ? $marc->as_xml_record(C4::Context->preference('marcflavour')) : $marc->as_usmarc();
356                 $num_exported++;
357             };
358             if ($@) {
359               warn "Error exporting record $record_number ($record_type) ".($noxml ? "not XML" : "XML");
360             }
361         }
362     }
363     print "\nRecords exported: $num_exported\n" if ( $verbose_logging );
364     close OUT;
365     return $num_exported;
366 }
367
368 sub export_marc_records_from_list {
369     my ($record_type, $entries, $directory, $as_xml, $noxml, $records_deleted) = @_;
370
371     my $num_exported = 0;
372     open (OUT, ">:utf8 ", "$directory/exported_records") or die $!;
373     my $i = 0;
374
375     # Skip any deleted records. We check for this anyway, but this reduces error spam
376     my %found = %$records_deleted;
377     foreach my $record_number ( map { $_->{biblio_auth_number} }
378                                 grep { !$found{ $_->{biblio_auth_number} }++ }
379                                 @$entries ) {
380         print "." if ( $verbose_logging );
381         print "\r$i" unless ($i++ %100 or !$verbose_logging);
382         my ($marc) = get_corrected_marc_record($record_type, $record_number, $noxml);
383         if (defined $marc) {
384             # FIXME - when more than one record is exported and $as_xml is true,
385             # the output file is not valid XML - it's just multiple <record> elements
386             # strung together with no single root element.  zebraidx doesn't seem
387             # to care, though, at least if you're using the GRS-1 filter.  It does
388             # care if you're using the DOM filter, which requires valid XML file(s).
389             print OUT ($as_xml) ? $marc->as_xml_record(C4::Context->preference('marcflavour')) : $marc->as_usmarc();
390             $num_exported++;
391         }
392     }
393     print "\nRecords exported: $num_exported\n" if ( $verbose_logging );
394     close OUT;
395     return $num_exported;
396 }
397
398 sub generate_deleted_marc_records {
399     my ($record_type, $entries, $directory, $as_xml) = @_;
400
401     my $records_deleted = {};
402     open (OUT, ">:utf8 ", "$directory/exported_records") or die $!;
403     my $i = 0;
404     foreach my $record_number (map { $_->{biblio_auth_number} } @$entries ) {
405         print "\r$i" unless ($i++ %100 or !$verbose_logging);
406         print "." if ( $verbose_logging );
407
408         my $marc = MARC::Record->new();
409         if ($record_type eq 'biblio') {
410             fix_biblio_ids($marc, $record_number, $record_number);
411         } else {
412             fix_authority_id($marc, $record_number);
413         }
414         if (C4::Context->preference("marcflavour") eq "UNIMARC") {
415             fix_unimarc_100($marc);
416         }
417
418         print OUT ($as_xml) ? $marc->as_xml_record(C4::Context->preference("marcflavour")) : $marc->as_usmarc();
419
420         $records_deleted->{$record_number} = 1;
421     }
422     print "\nRecords exported: $i\n" if ( $verbose_logging );
423     close OUT;
424     return $records_deleted;
425     
426
427 }
428
429 sub get_corrected_marc_record {
430     my ($record_type, $record_number, $noxml) = @_;
431
432     my $marc = get_raw_marc_record($record_type, $record_number, $noxml); 
433
434     if (defined $marc) {
435         fix_leader($marc);
436         if ($record_type eq 'authority') {
437             fix_authority_id($marc, $record_number);
438         }
439         if (C4::Context->preference("marcflavour") eq "UNIMARC") {
440             fix_unimarc_100($marc);
441         }
442     }
443
444     return $marc;
445 }
446
447 sub get_raw_marc_record {
448     my ($record_type, $record_number, $noxml) = @_;
449   
450     my $marc; 
451     if ($record_type eq 'biblio') {
452         if ($noxml) {
453             my $fetch_sth = $dbh->prepare_cached("SELECT marc FROM biblioitems WHERE biblionumber = ?");
454             $fetch_sth->execute($record_number);
455             if (my ($blob) = $fetch_sth->fetchrow_array) {
456                 $marc = MARC::Record->new_from_usmarc($blob);
457                 unless ($marc) {
458                     warn "error creating MARC::Record from $blob";
459                 }
460             }
461             # failure to find a bib is not a problem -
462             # a delete could have been done before
463             # trying to process a record update
464
465             $fetch_sth->finish();
466             return unless $marc;
467         } else {
468             eval { $marc = GetMarcBiblio($record_number, 1); };
469             if ($@ || !$marc) {
470                 # here we do warn since catching an exception
471                 # means that the bib was found but failed
472                 # to be parsed
473                 warn "error retrieving biblio $record_number";
474                 return;
475             }
476         }
477     } else {
478         eval { $marc = GetAuthority($record_number); };
479         if ($@) {
480             warn "error retrieving authority $record_number";
481             return;
482         }
483     }
484     return $marc;
485 }
486
487 sub fix_leader {
488     # FIXME - this routine is suspect
489     # It blanks the Leader/00-05 and Leader/12-16 to
490     # force them to be recalculated correct when
491     # the $marc->as_usmarc() or $marc->as_xml() is called.
492     # But why is this necessary?  It would be a serious bug
493     # in MARC::Record (definitely) and MARC::File::XML (arguably) 
494     # if they are emitting incorrect leader values.
495     my $marc = shift;
496
497     my $leader = $marc->leader;
498     substr($leader,  0, 5) = '     ';
499     substr($leader, 10, 7) = '22     ';
500     $marc->leader(substr($leader, 0, 24));
501 }
502
503 sub fix_biblio_ids {
504     # FIXME - it is essential to ensure that the biblionumber is present,
505     #         otherwise, Zebra will choke on the record.  However, this
506     #         logic belongs in the relevant C4::Biblio APIs.
507     my $marc = shift;
508     my $biblionumber = shift;
509     my $biblioitemnumber;
510     if (@_) {
511         $biblioitemnumber = shift;
512     } else {    
513         my $sth = $dbh->prepare(
514             "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
515         $sth->execute($biblionumber);
516         ($biblioitemnumber) = $sth->fetchrow_array;
517         $sth->finish;
518         unless ($biblioitemnumber) {
519             warn "failed to get biblioitemnumber for biblio $biblionumber";
520             return 0;
521         }
522     }
523
524     # FIXME - this is cheating on two levels
525     # 1. C4::Biblio::_koha_marc_update_bib_ids is meant to be an internal function
526     # 2. Making sure that the biblionumber and biblioitemnumber are correct and
527     #    present in the MARC::Record object ought to be part of GetMarcBiblio.
528     #
529     # On the other hand, this better for now than what rebuild_zebra.pl used to
530     # do, which was duplicate the code for inserting the biblionumber 
531     # and biblioitemnumber
532     C4::Biblio::_koha_marc_update_bib_ids($marc, '', $biblionumber, $biblioitemnumber);
533
534     return 1;
535 }
536
537 sub fix_authority_id {
538     # FIXME - as with fix_biblio_ids, the authid must be present
539     #         for Zebra's sake.  However, this really belongs
540     #         in C4::AuthoritiesMarc.
541     my ($marc, $authid) = @_;
542     unless ($marc->field('001') and $marc->field('001')->data() eq $authid){
543         $marc->delete_field($marc->field('001'));
544         $marc->insert_fields_ordered(MARC::Field->new('001',$authid));
545     }
546 }
547
548 sub fix_unimarc_100 {
549     # FIXME - again, if this is necessary, it belongs in C4::AuthoritiesMarc.
550     my $marc = shift;
551
552     my $string;
553     if ( length($marc->subfield( 100, "a" )) == 35 ) {
554         $string = $marc->subfield( 100, "a" );
555         my $f100 = $marc->field(100);
556         $marc->delete_field($f100);
557     }
558     else {
559         $string = POSIX::strftime( "%Y%m%d", localtime );
560         $string =~ s/\-//g;
561         $string = sprintf( "%-*s", 35, $string );
562     }
563     substr( $string, 22, 6, "frey50" );
564     unless ( length($marc->subfield( 100, "a" )) == 35 ) {
565         $marc->delete_field($marc->field(100));
566         $marc->insert_grouped_field(MARC::Field->new( 100, "", "", "a" => $string ));
567     }
568 }
569
570 sub do_indexing {
571     my ($record_type, $op, $record_dir, $reset_index, $noshadow, $record_format, $zebraidx_log_opt) = @_;
572
573     my $zebra_server  = ($record_type eq 'biblio') ? 'biblioserver' : 'authorityserver';
574     my $zebra_db_name = ($record_type eq 'biblio') ? 'biblios' : 'authorities';
575     my $zebra_config  = C4::Context->zebraconfig($zebra_server)->{'config'};
576     my $zebra_db_dir  = C4::Context->zebraconfig($zebra_server)->{'directory'};
577
578     system("zebraidx -c $zebra_config $zebraidx_log_opt -g $record_format -d $zebra_db_name init") if $reset_index;
579     system("zebraidx -c $zebra_config $zebraidx_log_opt $noshadow -g $record_format -d $zebra_db_name $op $record_dir");
580     system("zebraidx -c $zebra_config $zebraidx_log_opt -g $record_format -d $zebra_db_name commit") unless $noshadow;
581
582 }
583
584 sub print_usage {
585     print <<_USAGE_;
586 $0: reindex MARC bibs and/or authorities in Zebra.
587
588 Use this batch job to reindex all biblio or authority
589 records in your Koha database.  This job is useful
590 only if you are using Zebra; if you are using the 'NoZebra'
591 mode, this job should not be used.
592
593 Parameters:
594     -b                      index bibliographic records
595
596     -a                      index authority records
597
598     -z                      select only updated and deleted
599                             records marked in the zebraqueue
600                             table.  Cannot be used with -r
601                             or -s.
602
603     -r                      clear Zebra index before
604                             adding records to index
605
606     -d                      Temporary directory for indexing.
607                             If not specified, one is automatically
608                             created.  The export directory
609                             is automatically deleted unless
610                             you supply the -k switch.
611
612     -k                      Do not delete export directory.
613
614     -s                      Skip export.  Used if you have
615                             already exported the records 
616                             in a previous run.
617
618     -noxml                  index from ISO MARC blob
619                             instead of MARC XML.  This
620                             option is recommended only
621                             for advanced user.
622
623     -x                      export and index as xml instead of is02709 (biblios only).
624                             use this if you might have records > 99,999 chars,
625                                                         
626     -nosanitize             export biblio/authority records directly from DB marcxml
627                             field without sanitizing records. It speed up
628                             dump process but could fail if DB contains badly
629                             encoded records. Works only with -x,
630
631     -w                      skip shadow indexing for this batch
632
633     -y                      do NOT clear zebraqueue after indexing; normally,
634                             after doing batch indexing, zebraqueue should be
635                             marked done for the affected record type(s) so that
636                             a running zebraqueue_daemon doesn't try to reindex
637                             the same records - specify -y to override this.  
638                             Cannot be used with -z.
639
640     -v                      increase the amount of logging.  Normally only 
641                             warnings and errors from the indexing are shown.
642
643     -munge-config           Deprecated option to try
644                             to fix Zebra config files.
645     --help or -h            show this message.
646 _USAGE_
647 }
648
649 # FIXME: the following routines are deprecated and 
650 # will be removed once it is determined whether
651 # a script to fix Zebra configuration files is 
652 # actually needed.
653 sub munge_config {
654 #
655 # creating zebra-biblios.cfg depending on system
656 #
657
658 # getting zebraidx directory
659 my $zebraidxdir;
660 foreach (qw(/usr/local/bin/zebraidx
661         /opt/bin/zebraidx
662         /usr/bin/zebraidx
663         )) {
664     if ( -f $_ ) {
665         $zebraidxdir=$_;
666     }
667 }
668
669 unless ($zebraidxdir) {
670     print qq|
671     ERROR: could not find zebraidx directory
672     ERROR: Either zebra is not installed,
673     ERROR: or it's in a directory I don't checked.
674     ERROR: do a which zebraidx and edit this file to add the result you get
675 |;
676     exit;
677 }
678 $zebraidxdir =~ s/\/bin\/.*//;
679 print "Info : zebra is in $zebraidxdir \n";
680
681 # getting modules directory
682 my $modulesdir;
683 foreach (qw(/usr/local/lib/idzebra-2.0/modules/mod-grs-xml.so
684             /usr/local/lib/idzebra/modules/mod-grs-xml.so
685             /usr/lib/idzebra/modules/mod-grs-xml.so
686             /usr/lib/idzebra-2.0/modules/mod-grs-xml.so
687         )) {
688     if ( -f $_ ) {
689         $modulesdir=$_;
690     }
691 }
692
693 unless ($modulesdir) {
694     print qq|
695     ERROR: could not find mod-grs-xml.so directory
696     ERROR: Either zebra is not properly compiled (libxml2 is not setup and you don t have mod-grs-xml.so,
697     ERROR: or it's in a directory I don't checked.
698     ERROR: find where mod-grs-xml.so is and edit this file to add the result you get
699 |;
700     exit;
701 }
702 $modulesdir =~ s/\/modules\/.*//;
703 print "Info: zebra modules dir : $modulesdir\n";
704
705 # getting tab directory
706 my $tabdir;
707 foreach (qw(/usr/local/share/idzebra/tab/explain.att
708             /usr/local/share/idzebra-2.0/tab/explain.att
709             /usr/share/idzebra/tab/explain.att
710             /usr/share/idzebra-2.0/tab/explain.att
711         )) {
712     if ( -f $_ ) {
713         $tabdir=$_;
714     }
715 }
716
717 unless ($tabdir) {
718     print qq|
719     ERROR: could not find explain.att directory
720     ERROR: Either zebra is not properly compiled,
721     ERROR: or it's in a directory I don't checked.
722     ERROR: find where explain.att is and edit this file to add the result you get
723 |;
724     exit;
725 }
726 $tabdir =~ s/\/tab\/.*//;
727 print "Info: tab dir : $tabdir\n";
728
729 #
730 # AUTHORITIES creating directory structure
731 #
732 my $created_dir_or_file = 0;
733 if ($authorities) {
734     if ( $verbose_logging ) {
735         print "====================\n";
736         print "checking directories & files for authorities\n";
737         print "====================\n";
738     }
739     unless (-d "$authorityserverdir") {
740         system("mkdir -p $authorityserverdir");
741         print "Info: created $authorityserverdir\n";
742         $created_dir_or_file++;
743     }
744     unless (-d "$authorityserverdir/lock") {
745         mkdir "$authorityserverdir/lock";
746         print "Info: created $authorityserverdir/lock\n";
747         $created_dir_or_file++;
748     }
749     unless (-d "$authorityserverdir/register") {
750         mkdir "$authorityserverdir/register";
751         print "Info: created $authorityserverdir/register\n";
752         $created_dir_or_file++;
753     }
754     unless (-d "$authorityserverdir/shadow") {
755         mkdir "$authorityserverdir/shadow";
756         print "Info: created $authorityserverdir/shadow\n";
757         $created_dir_or_file++;
758     }
759     unless (-d "$authorityserverdir/tab") {
760         mkdir "$authorityserverdir/tab";
761         print "Info: created $authorityserverdir/tab\n";
762         $created_dir_or_file++;
763     }
764     unless (-d "$authorityserverdir/key") {
765         mkdir "$authorityserverdir/key";
766         print "Info: created $authorityserverdir/key\n";
767         $created_dir_or_file++;
768     }
769     
770     unless (-d "$authorityserverdir/etc") {
771         mkdir "$authorityserverdir/etc";
772         print "Info: created $authorityserverdir/etc\n";
773         $created_dir_or_file++;
774     }
775     
776     #
777     # AUTHORITIES : copying mandatory files
778     #
779     # the record model, depending on marc flavour
780     unless (-f "$authorityserverdir/tab/record.abs") {
781         if (C4::Context->preference("marcflavour") eq "UNIMARC") {
782             system("cp -f $kohadir/etc/zebradb/marc_defs/unimarc/authorities/record.abs $authorityserverdir/tab/record.abs");
783             print "Info: copied record.abs for UNIMARC\n";
784         } else {
785             system("cp -f $kohadir/etc/zebradb/marc_defs/marc21/authorities/record.abs $authorityserverdir/tab/record.abs");
786             print "Info: copied record.abs for USMARC\n";
787         }
788         $created_dir_or_file++;
789     }
790     unless (-f "$authorityserverdir/tab/sort-string-utf.chr") {
791         system("cp -f $kohadir/etc/zebradb/lang_defs/fr/sort-string-utf.chr $authorityserverdir/tab/sort-string-utf.chr");
792         print "Info: copied sort-string-utf.chr\n";
793         $created_dir_or_file++;
794     }
795     unless (-f "$authorityserverdir/tab/word-phrase-utf.chr") {
796         system("cp -f $kohadir/etc/zebradb/lang_defs/fr/sort-string-utf.chr $authorityserverdir/tab/word-phrase-utf.chr");
797         print "Info: copied word-phase-utf.chr\n";
798         $created_dir_or_file++;
799     }
800     unless (-f "$authorityserverdir/tab/auth1.att") {
801         system("cp -f $kohadir/etc/zebradb/authorities/etc/bib1.att $authorityserverdir/tab/auth1.att");
802         print "Info: copied auth1.att\n";
803         $created_dir_or_file++;
804     }
805     unless (-f "$authorityserverdir/tab/default.idx") {
806         system("cp -f $kohadir/etc/zebradb/etc/default.idx $authorityserverdir/tab/default.idx");
807         print "Info: copied default.idx\n";
808         $created_dir_or_file++;
809     }
810     
811     unless (-f "$authorityserverdir/etc/ccl.properties") {
812 #         system("cp -f $kohadir/etc/zebradb/ccl.properties ".C4::Context->zebraconfig('authorityserver')->{ccl2rpn});
813         system("cp -f $kohadir/etc/zebradb/ccl.properties $authorityserverdir/etc/ccl.properties");
814         print "Info: copied ccl.properties\n";
815         $created_dir_or_file++;
816     }
817     unless (-f "$authorityserverdir/etc/pqf.properties") {
818 #         system("cp -f $kohadir/etc/zebradb/pqf.properties ".C4::Context->zebraconfig('authorityserver')->{ccl2rpn});
819         system("cp -f $kohadir/etc/zebradb/pqf.properties $authorityserverdir/etc/pqf.properties");
820         print "Info: copied pqf.properties\n";
821         $created_dir_or_file++;
822     }
823     
824     #
825     # AUTHORITIES : copying mandatory files
826     #
827     unless (-f C4::Context->zebraconfig('authorityserver')->{config}) {
828     open ZD,">:utf8 ",C4::Context->zebraconfig('authorityserver')->{config};
829     print ZD "
830 # generated by KOHA/misc/migration_tools/rebuild_zebra.pl 
831 profilePath:\${srcdir:-.}:$authorityserverdir/tab/:$tabdir/tab/:\${srcdir:-.}/tab/
832
833 encoding: UTF-8
834 # Files that describe the attribute sets supported.
835 attset: auth1.att
836 attset: explain.att
837 attset: gils.att
838
839 modulePath:$modulesdir/modules/
840 # Specify record type
841 iso2709.recordType:grs.marcxml.record
842 recordType:grs.xml
843 recordId: (auth1,Local-Number)
844 storeKeys:1
845 storeData:1
846
847
848 # Lock File Area
849 lockDir: $authorityserverdir/lock
850 perm.anonymous:r
851 perm.kohaadmin:rw
852 register: $authorityserverdir/register:4G
853 shadow: $authorityserverdir/shadow:4G
854
855 # Temp File area for result sets
856 setTmpDir: $authorityserverdir/tmp
857
858 # Temp File area for index program
859 keyTmpDir: $authorityserverdir/key
860
861 # Approx. Memory usage during indexing
862 memMax: 40M
863 rank:rank-1
864     ";
865         print "Info: creating zebra-authorities.cfg\n";
866         $created_dir_or_file++;
867     }
868     
869     if ($created_dir_or_file) {
870         print "Info: created : $created_dir_or_file directories & files\n";
871     } else {
872         print "Info: file & directories OK\n";
873     }
874     
875 }
876 if ($biblios) {
877     if ( $verbose_logging ) {
878         print "====================\n";
879         print "checking directories & files for biblios\n";
880         print "====================\n";
881     }
882
883     #
884     # BIBLIOS : creating directory structure
885     #
886     unless (-d "$biblioserverdir") {
887         system("mkdir -p $biblioserverdir");
888         print "Info: created $biblioserverdir\n";
889         $created_dir_or_file++;
890     }
891     unless (-d "$biblioserverdir/lock") {
892         mkdir "$biblioserverdir/lock";
893         print "Info: created $biblioserverdir/lock\n";
894         $created_dir_or_file++;
895     }
896     unless (-d "$biblioserverdir/register") {
897         mkdir "$biblioserverdir/register";
898         print "Info: created $biblioserverdir/register\n";
899         $created_dir_or_file++;
900     }
901     unless (-d "$biblioserverdir/shadow") {
902         mkdir "$biblioserverdir/shadow";
903         print "Info: created $biblioserverdir/shadow\n";
904         $created_dir_or_file++;
905     }
906     unless (-d "$biblioserverdir/tab") {
907         mkdir "$biblioserverdir/tab";
908         print "Info: created $biblioserverdir/tab\n";
909         $created_dir_or_file++;
910     }
911     unless (-d "$biblioserverdir/key") {
912         mkdir "$biblioserverdir/key";
913         print "Info: created $biblioserverdir/key\n";
914         $created_dir_or_file++;
915     }
916     unless (-d "$biblioserverdir/etc") {
917         mkdir "$biblioserverdir/etc";
918         print "Info: created $biblioserverdir/etc\n";
919         $created_dir_or_file++;
920     }
921     
922     #
923     # BIBLIOS : copying mandatory files
924     #
925     # the record model, depending on marc flavour
926     unless (-f "$biblioserverdir/tab/record.abs") {
927         if (C4::Context->preference("marcflavour") eq "UNIMARC") {
928             system("cp -f $kohadir/etc/zebradb/marc_defs/unimarc/biblios/record.abs $biblioserverdir/tab/record.abs");
929             print "Info: copied record.abs for UNIMARC\n";
930         } else {
931             system("cp -f $kohadir/etc/zebradb/marc_defs/marc21/biblios/record.abs $biblioserverdir/tab/record.abs");
932             print "Info: copied record.abs for USMARC\n";
933         }
934         $created_dir_or_file++;
935     }
936     unless (-f "$biblioserverdir/tab/sort-string-utf.chr") {
937         system("cp -f $kohadir/etc/zebradb/lang_defs/fr/sort-string-utf.chr $biblioserverdir/tab/sort-string-utf.chr");
938         print "Info: copied sort-string-utf.chr\n";
939         $created_dir_or_file++;
940     }
941     unless (-f "$biblioserverdir/tab/word-phrase-utf.chr") {
942         system("cp -f $kohadir/etc/zebradb/lang_defs/fr/sort-string-utf.chr $biblioserverdir/tab/word-phrase-utf.chr");
943         print "Info: copied word-phase-utf.chr\n";
944         $created_dir_or_file++;
945     }
946     unless (-f "$biblioserverdir/tab/bib1.att") {
947         system("cp -f $kohadir/etc/zebradb/biblios/etc/bib1.att $biblioserverdir/tab/bib1.att");
948         print "Info: copied bib1.att\n";
949         $created_dir_or_file++;
950     }
951     unless (-f "$biblioserverdir/tab/default.idx") {
952         system("cp -f $kohadir/etc/zebradb/etc/default.idx $biblioserverdir/tab/default.idx");
953         print "Info: copied default.idx\n";
954         $created_dir_or_file++;
955     }
956     unless (-f "$biblioserverdir/etc/ccl.properties") {
957 #         system("cp -f $kohadir/etc/zebradb/ccl.properties ".C4::Context->zebraconfig('biblioserver')->{ccl2rpn});
958         system("cp -f $kohadir/etc/zebradb/ccl.properties $biblioserverdir/etc/ccl.properties");
959         print "Info: copied ccl.properties\n";
960         $created_dir_or_file++;
961     }
962     unless (-f "$biblioserverdir/etc/pqf.properties") {
963 #         system("cp -f $kohadir/etc/zebradb/pqf.properties ".C4::Context->zebraconfig('biblioserver')->{ccl2rpn});
964         system("cp -f $kohadir/etc/zebradb/pqf.properties $biblioserverdir/etc/pqf.properties");
965         print "Info: copied pqf.properties\n";
966         $created_dir_or_file++;
967     }
968     
969     #
970     # BIBLIOS : copying mandatory files
971     #
972     unless (-f C4::Context->zebraconfig('biblioserver')->{config}) {
973     open ZD,">:utf8 ",C4::Context->zebraconfig('biblioserver')->{config};
974     print ZD "
975 # generated by KOHA/misc/migrtion_tools/rebuild_zebra.pl 
976 profilePath:\${srcdir:-.}:$biblioserverdir/tab/:$tabdir/tab/:\${srcdir:-.}/tab/
977
978 encoding: UTF-8
979 # Files that describe the attribute sets supported.
980 attset:bib1.att
981 attset:explain.att
982 attset:gils.att
983
984 modulePath:$modulesdir/modules/
985 # Specify record type
986 iso2709.recordType:grs.marcxml.record
987 recordType:grs.xml
988 recordId: (bib1,Local-Number)
989 storeKeys:1
990 storeData:1
991
992
993 # Lock File Area
994 lockDir: $biblioserverdir/lock
995 perm.anonymous:r
996 perm.kohaadmin:rw
997 register: $biblioserverdir/register:4G
998 shadow: $biblioserverdir/shadow:4G
999
1000 # Temp File area for result sets
1001 setTmpDir: $biblioserverdir/tmp
1002
1003 # Temp File area for index program
1004 keyTmpDir: $biblioserverdir/key
1005
1006 # Approx. Memory usage during indexing
1007 memMax: 40M
1008 rank:rank-1
1009     ";
1010         print "Info: creating zebra-biblios.cfg\n";
1011         $created_dir_or_file++;
1012     }
1013     
1014     if ($created_dir_or_file) {
1015         print "Info: created : $created_dir_or_file directories & files\n";
1016     } else {
1017         print "Info: file & directories OK\n";
1018     }
1019     
1020 }
1021 }