Genealogy-Wills

 view release on metacpan or  search on metacpan

bin/create_db.PL  view on Meta::CPAN

		   ($warning =~ /isn't numeric in numeric eq /i)) {
			die $warning;
		}
		warn $warning;
	}
}

my $force_flag;
my $dir  = 'lib/Genealogy/Wills/data';
my $bdir = File::Spec->catdir('blib', $dir);

if(defined($ARGV[0]) && ($ARGV[0] eq '-f')) {
	$force_flag++;
} elsif($ENV{'AUTOMATED_TESTING'}) {
	if(!-d $dir) {
		mkdir $dir, 0755;
	}
	exit;
}

if(!-d $dir) {
	mkdir $dir, 0755;
}

my $filename = File::Spec->catdir($dir, 'wills.sql');

if(-r $filename) {
	# Don't bother downloading if the file is less than a day old
	if(((-s $filename) > 0) && (-M $filename < 1) && !$force_flag) {
		_sync_to_blib();
		exit;
	}
	unlink $filename;
}

# $ENV{CACHE_DIR}/$ENV{CACHEDIR} is external input: validate before use in
# file operations. A tainted or attacker-controlled path (e.g. ../../etc)
# could cause mkdir or HTTP::Cache::Transparent to write outside the
# intended cache tree. Only allow safe filesystem characters and reject
# path traversal sequences.
my $cache_dir_raw = $ENV{'CACHE_DIR'} // $ENV{'CACHEDIR'};
my $cache_dir;
if(defined $cache_dir_raw) {
	unless($cache_dir_raw =~ /\A[\w.\-\/~]+\z/ && index($cache_dir_raw, '..') < 0) {
		Carp::croak("Unsafe cache directory path in CACHE_DIR/CACHEDIR: $cache_dir_raw");
	}
	$cache_dir = $cache_dir_raw;
	mkdir $cache_dir, 0700 if(!-d $cache_dir);
	$cache_dir = File::Spec->catfile($cache_dir, 'http-cache-transparent');
} else {
	$cache_dir = File::Spec->catfile(File::HomeDir->my_home(), '.cache', 'http-cache-transparent');
}

HTTP::Cache::Transparent::init({
	BasePath => $cache_dir,
	Verbose  => 0,
	NoUpdate => 60 * 60 * 24 * 7 * 31,	# The archive never changes
	MaxAge   => 30 * 24
}) || Carp::croak("$0: $cache_dir: $!");

my $ua = LWP::UserAgent::WithCache->new(timeout => 10, keep_alive => 1);
$ua->env_proxy(1);
$ua->agent('Genealogy::Wills');
# $ua->agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36');
$ua->conn_cache()->total_capacity(undef);
$Lingua::EN::NameCase::POSTNOMINAL = 0;

# RaiseError => 1 means DBI throws on failure before ever returning undef
my $dbh = DBI->connect("dbi:SQLite:dbname=$filename", undef, undef, { RaiseError => 1, AutoCommit => 0, synchronous => 0, locking_mode => 'EXCLUSIVE' });

$dbh->do('PRAGMA cache_size = -65536');	# 64MB
$dbh->do('PRAGMA journal_mode = OFF');
$dbh->do('CREATE TABLE wills(first VARCHAR NOT NULL, middle VARCHAR, last VARCHAR NOT NULL, town VARCHAR, year INTEGER, url VARCHAR)');

my @queue;
foreach my $page ('ab', 'c', 'dg', 'hj', 'km', 'nr', 'sv', 'wy') {
	mrawson($ua, $page);
	flush($dbh) if(scalar(@queue) > 200_000);
};

print ' ' x 78, "\r";

flush($dbh);

$dbh->commit();
$dbh->prepare('CREATE INDEX name_index ON wills(first, last)')->execute();
$dbh->prepare('CREATE INDEX name_index_year ON wills(first, last, year)')->execute();
$dbh->do('pragma optimize');
$dbh->disconnect();

print "\n";

_sync_to_blib();

sub _sync_to_blib {
	mkdir $bdir, 0755 unless -d $bdir;
	return unless -d $bdir && -r $filename;
	my $bfilename = File::Spec->catdir($bdir, 'wills.sql');
	unlink $bfilename if -e $bfilename;
	link $filename, $bfilename;
}

sub mrawson {
	my ($ua, $page) = @_;

	my $url = "https://freepages.rootsweb.com/~mrawson/genealogy/will_$page.html";

	# local $| flushes immediately and restores on scope exit
	local $| = 1;
	printf "%-70s\r", $url;

	my $response = $ua->get($url);

	my $data;
	if($response->is_success) {
		$data = $response->decoded_content();
	} else {
		# status_line() comes from the upstream server; concatenate (not
		# comma-list) to form one string before passing to Carp::croak.
		Carp::croak("\n$url: " . $response->status_line());
	}



( run in 2.136 seconds using v1.01-cache-2.11-cpan-14f38c9f855 )