[xbuild] Add 'OverrideReadOnlyFiles' property to Copy task.
[mono.git] / mcs / class / Microsoft.Build.Tasks / Microsoft.Build.Tasks / Copy.cs
index 3f6ae1a92ef55bb6d69fdebafef426a3c306e089..8c28c2ae27b5a9c8a8dcfec93da8975974c9b151 100644 (file)
@@ -28,6 +28,7 @@
 #if NET_2_0
 
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using Microsoft.Build.Framework;
@@ -41,6 +42,7 @@ namespace Microsoft.Build.Tasks {
                ITaskItem       destinationFolder;
                bool            skipUnchangedFiles;
                ITaskItem[]     sourceFiles;
+               bool            overwriteReadOnlyFiles;
                
                public Copy ()
                {
@@ -48,66 +50,74 @@ namespace Microsoft.Build.Tasks {
 
                public override bool Execute ()
                {
+                       if (sourceFiles.Length == 0)
+                               // nothing to copy!
+                               return true;
+
                        try {
                                List <ITaskItem> temporaryCopiedFiles = new List <ITaskItem> ();
                        
-                               if (sourceFiles.Length != destinationFiles.Length)
-                                       throw new Exception ("Number of source files is different than number of destination files.");
-                               if (destinationFiles != null && destinationFolder != null)
-                                       throw new Exception ("You must specify only one attribute from DestinationFiles and DestinationFolder");
-                               if (destinationFiles != null) {
-                                       IEnumerator <ITaskItem> source, destination;
-                                       source = (IEnumerator <ITaskItem>) sourceFiles.GetEnumerator ();
-                                       destination = (IEnumerator <ITaskItem>) destinationFiles.GetEnumerator ();
-                                       source.Reset ();
-                                       destination.Reset ();
-                                       while (source.MoveNext ()) {
-                                               destination.MoveNext ();
-                                               ITaskItem sourceItem = source.Current;
-                                               ITaskItem destinationItem = destination.Current;
+                               if (sourceFiles != null && destinationFiles != null &&
+                                       sourceFiles.Length != destinationFiles.Length) {
+                                       Log.LogError ("Number of source files is different than number of destination files.");
+                                       return false;
+                               }
+
+                               if (destinationFiles != null && destinationFolder != null) {
+                                       Log.LogError ("You must specify only one attribute from DestinationFiles and DestinationFolder");
+                                       return false;
+                               }
+
+                               if (destinationFiles != null && destinationFiles.Length > 0) {
+                                       for (int i = 0; i < sourceFiles.Length; i ++) {
+                                               ITaskItem sourceItem = sourceFiles [i];
+                                               ITaskItem destinationItem = destinationFiles [i];
                                                string sourceFile = sourceItem.GetMetadata ("FullPath");
                                                string destinationFile = destinationItem.GetMetadata ("FullPath");
 
-                                               if (skipUnchangedFiles == true) {
-                                                       FileInfo sourceInfo = new FileInfo (sourceFile);
-                                                       FileInfo destinationInfo = new FileInfo (destinationFile);
-                                                       if (sourceInfo.Length == destinationInfo.Length && File.GetLastWriteTime(sourceFile) <=
-                                                               File.GetLastWriteTime (destinationFile))
-                                                               continue;
+                                               if (!File.Exists (sourceFile)) {
+                                                       Log.LogError ("Cannot copy {0} to {1}, as the source file doesn't exist.", sourceFile, destinationFile);
+                                                       continue;
                                                }
-                                               File.Copy (sourceFile, destinationFile);
-                                               temporaryCopiedFiles.Add (source.Current);
+
+                                               if (!skipUnchangedFiles || HasFileChanged (sourceFile, destinationFile))
+                                                       CopyFile (sourceFile, destinationFile, true);
+
+                                               sourceItem.CopyMetadataTo (destinationItem);
+                                               temporaryCopiedFiles.Add (destinationItem);
                                        }
                                        
                                } else if (destinationFolder != null) {
-                                       bool directoryCreated = false;
+                                       List<ITaskItem> temporaryDestinationFiles = new List<ITaskItem> ();
                                        string destinationDirectory = destinationFolder.GetMetadata ("FullPath");
-                                       if (Directory.Exists (destinationDirectory) == false) {
-                                               Directory.CreateDirectory (destinationDirectory);
-                                               directoryCreated = true;
-                                       }
+                                       bool directoryCreated = CreateDirectoryIfRequired (destinationDirectory);
                                        
-                                       IEnumerator <ITaskItem> source;
-                                       source = (IEnumerator <ITaskItem>) sourceFiles.GetEnumerator ();
-                                       source.Reset ();
-                                       while (source.MoveNext ()) {
-                                               ITaskItem sourceItem = source.Current;
+                                       foreach (ITaskItem sourceItem in sourceFiles) {
                                                string sourceFile = sourceItem.GetMetadata ("FullPath");
                                                string filename = sourceItem.GetMetadata ("Filename") + sourceItem.GetMetadata ("Extension");
                                                string destinationFile = Path.Combine (destinationDirectory,filename);
 
-                                               if (skipUnchangedFiles == true && directoryCreated == false) {
-                                                       FileInfo sourceInfo = new FileInfo (sourceFile);
-                                                       FileInfo destinationInfo = new FileInfo (destinationFile);
-                                                       if (sourceInfo.Length == destinationInfo.Length && File.GetLastWriteTime(sourceFile) <=
-                                                               File.GetLastWriteTime (destinationFile))
-                                                               continue;
+                                               if (!File.Exists (sourceFile)) {
+                                                       Log.LogError ("Cannot copy {0} to {1}, as the source file doesn't exist.", sourceFile, destinationFile);
+                                                       continue;
                                                }
-                                               File.Copy (sourceFile, destinationFile);
-                                               temporaryCopiedFiles.Add (source.Current);
+
+                                               if (!skipUnchangedFiles || directoryCreated ||
+                                                       HasFileChanged (sourceFile, destinationFile))
+                                                       CopyFile (sourceFile, destinationFile, false);
+
+                                               temporaryCopiedFiles.Add (new TaskItem (
+                                                               Path.Combine (destinationFolder.GetMetadata ("Identity"), filename),
+                                                               sourceItem.CloneCustomMetadata ()));
+
+                                               temporaryDestinationFiles.Add (new TaskItem (
+                                                               Path.Combine (destinationFolder.GetMetadata ("Identity"), filename),
+                                                               sourceItem.CloneCustomMetadata ()));
                                        }
+                                       destinationFiles = temporaryDestinationFiles.ToArray ();
                                } else {
-                                       throw new Exception ("You must specify DestinationFolder or DestinationFiles attribute.");
+                                       Log.LogError ("You must specify DestinationFolder or DestinationFiles attribute.");
+                                       return false;
                                }
                                
                                copiedFiles = temporaryCopiedFiles.ToArray ();
@@ -155,6 +165,17 @@ namespace Microsoft.Build.Tasks {
                        }
                }
 
+#if NET_3_5 || NET_4_0
+               public bool OverwriteReadOnlyFiles {
+                       get {
+                               return overwriteReadOnlyFiles;
+                       }
+                       set {
+                               overwriteReadOnlyFiles = value;
+                       }
+               }
+#endif
+
                [Required]
                public ITaskItem[] SourceFiles {
                        get {
@@ -164,7 +185,49 @@ namespace Microsoft.Build.Tasks {
                                sourceFiles = value;
                        }
                }
+
+               // returns whether directory was created or not
+               bool CreateDirectoryIfRequired (string name)
+               {
+                       if (Directory.Exists (name))
+                               return false;
+
+                       Log.LogMessage ("Creating directory '{0}'", name);
+                       Directory.CreateDirectory (name);
+                       return true;
+               }
+
+               void CopyFile (string source, string dest, bool create_dir)
+               {
+                       if (create_dir)
+                               CreateDirectoryIfRequired (Path.GetDirectoryName (dest));
+                       if (overwriteReadOnlyFiles)
+                               ClearReadOnlyAttribute (dest);
+                       Log.LogMessage ("Copying file from '{0}' to '{1}'", source, dest);
+                       if (String.Compare (source, dest) != 0)
+                               File.Copy (source, dest, true);
+                       ClearReadOnlyAttribute (dest);
+               }
+
+               void ClearReadOnlyAttribute (string name)
+               {
+                       if (File.Exists (name) && ((File.GetAttributes (name) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly))
+                               File.SetAttributes (name, FileAttributes.Normal);
+               }
+
+               bool HasFileChanged (string source, string dest)
+               {
+                       if (!File.Exists (dest))
+                               return true;
+
+                       FileInfo sourceInfo = new FileInfo (source);
+                       FileInfo destinationInfo = new FileInfo (dest);
+
+                       return !(sourceInfo.Length == destinationInfo.Length &&
+                                       File.GetLastWriteTime (source) <= File.GetLastWriteTime (dest));
+               }
+
        }
 }
 
-#endif
\ No newline at end of file
+#endif