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