none
TFS2008 recursively copying files not always works (compiling vs2003) (AfterCompile target)

    Question

  • Hi All, I'm having some strange problems copying files in a custom script in TFS2008 without SP1, I have to run the build several times to get the files copied (most of the times its in the second build that i get the files), let me give you the details:

    This is happening with ASP sites and VS2003 Web solutions,  (vs2008 solutions are OK)
    In ASP I have a dummy 2008 solution, the build compiles this dummy, I override AfterCompile and in there I copy all the files to the drop location
    In VS 2003 i have also a dummy 2008 solution, the build first compiles the dummy, I override AfterCompile,  use "Exec" and "Command" to compile the 2003 solution and then copy the files to the drop location.

    As you can see both approaches are similar, I'm not having problems with the builds per se, my problem is reproducible in two ways (and yes, i do check out, update, check in and then test the build):

    1. Create a new build, configure the script, run the build the first time, some DLL's in the bin folder are not copied, run the build for the second time and i get all the files.

    2. Build already configured and running OK, add some file to the project (this mostly happens with the ASP sites), run the build, don't get this new file, run the build again and i get this new file.

    Here is my build script for a VS2003 Web solution as an example

    <PropertyGroup>  
        <TasksPath>D:\BuildTools\</TasksPath>  
            <VS2003Devenv>D:\Archivos de programa\Microsoft Visual Studio .NET 2003\Common7\IDE\devenv.com</VS2003Devenv>  
            <VS2003VirtualFolder>CnbvPifWeb</VS2003VirtualFolder>  
            <VS2003Suba>Cnbv.Pif.Web</VS2003Suba>  
            <VS2003Project>Cnbv.Pif.Web</VS2003Project>  
            <VS2003WebSiteName>Sitio Web predeterminado</VS2003WebSiteName>  
            <VS2003Configuration>Release</VS2003Configuration>  
            <VS2003Branch>Desarrollo</VS2003Branch>  
            <VS2003RelativePath>$(SolutionRoot)\$(VS2003Branch)\$(VS2003Suba)\</VS2003RelativePath>  
            <VS2003SolutionPath>$(VS2003RelativePath)Cnbv.Pif.Web.sln</VS2003SolutionPath>  
            <VS2003LocalFolder>$(VS2003RelativePath)Sources\$(VS2003Project)\</VS2003LocalFolder>  
            <VS2003Output>$(BinariesRoot)\$(VS2003Project)\</VS2003Output>  
            <VS2003CachePath>C:\Documents and Settings\srvfoundation\VSWebCache\230-2555-CPU015\</VS2003CachePath>  
            <VS2003ProjectExtension>vbproj</VS2003ProjectExtension>  
            <VS2003CacheFile>$(VS2003CachePath)$(VS2003VirtualFolder)\_vti_pvt\$(VS2003Project).$(VS2003ProjectExtension).cache</VS2003CacheFile>  
    </PropertyGroup>  
    <Import Project="$(TasksPath)Microsoft.Sdc.Common.tasks"/>  
    <UsingTask TaskName="Microsoft.Sdc.Tasks.Web.WebSite.CreateVirtualDirectory" AssemblyFile="Microsoft.Sdc.Tasks.dll" />  
    <UsingTask TaskName="Microsoft.Sdc.Tasks.Web.WebSite.DeleteVirtualDirectory" AssemblyFile="Microsoft.Sdc.Tasks.dll" />  
    <ItemGroup>  
        <!--list of ouput files, excluding .DLL outside bin and some other files-->  
            <VS2003OutputFiles  
                Include="$(VS2003LocalFolder)**\*.*"  
                Exclude="$(VS2003LocalFolder)**\*.vb;$(VS2003LocalFolder)**\*.cs;$(VS2003LocalFolder)**\*.resx;$(VS2003LocalFolder)**\*.vspscc;$(VS2003LocalFolder)**\*.csproj;$(VS2003LocalFolder)**\*.vbproj;$(VS2003LocalFolder)**\*.scc;$(VS2003LocalFolder)**\*.webinfo;$(VS2003LocalFolder)**\*.snk;$(VS2003LocalFolder)**\*.dll;$(VS2003LocalFolder)**\*.exe;" /> 
        <!-- copy dll to bin folder --> 
            <VS2003OutputBinFiles  
                Include="$(VS2003LocalFolder)bin\*.dll"/>  
    </ItemGroup>  
    <Target Name="AfterCompile">  
        <Message Text="Deleting cache file" />  
            <Microsoft.Build.Tasks.Delete  
                Condition="Exists('$(VS2003CacheFile)')"  
                Files="$(VS2003CacheFile)" />  
            <Message Text="Creating virtual folder $(VS2003VirtualFolder) in IIS in local path $(VS2003LocalFolder)" />  
            <Web.WebSite.CreateVirtualDirectory  
                VirtualDirectoryName="$(VS2003VirtualFolder)"  
                Path="$(VS2003LocalFolder)"  
                WebSiteName="$(VS2003WebSiteName)" />  
            <Message Text="Compiling $(VS2003Project) in $(VS2003Branch)" />  
            <Exec  
                Command="&quot;$(VS2003Devenv)&quot; &quot;$(VS2003SolutionPath)&quot; /build $(VS2003Configuration) /out &quot;$(VS2003LocalFolder)$(VS2003Project).log&quot; "/>  
            <Message Text="Eliminando la carpeta virtual $(VS2003VirtualFolder) en IIS" />  
            <Web.WebSite.DeleteVirtualDirectory  
                WebSiteName="$(VS2003WebSiteName)"  
                VirtualDirectoryName="$(VS2003VirtualFolder)" />  
            <MakeDir Condition="!Exists('$(VS2003Output)')" Directories="$(VS2003Output)" />  
            <Message Text="Copying output files @(VS2003OutputFiles)" />  
            <Copy  
                SourceFiles="@(VS2003OutputFiles)"  
                DestinationFiles="@(VS2003OutputFiles->'$(VS2003Output)%(RecursiveDir)%(Filename)%(Extension)')"  
            />  
            <MakeDir Condition="!Exists('$(VS2003Output)bin\')" Directories="$(VS2003Output)bin\" />  
            <Message Text="Copying DLL to bin folder @(VS2003OutputBinFiles)" />  
            <Copy  
                SourceFiles="@(VS2003OutputBinFiles)"  
                DestinationFiles="@(VS2003OutputBinFiles->'$(VS2003Output)bin\%(Filename)%(Extension)')"  
            />  
            <OnError ExecuteTargets="VS2003Fail" />  
    </Target>  
    <Target Name="VS2003Fail">  
        <Message Text="Copying log file $(VS2003RelativePath)$(VS2003Project).log" />  
            <Copy Condition="Exists('$(VS2003RelativePath)$(VS2003Project).log')" SourceFiles="$(VS2003RelativePath)$(VS2003Project).log" DestinationFolder="$(DropLocation)\$(BuildNumber)" />  
            <CallTarget ContinueOnError ="true" Targets ="CreateWorkItemWhenPartialSucceed" />  
    </Target>  
    <Target  
            Name="CreateWorkItemWhenPartialSucceed"  
            Condition=" '$(SkipWorkItemCreation)'!='true' and '$(IsDesktopBuild)'!='true' ">  
            <Message Text="ejecutando work" />  
            <PropertyGroup>  
                <WorkItemTitle>$(WorkItemTitle) $(BuildNumber)</WorkItemTitle>  
                <BuildLogText>$(BuildlogText) &lt;a href='file:///$(DropLocation)\$(BuildNumber)\BuildLog.txt'&gt;$(DropLocation)\$(BuildNumber)\BuildLog.txt&lt;/a &gt;.</BuildLogText>  
                <ErrorWarningLogText Condition="!Exists('$(MSBuildProjectDirectory)\ErrorsWarningsLog.txt')"></ErrorWarningLogText>  
                <ErrorWarningLogText Condition="Exists('$(MSBuildProjectDirectory)\ErrorsWarningsLog.txt')">$(ErrorWarningLogText) &lt;a href='file:///$(DropLocation)\$(BuildNumber)\ErrorsWarningsLog.txt'&gt;$(DropLocation)\$(BuildNumber)\ErrorsWarningsLog.txt&lt;/a &gt;.</ErrorWarningLogText>  
                <WorkItemDescription>$(DescriptionText) %3CBR%2F%3E $(BuildlogText) %3CBR%2F%3E $(ErrorWarningLogText)</WorkItemDescription>  
            </PropertyGroup>  
            <CreateNewWorkItem  
                TeamFoundationServerUrl="$(TeamFoundationServerUrl)"  
          BuildUri="$(BuildUri)"  
          BuildNumber="$(BuildNumber)"  
          Description="$(WorkItemDescription)"  
          TeamProject="$(TeamProject)"  
          Title="$(WorkItemTitle)"  
          WorkItemFieldValues="$(WorkItemFieldValues)"  
          WorkItemType="$(WorkItemType)"  
          ContinueOnError="true" />  
    </Target>  

    When I see the ouput of this message in the log
    <Message Text="Copying DLL to bin folder @(VS2003OutputBinFiles)" />  

    the first time i see just the name of one file, the second time it prints all the correct files, and the same happens with the ASP sites, if I add a file i see the file in the output in the second build.

    I hope you can help me out figuring this out, thanks a lot.


    Juan Zamudio



    Friday, March 06, 2009 6:54 PM

