Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / Microsoft.Build.Tasks / Microsoft.Build.Tasks / Copy.cs
1 //
2 // Copy.cs: Task that can copy files
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 //
7 // (C) 2005 Marek Sieradzki
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.IO;
32 using Microsoft.Build.Framework;
33 using Microsoft.Build.Utilities;
34
35 namespace Microsoft.Build.Tasks {
36         public class Copy : TaskExtension {
37         
38                 ITaskItem[]     copiedFiles;
39                 ITaskItem[]     destinationFiles;
40                 ITaskItem       destinationFolder;
41                 bool            skipUnchangedFiles;
42                 ITaskItem[]     sourceFiles;
43                 bool            overwriteReadOnlyFiles;
44                 
45                 public Copy ()
46                 {
47                 }
48
49                 public override bool Execute ()
50                 {
51                         if (sourceFiles.Length == 0)
52                                 // nothing to copy!
53                                 return true;
54
55                         try {
56                                 List <ITaskItem> temporaryCopiedFiles = new List <ITaskItem> ();
57                         
58                                 if (sourceFiles != null && destinationFiles != null &&
59                                         sourceFiles.Length != destinationFiles.Length) {
60                                         Log.LogError ("Number of source files is different than number of destination files.");
61                                         return false;
62                                 }
63
64                                 if (destinationFiles != null && destinationFolder != null) {
65                                         Log.LogError ("You must specify only one attribute from DestinationFiles and DestinationFolder");
66                                         return false;
67                                 }
68
69                                 if (destinationFiles != null && destinationFiles.Length > 0) {
70                                         for (int i = 0; i < sourceFiles.Length; i ++) {
71                                                 ITaskItem sourceItem = sourceFiles [i];
72                                                 ITaskItem destinationItem = destinationFiles [i];
73                                                 string sourceFile = sourceItem.GetMetadata ("FullPath");
74                                                 string destinationFile = destinationItem.GetMetadata ("FullPath");
75
76                                                 if (!File.Exists (sourceFile)) {
77                                                         Log.LogError ("Cannot copy {0} to {1}, as the source file doesn't exist.", sourceFile, destinationFile);
78                                                         continue;
79                                                 }
80
81                                                 if (!skipUnchangedFiles || HasFileChanged (sourceFile, destinationFile))
82                                                         CopyFile (sourceFile, destinationFile, true);
83
84                                                 sourceItem.CopyMetadataTo (destinationItem);
85                                                 temporaryCopiedFiles.Add (destinationItem);
86                                         }
87                                         
88                                 } else if (destinationFolder != null) {
89                                         List<ITaskItem> temporaryDestinationFiles = new List<ITaskItem> ();
90                                         string destinationDirectory = destinationFolder.GetMetadata ("FullPath");
91                                         bool directoryCreated = CreateDirectoryIfRequired (destinationDirectory);
92                                         
93                                         foreach (ITaskItem sourceItem in sourceFiles) {
94                                                 string sourceFile = sourceItem.GetMetadata ("FullPath");
95                                                 string filename = sourceItem.GetMetadata ("Filename") + sourceItem.GetMetadata ("Extension");
96                                                 string destinationFile = Path.Combine (destinationDirectory,filename);
97
98                                                 if (!File.Exists (sourceFile)) {
99                                                         Log.LogError ("Cannot copy {0} to {1}, as the source file doesn't exist.", sourceFile, destinationFile);
100                                                         continue;
101                                                 }
102
103                                                 if (!skipUnchangedFiles || directoryCreated ||
104                                                         HasFileChanged (sourceFile, destinationFile))
105                                                         CopyFile (sourceFile, destinationFile, false);
106
107                                                 temporaryCopiedFiles.Add (new TaskItem (
108                                                                 Path.Combine (destinationFolder.GetMetadata ("Identity"), filename),
109                                                                 sourceItem.CloneCustomMetadata ()));
110
111                                                 temporaryDestinationFiles.Add (new TaskItem (
112                                                                 Path.Combine (destinationFolder.GetMetadata ("Identity"), filename),
113                                                                 sourceItem.CloneCustomMetadata ()));
114                                         }
115                                         destinationFiles = temporaryDestinationFiles.ToArray ();
116                                 } else {
117                                         Log.LogError ("You must specify DestinationFolder or DestinationFiles attribute.");
118                                         return false;
119                                 }
120                                 
121                                 copiedFiles = temporaryCopiedFiles.ToArray ();
122
123                                 return true;
124                         }
125                         catch (Exception ex) {
126                                 Log.LogErrorFromException (ex);
127                                 return false;
128                         }
129                 }
130
131                 [Output]
132                 public ITaskItem[] CopiedFiles {
133                         get {
134                                 return copiedFiles;
135                         }
136                 }
137
138                 [Output]
139                 public ITaskItem[] DestinationFiles {
140                         get {
141                                 return destinationFiles;
142                         }
143                         set {
144                                 destinationFiles = value;
145                         }
146                 }
147
148                 public ITaskItem DestinationFolder {
149                         get {
150                                 return destinationFolder;
151                         }
152                         set {
153                                 destinationFolder = value;
154                         }
155                 }
156
157                 public bool SkipUnchangedFiles {
158                         get {
159                                 return skipUnchangedFiles;
160                         }
161                         set {
162                                 skipUnchangedFiles = value;
163                         }
164                 }
165
166 #if NET_3_5
167                 public bool OverwriteReadOnlyFiles {
168                         get {
169                                 return overwriteReadOnlyFiles;
170                         }
171                         set {
172                                 overwriteReadOnlyFiles = value;
173                         }
174                 }
175 #endif
176
177                 [Required]
178                 public ITaskItem[] SourceFiles {
179                         get {
180                                 return sourceFiles;
181                         }
182                         set {
183                                 sourceFiles = value;
184                         }
185                 }
186
187                 // returns whether directory was created or not
188                 bool CreateDirectoryIfRequired (string name)
189                 {
190                         if (Directory.Exists (name))
191                                 return false;
192
193                         Log.LogMessage ("Creating directory '{0}'", name);
194                         Directory.CreateDirectory (name);
195                         return true;
196                 }
197
198                 void CopyFile (string source, string dest, bool create_dir)
199                 {
200                         if (create_dir)
201                                 CreateDirectoryIfRequired (Path.GetDirectoryName (dest));
202                         if (overwriteReadOnlyFiles)
203                                 ClearReadOnlyAttribute (dest);
204                         Log.LogMessage ("Copying file from '{0}' to '{1}'", source, dest);
205                         if (String.Compare (source, dest) != 0)
206                                 File.Copy (source, dest, true);
207                         ClearReadOnlyAttribute (dest);
208                 }
209
210                 void ClearReadOnlyAttribute (string name)
211                 {
212                         if (File.Exists (name) && ((File.GetAttributes (name) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly))
213                                 File.SetAttributes (name, FileAttributes.Normal);
214                 }
215
216                 bool HasFileChanged (string source, string dest)
217                 {
218                         if (!File.Exists (dest))
219                                 return true;
220
221                         FileInfo sourceInfo = new FileInfo (source);
222                         FileInfo destinationInfo = new FileInfo (dest);
223
224                         return !(sourceInfo.Length == destinationInfo.Length &&
225                                         File.GetLastWriteTime (source) <= File.GetLastWriteTime (dest));
226                 }
227
228         }
229 }