14
Feb
2005

basic perl file handling

Here is the basic perl program which does the same as the UNIX
cat command on a certain file.

#!/usr/local/bin/perl
#
# Program to open the password file, read it in,
# print it, and close it again.

$file = '/etc/passwd';		# Name the file
open(INFO, $file);		# Open the file
@lines = <INFO>;		# Read it into an array
close(INFO);			# Close the file
print @lines;			# Print the array

The open function opens a file for input (i.e. for
reading). The first parameter is the filehandle which allows Perl
to refer to the file in future. The second parameter is an expression
denoting the filename. If the filename was given in quotes then it is taken
literally without shell expansion. So the expression
'~/notes/todolist' will not be interpreted successfully. If
you want to force shell expansion then use angled brackets: that is, use

<~/notes/todolist> instead.

The close function tells Perl to finish with that file.

There are a few useful points to add to this discussion on filehandling.
First, the open statement can also specify a file for output
and for appending as well as for input. To do this, prefix the filename
with a > for output and a >> for
appending:

open(INFO, $file);	# Open for input
open(INFO, ">$file");	# Open for output
open(INFO, ">>$file");	# Open for appending
open(INFO, "<$file");	# Also open for input

Second, if you want to print something to a file you've already
opened for output then you can use the print statement with an
extra parameter. To print a string to the file with the INFO filehandle use

print INFO "This line goes to the file.\n";

Third, you can use the following to open
the standard input (usually the keyboard) and standard output
(usually the screen) respectively:

open(INFO, '-');	# Open standard input
open(INFO, '>-');	# Open standard output
In the above
program the information is read from a file. The
file is the INFO file and to read from it Perl uses angled brackets.
So the statement
@lines = <INFO>;
reads the file denoted by the filehandle into the array @lines. Note that
the <INFO> expression reads in the file entirely in one go. This
because the reading takes place in the context of an array variable. If
@lines is replaced by the scalar $lines then only the next one line would
be read in. In either case each line is stored complete with its newline
character at the end.


original link

CVS: Using loginfo to send mail with diffs on Win32/CVSNT

Like presumably so many other CVS administrators, I was faced with the task of making my CVS server send mail every time somebody commits something. The additional spice in the soup was the platform, Win32. Just sending the CVS log message and the files modified is trivial, but it all gets a bit more complicated when you want to include a unidiff of the changes.

In this article, I will present some of the problems involved and a Perl-based solution. If you wish to understand the specifics, some basic knowledge of Perl is necessary. If you just want to get the source, it is available for download - but please note that the code is not luxuriously documented! Much of your ability to understand the implementation (and modify its behaviour) probably depends on reading and understanding this text. You will also probably at least need the Installation Instructions.

The solution I present here is designed to work on Win32 servers with ActiveState">http://www.activestate.com/Products/ASPN_Perl/">ActiveState ActivePerl and CVSNT. It is probably fairly easy to make this use another Perl distribution or the standard-class CVS server, but you don't want to try to port this to another OS. If you're running on unix, there are solutions available for you already.

A quick revision: How does loginfo work?

Each time a commit is made, CVS searches through an administrative file called loginfo. It is a text file whose each line contains a regexp and a command line, separated by a space. The lines are searched in order, and the regexp matching the directory being handled is executed. The special regexp "ALL" is always executed, and the command line with regexp "DEFAULT" when no other expression matches.

The command line is executed, and the log message (the stuff that usually pops up in a editor when committing) is piped to the executing process' stdin. Information to the logging task can also be transmitted through command-line parameters. There are two different approaches to this, actually.

First, CVS has several variables which are prefixed by $ - a list of them is available. Second, a special format string can be used as a parameter. For example, a format string of %{sVv} produces a string that contains file names (s), old revisions (V) and new revisions (v) for the changes. Missing revisions are marked as NONE. Information about each file is separated by commas, file specifications are separated by spaces. The first file specification is always the directory being accessed relative to the cvsroot. So, for example the string myproject/code a.c,1.4,1.5 b.c,NONE,1.1 c.c,1.8,NONE means that in directory myproject/code, the file a.c is updated from revision 1.4 to 1.5, file b.c is created (its old revision being NONE) and file c.c is deleted (its new revision is NONE).

So what are the problems?