Answers

  • Hi Juan,

    The problem is that you define your item groups at the root level. This means that they are evaluated immediately when the project file loaded. What you want is for them to be evaluated when the AfterCompile target is executed.

    Since you are running TFS 2008, you can solve this problem by moving the item groups into the AfterCompile target (a.k.a. Dynamic item groups). This will cause the item group to be evaluated by the time the AfterCompile target is executed, and will give you the correct result.

    Regards
    /Jakob
    • Marked as answer by Juansss Monday, March 09, 2009 8:18 PM
    Friday, March 06, 2009 9:00 PM

All replies

  • Hi Juan,

    The problem is that you define your item groups at the root level. This means that they are evaluated immediately when the project file loaded. What you want is for them to be evaluated when the AfterCompile target is executed.

    Since you are running TFS 2008, you can solve this problem by moving the item groups into the AfterCompile target (a.k.a. Dynamic item groups). This will cause the item group to be evaluated by the time the AfterCompile target is executed, and will give you the correct result.

    Regards
    /Jakob
    • Marked as answer by Juansss Monday, March 09, 2009 8:18 PM
    Friday, March 06, 2009 9:00 PM
  • Hi Jakob, i tried your solution and it worked,  I moved the item groups after the Exec task and now is working, thanks a lot for your help.


    Juan Zamudio

    Monday, March 09, 2009 5:01 PM