.NET Framework Developer Center > .NET Development Forums > MSBuild > Recursive Delete - A real Clean build
Ask a questionAsk a question
 

AnswerRecursive Delete - A real Clean build

  • Monday, March 13, 2006 10:26 PMmonsoondawn Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I'm having trouble recursively deleting through MSBuild. All the examples I've seen of the RemoveDir Task assume a single folder as the input. This is useless to me because the project I'm building a web project so the root deployment folder is always locked by IIS. Here's my folder structure:

    • Build Root
      • Version
        • Source
        • Compiled
      • Deploy
      • Archive

    Build Root: where the msbuild file sits
    Version: Container folder for Source & Compiled
    Source:
    Latest uncompiled source code from version control (Subversion)
    Compiled: Target for compilation of Source
    Deploy:
    Website virtual root
    Archive: Zip archives of previous successful builds

    The trouble is the Deploy folder. I am able to easily delete every file in Deploy using the Delete Task and an ItemGroup array but I cannot seem to do the same thing for folders.

    <ItemGroup>
      <DeployCleanFiles Include="$(DeployRoot)\**\*.*" />
      <DeployCleanFolders Include="$(DeployRoot)\**" />
     </ItemGroup>

    <Target Name="Deploy">
      <Delete Files="@(DeployCleanFiles)" />
      <RemoveDir Directories="@(DeployCleanFolders)" />
      <CreateItem Include="$(VersionCompiled)\**\*.*">
       <Output TaskParameter="Include" ItemName="DeploySourceFiles" />
      </CreateItem>
      <Copy
       SourceFiles="@(DeploySourceFiles)"
       DestinationFolder="$(DeployRoot)\%(DeploySourceFiles.RecursiveDir)"
       ContinueOnError="true"
      />
     </Target>

Answers

  • Wednesday, March 15, 2006 12:36 AMJeffery CallahanModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Ultimately there's no good way to get a directory listing without writing a custom task.  I'll open a bug on this.

    Here's an admittedly hacky way to do this w/o writing a custom task, using the Exec command:

    <PropertyGroup>
             <DeployRoot>.\Deploy</DeployRoot>
    </PropertyGroup>

    <!-- this item will contain all FILES underneath $(DeployRoot) -->
    <ItemGroup>
          
    <DeployCleanFiles Include="$(DeployRoot)\**\*.*" />
    </ItemGroup>

    <Target Name="Deploy">

            <Message Text="Clean Folders @(DeployCleanFolders)" />
            <Delete Files="@(DeployCleanFiles)" />
            <Exec Command="for /f %%d in ('dir /ad /b') do rd /s /q %%d"
                        WorkingDirectory="$(DeployRoot)" />

           <CreateItem Include="$(VersionCompiled)\**\*.*">
                <Output TaskParameter="Include" ItemName="DeploySourceFiles" />
            </CreateItem>
            <Copy
                SourceFiles="@(DeploySourceFiles)"
                DestinationFolder="$(DeployRoot)\%(DeploySourceFiles.RecursiveDir)"
                ContinueOnError="true"
            />
     </Target>

All Replies

  • Tuesday, March 14, 2006 10:48 PMJeffery CallahanModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi monsoondawn,

    What problem are you having?  Are some but not all folders deleted?  Are you seeing an error?  A snippet from your build log while it's building the "Deploy" target would also help me figure out what's happening.

    Thanks,

    jeff.

  • Tuesday, March 14, 2006 11:12 PMmonsoondawn Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Assume that I have no way of knowing how many folders any particular compilation will produce. But I need to make sure every single folder under Deploy is deleted prior to running another compilation. Deploy has to be completely emptied but I am not allowed to just delete and recreate the Deploy folder.

    Here's a snippet of what I tried:

    <PropertyGroup>
    <DeployRoot>.\Deploy</DeployRoot>
    </PropertyGroup>

    <ItemGroup>
    <DeployCleanFolders Include="$(DeployRoot)\**\*.*" />
    </ItemGroup>

    <Target Name="Deploy">
    <Message Text="Clean Folders @(DeployCleanFolders)" />
            <Delete Files="@(DeployCleanFiles)" />
            <RemoveDir Directories="@(DeployCleanFolders)" />
            <CreateItem Include="$(VersionCompiled)\**\*.*">
                <Output TaskParameter="Include" ItemName="DeploySourceFiles" />
            </CreateItem>
            <Copy
                SourceFiles="@(DeploySourceFiles)"
                DestinationFolder="$(DeployRoot)\%(DeploySourceFiles.RecursiveDir)"
                ContinueOnError="true"
            />
        </Target>

    Now of course this doesn't work because there is no way to obtain just a list of folders with writing a custom task. I could of course hard-code in a list of folders but that's really not efficient. I'm not going to update the build script every time someone on the team requires a new folder.
  • Wednesday, March 15, 2006 12:36 AMJeffery CallahanModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Ultimately there's no good way to get a directory listing without writing a custom task.  I'll open a bug on this.

    Here's an admittedly hacky way to do this w/o writing a custom task, using the Exec command:

    <PropertyGroup>
             <DeployRoot>.\Deploy</DeployRoot>
    </PropertyGroup>

    <!-- this item will contain all FILES underneath $(DeployRoot) -->
    <ItemGroup>
          
    <DeployCleanFiles Include="$(DeployRoot)\**\*.*" />
    </ItemGroup>

    <Target Name="Deploy">

            <Message Text="Clean Folders @(DeployCleanFolders)" />
            <Delete Files="@(DeployCleanFiles)" />
            <Exec Command="for /f %%d in ('dir /ad /b') do rd /s /q %%d"
                        WorkingDirectory="$(DeployRoot)" />

           <CreateItem Include="$(VersionCompiled)\**\*.*">
                <Output TaskParameter="Include" ItemName="DeploySourceFiles" />
            </CreateItem>
            <Copy
                SourceFiles="@(DeploySourceFiles)"
                DestinationFolder="$(DeployRoot)\%(DeploySourceFiles.RecursiveDir)"
                ContinueOnError="true"
            />
     </Target>

  • Thursday, August 07, 2008 1:37 PMDriesie Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
     All the File System tasks in MSBuild are so incredibly rubish you wouldn't believe. I tend to rely on the native DOS commands (xcopy ...). In your example, I would do:

    <Exec Command="RmDir /S $(DeployRoot)" />


     Alternatively, you could off course use a propper build tool ;)

  • Thursday, August 07, 2008 9:17 PMMike Fourie [MVP]ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    You could also try the following task

    <FTDFolder TaskAction="RemoveContent" Path="c:\Demo"/>

    That will remove all files and folders, but leave c:\Demo. If there are readonly files, pass in Force="true".

    All available here: http://www.codeplex.com/freetodevtasks. (A new release is due in the next few days...)