Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronize two folders using MSBUILD

Tags:

msbuild

I wonder how to synchronize two folders including subfolders using MSBuild.

What I like to do is

a) to copy all files from the source folder to the dest folder that are newer or don't exist in the dest folder

and

b) to remove all files from the dest folder that don't exist (anymore) in the source folder

a) is pretty easy using the <Copy> task but how can I accomplish b) ?

This is my build file so far:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 
    ToolsVersion="4.0" 
    DefaultTargets="Backup">
    <PropertyGroup>
        <SourceFolder>C:\source</SourceFolder>
        <DestFolder>C:\dest</DestFolder>
    </PropertyGroup>
    <ItemGroup>
        <FilesToCopy Include="$(SourceFolder)\**" />
    </ItemGroup>
    <Target Name="Backup">
        <!-- copy all files from the source folder to the dest folder 
            that are newer or don't exist in the dest folder -->
        <Copy 
            SourceFiles="@(FilesToCopy)" 
            DestinationFiles="@(FilesToCopy->'$(DestFolder)\%(RecursiveDir)%(Filename)%(Extension)')" 
            SkipUnchangedFiles="True" />
        <!-- TODO: remove all files from the dest folder 
            that don't exist in the source folder -->
    </Target>
</Project>
like image 824
miasbeck Avatar asked Sep 15 '11 08:09

miasbeck


2 Answers

You can do it with the GetDistinctItems task from MSBuild Extension pack. The basic idea is to get the distinct items between files from the source and the destination folder.

<Project ToolsVersion="3.5" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks" />

  <PropertyGroup>
    <SourceFolder>C:\source</SourceFolder>
    <DestFolder>C:\dest</DestFolder>
  </PropertyGroup>

  <ItemGroup>
    <FilesToCopy Include="$(SourceFolder)\**" />
  </ItemGroup>

  <Target Name="Backup">
    <!-- copy all files from the source folder to the dest folder 
                  that are newer or don't exist in the dest folder -->
    <Copy SourceFiles="@(FilesToCopy)" 
          DestinationFiles="@(FilesToCopy->'$(DestFolder)\%(RecursiveDir)%(Filename)%(Extension)')" 
          SkipUnchangedFiles="True" />

    <!-- Remove all files from the dest folder 
            that don't exist in the source folder -->
    <ItemGroup>
      <DestFiles Include="$(DestFolder)\**"/>
    </ItemGroup>

    <!-- Cannot compare FilesToCopy with DestFiles directly, 
         root folders are different-->
    <ItemGroup>
      <SrcFilesLeave Include="%(FilesToCopy.RecursiveDir)%(FilesToCopy.Filename)%(FilesToCopy.Extension)"/>
      <DestFilesLeave Include="%(DestFiles.RecursiveDir)%(DestFiles.Filename)%(DestFiles.Extension)"/>
    </ItemGroup>

    <MSBuild.ExtensionPack.Framework.MsBuildHelper TaskAction="GetDistinctItems" 
                                                   InputItems1="@(SrcFilesLeave)" 
                                                   InputItems2="@(DestFilesLeave)">
      <Output TaskParameter="OutputItems" ItemName="Distinct"/>
    </MSBuild.ExtensionPack.Framework.MsBuildHelper>

    <Message Text="Distinct %(Distinct.Identity)"/>
    <Delete Files="$(DestFolder)\%(Distinct.Identity)" />
  </Target>

</Project>
like image 115
Julien Hoarau Avatar answered Sep 25 '22 15:09

Julien Hoarau


In case someone don't want or can't install the expansion pack

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 
    ToolsVersion="4.0" 
    DefaultTargets="Backup">
    <PropertyGroup>
        <SourceFolder>C:\source</SourceFolder>
        <DestFolder>C:\dest</DestFolder>
    </PropertyGroup>
    <ItemGroup>
        <FilesToCopy Include="$(SourceFolder)\**" />
    </ItemGroup>
    <Target Name="Backup">
        <!-- copy all files from the source folder to the dest folder 
            that are newer or don't exist in the dest folder -->
        <Copy 
            SourceFiles="@(FilesToCopy)" 
            DestinationFiles="@(FilesToCopy->'$(DestFolder)\%(RecursiveDir)%Filename)%(Extension)')" 
            SkipUnchangedFiles="True">
            <Output TaskParameter="CopiedFiles" ItemName="Copied"/>
         </Copy>
         <ItemGroup>
            <OutdatedFiles Include="$(DestFolder)\**" Exclude="@(Copied)"/>
         </ItemGroup>
         <Delete Files="@(OutdatedFiles)"/>
    </Target>
</Project>
like image 36
Mikey Avatar answered Sep 24 '22 15:09

Mikey