// ---------------------------------------------------------------------------- // // 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; } /// /// Initializes the destinationFiles member in preparation if not /// specified by the user. /// /// true on success, false if a failure composing names /// occurs. 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; } /// /// Walks lists of source and destination files and performs /// copies if files differ. /// /// true on success, false if an exception /// stopped processing. 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; } /// /// Copies source file to destination if the destination does /// not exist or the source file differs from the destination. /// /// source file name /// destination file name /// true on success, false if an exception occurred during /// checking or copy. 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; } } /// /// Compares source and destination file contents. /// /// source file name /// destination file name /// true if file contents differ, false if the same 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; } } } }