2005-06-05 Peter Bartok <pbartok@novell.com>
[mono.git] / mcs / nant / src / Tasks / DeleteTask.cs
1 // NAnt - A .NET build tool\r
2 // Copyright (C) 2001 Gerry Shaw\r
3 //\r
4 // This program is free software; you can redistribute it and/or modify\r
5 // it under the terms of the GNU General Public License as published by\r
6 // the Free Software Foundation; either version 2 of the License, or\r
7 // (at your option) any later version.\r
8 //\r
9 // This program is distributed in the hope that it will be useful,\r
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12 // GNU General Public License for more details.\r
13 //\r
14 // You should have received a copy of the GNU General Public License\r
15 // along with this program; if not, write to the Free Software\r
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
17 //\r
18 // Gerry Shaw (gerry_shaw@yahoo.com)\r
19 \r
20 \r
21 // TODO: move this into the task documentation (once we figure out how tasks\r
22 // should be documented - xml??\r
23 /*\r
24 \r
25 verbose: Show name of each deleted file ("true"/"false"). Default is "false"\r
26 when omitted.\r
27 \r
28 quiet: If the file does not exist, do not display a diagnostic message or\r
29 modify the exit status to reflect an error (unless Ant has been invoked with\r
30 the -verbose or -debug switches). This means that if a file or directory cannot\r
31 be deleted, then no error is reported. This setting emulates the -f option to\r
32 the Unix "rm" command. ("true"/"false"). Default is "false" meaning things are\r
33 "noisy". Setting this to true, implies setting failonerror to false.\r
34 \r
35 failonerror: This flag (which is only of relevance if 'quiet' is false),\r
36 controls whether an error -such as a failure to delete a file- stops the build\r
37 task, or is merely reported to the screen. The default is "true"\r
38 \r
39 */\r
40 \r
41 namespace SourceForge.NAnt {\r
42 \r
43     using System;\r
44     using System.IO;\r
45 \r
46     [TaskName("delete")]\r
47     public class DeleteTask : Task {\r
48 \r
49         [TaskAttribute("file")]\r
50         string _file = null;\r
51 \r
52         [TaskAttribute("dir")]\r
53         string _dir = null;\r
54 \r
55         [TaskAttribute("verbose")]\r
56         [BooleanValidator()]\r
57         string _verbose = Boolean.FalseString;\r
58 \r
59         [TaskAttribute("failonerror")]\r
60         [BooleanValidator()]\r
61         string _failOnError = Boolean.TrueString;\r
62 \r
63         /// <summary>If true then delete empty directories when using filesets.</summary>\r
64         [TaskAttribute("includeEmptyDirs")]\r
65         [BooleanValidator()]\r
66         string _includeEmptyDirs = Boolean.FalseString;\r
67 \r
68         [TaskFileSet("fileset")]\r
69         FileSet _fileset = new FileSet(false);\r
70 \r
71         public string FileName       { get { return _file; } }\r
72         public string DirectoryName  { get { return _dir; } }\r
73         public bool FailOnError      { get { return Convert.ToBoolean(_failOnError); } }\r
74         public bool IncludeEmptyDirectories { get { return Convert.ToBoolean(_includeEmptyDirs); } }\r
75         public FileSet DeleteFileSet { get { return _fileset; } }\r
76 \r
77         public bool Verbose { \r
78             get {\r
79                 return (Project.Verbose || Convert.ToBoolean(_verbose));\r
80             } \r
81         }\r
82 \r
83         protected override void ExecuteTask() {\r
84 \r
85             // limit task to deleting either a file or a directory or a file set\r
86             if (FileName != null && DirectoryName != null) {\r
87                 throw new BuildException("Cannot specify 'file' and 'dir' in the same delete task", Location);\r
88             }\r
89 \r
90             // try to delete specified file\r
91             if (FileName != null) {\r
92                 string path = null;\r
93                 try {\r
94                     path = Project.GetFullPath(FileName);\r
95                 } catch (Exception e) {\r
96                     string msg = String.Format("Could not determine path from {0}", FileName);\r
97                     throw new BuildException(msg, Location, e);\r
98                 }\r
99                 DeleteFile(path);\r
100 \r
101             // try to delete specified directory\r
102             } else if (DirectoryName != null) {\r
103                 string path = null;\r
104                 try {\r
105                     path = Project.GetFullPath(DirectoryName);\r
106                 } catch (Exception e) {\r
107                     string msg = String.Format("Could not determine path from {0}", DirectoryName);\r
108                     throw new BuildException(msg, Location, e);\r
109                 }\r
110                 DeleteDirectory(path);\r
111 \r
112             // delete files/directories in fileset\r
113             } else {\r
114                 // only use the file set if file and dir attributes have NOT been set\r
115                 foreach (string path in DeleteFileSet.FileNames) {\r
116                     DeleteFile(path);\r
117                 }\r
118 \r
119                 if (IncludeEmptyDirectories) {\r
120                     foreach (string path in DeleteFileSet.DirectoryNames) {\r
121                         // only delete EMPTY directories (no files, no directories)\r
122                         DirectoryInfo dirInfo = new DirectoryInfo(path);\r
123 \r
124                         if ((dirInfo.GetFiles().Length == 0) && (dirInfo.GetDirectories().Length == 0)) {\r
125                             DeleteDirectory(path);\r
126                         }\r
127                     }\r
128                 }\r
129             }\r
130         }\r
131 \r
132         void DeleteDirectory(string path) {\r
133             try {\r
134                 if (Directory.Exists(path)) {\r
135                     if (Verbose) {\r
136                         Log.WriteLine(LogPrefix + "Deleting directory {0}", path);\r
137                     }\r
138                     if (path.Length > 10) {\r
139                         Directory.Delete(path, true);\r
140                     } else {\r
141                         // TODO: remove this once this task is fully tested and NAnt is at 1.0\r
142                         Console.WriteLine(LogPrefix + "Path {0} is too close to root to delete this early in development", path);\r
143                     }\r
144                 } else {\r
145                     throw new DirectoryNotFoundException();\r
146                 }\r
147             } catch (Exception e) {\r
148                 if (FailOnError) {\r
149                     string msg = String.Format("Cannot delete directory {0}", path);\r
150                     throw new BuildException(msg, Location, e);\r
151                 }\r
152             }\r
153         }\r
154 \r
155         void DeleteFile(string path) {\r
156             try {\r
157                 if (File.Exists(path)) {\r
158                     if (Verbose) {\r
159                         Log.WriteLine(LogPrefix + "Deleting file {0}", path);\r
160                     }\r
161                     File.Delete(path);\r
162                 } else {\r
163                     throw new FileNotFoundException();\r
164                 }\r
165             } catch (Exception e) {\r
166                 if (FailOnError) {\r
167                     string msg = String.Format("Cannot delete file {0}", path);\r
168                     throw new BuildException(msg, Location, e);\r
169                 }\r
170             }\r
171         }\r
172     }\r
173 }\r