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