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