Why Doesn't Delete Take Wildcards?
Here's another question from our internal conversion discussion alias that came through last week:
Does the Delete task in MSBuild not use wildcards? The documentation doesn’t say anything about it but that seems to be the behavior I am seeing. I can always create an ItemList then pass that into delete, but I wanted to verify this was “right”.
The person asking the question is correct: the right way to do this is to create an ItemGroup that contains the list of items you want to delete. Generally you'll do this by specifying each file individually, although you can use a wildcard in the ItemGroup's Include attribute to pick up files as well. You then pass this ItemGroup into the delete task to perform the delete.
Why do we do it this way? We really wanted to ensure people passed around strongly-typed lists of objects through the build process, so things like metadata can flow through the entire build. If you have an individual task like delete take wildcards, people will tend to use the wildcards in the task directly instead of creating a strongly-typed group first.
Of course, sometimes you can't know ahead of time what the item group will be, and that's why we have the CreateItem task (which is, as we've found during the conversion of our internal build process, often required and never very pretty...).
[ Author: Neil Enns ]
Comments
Anonymous
June 14, 2006
Article could be much more useful if it contained example of how to do it properly, because people keep wasting time looking for it.Anonymous
November 09, 2006
Here's a sample I cooked up: <ItemGroup> <TempFiles Include="C:BuildTempDir*" /> </ItemGroup> <Target Name="Clean"> <Delete Files="@(TempFiles)" /> </Target>Anonymous
December 06, 2006
This doesn't seem to be working for me, but I don't get any errors. Does anyone happen to see why? Here's my target. <ItemGroup > <FilesToDelete Include="$(ConfigBinDebugDirectory)VCCustomSteps1.*"/> </ItemGroup> <Target Name="CleanVCCustomSteps1" > <!-- Delete all VCCustomSteps1 output so the build events will be triggered --> <Delete Condition=" '%(ConfigurationToBuild.PlatformToBuild)'=='Win32' And '%(ConfigurationToBuild.FlavorToBuild)'=='Debug'" Files="@(FilesToDelete)"> <Output TaskParameter="DeletedFiles" PropertyName="DeletedVCCS1Files" /> </Delete> <Message Text="Config bin debug dir = $(ConfigBinDebugDirectory)"/> <Message Text="Config bin release dir = $(ConfigBinReleaseDirectory)"/> <Message Text="Deleted files: @(DeletedVCCS1Files)"/> </Target> Here's the output in the build log: Target CleanVCCustomSteps1: Config bin debug dir = X:BuildAscentNightlyBuildBuildType..Sources..BinariesWin32Debug Config bin release dir = X:BuildAscentNightlyBuildBuildType..Sources..BinariesWin32Release Deleted files:Anonymous
May 29, 2007
I just use an Exec like this: <Exec Command="del wix*.wxs"/> Works great and don't have to put in 5 lines of harder to understand nodes when one clear one will do. I do the same for copy - makes the .proj file a LOT easier to understand and easier to understand means fewer bugs.Anonymous
September 02, 2007
I have some experience with NAnt, and because I wanted an easy solution for my co-developers I just wanted to give MSBuild a try for some trivial build task (because it comes with .NET Framework so everybody already has it). I stumbled across this issue, and while I could somehow understand why there is no wildcard support for Delete, I think the way ItemGroups were implemented is pretty unusable: If I want to copy or delete files that were generated by my build task - which should not only be common but the normal case in a build script! - they won't get copied or deleted because the wildcard for the ItemGroup's Includes seems to be resolved at the start of the whole script, when the files are not yet existing, and not at the first or every time the ItemGroup is used. At least you comment on CreateTask showed me some kind of workaround, but as you already stated it's "not very pretty", e. g. because it takes just one Include attribute where I have to put everything in separated by semicolons which of course looks awful and is simply unhandy compared to a list of Include nodes. Honestly, I would understand such issues to some degree if you would have been the first to create a build tool like this. But since Ant and NAnt have already been around much longer than MSBuild and seem to do the job much better, I really wonder how it was possible to create such an inefficient solution... Too bad, I hoped to see some improvements on NAnt which is far from being perfect as well... but at least behaves consistently.Anonymous
September 07, 2007
You can use CreateItem instead of ItemGroups. Here is a reference to Brennan's blog.Anonymous
January 10, 2008
The comment has been removedAnonymous
April 15, 2008
The comment has been removedAnonymous
May 21, 2008
Thanks for the tip about using the exec command "I just use an Exec like this: <Exec Command="del wix*.wxs"/>" However, I get a strange behavior in VS 2008. The following works fine <Exec Command="del $(ReleaseDirectory).txt" /> But it won't take a double wildcard <Exec Command="del $(ReleaseDirectory)." /> or a single wildcard like this <Exec Command="del $(ReleaseDirectory)" /> Returning The command "del ProjectRelease*.*" exited with code 1. I don't know if I am doing something wrong, but I just thought I would mention this in case anyone else sees this behavior.Anonymous
August 08, 2008
@Boomer to delete directory/* or directory/., you are basically deleting the directory <RemoveDir Directories="$(OutputPath)dir" /> value can be semi-colon delimited string of directories if you need to add it back in, just use <MakeDir Directories="$(OutputPath)dir" /> now you've only used two lines, got around the exec bug, and kept yourself from using all of the steps needed for ItemGroupAnonymous
August 24, 2008
PingBack from http://www.1160pm.net/?p=34Anonymous
February 17, 2009
This post in incorrect, if you use wildcards in the include attribute of a tag in an itemgroup, the delete task will not work either!Anonymous
September 23, 2009
@Mike: Working fine for me. Just used Alexander M's example.Anonymous
December 02, 2009
It looks like <Exec Command="del $(ReleaseDirectory)*.txt" /> doesn't work because the $(...) evaluates to an empty string so the result becomes "del .txt" I tried "del @(ReleaseDirectory).txt" but it doesn't work because @(...) evaluates to everything that matches so the result becomes something like "del readme.txt;otherfile.txt;echelon.txt" which doesn't work. I still havn't found out how delete with wildcards in msbuild.Anonymous
January 05, 2010
Your wildcard examples are failing because by default the DEL command prompts for confirmation. If you add the /Q option it will succeed. You can also add the /S option to make it recursive and /F to force it to delete read-only files: <Exec Command="del /Q /F /S $(ReleaseDirectory)." /> This won't delete subdirectories, though.Anonymous
February 04, 2010
I have done with the following, but it seems nothing is deleted. <ItemGroup> <BinDirectories Include="$(dist)samplesrcbin"/> <ObjDirectories Include="$(dist)samplesrcobj"/> </ItemGroup> <RemoveDir Directories="@(BinDirectories)"/> <RemoveDir Directories="@(ObjDirectories)"/>Anonymous
August 12, 2010
Wow! Did any of you test what you were suggesting? :) The "Delete" task works just like "<Exec Command="del ..." /> and this will only delete files, leaving the directory and any sub-directories. The "RemoveDir" task would be valid, but will error if the directory is not empty. To fix all of the suggestions for someone who is attempting to wipe-out an entire directory, use the following: <Exec Command="RMDIR /S /Q {PATH}" /> ... where {PATH} is your path. For example, I need to delete some content files (MVC Views) that get dumped in the /bin directory from a badly coded "Preview" assembly from Microsoft :P. So, I add the task to an "AfterBuild" target... <Exec Command="RMDIR /S /Q $(OutputPath)Views" /> to delete the "Views" directory and anything inside it that is copied by the build into the "bin" directory.Anonymous
June 23, 2011
<ItemGroup> <TempFiles Include="C:BuildTempDir*" /> </ItemGroup> <Target Name="Clean"> <Delete Files="@(TempFiles)" /> </Target> This works for me.