## Set up your connection info here or the trigger won't work!
$p4 = 'p4 -p PORT -u USER -P PASSWD';
##
# ALL WARRANTIES ARE HEREBY DISCLAIMED.
#
# Triggers:
# protexpOut form-out protect "perl protexp.pl out %formfile%"
# protexpIn form-in protect "perl protexp.pl in %formfile%"
#
# When this trigger is in place, you can use the variable $user
# in your protection table and have it expanded to multiple lines
# with the variable replaced with each of your Perforce users in
# each expanded line. To limit this to users in a particular
# group, use $user(group).
#
# For example:
# write user $user(bobs) * //dev/$user(bobs)/...
# becomes:
# write user bobA * //dev/bobA/...
# write user bobB * //dev/bobB/...
# write user bobC * //dev/bobC/...
# if you have a group "bobs" that contains bobA, bobB, and bobC.
#
# The $dirs variable can be used to expand lists of directories.
# For example:
# write group * $dirs(//depot/*)/bin/...
# becomes:
# write group * //depot/main/bin/...
# write group * //depot/r011/bin/...
# write group * //depot/r012/bin/...
# This can serve as a replacement for double wildcards.
#
# Before your protections are saved, the "in" trigger will perform
# this expansion and save a hex-encoded "comment" in the spec with
# the line you originally entered. When you retrieve the table,
# the "out" trigger will collapse the expanded lines back into their
# original form so that it looks like it did when you edited it last.
#
# Since the triggers only fire when the form is edited, the actual
# protections will NOT automatically update when new users or groups
# are added. To refresh the protections, you can simply do:
# p4 protect -o | p4 protect -i
# since re-saving the protections will redo the expansion.
#
# To temporarily disable the trigger, you can pass "none" instead of
# "out" or "in". This might be useful if you want to confirm that
# the table generated by the "in" trigger is correct, since the "out"
# trigger will normally hide the "in" trigger's output from you.
if ( $ARGV[0] eq "in" ) { in ( $ARGV[1] ); }
elsif ( $ARGV[0] eq "out" ) { out( $ARGV[1] ); }
elsif ( $ARGV[0] eq "none") { exit 0; }
else { print "bad trigger usage!"; }
sub in
{
my ( $formfile ) = @_;
my @result;
open FILE, $formfile or die "couldn't open file: $!";
while ( <FILE> )
{
my $line, $group, @users;
if ( !/\$user/ && !/\$dirs/ )
{
push @result, $_;
next;
}
$line = $_;
chomp;
$_ = ascii_to_hex( $_ );
push @result, "\tlist group _ * //---$_---\n";
$_ = $line;
if ( /\$user/ )
{
$group = "";
if ( /\$user\((\S+)\)/ )
{
$group = $1;
s/\$user\(\S+\)/\$user/g;
}
$line = $_;
if ( $group ) { @users = users_in_group( $group ); }
else { @users = users(); }
foreach( @users )
{
$out = $line;
$out =~ s/\$user/$_/g;
push @result, $out;
}
}
if ( /\$dirs\((\S+)\)/ )
{
@dirs = `$p4 dirs \"$1\"`;
s/\$dirs\(\S+\)/\$dirs/g;
$line = $_;
foreach( @dirs )
{
chomp;
$out = $line;
$out =~ s/\$dirs/$_/g;
push @result, $out;
}
}
push @result, "\tlist group _ * //------\n";
}
close FILE;
open FILE, '>', $formfile or die "couldn't open file: $!";
foreach( @result )
{
print FILE $_;
}
close FILE;
}
sub out
{
my ( $formfile ) = @_;
my @result;
open FILE, $formfile or die "couldn't open file: $!";
my $skip = 0;
while ( <FILE> )
{
if ( !/\tlist group _ \* \/\/---/ )
{
if ( !$skip ) { push @result, $_; }
next;
}
if ( $skip )
{
$skip = 0;
next;
}
if ( !/\tlist group _ \* \/\/---(.+)---/ ) { next; }
push @result, hex_to_ascii( $1 )."\n";
$skip = 1;
}
close FILE;
open FILE, '>', $formfile or die "couldn't open file: $!";
foreach( @result )
{
print FILE $_;
}
close FILE;
}
sub users
{
my @users = ();
my @lines = `$p4 users`;
foreach( @lines )
{
s/\s.*//;
chomp;
push @users, $_;
}
return @users;
}
sub users_in_group
{
my @done, @lines, @todo, @users, $group;
@todo = @_;
while ( @todo )
{
$group = pop @todo;
if ( grep( $_ eq $group, @done ) ) { next; }
push @done, $group;
@lines = `$p4 -Ztag group -o $group`;
foreach( @lines )
{
if ( /\.\.\. Subgroups\d+ (\S+)/ )
{ push @todo, $1; }
if ( /\.\.\. Users\d+ (\S+)/ && !grep( $_ eq $1, @users ) )
{ push @users, $1; }
}
}
return sort @users;
}
sub ascii_to_hex
{
(my $str = shift) =~ s/(.|\n)/sprintf("%02lx", ord $1)/eg;
return $str;
}
sub hex_to_ascii
{
(my $str = shift) =~ s/([a-fA-F0-9]{2})/chr(hex $1)/eg;
return $str;
}
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #5 | 7389 | Sam Stafford | Quote the "p4 dirs" argument just in case it has spaces. | ||
| #4 | 7386 | Sam Stafford |
Add $dirs variable to protexp.pl trigger. This is to reduce multiple wildcard usage in protections tables; a line like: write group * //depot/*/bin/... can be rewritten as: write group * $dirs(//depot/*)/bin/... and expanded by the trigger to: write group * //depot/A/bin/... write group * //depot/B/bin/... write group * //depot/C/bin/... |
||
| #3 | 7342 | Sam Stafford |
A little bit of rearranging to open the possibility of adding new variables to expand. No functional change. |
||
| #2 | 7290 | Sam Stafford | Fix typo in comments. | ||
| #1 | 7289 | Sam Stafford |
Inspired by a thread on perforce-user the other day, here is a trigger that enables variable expansion in the protection table. If we were to install this in the Public Depot and it worked correctly, we could replace about 95% of our (user-visible) protection table with the single line: write user $user(registered) * //guest/$user/... In my limited testing so far it seems to work pretty nicely, but I wouldn't put it in production just yet. |