Monthly Scripting Column for January

Greetings! This begins a series of bulletins, in which we introduce one of the scripts that will be in a future release.

Tip: Maybe it was there all along, but you needed the "-Ztag" decoder ring to actually see it?

Today's script

It's easy to sing the praises of shell scripts.

Sometimes, however, you need to store away or parse something for later in the same script. In Perl, with the Perforce API enabled, the parsing is easy.

As an example, we notice that sometimes people want to see the local pathname for their opened files.

  • The simplest option might be to invoke "p4 where" for each file - but the extra calls don't make sense.
  • It's useful to notice that "p4 -Ztag opened" returned many more fields than we're used to seeing. Each of those can be used, and the "clientFile" field is suspiciously close to what we need.

    We introduce "p4opened.p4perl", which is another of a line of simple (and dumb, but helpful) scripts. This variant, below, is an example of P4Perl; the full source code is here and at the end of this page.

    Note for reading any code on this page: Green text is what you'll cut/paste when you make your own P4Perl script.

    Comments should indicate the flow:

    1. Get a list of opened files from 'p4 opened' (with tagged output)
    2. For each of those files, print the clientFile field of the output. (Err, massage it first, mapping "//clientname" to the client root directory.)

    First step: Setting up P4 object

    If you're using P4Perl, which is the Perforce hook for Perl, then you'll need to initialize your Perforce connection:

       use P4;
    
       my $p4 = new P4;
       $p4->ParseForms();
       $p4->Init() or die "Failed to initialize 'p4' object!";
       $p4->Tagged(); 
    

    Note that we copy this block into most of our P4Perl programs. The other calls are handy because they foist the parsing off to someone else:

    1. The 'ParseForms' call make it easy to process any specs (client specs, etc),
    2. and the 'Tagged' call makes it easy to process the 'opened' output.

    Second step: retrieving information from a client spec

    Note how easy certain things are. "Retrieve a client spec" boils down to this:

      my $info = $p4->FetchClient();
    
      $cl_name = $info->{"Client"};
      $cl_root = $info->{"Root"};
    

    If we'd wanted to update it and stash it back into the database, we'd use a call to 'SaveClient'.

      my $info = $p4->FetchClient();
    
      $cl_name = $info->{"Client"};
      $info->{"Root"} = "/tmp/herman";
      print "Setting root of $cl_name to $info->{'Root'}\n";
      $ret = $p4->SaveClient($info);
    

    Third step: getting information about what's opened

    We chose to run:

      @ret = $p4->Opened();
    

    This, in turn, runs "p4 opened".

    From there, it's a matter of writing out the correct field from each filename returned in @ret.


    Reminder: Green text for P4Perl hooks.

    # Task: output list of 'opened' files, using local pathnames.
    
    #
    # status: tested on Win/NT using perl 5.6 with p4perl API
    # num of calls to 'p4': 2
    # room for optimization/improvement: add getopts call
    #
    # Copyright 2004 Perforce Corporation, Inc. All rights reserved.
    
    use P4;
    
    my $p4 = new P4;
    $p4->ParseForms();
    $p4->Init() or die "Failed to initialize 'p4' object!";
    $p4->Tagged();
    
    #-----------------------------------------------------------
    # first call to P4: 'p4 client -o'
    # Note that it's easier to get the client root dir from
    # the 'client spec', hence the "FetchClient" call.
    #-----------------------------------------------------------
    
    my $info = $p4->FetchClient();
    
    $cl_name = $info->{"Client"};
    $cl_root = $info->{"Root"};
    
    #-----------------------------------------------------------
    # second call to P4: 'p4 opened'
    #-----------------------------------------------------------
    @ret = $p4->Opened();
    
    #-----------------------------------------------------------
    # Now, loop through the output of 'p4 opened'. The tagged
    # output gives us a client-syntax version of the name
    # in the form    "//clientName/rest-of-local-path",
    # so we substitute the client root dir before printing.
    #-----------------------------------------------------------
    $oldtag = "//$cl_name";
    foreach $h (@ret) {
        $localFile = $h->{'clientFile'};
    
        $localFile =~  s/$oldtag/$cl_root/;
        print "$localFile\n";
    }
    

    Note: all the programs shown in these columns have been written four times: in Perl, in P4Perl, in Python, and in P4Ruby. Look into the Perforce example database for the other versions. $Id: //guest/jeff_bowles/scripts/0130p4perl.html#1 $
    © 2004 Perforce Corporation, Inc.