#! /usr/bin/perl
=comment
Copyright (c) Perforce Software, Inc., 1997-2010. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE
SOFTWARE, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=cut
////////////////////////////////////////////////////////////////////////////////
=comment
Script to illustrate the use of the P4::Map API - i.e., how to convert between
depot and local filesystem paths without making 'fstat' or 'where' do the work.
All the map API needs is info from the client spec: the workspace root and
the view mapping lines.
This example code was written and tested on unix. Null or network-share roots
have not been accommodated. Those cases could be added in the future, given
interest.
P4Perl and its P4::Map documentation are available here:
http://www.perforce.com/perforce/loadsupp.html#api
http://www.perforce.com/perforce/doc.092/manuals/p4script/02_perl.html#1057396
The C++ API's mapping can be referenced here:
http://www.perforce.com/perforce/doc.092/manuals/p4api/03_methods.html#1127217
Or in its source header: p4api_distro/include/p4/mapapi.h
=cut
################################################################################
use strict;
use warnings;
use Data::Dumper;
use P4;
my $p4 = new P4;
$p4->Connect() or die( "Failed to connect to Perforce Server.\n" );
# The 'info' hash is packaged as a one-element array.
my $info = @{ $p4->RunInfo() }[ 0 ];
my $client_name = $$info{ clientName };
my $client_spec = $p4->FetchClient( $client_name );
# See the structure of what is returned.
#print Dumper( $client_spec );
#print join "\n", @{ $$client_spec{ View } };
my $root = $$client_spec{ Root } ;
my @view = @{ $$client_spec{ View } };
# Append a trailing slash if it's not there.
$root .= $root =~ /\/$/ ? "" : "/";
# Make it look like a Perforce path mapping.
$root .= "...";
my $client_path = "//$client_name/...";
my $client_view_map = new P4::Map;
map
{
# Each line in the view comes to us as a single string containing two paths.
# E.g.: "//depot/path/... //client/some/path/..."
#
# Split the string on ' //' to extract the depot and client paths. Two
# slashes in paths are limited to the beginning of each part of the string.
# You get a 'Null directory' error trying to save a client spec that breaks
# that rule.
my( $lhs, $rhs ) = split / (\/\/.*)/, $_;
$client_view_map->Insert( $lhs, $rhs );
} @view;
my $client_root_map = new P4::Map;
$client_root_map->Insert( $client_path, $root );
my $depot_to_local_map = P4::Map::Join( $client_view_map, $client_root_map );
################################################################################
=comment
The path translation is now ready. You can use any test data you want, but here
is some example output to show what is expected.
p4 opened
//builds/nightly/proj-current.tar.bz2
//depot/dev/proj/user/source.pl
//depot/dev/proj/user2/test.pl
//depot/readme.txt
(from 'p4 client -o'):
View:
-//remote/... //user-ws/remote/...
//depot/... //user-ws/depot/...
//depot/dev/proj/user/... //user-ws/proj/...
+//depot/dev/proj/user2/... //user-ws/proj/...
//builds/nightly/... //user-ws/proj/nightly/...
=cut
# Some sample depot paths to convert to their local filesystem representation.
my @depot_paths = ( '//depot/...',
'//depot/readme.txt',
'//builds/...',
'//builds/nightly/...',
'//remote/...',
'//depot/dev/proj/user/...',
'//depot/dev/proj/user2/...',
'//depot/dev/proj/user/source.pl',
'//depot/dev/proj/user2/test.pl',
'//builds/nightly/proj-current.tar.bz2',
'//fake_depot/...'
);
foreach my $depot_path ( @depot_paths )
{
my $local_path = $depot_to_local_map->Translate( $depot_path );
print "'$depot_path' is not mapped.\n\n" and next if ! defined $local_path;
print "depot path: $depot_path\n" .
"local path: $local_path\n" .
"\n" ;
}
$p4->Disconnect();
exit;
=comment
This program's output on the sample mapping/files:
depot path: //depot/...
local path: /path/to/client_root/depot/...
depot path: //depot/readme.txt
local path: /path/to/client_root/depot/readme.txt
'//builds/...' is not mapped.
depot path: //builds/nightly/...
local path: /path/to/client_root/proj/nightly/...
'//remote/...' is not mapped.
depot path: //depot/dev/proj/user/...
local path: /path/to/client_root/proj/...
depot path: //depot/dev/proj/user2/...
local path: /path/to/client_root/proj/...
depot path: //depot/dev/proj/user/source.pl
local path: /path/to/client_root/proj/source.pl
depot path: //depot/dev/proj/user2/test.pl
local path: /path/to/client_root/proj/test.pl
depot path: //builds/nightly/proj-current.tar.bz2
local path: /path/to/client_root/proj/nightly/proj-current.tar.bz2
'//fake_depot/...' is not mapped.
=cut