It's fairly trivial to create a program that reads from stdin, parses some parameters and outputs the stuff into a log file or even sends the mail. However, it gets way more complicated when you want the diffs in. The problem starts with the fact that you don't get the diff information piped from cvs (like you get the log message) or through parameters (like you get the file modification list). Therefore, you will have to run cvs diff to get the diff and then attach it to your mail.

Running diff isn't problematic, but the cvs locking scheme is. If you run diff directly from the task you spawned off using loginfo, it will note that "oops, the repository is locked because of a commit, I'd better wait". Yes, you guessed right - it's the commit process that we're supposed to mail about right now! So, we end up locking the cvs task forever, since the commit won't certainly finish until the loginfo process is done, and it won't be done until the commit lock preventing diffing has vanished...

So let's just fork?

For those of you who don't know what fork means, it's a unixish concept of creating a nigh-exact duplicate of the current running process, which can then run totally separately from its parent. So effectively, the execution of the code forks, hence the name.

This is where the multitasking model of unix-based systems is cool. Most scripts running on unix simply fork, so that the original task can exit and let the child do the job. That's nice, but since the multitasking model of Windows is based on threads rather than forks, we're out of luck.

ActiveState Perl emulates fork, but as of version 5.6.1, the emulation is based on threaded implementation of the interpreter. Essentially, that means that the Perl script is run just fine, but in the same process context as the original parent. The process that contains both the threads terminates when both of the forks have called exit(). Thus, the parent doesn't exit and the commit lock is never released. So, forking doesn't help us here - at least until ActiveState implements a split-process fork() model.

But the problem can be solved, it's just ugly...

So essentially what you need to do is get the stuff running in two processes instead of two threads. Doing this is relatively easy, but doesn't look good. In this example, we do it by having two Perl scripts: the other is mail.pl which is called from loginfo, and the other is mailbe.pl (where be stands for backend), which is in turn called by mail.pl.

Mail.pl calls mailbe.pl by running the command interpreter, with a command line of "start perl somepathhere\mailbe.pl parameters". This makes Windows start a new process, a Perl interpreter, which then runs the backend. Since the backend is a separate process, it's free to do whatever it wishes with cvs - if it can't make diffs because of a lock in the repository, it will wait. The important thing here is that waiting will not permanently block the execution of anything else - mail.pl exited already, and thus the cvs commit process continues.

mailbe.pl contains a "sleep 5" to wait for five seconds before doing anything. This is not strictly necessary, but it's an optimization. If we don't add it, it almost always bumps to a lock when trying to do the diff, since the cvs commit hasn't finished yet. It would work even without the delay, but then cvs would end up in the "Waiting for somebody's lock on ..." loop, and then it takes at least 15 seconds before it tries again.

There is one more issue here. When mail.pl spawns the new backend task, the content waiting in stdin is not conveyed (if we did a fork(), it would - but this is not possible as already stated). Thus, mail.pl writes out the data in stdin to a temporary files and passes its name as a parameter to mailbe.pl, which then in turn reads the file, processes it and finally deletes the temporary file. Ugly, but it works.

Call syntax and installation

I warmly recommend that you put the perl files into your CVSROOT directory and add their names into the checkoutlist file. Also, you should have perl.exe in your path and .pl files associated to it. You can do otherwise, but these instructions are based on these presumptions. Improvise if necessary.

mail.pl takes three parameters: the CVS loginfo string with the format specifier %{sVv}, the name of the user committing the changes (whatever you want to show up in the mail) and the address the message should be sent to. mailbe.pl takes the name of the file containing the CVS log information (see above) followed by all the params mail.pl takes. Examine mail.pl to understand this better.

Basically, you can just add the following line to your loginfo file:

DEFAULT perl d:\cvsnt\repository\cvsroot\mail.pl %{sVv} $USER cvsnotifications@mydomain.com

But before you commit, edit mailbe.pl, particularly the end of it. The version downloadable from this page uses a Perl module called NTsendmail. I recommend you use it. That way you can only change your mail server address and the from name near the end of the Perl script and off you go. If you want to use another mailing system, replace the NTsendmail specific part of mailbe.pl with your own implementation.



original link


NTsendmail

