#! /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