#! /usr/bin/perl -w
use strict;
=head1 Notices
Originally developed for Perforce by VIZIM (www.vizim.com)
Copyright (c) 2014 Perforce Software, Inc. and VIZIM Worldwide, Inc.
All rights reserved.
Please see LICENSE.txt in top-level folder of this distribution for
license information
=cut
use v5.14.0; # Earliest version testing was performed against
my $APPNAME = 'ctrlPathLength.pl';
my $APPWHAT = 'path length manager; version 2.05';
my $APPNOTICES = "Copyright (c) 2014 Perforce Software, Inc. and VIZIM Worldwide, Inc.
All rights reserved.
See LICENSE.txt for license information.";
=head1 Path length manager
Tool to manage path information within a ctrl file.
Analysis is based on length.
Skip processing is based on path.
=cut
=head2 List mode
With one argument the tool operates in list mode.
The file specified by the argument is scanned for path attribute patterns.
reference, source, and target attributes specify paths.
If the action is IGNORE the path is not scanned.
By default, output identifies the longest path encountered, all paths over
240 characters, and paths involved in case only renames.
The optional length argument can modify this value.
The environment variable TFS_LONGPATH can be used to establish a reporting
length other than 240 characters if the length argument is not specified.
The tool fails if TFS_LONGPATH is less than 10 or more than 255.
=cut
=head2 Skip mode
With two arguments the tool operates in skip mode.
The file specified by the first argument is scanned for path attribute
patterns.
reference, source, and target attributes specify paths.
The file specified by the second argument is the path skip specification.
Output is the content of the first argument with actions referencing skip
paths being changed to LENGTH.
=cut
if( defined $ARGV[0] && ($ARGV[0] =~ m!^\-+V!) ) {
print "$APPWHAT\n";
exit(0);
}
if( ! defined $ARGV[0]
|| $ARGV[0] =~ m!^\-+[h\?]! ) {
print "$APPWHAT
$APPNOTICES
Usage:
$APPNAME -V
$APPNAME [-h|-?]
$APPNAME [-N] ctrl
$APPNAME ctrl skip
N is a numeric value between 10 and 2455 that specifies a reporting
length other than 240. It overrides TFS_LONGPATH if that environment
variable has a value.
One argument is listing mode.
Two arguments is skip mode. Where the skip file contains the TFS
reference or files to skip (regardless of lenght).\n";
exit( 0 );
}
my $longIs = exists $ENV{TFS_LONGPATH} ? $ENV{TFS_LONGPATH} : 240;
if( $longIs < 10 || $longIs > 255 ) {
print "TFS_LONGPATH must be between 10 and 255\n";
exit 1;
}
if( defined $ARGV[0] && $ARGV[0] =~ m!^\-+(\d+)$! ) {
$longIs = $1;
if( $longIs < 10 || $longIs > 255 ) {
print "LENGTH option must be between 10 and 255\n";
exit 1;
}
shift @ARGV;
}
if( ! -e $ARGV[0] ) {
print "ctrl file does not exist - $ARGV[0]\n";
exit( 1 );
}
my $hIn = undef;
open $hIn, '<', $ARGV[0] or die "Can't open $ARGV[0] - $!";
my $modeSkip = exists $ARGV[1];
if( $modeSkip && ! -e $ARGV[1] ) {
print "Skip file does not exist - $ARGV[1]\n";
exit( 1 );
}
=head3 Skip file format
Each line within the skip file is processed individually.
Blank lines, lines that contain only space characters, and lines
that have # as the first non-blank character are ignored as comments.
All other lines are expected to follow the pattern:
info\tskip
where info is any random text that doesn't contain the tab character,
\t is the tab character, and skip is the path to skip.
The info can be used by skip file generation tools to insert potentially
useful.
=cut
my %skipPaths = ();
if( $modeSkip ) {
my $hSkip = undef;
open $hSkip, '<', $ARGV[1] or die "Can't open $ARGV[1] - $!";
while(<$hSkip>) {
chomp;
next if m!^\s*$!;
next if m!^\s*\#!;
my ($info, $skip) = (undef, undef);
($info, $skip) = split "\t";
if( ! defined $info ) {
print "Don't understand mapping - $_\n";
close $hSkip;
exit( 1 );
}
$skipPaths{$skip} = $info;
}
close $hSkip;
}
my $longestPath = 0;
my %longPaths = ();
my $seq = 0;
while (<$hIn>) {
my ($before, $action, $after) = ('', '', '');
($before, $action, $after) = ($1, $2, $3)
if m!^(.+ action\=\")([^\"]+)(\".*)$!;
if( $action eq '' || $action eq 'IGNORE' || $action eq 'LENGTH' ) {
print $_
if $modeSkip;
next;
}
my $actionWas = $action;
foreach my $attrib (qw/reference source target/) {
my $path = '';
$path = $1
if m! $attrib\=\"([^\"]+)\"!;
if( $path ne '' ) {
$path =~ s!\;[XC]\d+$!!;
if( $modeSkip ) {
$action = 'LENGTH'
if exists $skipPaths{$path};
} else {
my $length = length $path;
$longestPath = $length
if $length > $longestPath;
$longPaths{$path} = $length
if $length >= $longIs;
}
}
}
if( $modeSkip && $action eq 'LENGTH' ) {
print $before, "$action\" actionwas\=\"$actionWas", $after, "\n";
} elsif( $modeSkip ) {
print $_;
}
}
if( ! $modeSkip ) {
print "Longest path: $longestPath\n";
print "\n\nPaths with $longIs or more characters:\n";
foreach my $path (sort keys %longPaths) {
print sprintf "%3d %s\n", $longPaths{$path}, $path;
}
print " - none -\n"
if scalar keys %longPaths == 0;
}