FAQ for integrating Perforce with your build scripts

Contributed by Jeff Bowles

Note - the intended audience for this FAQ is a shell/perl hacker who writes or maintains local build scripts and wants to integrate Perforce into them.

    Labels
  1. How do I create a label? What should I include in a label?
  2. If I want to create a new label for each overnight build, how would I do it?
  3. Should I use labels or change numbers to track the contents of overnight builds?
  4. So the release needs to be remade three months after it went out. What do I do?
  5. I like this overnight build and want to officially designate it as a "release" build. What should I do?
  6. I need to create a release build - what's different in that process?
  7. Clients
  8. How do I populate the build area from a nightly build script? What are the problems that will come up?
  9.  Updating depot files from a script
  10. How do I update the depot to include a new log, or to include a new line in a logfile?
  11. Should l check in my log files? What files might need to be modified and checked in as part of a build?
  12. Putting a release out
  13. What should I back up when I put a release out?
  14. How do I make an "escrow" copy of the files (that built the release) for the off-site vaults?

  1. How do I create a build label? What should I include in a label?
    • Pick a regular format for the label name, e.g. "bld_xxx_1" where 'xxx' is the name of the codeline you're building and '1' is just a counter, i.e. the first such label. Remember this format - you'll need it in the next question!
    • Make the label itself:
    •     p4 label bld_xxx_1

      It'll dump you into an editor, and you can change the default "Views:" lines from

          //depot/...

      to look solely at the codeline you want, e.g.

          //depot/xxx/...

      Save/Quit the editor.

    • Populate the label with the file/revision list you want:
    •     p4 labelsync -l bld_xxx_1  //depot/xxx/...

      or

          p4 labelsync -l bld_xxx_1 //depot/...

      In this second example, it's okay to include all files in the depot - it'll really only include files described in the label spec you edited when you ran "p4 label".
       

    • Always include all files [that are under source management] that are needed to recreate the build . If your build scripts aren't in codeline "xxx" you'll want to have the label specification include the directory where they are, and "p4 labelsync" needs to include them.

  2. If I want to create a new label for each overnight build, how would I do it?

  3.  
    1. Make sure you're using a regular name for the label, e.g. "bld_xxx_yyy" where "xxx" is the codeline name and "yyy" is a counter.
    2. Create the first label in the sequence, which would be "bld_xxx_1". See the previous question for that.
    3. In the Unix shell, you would do the following (cut and paste):
    4.    CodeLineName=xxx
         LabelSpec=tst_${CodeLineName}_
         toplabelnumber=`p4 labels | grep $LabelSpec | sed "s/^Label $LabelSpec//" | \
              sed "s/ .*//" | sort -r -n | head -1`
         # at this point, we know the most recent label in this codeline and just need
         # to create a new label and populate it.
         TopLabel=$LabelSpec$toplabelnumber
         echo Current Label is $LabelSpec$toplabelnumber
         if [ "$toplabelnumber" != "" ]
         then
              newlabelnumber=`expr $toplabelnumber + 1`
              NewLabel=$LabelSpec$newlabelnumber
              echo "New Label is $NewLabel"
       
              # the following two commands are from the previous FAQ item.
              p4 label -o -t $TopLabel $NewLabel | p4 label -i
              p4 labelsync -l $NewLabel //depot/...
              # It's best to obsolete labels that are kinda of old, so we
              # do it here.
              if [ "$toplabelnumber" -gt 10 ]
              then
                      obsoletelabelnumber=`expr $toplabelnumber - 10`
                      ObsoleteLabel=$LabelSpec$obsoletelabelnumber
                      p4 label -d $ObsoleteLabel
              fi
         else
              echo "There was no label to match!" 1>&2
              exit 1
         fi
       

    5. Perl hackers will look at the previous "Bourne shell" example and use it as an example of why you don't want to do string processing in "Bourne shell". One perl treatment of this follows: 
    6.    $CodeLineName = "xxx";
         $LabelSpec="tst_" . $CodeLineName . "_";

         @AllLabels = `p4 labels`;
         @ThisCodeLineLabels = sort(sortrevlabel grep(/$LabelSpec/, @AllLabels));
         $TopLabelLine = $ThisCodeLineLabels[0];
         $TopLabel = $1 if ($TopLabelLine =~ /^Label\s(\S+)\s/);
         $TopLabelNumber = $1 if ($TopLabel =~ /^\S+_(\d+)$/);

         print "The last label in this codeline is $TopLabel\n";
         $NewLabelNumber = $TopLabelNumber + 1;
         $NewLabel = "$LabelSpec$NewLabelNumber";
         print "New Label is $NewLabel\n";
         system("p4 label -o -t $TopLabel $NewLabel | p4 label -i");   # in real life, return code would be checked!
         system("p4 labelsync -l $NewLabel //depot/...");
         if ($TopLabelNumber > 10 )
         {
              $ObsoleteLabelNumber = $TopLabelNumber - 10;
              $ObsoleteLabel = "$LabelSpec$ObsoleteLabelNumber";
              system("p4 label -d $ObsoleteLabel");
         }

         sub sortrevlabel {
              my($labelnum_a, $labelnum_b) = ();
              $labelnum_a = $1 if ($a =~ /.*_(\d+)/);
              $labelnum_b = $1 if ($b =~ /.*_(\d+)/);
              return ($labelnum_b <=> $labelnum_a);
              }

    7. The underlined part in the above fragments probably should have a "sed" command between the two 'p4 label' commands, to change the description for each label.

  4. Should I use labels or change numbers to track the contents of overnight builds?

  5.  
    • There's no right answer. The command
    •     p4 changes -m1 //depot/xxx/...

      will tell a build script what the top change number for codeline 'xxx' (assuming it's mapped there), so it can parse this output and use that in build logs and build e-mail. The developer would type:

         p4 sync @12345

      to pull over all files current as of change #12345, but that has a problem: it'll pull over all files [that his/her client maps in] as of that revision, not just the files for codeline 'xxx'. You can tell them to type:

         p4 sync //depot/xxx/...@12345

      but, by then, you've lost the simplicity that using the change numbers might've given you.
       

    • You should probably always use labels for release builds - when you create a release you'll often need to include an additional change to one particular file that you need to track, and you want the label to include exactly the files used to build the release on the build client.

  6. So the release needs to be remade three months after it went out. What do I do?
  7. You'll need a slightly-hacked version of your "get the source and do a build" script. The hacks are:
    • It shouldn't use or touch any labels except for the release label you've remembered to create when you made the release. Delete the lines in the script that create labels or run "p4 labelsync" on them.
    • Change the line in the script that does the "p4 sync -f  ...#have" so that it looks like:
    •    p4 sync -f  //depot/xxx/...@labelname

      where "xxx" is the name of the codeline, and "labelname" is the release label.

    • Bug your system administrators about whether compiler versions, OS releases, etc, have changed since the release was created. Listen carefully to their answers.
    • Run the script. It should create the original release faithfully, although most compilers embed timestamps within the .exe and .obj files, so you might not have byte-for-byte identical files.
    • Rerun your regressions to gain confidence in the newly-built product.

  8. I like this overnight build and want to officially designate it as a "release" build. What should I do?
  9. See the previous step - you just need to run "p4 label" (to create a label) and then "p4 labelsync" to the overnight label or change number that created the build:

       p4 labelsync -l release_label_name  //depot/xxx/...@bld_xxx_23

    or

       p4 labelsync -l release_label_name  //depot/xxx/...@12345

    The first case is for "overnight build #23 for codeline xxx", if you're using that convention for overnight builds; the second case is if you use change numbers to track the overnight build contents.
     


  10. I need to create a release build - what's different in that process?

  11.  
    This depends on what packages the release for deployment. If you use the same build mechanisms for overnight and release builds, you should only need to do a few steps:
    • Run the overnight build script to create the build.
    • Label the build area that created the release, using "p4 label" and then "p4 labelsync". Pick the 'view' for the label carefully, so that it doesn't include parts of the depot not included in this release.
    • Run "p4 label" a second time on the new label, and change the status of the label to "locked" so that "p4 labelsync" cannot be run against it accidently.
     

  12. How do I populate the build area for an overnight build? What are the problems that will come up?

  13.  
    • If the Perforce client root is C:/p4root, and the codeline is C:/p4root/xxx, then you'll need to do 2-3 things to populate the area prior to building:
      • Make a copy of the scripts that'll do the populating, if there's a chance that you'll delete them in the next two steps! (Leave a place for your scripts to stand.)
      • Run the OS command to delete the codeline directory, e.g.
      •    del/s   c:\p4root\xxx

        it's important to do this if you want a clean build - don't rely on incremental compile for overnight compiles unless the compilation process takes many hours.

      • Repopulate the source:
      •    p4  sync  -f   C:/p4root/xxx/...#have

      • Update the source to the most recent revisions:
      •    p4  sync  C:/p4root/xxx/...

      • Update your build labels (or remember the current change numbers) to reflect this new content.
      Deleting the entire codeline build tree (and any "obj" or "lib" directories if they're not directly under C:\p4root\xxx) is important because old object files often can bite you.
       
    • Most problems that come up in this area have to do with obsolete object/library files. Entirely removing the source area and repopulating saves you from this headache completely.

  14. How do I update the depot to include a new log, or to include a new line in a logfile?

  15.  
    • To include a new log or edit a file, you should:
      • Open the file for either "add" or "edit";
      • Modify the file in whatever ways make sense;
      • Use "p4 change -o" and "p4 submit -i" to create the submitted change.
      An example of this, in a Unix shell script, follows:

         operation=add
         filename=newfile.txt
         filetype=ltext
         [ -f $filename ] && operation=edit
         description="log of build for `date`"

         p4 $operation -t $filetype $filename

         echo New information as of `date` >> $filename
         # this point, we need to construct the change submission with
         # an accurate description in the change text.
         p4 change -o  > xx.tmp
         (
              echo "/^Files:/+1,\$v/$filename/d"
              echo "/<enter description here>/s/.*/    $description/"
              echo w
              echo q
         ) | ed - xx.tmp
         p4 submit -i < xx.tmp
         rm xxx.tmp

      Perl hackers won't see substantial gains by doing this in perl, and the 'ed' is actually easier from the shell script.
       

    • The underlined part above is important, if the file you're working with is a giant log file, because giant text files should include this hint so that the files will be stored in more efficient ways.

  16. Should l check in my log files? What files might need to be modified and checked in as part of a build?

  17.  
    • There's no good answer for this - log files are usually huge, and can start eating space quickly. It's probably best to keep them in a disk area that's backed up regularly, but not to check them in if you can avoid it.
    • If, however, you track overnight builds based on change numbers instead of labels, you might want to have a file somewhere in the depot that contains one-line entries of the form:

    •    change 12345 - overnight build for 07/22/98
         change 12366 - overnight build for 07/23/98
      and so on. That should be modified (appended to) by the build scripts using code similar to the example above. It gets really hard to track which change corresponded to which nightly build, otherwise.
       

  18. What should I back up when I put a release out?

  19.  
    • As a minimum, you'll need to back up the source files and build scripts in Perforce that created the product. This makes several assumptions: Usually, however, you'll probably just want to back up the entire Perforce depot so that you have a complete snapshot of everything, and then if you restore from this backup you can refer to current labels such as the product release label you made when you released the product. (You can also refer to intermediate build labels if you choose, since they'll be included in the backup.) The second and third steps are slight overkill for many situations, but if you wanna be incredibly paranoid, that's the approach to take.
    • That the build environment (machine, OS, compilers, etc) are easily recreateable from media you have in-hand;
    • That, if you only back up the top revision of those files, you won't need file revision history and the like.
    • To make the most comprehensive backup, you'll need to do the following:
    • Checkpoint the Perforce database and save the checkpoint and the subdirectory $P4ROOT/depot with all its contents:
    •    cd $P4ROOT
         p4d   -r   .   -jc

      Note that this is documented in the "FAQ for System Administrators" and also on-line in the Perforce manuals.

    • Save a copy of the Perforce executables you're using, server and client versions.
    • Do a full system backup of the build machine on which the product was created. This isn't so much to get the source onto media as to get compilers, OS, etc.
    • Put this all onto a medium you trust, that'll be around for a while.
    • Write the product release label, the one that you created when you built the product, on the media case. Include with the case a hard-copy printout of the exact commands you typed to create the media, e.g. created using "tar rvf".
     
  20. How do I make an "escrow" copy of the files (that built the release) for the off-site vaults?

  21.  
    You can use a label to create an initial fileset that you'll archive. It's pretty easy:
    • Create a label using p4 label, escrowlabelname1.0, that maps in only the directories you want. (You'll edit the label specification to either include as many directories as you choose, or perhaps the exact file list itself.)
    • Populate the label, using:
    •         p4 labelsync -l  escrowlabelname1.0   //buildclientname/...#have

      or,

              p4 labelsync -l   escrowlabelname1.0   @release_source_label

      The first example relies on the build client having the exact files, at this moment, that it did when it created the build; the second example relies on having a label of all the source files that were built to create the release.

    • Create a new Perforce client that maps its client area to an empty part of the disk, and on that new client run the command:

    •         p4 sync  @escrowlabelname1.0
    • Back up this new area.
    • Run p4 label escrowlabel1.0  and mark the label "locked". This will prevent accidently updates of that label.
    • When release 2.0 goes out and you need to do this again, follow the same steps. When you create the label, however, use the original (release 1.0) escrowlabel as a template, using  p4  label -t escrowlabel1.0  escrowlabel2.0 .