## 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. |