Merge pull request #199 from slide/master
authorAnkit Jain <radical@gmail.com>
Wed, 7 Dec 2011 14:05:41 +0000 (06:05 -0800)
committerAnkit Jain <radical@gmail.com>
Wed, 7 Dec 2011 14:05:41 +0000 (06:05 -0800)
[xbuild] Add 'OverrideReadOnlyFiles' property to Copy task. bug#2239

Also, fixed bug #2239 where the copy task does not
behave the same as msbuild when a file being copied is
ReadOnly. msbuild resets the attributes of the file to
Normal.

mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/Copy.cs
mcs/class/Microsoft.Build.Tasks/Test/Microsoft.Build.Tasks/CopyTest.cs

index a090e4716d46179eac1ac836c997a2500907297e..8c28c2ae27b5a9c8a8dcfec93da8975974c9b151 100644 (file)
@@ -42,6 +42,7 @@ namespace Microsoft.Build.Tasks {
                ITaskItem       destinationFolder;
                bool            skipUnchangedFiles;
                ITaskItem[]     sourceFiles;
+               bool            overwriteReadOnlyFiles;
                
                public Copy ()
                {
@@ -164,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 {
@@ -189,9 +201,18 @@ namespace Microsoft.Build.Tasks {
                {
                        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)
@@ -203,7 +224,7 @@ namespace Microsoft.Build.Tasks {
                        FileInfo destinationInfo = new FileInfo (dest);
 
                        return !(sourceInfo.Length == destinationInfo.Length &&
-                                       File.GetLastWriteTime(source) <= File.GetLastWriteTime (dest));
+                                       File.GetLastWriteTime (source) <= File.GetLastWriteTime (dest));
                }
 
        }
index e3cd166b9f9ad123dfb0713299d0cb3e832d08e3..63c3ea9456cd689837597ca4782002a5eec034dd 100644 (file)
@@ -57,7 +57,7 @@ namespace MonoTests.Microsoft.Build.Tasks {
                {
                        Engine engine;
                        Project project;
-                       string file_path = Path.Combine(source_path, "copy.txt");
+                       string file_path = Path.Combine (source_path, "copy.txt");
                        string target_file = Path.Combine (target_path, "copy.txt");
 
                        using (File.CreateText (file_path)) { }
@@ -243,6 +243,143 @@ namespace MonoTests.Microsoft.Build.Tasks {
                        }
                }
 
+               [Test]
+               public void TestCopy_ReadOnlyUpdate ()
+               {
+                       Engine engine;
+                       Project project;
+                       string file_path = Path.Combine (source_path, "copyro.txt");
+                       string target_file = Path.Combine (target_path, "copyro.txt");                  
+
+                       using (File.CreateText (file_path)) { }
+                       
+                       string documentString = @"
+                               <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+                                       <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
+                                       <ItemGroup>
+                                               <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
+                                               <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
+                                       </ItemGroup>
+                                       <Target Name='1'>
+                                               <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' >
+                                                       <Output TaskParameter='CopiedFiles' ItemName='I0'/>
+                                                       <Output TaskParameter='DestinationFiles' ItemName='I1'/>
+                                               </Copy>
+                                               <Message Text=""I0 : @(I0), I1: @(I1)""/>
+                                       </Target>
+                               </Project>
+                       ";
+
+                       engine = new Engine (Consts.BinPath);
+                       project = engine.CreateNewProject ();
+
+                       TestMessageLogger testLogger = new TestMessageLogger ();
+                       engine.RegisterLogger (testLogger);
+
+                       project.LoadXml (documentString);
+
+                       if (!project.Build ("1")) {
+                               testLogger.DumpMessages ();
+                               Assert.Fail ("Build failed");
+                       }
+                       Assert.IsTrue (File.Exists (target_file), "A2");
+                       Assert.AreEqual (FileAttributes.Normal, File.GetAttributes (target_file), "A3");                                        
+               }
+
+#if NET_3_5 || NET_4_0
+               [Test]
+               public void TestCopy_OverwriteReadOnlyTrue ()
+               {
+                       Engine engine;
+                       Project project;
+                       string file_path = Path.Combine (source_path, "copyro1.txt");
+                       string target_file = Path.Combine (target_path, "copyro1.txt");                 
+
+                       using (File.CreateText (file_path)) { }
+                       using (File.CreateText (target_file)) { }
+
+                       File.SetAttributes (target_file, FileAttributes.ReadOnly);
+                       Assert.AreEqual (FileAttributes.ReadOnly, File.GetAttributes (target_file), "A1");
+                       
+                       string documentString = @"
+                               <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+                                       <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
+                                       <ItemGroup>
+                                               <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
+                                               <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
+                                       </ItemGroup>
+                                       <Target Name='1'>
+                                               <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' OverwriteReadOnlyFiles='true'>
+                                                       <Output TaskParameter='CopiedFiles' ItemName='I0'/>
+                                                       <Output TaskParameter='DestinationFiles' ItemName='I1'/>
+                                               </Copy>
+                                               <Message Text=""I0 : @(I0), I1: @(I1)""/>
+                                       </Target>
+                               </Project>
+                       ";
+
+                       engine = new Engine (Consts.BinPath);
+                       project = engine.CreateNewProject ();
+
+                       TestMessageLogger testLogger = new TestMessageLogger ();
+                       engine.RegisterLogger (testLogger);
+
+                       project.LoadXml (documentString);
+
+                       if (!project.Build ("1")) {
+                               testLogger.DumpMessages ();
+                               Assert.Fail ("Build failed");
+                       }
+                       Assert.IsTrue (File.Exists (target_file), "A2");
+                       Assert.AreEqual (FileAttributes.Normal, File.GetAttributes (target_file), "A3");                                        
+               }
+
+               [Test]
+               public void TestCopy_OverwriteReadOnlyFalse ()
+               {
+                       Engine engine;
+                       Project project;
+                       string file_path = Path.Combine (source_path, "copyro2.txt");
+                       string target_file = Path.Combine (target_path, "copyro2.txt");                 
+
+                       using (File.CreateText (file_path)) { }
+                       using (File.CreateText (target_file)) { }
+
+                       File.SetAttributes (target_file, FileAttributes.ReadOnly);
+                       Assert.AreEqual (FileAttributes.ReadOnly, File.GetAttributes (target_file), "A1");
+                       
+                       string documentString = @"
+                               <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+                                       <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
+                                       <ItemGroup>
+                                               <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
+                                               <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
+                                       </ItemGroup>
+                                       <Target Name='1'>
+                                               <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)'>
+                                                       <Output TaskParameter='CopiedFiles' ItemName='I0'/>
+                                                       <Output TaskParameter='DestinationFiles' ItemName='I1'/>
+                                               </Copy>
+                                               <Message Text=""I0 : @(I0), I1: @(I1)""/>
+                                       </Target>
+                               </Project>
+                       ";
+
+                       engine = new Engine (Consts.BinPath);
+                       project = engine.CreateNewProject ();
+
+                       TestMessageLogger testLogger = new TestMessageLogger ();
+                       engine.RegisterLogger (testLogger);
+
+                       project.LoadXml (documentString);
+
+                       // build should fail because of the readonly target file
+                       Assert.IsFalse (project.Build ("1"));
+                       
+                       File.SetAttributes (target_file, FileAttributes.Normal);
+               }
+#endif
+
                void CheckCopyBuildItems (Project project, string [] source_files, string destination_folder, string prefix)
                {
                        int num = source_files.Length;