219 lines
7.4 KiB
C#
219 lines
7.4 KiB
C#
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
using System;
|
||
|
using System.IO;
|
||
|
using Microsoft.Build.Framework;
|
||
|
using Microsoft.Build.Utilities;
|
||
|
using System.Collections;
|
||
|
|
||
|
namespace Microsoft.Singularity.BuildTasks
|
||
|
{
|
||
|
public class CompareCopy : ExecTaskBase
|
||
|
{
|
||
|
private ITaskItem[] copiedFiles;
|
||
|
private ITaskItem[] destinationFiles;
|
||
|
private ITaskItem destinationFolder;
|
||
|
private ITaskItem[] sourceFiles;
|
||
|
|
||
|
protected override bool Execute()
|
||
|
{
|
||
|
if (this.sourceFiles == null || this.sourceFiles.Length == 0) {
|
||
|
this.destinationFiles = new TaskItem[0];
|
||
|
this.copiedFiles = new TaskItem[0];
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (!this.InputsValid() || !this.InitializeDestinationFiles()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return MakeCopies();
|
||
|
}
|
||
|
|
||
|
private void LogError(string format, params Object[] args)
|
||
|
{
|
||
|
base.LogError(string.Format(format, args));
|
||
|
}
|
||
|
|
||
|
private bool InputsValid()
|
||
|
{
|
||
|
if (IsNullOrEmpty(this.destinationFiles) ||
|
||
|
null == this.destinationFolder) {
|
||
|
LogError("No destination files were specified.");
|
||
|
return false;
|
||
|
}
|
||
|
else if (null != this.destinationFolder &&
|
||
|
null != this.destinationFiles) {
|
||
|
LogError("Specify DestinationFolder OR DestinationFiles.");
|
||
|
return false;
|
||
|
}
|
||
|
else if (null != this.destinationFiles &&
|
||
|
this.sourceFiles.Length != this.destinationFiles.Length) {
|
||
|
LogError("Number of SourceFiles and DestinationFiles differs.");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initializes the destinationFiles member in preparation if not
|
||
|
/// specified by the user.
|
||
|
/// </summary>
|
||
|
/// <returns>true on success, false if a failure composing names
|
||
|
/// occurs.</returns>
|
||
|
private bool InitializeDestinationFiles()
|
||
|
{
|
||
|
if (this.destinationFiles != null) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
this.destinationFiles = new ITaskItem [this.sourceFiles.Length];
|
||
|
|
||
|
string directory = this.destinationFolder.ItemSpec;
|
||
|
|
||
|
for (int i = 0; i < this.sourceFiles.Length; i++) {
|
||
|
string destination;
|
||
|
|
||
|
try {
|
||
|
string file = Path.GetFileName(
|
||
|
this.sourceFiles[i].ItemSpec
|
||
|
);
|
||
|
destination = Path.Combine(directory, file);
|
||
|
}
|
||
|
catch (System.ArgumentException) {
|
||
|
LogError(
|
||
|
"Failed making destination file name for \"{0}\"",
|
||
|
this.sourceFiles[i].ItemSpec
|
||
|
);
|
||
|
this.destinationFiles = new ITaskItem [0];
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
this.destinationFiles[i] = new TaskItem(destination);
|
||
|
this.sourceFiles[i].CopyMetadataTo(this.destinationFiles[i]);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Walks lists of source and destination files and performs
|
||
|
/// copies if files differ.
|
||
|
/// </summary>
|
||
|
/// <returns>true on success, false if an exception
|
||
|
/// stopped processing.</returns>
|
||
|
private bool MakeCopies()
|
||
|
{
|
||
|
ArrayList copied = new ArrayList();
|
||
|
|
||
|
bool success = true;
|
||
|
for (int i = 0; i < this.sourceFiles.Length; i++) {
|
||
|
if (this.CopyIfNecessary(this.sourceFiles[i].ItemSpec,
|
||
|
this.destinationFiles[i].ItemSpec)) {
|
||
|
copied.Add(this.destinationFiles[i]);
|
||
|
}
|
||
|
else {
|
||
|
success = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.copiedFiles = (ITaskItem[])copied.ToArray(typeof(ITaskItem));
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Copies source file to destination if the destination does
|
||
|
/// not exist or the source file differs from the destination.
|
||
|
/// </summary>
|
||
|
/// <param name="source">source file name</param>
|
||
|
/// <param name="destination">destination file name</param>
|
||
|
/// <returns>true on success, false if an exception occurred during
|
||
|
/// checking or copy.</returns>
|
||
|
private bool CopyIfNecessary(string source, string destination)
|
||
|
{
|
||
|
try {
|
||
|
if (File.Exists(source) == false) {
|
||
|
LogError("Source file does not exist: \"{0}\".", source);
|
||
|
return false;
|
||
|
}
|
||
|
if (File.Exists(destination) == false ||
|
||
|
FileContentsDiffer(source, destination)) {
|
||
|
File.Copy(source, destination);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
LogError("Exception raised: {0}.", e);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Compares source and destination file contents.
|
||
|
/// </summary>
|
||
|
/// <param name="source">source file name</param>
|
||
|
/// <param name="destination">destination file name</param>
|
||
|
/// <returns>true if file contents differ, false if the same</returns>
|
||
|
private static bool FileContentsDiffer(string source,
|
||
|
string destination)
|
||
|
{
|
||
|
FileInfo fis = new FileInfo(source);
|
||
|
FileInfo fid = new FileInfo(destination);
|
||
|
|
||
|
if (fis.Length != fid.Length) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int bs, bd;
|
||
|
using (Stream ss = fis.OpenRead()) {
|
||
|
using (Stream sd = fid.OpenRead()) {
|
||
|
do {
|
||
|
bs = ss.ReadByte();
|
||
|
bd = sd.ReadByte();
|
||
|
} while ((bs == bd) && (bs != -1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bs != bd;
|
||
|
}
|
||
|
|
||
|
private static bool IsNullOrEmpty(ITaskItem[] x)
|
||
|
{
|
||
|
return null == x || 0 == x.Length;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------
|
||
|
// Properties
|
||
|
|
||
|
public ITaskItem[] CopiedFiles
|
||
|
{
|
||
|
get { return this.copiedFiles; }
|
||
|
set { this.copiedFiles = value; }
|
||
|
}
|
||
|
|
||
|
public ITaskItem[] DestinationFiles
|
||
|
{
|
||
|
get { return this.destinationFiles; }
|
||
|
set { this.destinationFiles = value; }
|
||
|
}
|
||
|
|
||
|
public ITaskItem DestinationFolder
|
||
|
{
|
||
|
get { return this.destinationFolder; }
|
||
|
set { this.destinationFolder = value; }
|
||
|
}
|
||
|
|
||
|
public ITaskItem[] SourceFiles
|
||
|
{
|
||
|
get { return this.sourceFiles; }
|
||
|
set { this.sourceFiles = value; }
|
||
|
}
|
||
|
}
|
||
|
}
|