1#!/usr/bin/perl
2##!~_~perlpath~_~
3#
4# Interchange database builder and indexer
5#
6# $Id: offline.PL,v 2.7 2007-08-09 13:40:57 pajamian Exp $
7#
8# Copyright (C) 2002-2007 Interchange Development Group
9# Copyright (C) 1996-2002 Red Hat, Inc.
10#
11# This program was originally based on Vend 0.2 and 0.3
12# Copyright 1995-96 by Andrew M. Wilcox <amw@wilcoxsolutions.com>
13#
14# This program is free software; you can redistribute it and/or modify
15# it under the terms of the GNU General Public License as published by
16# the Free Software Foundation; either version 2 of the License, or
17# (at your option) any later version.
18#
19# This program is distributed in the hope that it will be useful,
20# but WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22# GNU General Public License for more details.
23#
24# You should have received a copy of the GNU General Public
25# License along with this program; if not, write to the Free
26# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
27# MA  02110-1301  USA.
28
29use lib '/usr/local/interchange/lib';
30#use lib '~_~INSTALLPRIVLIB~_~';
31use lib '/usr/local/interchange';
32#use lib '~_~INSTALLARCHLIB~_~';
33
34use strict;
35use Fcntl;
36use Vend::Util;
37use Vend::Config;
38use Vend::Data;
39use Getopt::Long;
40use Data::Dumper;
41use File::Copy;
42
43$Data::Dumper::Terse = 1;
44$Data::Dumper::Indent = 2;
45
46BEGIN {
47	eval {
48		require 5.004;
49		require FindBin;
50		1 and $Global::VendRoot = $FindBin::RealBin;
51		1 and $Global::VendRoot =~ s/.bin$//;
52	};
53	($Global::VendRoot = $ENV{MINIVEND_ROOT})
54		if defined $ENV{MINIVEND_ROOT};
55
56	$Global::VendRoot = $Global::VendRoot || '/usr/local/interchange';
57#	$Global::VendRoot = $Global::VendRoot || '~_~INSTALLARCHLIB~_~';
58
59	if(-f "$Global::VendRoot/interchange.cfg") {
60		$Global::ExeName = 'interchange';
61		$Global::ConfigFile = 'interchange.cfg';
62	}
63	elsif(-f "$Global::VendRoot/minivend.cfg") {
64		$Global::ExeName = 'minivend';
65		$Global::ConfigFile = 'minivend.cfg';
66	}
67	elsif(-f "$Global::VendRoot/interchange.cfg.dist") {
68		$Global::ExeName = 'interchange';
69		$Global::ConfigFile = 'interchange.cfg';
70	}
71}
72
73### END CONFIGURATION VARIABLES
74
75$Global::ErrorFile = "$Global::VendRoot/error.log";
76$Vend::ExternalProgram = 1;
77
78#select a DBM
79
80BEGIN {
81
82	$ENV{MINIVEND_STORABLE_DB} = 1 if -e "$Global::VendRoot/_db_storable";
83	$Global::GDBM = $Global::DB_File = $Global::DBI = 0;
84    # Now can use any type of database
85	AUTO: {
86		last AUTO if
87			(defined $ENV{MINIVEND_DBFILE} and $Global::DB_File = 1);
88		last AUTO if
89			(defined $ENV{MINIVEND_NODBM});
90		eval {require GDBM_File and $Global::GDBM = 1};
91		last AUTO if
92			(defined $ENV{MINIVEND_GDBM} and $Global::GDBM = 1);
93		eval {require DB_File and $Global::DB_File = 1};
94	}
95
96	if($Global::GDBM) {
97		require Vend::Table::GDBM;
98		import GDBM_File;
99		$Global::GDBM = 1;
100		$Global::Default_database = 'GDBM'
101			unless defined $Global::Default_database;
102	}
103	if($Global::DB_File) {
104		require Vend::Table::DB_File;
105		import DB_File;
106		$Global::DB_File = 1;
107		$Global::Default_database = 'DB_FILE'
108			unless defined $Global::Default_database;
109	}
110
111	unless($Global::GDBM || $Global::DB_File || $Global::DBI) {
112		die "No DBM or DBI defined! Offline import not necessary.\n";
113	}
114}
115
116my $USAGE = <<EOF;
117usage: offline -c catalog [-d offline_dir]
118
119If specifying a subcatalog, make sure the databases to be built
120are defined in the subcatalog definition.  If they are in the base
121catalog, use that catalog as the parameter for the -c directive.
122EOF
123
124my ($catalog,$directory,$delimiter);
125my (@Catalogs);
126my (@Directories);
127my ($Live, $NoBackup, $Verbose, $BackupExt);
128
129my %optctl = (
130			catalog   => \@Catalogs,
131			directory => \@Directories,
132			live => \$Live,
133			backup => \$BackupExt,
134			verbose => \$Verbose,
135			nobackup => \$NoBackup,
136			);
137
138my @options = qw(
139			catalog|c=s
140			directory|d=s
141			live|l
142			backup|b=s
143			nobackup|n
144			verbose|v
145			);
146GetOptions(\%optctl, @options)
147	or die "$@\n\n$USAGE\n";
148
149$BackupExt = '.bak' unless $BackupExt;
150
151die "$USAGE\n" unless @Catalogs;
152
153chdir $Global::VendRoot;
154
155global_config();
156
157$| = 1;
158
159foreach my $name (@Catalogs) {
160	my $directory = shift @Directories;
161	my $g = $Global::Catalog{$name};
162	die "No catalog named $_.\n"
163		unless($g);
164
165	my ($dir, $subconfig) = @{$g}{qw/dir base/};
166	warn "Probably hard to offline build a subcatalog, but we will try.\n"
167		if $subconfig;
168	chdir $dir or die "Couldn't change directory to $dir: $!\n";
169	$Vend::Cfg = config($name, $dir, 'config', $subconfig || undef);
170	$::Variable = $Vend::Cfg->{Variable};
171	chdir $dir or die "Couldn't change directory to $dir: $!\n";
172
173	my $realprod = $Vend::Cfg->{ProductDir};
174	$Vend::Cfg->{ProductDir} = $directory || $Vend::Cfg->{OfflineDir};
175
176	open_database();
177
178	my $db;
179	my $obj;
180	$Vend::Quiet = 1;
181	foreach $db (keys %{$Vend::Cfg->{Database}}) {
182		# Skip SQL and MEMORY databases
183		my $config = $Vend::Cfg->{Database}->{$db};
184		next if $config->{Class} =~ /MEMORY|DBI/;
185		print "Checking $db....";
186		eval {
187			$obj = database_exists_ref($db)
188				or die "Trouble importing $db: $!\n";
189			$obj = $obj->ref();
190		};
191		if($@) {
192			my $msg = "Trouble importing $db: $@\n\n";
193			if($msg =~ /source.*exist|no.*such.*file/i) {
194				print "no source file, skipping.\n";
195				next;
196			}
197			$msg .= Dumper($config) if $Verbose;
198			warn "$msg\n";
199			next;
200		}
201		if($Live) {
202			print "taking $db live....";
203			my $asc_src  = "$config->{dir}/$config->{file}";
204			my $dbm_src  = "$config->{db_file}";
205			my $asc_targ = "$realprod/$config->{file}";
206			my $dbm_targ = $dbm_src;
207			$dbm_targ =~ s{^$config->{dir}}{$realprod}
208				or die "Couldn't derive DBM target name.\n";
209			open(TARG, "+<$asc_targ")
210				or die "Couldn't open ASCII file $asc_targ read/write: $!\n";
211			lockfile(\*TARG, 1, 1)
212				or die "Couldn't lock ASCII file $asc_targ: $!\n";
213			open(SRC, "+<$asc_src")
214				or die "Couldn't open ASCII file $asc_src read/write: $!\n";
215			lockfile(\*SRC, 1, 1)
216				or die "Couldn't lock ASCII file $asc_src: $!\n";
217
218			#DBM
219			File::Copy::move($dbm_targ, "$dbm_targ$BackupExt")
220				or warn "move $dbm_targ --> $dbm_targ$BackupExt: $!\n"
221				unless $NoBackup;
222			File::Copy::move($dbm_src, $dbm_targ)
223					or die "move $dbm_src --> $dbm_targ: $!\n";
224
225			my $now = time();
226			#ASC
227			File::Copy::move($asc_targ, "$asc_targ$BackupExt")
228				or warn "move $asc_targ --> $asc_targ$BackupExt: $!\n"
229				unless $NoBackup;
230			# Possible race condition, but oh well
231			File::Copy::move($asc_src, $asc_targ)
232					or die "move $asc_src --> $asc_targ: $!\n";
233			utime $now, $now, $asc_targ, $dbm_targ;
234			unlockfile(\*TARG);
235			unlockfile(\*SRC);
236			close SRC;
237			close TARG;
238		}
239		print "done with $db.\n";
240	}
241
242	close_database();
243}
244
245=head1 NAME
246
247offline -- Interchange offline database builder
248
249=head1 VERSION
250
251# $Id: offline.PL,v 2.7 2007-08-09 13:40:57 pajamian Exp $
252
253=head1 DESCRIPTION
254
255Skeleton POD to avoid make errors.
256
257=head1 SEE ALSO
258
259interchange(1), http://www.icdevgroup.org/
260
261=cut
262