#!/usr/bin/perl -w ########################################### # rummage - Index and search the home dir # 2005, Mike Schilli ########################################### use strict; use Getopt::Std; use File::Find; use DBI; use Class::DBI::Loader; use Log::Log4perl qw(:easy); use SWISH::API::Common; use Time::Piece::MySQL; my $MAX_SIZE = 100_000; my $DSN = "dbi:mysql:dts"; my @DIRS = ("$ENV{HOME}"); my $COUNTER = 0; @DIRS = map { -l $_ ? readlink $_ : $_ } @DIRS; sub psearch($); getopts("un:m:k:p:v", \my %opts); if($opts{u}) { Log::Log4perl->easy_init({ level => $opts{v} ? $DEBUG : $INFO, file => ">/tmp/rummage.log", }); } db_init($DSN); my $loader = Class::DBI::Loader->new( dsn => $DSN, user => "root", namespace => "Rummage", ); my $filedb = $loader->find_class("file"); my $swish = SWISH::API::Common->new( file_len_max => $MAX_SIZE, preserve_atime => 1, ); # Keyword search if($opts{k}) { my @docs = $swish->search($opts{k}); print $_->path(), "\n" for @docs; # Search by mtime } elsif($opts{m}) { $filedb->set_sql(modified => qq{ SELECT __ESSENTIAL__ FROM __TABLE__ WHERE DATE_SUB(NOW(), INTERVAL $opts{m}) <= mtime }); psearch($filedb->search_modified()); # Search by path } elsif($opts{p}) { psearch($filedb->search_like( path => "%$opts{p}%")); # Search newest } elsif(exists $opts{n}) { $opts{n} = 10 unless $opts{n}; $filedb->set_sql(newest => qq{ SELECT __ESSENTIAL__ FROM __TABLE__ ORDER BY mtime DESC LIMIT $opts{n} }); psearch($filedb->search_newest()); # Index Home Directory } elsif($opts{u}) { # Set all documents unchecked $filedb->set_sql("uncheck_all", qq{ UPDATE __TABLE__ SET checked=0 }); $filedb->sql_uncheck_all()->execute(); find(\&wanted, @DIRS); # Update keyword index $swish->index_remove(); $swish->index(@DIRS); # Delete all dead documents in the DB $filedb->set_sql("delete_dead", qq{ DELETE FROM __TABLE__ WHERE checked=0 }); $filedb->sql_delete_dead()->execute(); } else { LOGDIE "usage: $0 [-u] [-v] [-n [N]] ", "[-p pathlike] [-k keyword] ", "[-m interval]"; } ########################################### sub wanted { ########################################### return unless -f; DEBUG ++$COUNTER, " $File::Find::name"; my($size,$atime,$mtime) = (stat($_))[7,8,9]; $atime = mysqltime($atime); $mtime = mysqltime($mtime); my $entry; if(($entry) = $filedb->search( path => $File::Find::name)) { if($entry->mtime() eq $mtime) { DEBUG "$File::Find::name unchanged"; } else { INFO "$File::Find::name changed"; $entry->mtime($mtime); $entry->size($size); $entry->atime($atime); } } else { $entry = $filedb->create({ path => $File::Find::name, mtime => $mtime, atime => $atime, size => $size, first_seen => mysqltime(time()), }); } $entry->checked(1); $entry->update(); return; } ########################################### sub db_init { ########################################### my($dsn) = @_; my $dbh = DBI->connect($dsn, "root", "", { PrintError => 0 }); LOGDIE "Connecting to DB failed: ", DBI::errstr unless $dbh; if(! $dbh->do(q{select * from file limit 1})) { $dbh->do(q{ CREATE TABLE file ( fileid INTEGER PRIMARY KEY AUTO_INCREMENT, path VARCHAR(255), size INTEGER, mtime DATETIME, atime DATETIME, first_seen DATETIME, type VARCHAR(255), checked INTEGER )}) or LOGDIE "Cannot create table"; $dbh->do(q{ CREATE INDEX file_idx ON file (path) }); } } ########################################### sub psearch($) { ########################################### my($it) = @_; while(my $doc = $it->next()) { print $doc->path(), " (", $doc->mtime(), ")", "\n"; } } ########################################### sub mysqltime { ########################################### my($time) = @_; return Time::Piece ->new($time)->mysql_datetime(); }