Perforce P4 .NET API GetFileMetaData() returns NullReferenceException

2.1k Views Asked by At

I ran a P4api.net sample C# code downloaded from P4 to traverse a local P4 /depot repository that I have. When the sample code attempts to read the //depot/subdirA for sub directories and files, the call to API function GetFileMetaData() hits a null pointer exception. This happens when //depot/subdirA has only sub directories with no file in it. If //depot/subdirA has one or more files then GetFileMetaData() works properly. I must be missing something as I assume that GetFileMetaData() should work for directory with or without files existing.

Following is the P4 sample code - please see code comment for exception location:

// if we have the depot path, get a list of the subdirectories from the depot
if (!String.IsNullOrEmpty(depotPath))
{
    IList<string> subdirs = _repository.GetDepotDirs(null, String.Format("{0}/*", depotPath));
    if ((subdirs != null) && (subdirs.Count >0))
    {
        subdirectories = P4DirectoryMap.FromDirsOutput(_repository, Workspace, this, subdirs);
        foreach (P4Directory dir in subdirectories.Values)
        {
            dir.InDepot = true;
        }
    }

    IList<FileMetaData> fileList = _repository.GetFileMetaData(null, FileSpec.DepotSpec(String.Format("{0}/*", depotPath)));
    // get a list of the files in the directory - debugger hit Null Exception within this call.

    if (fileList != null)
    {
        files = P4FileMap.FromFstatOutput(fileList);

        // if the directory contains files from the depot, we can use 
        // the local path of one of those files to determine the local 
        // path for this directory
        if ((String.IsNullOrEmpty(localPath)) && (files != null) && (files.Count > 0))
        {

I downloaded the P4api.net API source code and observed within GetFileMetaData() that the r.TaggedOutput == null when the subject directory contains no file in it, just more sub directories. It could be my misunderstanding of the source code but I would think that the code should check for r.TaggedOutput == null before running the FOR loop thereafter, please see code comment for exception location:

public IList<FileMetaData> GetFileMetaData(Options options, params FileSpec[] filespecs ) 
{
    P4.P4Command fstatCmd = new P4.P4Command(_connection._p4server, "fstat", true, FileSpec.ToStrings(filespecs));
    P4.P4CommandResult r = fstatCmd.Run(options);
    if (r.Success != true)
    {
        P4Exception.Throw(r.ErrorList);
        return null;
    }
    List<FileMetaData> value = new List<FileMetaData>();

    foreach (P4.TaggedObject obj in r.TaggedOutput)
    // Null Exception was caused by r.TaggedOutput=null when the sub dir has no file.
    {
         FileMetaData fmd = new FileMetaData();
         fmd.FromFstatCmdTaggedData(obj);
         value.Add(fmd);
    }
    return value;
}

How do I get around this problem as one can expect a depot directory to have either directories or files or both but GetFileMetaData() seems to expect the dir always have files in it? Is there an option I have to specify for the passed-in "options" param that can prevent this exception? Or is there another API call to check for the existence of files within a directory that code can call before calling GetFileMetaData()? Thank you in advance for your help.

1

There are 1 best solutions below

1
On

This bug was reported and already fixed for the GA release of P4API.NET. I'm not sure when that is being released, but you can call Perforce Support and ask about it.

In the meantime, here's a possible work-around to see if a directory is empty or not.

String[] cmdargs = new String[1];
cmdargs[0] = depotPath + "/*";
P4Command cmd = new P4Command(rep, "files", true, cmdargs);
P4CommandResult results = cmd.Run(null);
if (results != null && results.TaggedOutput != null)
{
    foreach (TaggedObject obj in results.TaggedOutput)
    {
        // do something with file list if you want
    }
}
else
{                        
    Console.WriteLine("No files in this directory!");                        
}

Basically it's using similar logic as GetFileMetaData, but using a lower level command to get tagged output from the server directly. Then you can check the result set for the existence of any files in the directory before you call the other methods.