Third Shelf

CopyDirectoryDifferences Build Task

Posted in team foundation server by Sydney du Plooy on September 1, 2008

In my attempt to optimize our build script work, I found myself needing to copy a list of files from one directory to another without overwriting existing files in the destination directory.

Scenario:

We need to gather code coverage information using multiple test containers (assemblies with unit tests inside them). This results in instrumenting all the assemblies that the test container depends on. This happens before the execution of unit tests in each test container.

Solution:

Use the MSBuild copy task to copy all the files from the source directory to the destination directory without overwriting the files that already exists in the destination directory. Simple enough, eh? Except, there is no support for this scenario to be found in the Copy Task that ships with MSBuild by default.

We are left no choice but to roll our own. Here is a code listing of the task that I wrote to do precisely that:

/// <summary>
/// Copies files from a source directory to a destination directory that
/// do not exist in the destination directory.
/// </summary>
public class CopyDirectoryDifference : Task
{
  private string _SourcePath = string.Empty;
  private string _DestinationPath = string.Empty;
  private ITaskItem[] _FilesCopied = {};

  /// <summary>
  /// Gets or sets the source path from where files will be copied.
  /// </summary>
  [Required]
  public string SourcePath
  {
    get { return _SourcePath; }
    set { _SourcePath = value; }
  }

  /// <summary>
  /// Gets or sets the destination path to where files will be copied.
  /// </summary>
  [Required]
  public string DestinationPath
  {
    get { return _DestinationPath; }
    set { _DestinationPath = value; }
  }

  /// <summary>
  /// Gets the files that were copied to the destination path.
  /// </summary>
  [Output]
  public ITaskItem[] FilesCopied
  {
    get { return _FilesCopied; }
  }

  /// <summary>
  /// Finds the files that are different between two directories and copies them from
  /// the source directory to the target directory.
  /// </summary>
  /// <returns>true if the task completed successfully, otherwise false.</returns>
  public override bool Execute()
  {
    if (!Directory.Exists(_SourcePath))
    {
      Log.LogError("Source path does not exist.");
      return false;
    }

    if (!Directory.Exists(_DestinationPath))
    {
      Log.LogError("Destination path does not exist.");
      return false;
    }

    string[] sourceFiles = Directory.GetFiles(_SourcePath);
    string[] destinationFiles = Directory.GetFiles(_DestinationPath);
    List<itaskitem> copiedFiles = new List</itaskitem><itaskitem>();

    foreach (string file in sourceFiles)
    {
      string fileName = Path.GetFileName(file);

      if (!File.Exists(Path.Combine(_DestinationPath, fileName)))
      {
        Log.LogMessage("Copying file {0} from {1} to {2}.", fileName, _SourcePath, _DestinationPath);

	try
	{
	  File.Copy(Path.Combine(_SourcePath, fileName), Path.Combine(_DestinationPath, fileName), false);
	  copiedFiles.Add(new TaskItem(Path.Combine(_SourcePath, fileName)));
	}
	catch (IOException ex)
	{
	  Log.LogError("Failed to copy the file {0}. Exception: {1}", Path.Combine(_SourcePath, fileName), ex.ToString());
	  return false;
	}
      }
    }

    if(copiedFiles.Count > 0)
      _FilesCopied = copiedFiles.ToArray();

    Log.LogMessage("Done.");

    return true;
  }
}

Tagged with: , ,

Leave a Reply