NTsendmail is Highly Acclaimed UNIX Sendmail replacement for NT. NTsendmail is realeased under the GNU Public License. NTsendmail was designed to enable script writers to use their UNIX CGIs on Windows 95/98/NT/2000. NTsendmail also works on UNIX/Linux.

Current Version: 2.0.24.

PROBLEM: You have a UNIX CGI written in Perl whose method for sending mail is to open a pipe to sendmail and feed it a mail message.

E.g.:
#! /usr/bin/perl -w
$|=1;
$sendmail = "/usr/lib/sendmail";
open (MAIL, "| $sendmail -t -f \'tester\@1testdomain.com\'") || die ("Opening pipe failed."); 
print MAIL "From: tester\@1testdomain.com\r\n";
print MAIL "To: tester\@1testdomain.com\r\n";
print MAIL "Subject: Message from NTsendmail\r\n";
print MAIL "Hi there. This script sure works great on UNIX, doesn't it?\r\n";
close (MAIL);
exit 0;
You soon realize that NT doesn't have sendmail, or any other means of sending mail from a Perl script, unless you have installed an expensive third party sendmail emulator, and even then your scripts are likely to fail due to complex configuration problems.

SOLUTION:
# Install NTsendmail.pm, the NTsendmail object module in your perl libraries directory. Typically "c:\\perl\lib\."
# Modify your scripts to work with NTsendmail. NTsendmail syntax is as follows:
$ENV{"NTsendmail"} = "your.mail.server";
$mail = new NTsendmail;
$mail->send($sender, $recipient, $subject, $message);
SECURITY, CONFORMITY: NTsendmail calls the local mailserver, or another mailserver which accepts mail from your machine. This is done to guarantee that all mail handling, caching, etc. is done according to the same rules as all your other mail. NTsendmail is tested with UNIX sendmail. Other mail servers might or might not work.

This method of specifying a mailserver also allows you to run Perl CGIs on a server without a mailserver, using another machine's mailserver instead. By utilizing a mailserver behind a firewall, this feature can be used to complement your company's security policies for mail.

NTsendmail is a true plug and play solution, instead of requiring complex configurations of its own.

You plug it in and use it. That's all there is to it.

REQUIREMENTS: You must have Perl installed on your NT system. (Tested on Perl 5. Perl 4 might work.) Requires the Socket module to be installed (standard with most Perl installations).

GETTING NTSENDMAIL: NTsendmail is copyright 1997-2002 Troy Korjuslommi.

NTsendmail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License.

The username and password to download NTsendmail are "GNU" "license". Please visit the downloads page to download it.

SUPPORT:
The NTsendmail Help Page contains some more info. Please always check there first.

Tksoft, OY, Inc. is Linux consulting company. We sell support contracts for Linux. We do not plan to offer NT support, even for NTsendmail.

Our staff members answer questions in their spare time so please be considerate.

SUPPORTED MAIL SERVERS:
NTsendmail requires a mail server to exist somewhere on the network. Please let us know about the email server which you use, and whether or not NTsendmail works for you. If you are the first to report a server, we will list you here, along with your company's URL.

(List started: Thu Sep 9 11:09:22 PDT 1999)

original link
logo

vireas

Suche

 

Aktuelle Beiträge

C i s c o  V...
can get always the latest version of C i s c o  V...
vireas - 12. Jul, 11:07
WM5: Custom text on today...
You can set a small custom text message on the bottom...
vireas - 15. Mai, 21:44
WM5: Increase Performance...
Boost Windows Mobile 5 performance up to 20 percent [HKLM\System\Stor ageManager\FATFS]...
vireas - 15. Mai, 21:42
WM5: Speed Up your Pocket...
This tweak might help improving visual performance...
vireas - 15. Mai, 21:41
Windows Ordner
-Es ist nicht möglich unter Windows einen Ordner anzulegen...
vireas - 22. Feb, 13:37

Archiv

Februar 2005
Mo
Di
Mi
Do
Fr
Sa
So
 
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10
12
15
18
19
20
21
22
23
24
25
26
27
28
 
 
 
 
 
 
 

Status

Online seit 7702 Tagen
Zuletzt aktualisiert: 12. Jul, 11:07
vireas-plug

KnowHow
KnowHow - Mobiles
Tools
Profil
Abmelden
Weblog abonnieren