Customizing Perforce Editor Forms
PROBLEM
How do I customize forms used by Perforce?
SOLUTION
NOTE: As of the 2004.2 release of the Perforce Server, you no longer need to use this workaround. You can, instead, use form-in triggers and form-out triggers to modify the contents of a form prior to edit/display. Look in the Perforce System Administration Guide for more information on triggers.
Every Perforce command which requires user input causes the Perforce Command-Line Client to run the command specified by the environment variable P4EDITOR or, if that is not defined, the environment variable EDITOR. The program specified by P4EDITOR could be a script which does the following:
- runs the command specified by the environment variable EDITOR
- (optional) examines the contents of the form and/or alters the form
Using P4EDITOR makes these two tasks enforceable (set P4EDITOR in everyone's login script) without interfering with individual preferences for editors. However, P4V does not launch an editor to update forms, so this scheme has no effect on P4V users.
If the second task alters the form in such a way as to make it invalid, the Perforce command will not succeed. This error causes the Perforce client to start the editor on the file again, which re-runs the script. It is important, therefore, that the form be altered in a way that is easy to recover from. For example, if the script is verifying a change description entry and determines that the description is inadequate, a good method of causing the fail/re-edit is to print a helpful error message, then modify the "Description:" line to say "*Description: # fix this then delete the *". The user sees the error message and is put back into the editor with a comment indicating where the problem is.
The following is a sample script written in Perl, which you can use to enforce a standard style of change description. As of Release 99.1, this example is not as meaningful, because you can validate submitted changelists more effectively
with pre-submit triggers.
#!/usr/local/bin/perl -w
#!/usr/local/bin/perl -w
#
# This is a sample script to demonstrate a method to customize and/or validate
# forms with Perforce 97.3 and later. This script examines a form after it
# is edited and forces re-entry if it is a change form with a change
# description which does not start with "Simon Says".
#
# As I said, it's a demo.
#
# Set P4EDITOR to the name of this script to have it run every time a user
# edits a form. This is best done by setting the environment variable in
# everyone's login script.
#
# Note: this mechanism can be defeated by resetting P4EDITOR
# or by using the P4Win.
use Carp;
use strict;
# launch the editor
my $formfile = shift;
system("$ENV{EDITOR} $formfile");
# read the form
my %value=read_form("$formfile");
# verify the change description (if it's a change form)
if( defined($value{Change}) && # only a change form has a Change: entry
defined($value{Description}) &&
$value{Description} !~ /^simon says/i ) {
print "You must start your change description with 'Simon Says' - try again.\n";
# change the form so that the p4 change or p4 submit will fail
# but in such a way that the user can easily fix it
open(F,"$formfile");
my @form = ;
@form = map( (/^Description:/
? "*Description: # fix the description then delete the *\n"
: $_) , @form);
open(F,">$formfile"); # now overwrite the form
print F @form;
close(F);
}
sub read_form # read a Perforce style form and return it as a hash
{
my $file = shift;
my (%hash,$current_keyword);
open(F,"<$file") or croak("can't open $file: $!");
while() {
s/\s*#.*$//; # kill comments and any whitespace preceding the comment
if(/^$/) { # empty line or line with just a comment
undef($current_keyword);
} elsif(substr($_,0,1) eq "\t") {
croak("unrecognized line") if(!defined($current_keyword));
s/^\t//;
$hash{$current_keyword} .= $_;
} elsif(/(.*?):\s*(.*)/) { # keyword is everything up to the *first* colon
$hash{$current_keyword=$1} = $2;
}
}
close(F);
return %hash;
}
It should be easy to see how this script could be modified to
present a custom form, or to enforce valid fields on any form
(p4 user, p4 client, and so on). The
read_form subroutine should be generically useful.
