log.pl
changeset 21 2404b9e58749
parent 16 bb1b17fee8c3
child 25 e8f1315b1617
--- a/log.pl	Thu Mar 26 09:44:00 2009 +0100
+++ b/log.pl	Thu Mar 26 09:46:50 2009 +0100
@@ -13,7 +13,27 @@
 		  start special file processing (assuming output
 		  from apt, with text (default: APT: upgrade) going
 		  to the first line)
+    --logfile=s	  use this(!) logfile
 #
+# something about charsets
+# * We assume the LOG file is always UTF-8!
+#   (I know, it's not true for historical entries, may be we can
+#   build some tool to convert the file line-by-line, or at least
+#   entry-by-entry -- and our database too.
+# * The mail is sent always as UTF-8!
+# * The current charset could be found using "langinfo CODESET"
+#   (hopefully - needs to be tested)
+# Conclusion:
+#   - On opening/reading the log file: convert from UTF-8 -> current codeset
+#   - If this fails, issue a warning, use "head <something>" to show the
+#     last LOG entry directly and then fire up the editor with an 
+#     empty file (or just added notice why we do not show the old
+#     messages)
+#   - After editing: convert the current messsage to from the current
+#     codeset UTF-8
+#   - The same is for message on command line (but this is more easy, we
+#     do not have to cope with the old message log
+
 
 use strict;
 use warnings;
@@ -25,6 +45,8 @@
 use Mail::Mailer;
 use DBI;
 use MIME::QuotedPrint;
+use I18N::Langinfo qw(langinfo CODESET);
+use Text::Iconv;
 
 use Logbuch::HG;
 
@@ -47,19 +69,19 @@
 
 my $ME = basename $0;
 
-my $DSN = "DBI:mysql:logbuch:pu.schlittermann.de";
+my $DSN  = "DBI:mysql:logbuch:pu.schlittermann.de";
 my $USER = "logbuch";
-my $PW = "HIDDEN";
+my $PW   = "HIDDEN";
 
-my $LOG = "$ENV{HOME}/LOG";
 my $EDITOR = $ENV{VISUAL} || $ENV{EDITOR} || "vim";
 my $MAGIC = "#--- all changes below are ignored ---#\n";
 
-my $opt_db = 1;
-my $opt_mail = 1;
+my $opt_db      = 1;
+my $opt_mail    = 1;
 my $opt_message = "";
-my $opt_apt = "";
+my $opt_apt     = "";
 my $opt_initdir = "";
+my $opt_file    = "$ENV{HOME}/LOG";
 
 my $Dbh;
 
@@ -70,213 +92,214 @@
 
 MAIN: {
 
-    GetOptions("db!" => \$opt_db, 
-	"mail!" => \$opt_mail,
-	"message=s" => \$opt_message,
-	"type=s" => \$opt_apt,
-	"init-dir=s" => \$opt_initdir,
+    GetOptions(
+        "db!"        => \$opt_db,
+        "mail!"      => \$opt_mail,
+        "message=s"  => \$opt_message,
+        "type=s"     => \$opt_apt,
+        "init-dir=s" => \$opt_initdir,
+        "file=s"     => \$opt_file,
     ) or die eval "\"$USAGE\"";
 
     if ($opt_message =~ /^@(.*)/) {
-	@ARGV = $1;
-	$opt_message = join "", <>;
-    } elsif ($opt_message eq "-") {
-	$opt_message = join "", <STDIN>;
-    } elsif ($opt_message =~ /^apt(?::(.*))?\@(\S+)/) {
-	open(I, $2) or die "Can't open $2: $!\n";
-	$opt_message = ($1 ? "APT: $1\n" : "APT: upgrade\n")
-	    . join "", map { 
-		if (/^\d/) { ($_) }
-		elsif ( /^(?:Inst|Conf|Remv|Purg)/ ) { ("- $_") }
-		else { () } 
-	    } <I>;
+        @ARGV = $1;
+        $opt_message = join "", <>;
+    }
+    elsif ($opt_message eq "-") {
+        $opt_message = join "", <STDIN>;
+    }
+    elsif ($opt_message =~ /^apt(?::(.*))?\@(\S+)/) {
+        open(I, $2) or die "Can't open $2: $!\n";
+        $opt_message = ($1 ? "APT: $1\n" : "APT: upgrade\n") . join "", map {
+            if    (/^\d/)                      { ($_) }
+            elsif (/^(?:Inst|Conf|Remv|Purg)/) { ("- $_") }
+            else                               { () }
+        } <I>;
     }
 
     if ($opt_message =~ /\n/) {
-	$opt_message =~ s/\n/\n    /g;
+        $opt_message =~ s/\n/\n    /g;
     }
 
     if (defined @config::notify_dirs || $opt_initdir) {
-	check_hg_bin();
+        check_hg_bin();
     }
 
     if ($opt_initdir) {
-	my $repo = Logbuch::HG->new( repo => $opt_initdir );
+        my $repo = Logbuch::HG->new(repo => $opt_initdir);
 
-	$repo->is_repository() and
-	    die "$ME: directory already initialized, skipping\n";
+        $repo->is_repository()
+          and die "$ME: directory already initialized, skipping\n";
 
-	$repo->init() or
-	    die "E: initialization failed\n";
-	
-	$repo->addremove();
-	$repo->commit("initial check in");
+        $repo->init()
+          or die "E: initialization failed\n";
 
-	exit 0;
+        $repo->addremove();
+        $repo->commit("initial check in");
+
+        exit 0;
     }
 
     my $hg_status_text = "";
     if (defined @config::notify_dirs) {
-	foreach my $dir (@config::notify_dirs) {
-	    -d $dir or next;
+        foreach my $dir (@config::notify_dirs) {
+            -d $dir or next;
 
-	    print "$ME: Checking $dir for modifications\n";
+            print "$ME: Checking $dir for modifications\n";
 
-	    my $repo = Logbuch::HG->new( repo => $dir );
-	    $repo->is_repository() or
-		die "$ME: directory $dir not initialized please call: \n",
-		    "  # $ME --init-dir $dir \n";
+            my $repo = Logbuch::HG->new(repo => $dir);
+            $repo->is_repository()
+              or die "$ME: directory $dir not initialized please call: \n",
+              "  # $ME --init-dir $dir \n";
 
-	    $repo->addremove();
-	    $hg_status_text .= $repo->status();
-	}
+            $repo->addremove();
+            $hg_status_text .= $repo->status();
+        }
     }
 
     if ($opt_db) {
-	$Dbh = DBI->connect($DSN, $USER, $PW, {RaiseError => 1})
-	    or die $DBI::errstr;
-	END { $Dbh->disconnect() if $Dbh; }
+        $Dbh = DBI->connect($DSN, $USER, $PW, { RaiseError => 1 })
+          or die $DBI::errstr;
+        END { $Dbh->disconnect() if $Dbh; }
     }
 
     # Temporärfile öffnen
-    my ($fh, $file);
-    END { unlink $file if $file; }
-    ($fh, $file) = tempfile(DIR => "/tmp");
+    my ($fh, $file) = tempfile(DIR => "/tmp", UNLINK => 1);
 
-    my $auto_message = (not $hg_status_text) ? "" :
-	"\n"
-	. " Modified config files since last log entry listend below...\n"
-	. $hg_status_text
-	. "\n";
+    my $auto_message =
+      (not $hg_status_text)
+      ? ""
+      : "\n"
+      . " Modified config files since last log entry listend below...\n"
+      . $hg_status_text . "\n";
 
     # Kopftext eintragen
-    print $fh 
-	    "Date: ", scalar(localtime()), "\n",
-	    "User: ", identity(), "\n",
-	    "MailTo: ", mailto(), "\n",
-	    "\n",
-	    "  * $opt_message",
-	    "\n",
-	    $auto_message,
-	    "\n", $MAGIC, "\n";
+    print $fh "Date: ", scalar(localtime()), "\n",
+      "User: ",   identity(), "\n",
+      "MailTo: ", mailto(),   "\n",
+      "\n",
+      "  * $opt_message",
+      "\n",
+      $auto_message,
+      "\n", $MAGIC, "\n";
 
-    if (!-e $LOG) {
-	open(X, $_ = ">>$LOG") or die "Can't open $_: $!\n";
-	close X;
-    };
+    if (!-e $opt_file) {
+        open(X, $_ = ">>$opt_file") or die "Can't open $_: $!\n";
+        close X;
+    }
 
-    open(IN, $_ = $LOG) or die "Can't open $_: $!\n";
+    open(IN, $_ = $opt_file) or die "Can't open $_: $!\n";
     print $fh <IN>;
     close IN;
 
     if (!$opt_message) {
-	my $stamp = stat($file)->mtime();
-	system($EDITOR, "+5", $file);
-    
-	if ($stamp == stat($file)->mtime()) {
-	    print STDERR "Nothing changed.  Discarding the note.\n";
-	    unlink $file;
-	    exit 0;
-	}
+        my $stamp = stat($file)->mtime();
+        system($EDITOR, "+5", $file);
+
+        if ($stamp == stat($file)->mtime()) {
+            print STDERR "Nothing changed.  Discarding the note.\n";
+            unlink $file;
+            exit 0;
+        }
     }
 
     # Jetzt wie versprochen den (eventuell geänderten Rest) aus der
     # Temp-Datei wegschneiden
     {
-	my ($date, $user, $head, $text, $mailto);
-	my $pos;
+        my ($date, $user, $head, $text, $mailto);
+        my $pos;
+
+        seek $fh, 0, 0;
+        for ($pos = tell $fh ; defined($_ = <$fh>) ; $pos = tell $fh) {
 
-	seek $fh, 0, 0;
-	for($pos = tell $fh; defined($_ = <$fh>); $pos = tell $fh) {
+            $head .= "$_" if not $text and /^\S+:/;
 
-	    $head .= "$_" if not $text and /^\S+:/;
+            /^Date:\s+(.*)/  and $date   = $1, next;
+            /^User:\s+(.*)/  and $user   = $1, next;
+            /^MailTo:\s(.*)/ and $mailto = $1, next;
+            last if $_ eq $MAGIC;
 
-	    /^Date:\s+(.*)/ and $date = $1, next;
-	    /^User:\s+(.*)/ and $user = $1, next;
-	    /^MailTo:\s(.*)/ and $mailto = $1, next;
-	    last if $_ eq $MAGIC;
-
-	    $text .= $_ if /\S/ || $text;   # somit werden die ersten Leerzeilen übersprungen
-	}
+            $text .= $_
+              if /\S/
+                  || $text;   # somit werden die ersten Leerzeilen übersprungen
+        }
 
-	$text  =~ s/\s*$//s; # Leerzeichen am Ende weg
+        $text =~ s/\s*$//s;    # Leerzeichen am Ende weg
 
-	truncate $fh, $pos;
-	seek $fh, 0, 2;
+        truncate $fh, $pos;
+        seek $fh, 0, 2;
 
-	if ($opt_db) {
-	    my $sth = $Dbh->prepare("
+        if ($opt_db) {
+            my $sth = $Dbh->prepare("
 		    INSERT INTO log (host, date, user, mailto, text)
 		    VALUES(?, now(), ?, ?, ?)");
-	    $sth->execute(hostname(), $user, $mailto, $text);
-	    print STDERR "Database entry inserted\n";
-	}
+            $sth->execute(hostname(), $user, $mailto, $text);
+            print STDERR "Database entry inserted\n";
+        }
 
-	if ($opt_mail and $mailto) {
-	    my $mailer = new Mail::Mailer "sendmail"
-		or die "Can't create Mailer: $!\n";
+        if ($opt_mail and $mailto) {
+            my $mailer = new Mail::Mailer "sendmail"
+              or die "Can't create Mailer: $!\n";
 
-	    my $subject = (split /\n/, $text)[0];
-	    $subject =~ s/^\s*\S\s//;	# cut the "itemizer"
-	    $subject = encode_qp("Service [". hostname(). "]: $subject\n");
-	    $subject =~ s/\n(.)/\n\t$1/g;
+            my $subject = (split /\n/, $text)[0];
+            $subject =~ s/^\s*\S\s//;    # cut the "itemizer"
+            $subject = encode_qp("Service [" . hostname() . "]: $subject\n");
+            $subject =~ s/\n(.)/\n\t$1/g;
 
-	    $mailer->open({
-		"Content-Type" => "text/plain; charset=utf-8",
-		"Content-Transfer-Encoding" => "8bit",
-		"To" => $mailto,
-		"Subject" => $subject});
-	    print $mailer $head, "\n", $text;
-	    close $mailer;
-	    print STDERR "Mail sent (to $mailto).\n";
-	}
+            $mailer->open(
+                {
+                    "Content-Type"              => "text/plain; charset=utf-8",
+                    "Content-Transfer-Encoding" => "8bit",
+                    "To"                        => $mailto,
+                    "Subject"                   => $subject
+                }
+            );
+            print $mailer $head, "\n", $text;
+            close $mailer;
+            print STDERR "Mail sent (to $mailto).\n";
+        }
 
-	if (defined @config::notify_dirs) {
-	    foreach my $dir (@config::notify_dirs) {
-		-d $dir or next;
+        if (defined @config::notify_dirs) {
+            foreach my $dir (@config::notify_dirs) {
+                -d $dir or next;
 
-		my $repo = Logbuch::HG->new( repo => $dir );
-		$repo->commit();
-	    }
-	}
+                my $repo = Logbuch::HG->new(repo => $dir);
+                $repo->commit();
+            }
+        }
     }
 
     # Und jetzt das aus der alten Datei dort anhängen
-    open(IN, $_ = $LOG) or die "Can't open $_: $!\n";
+    open(IN, $_ = $opt_file) or die "Can't open $_: $!\n";
     print $fh <IN>;
     close $fh;
     close IN;
 
-    move $file, $LOG;
+    move $file, $opt_file;
 
 }
 
-sub identity()
-{
+sub identity() {
     my $user = `who am i`;
     chomp $user;
     $user .= " [" . ($ENV{IUS_PROFILE} || $ENV{REMOTE_USER} || "-") . "]";
     return $user;
 }
 
-sub hostname()
-{
+sub hostname() {
     my $r = `hostname -f`;
     chomp($r);
     return $r;
 }
 
-sub mailto()
-{
+sub mailto() {
     return join(", ", @config::mailto);
 }
 
-
-sub check_hg_bin()
-{
+sub check_hg_bin() {
     if (not Logbuch::HG::hg_available()) {
 
-	die <<'EOF';
+        die <<'EOF';
 
 You requested an operation based on hg/mercurial but this tool is 
 not installed!
@@ -292,6 +315,5 @@
     }
 }
 
-
 # vim:sts=4 sw=4 aw ai sm: