Search code examples
visual-studiomsbuildvisual-studio-2017microsoft-web-deploy

Publish Profile Copy Files To Relative Destination


I have a publish profile in visual studio 2017 I am trying to copy files from another project. No issues doing so when going to a simple relative directory. However, have a problem with the double recursion going on in the source, making it harder to determine the desired directory.

Source directory: $(MSBuildThisFileDirectory)..\..\..\..Foundation\**\App_Config\**\* gets me the relevant files.

Goes to: <DestinationRelativePath /> using %(RecursiveDir)%(Filename)%(Extension)

Which deploys to: \**\App_Config\**\*.

Not to my desire: \App_Config\**\*

I am missing the trick what ever I place in the <DestinationRelativePath> won't deploy to my desired location. Where am I going wrong? Or is this not possible?

<PropertyGroup>      
    <PipelineCollectFilesPhaseDependsOn>
        GetFoundationConfigFiles;
        GetProjectConfigFiles;
        $(PipelineCollectFilesPhaseDependsOn);
    </PipelineCollectFilesPhaseDependsOn>
</PropertyGroup>

<Target Name="GetFoundationConfigFiles">
    <Message Text="Inside of GetFoundationConfigFiles" Importance="high"/>
    <ItemGroup>
        <_CustomFiles Include="$(MSBuildThisFileDirectory)..\..\..\..\Foundation\**\App_Config\**\*" />
        <FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
            <DestinationRelativePath>App_Config\Include\%(Filename)%(Extension)</DestinationRelativePath>
        </FilesForPackagingFromProject>
    </ItemGroup>
</Target>

<Target Name="GetProjectConfigFiles">
    <Message Text="Inside of GetProjectConfigFiles" Importance="high"/>
    <ItemGroup>
        <_CustomFiles1 Include="$(MSBuildThisFileDirectory)..\..\..\..\Feature\**\App_Config\**\*" />
        <FilesForPackagingFromProject Include="%(_CustomFiles1.Identity)">
            <DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
        </FilesForPackagingFromProject>
    </ItemGroup>
</Target>

Solution

  • Decided to execute Powershell was the best option. Instead of doing Web Deploy I switched to File System publish in Visual Studio 2017.

    Using the publish profile I execute powershell script passing it two parameters.

    1. My solution directory
    2. Path we are deploying app too.

    What is great is I can check-in my .pubxml and use the .pubxml.user which is not checked-in file to define 2). This allows each developer to use the same publish profile locally.

    If anyone knows how to have custom variables in publish profiles that'd be great, restricted to passing through what we have from publishing profiles when calling command at the moment.

    Publish Profile .pubxml

    <?xml version="1.0" encoding="utf-8"?>
    <!--
    This file is used by the publish/package process of your Web project. You can customize the behavior of this process
    by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
    -->
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <WebPublishMethod>FileSystem</WebPublishMethod>
        <PublishProvider>FileSystem</PublishProvider>
        <LastUsedBuildConfiguration>Debug</LastUsedBuildConfiguration>
        <LastUsedPlatform>Any CPU</LastUsedPlatform>
        <SiteUrlToLaunchAfterPublish />
        <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
        <ExcludeApp_Data>False</ExcludeApp_Data>
        <DeleteExistingFiles>False</DeleteExistingFiles>
        <PipelineDependsOn>
          CopyAssets;
          $(PipelineDependsOn);
        </PipelineDependsOn>
      </PropertyGroup>
      <Target Name="CopyAssets">
        <Message Text="Inside of CopyAssets" Importance="high"/>
        <Exec Command="%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe -File &quot;$(SolutionDir)Foundation\Scripts\Powershell\CopyAssets.ps1&quot; $(SolutionDir) $(publishUrl)"/>
      </Target>
    </Project>
    

    Publish Profile .pubxml.user

    <?xml version="1.0" encoding="utf-8"?>
    <!--
    This file is used by the publish/package process of your Web project. You can customize the behavior of this process
    by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
    -->
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <TimeStampOfAssociatedLegacyPublishXmlFile />
        <_NewBackgroundProfile>False</_NewBackgroundProfile>
        <_PublishTargetUrl>C:\inetpub\wwwroot\mywebapp</_PublishTargetUrl>
      </PropertyGroup>
    </Project>
    

    CopyAssets.ps1

    #
    # CopyAssets.ps1
    #
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$True)]
        [string]$solutionDirectory,
    
        [Parameter(Mandatory=$True)]
        [string]$copyTo
    )
    
    #
    # Copy Assets Initializations
    #
    # Absolute path to copy files to and create folders in
    $absolutePath = @($copyTo + "/App_Config/Include")
    # Set paths we will be copy files from
    $featureDirectory = Join-Path $solutionDirectory "/Feature/*/App_Config/Include"
    $foundationDirectory = Join-Path $solutionDirectory "/Foundation/*/App_Config/Include"
    
    function Create-Files {
        Param ([string]$currentPath, [string]$pathTo)
        Write-Host "Attempting to create files..."
        # Copy files from root include folder
        $files = Get-ChildItem -Path $currentPath | Where-Object {$_.PSIsContainer -eq $false}
    
        foreach ($file in $files)
        {
            Write-Host "Attempting to copy file:"$file "to"$path
            New-Item -ItemType File -Path $pathTo -Name $file.Name -Force
        }
    }
    
    # Logic to create new directories and copy files over.
    function Copy-Assets {
    
        Param ([string]$directoryBase)
        $path = $absolutePath
        Write-Host "Directory copying from:" $directoryBase
        Write-Host "Creating files found in include folder"
        # Path hack to copy files from directoryBase
        $directoryBaseHack = Join-Path $directoryBase "\*"
        Create-Files -currentPath $directoryBaseHack -pathTo $path
        Write-Host "Getting sub directories to copy from"
        $directories = Get-ChildItem -Path $directoryBase -Recurse | Where-Object {$_.PSIsContainer -eq $true}
        Write-Host "Iterating through directories"
        foreach ($directory in $directories)
        {
            Write-Host "Checking if directory"$directory.Name "is part of absolute path."
            if($absolutePath -match $directory.Name)
            {
                # checking if directory already exists
                Write-Host "Directory is part of absolute path, confirming if path exists"
                $alreadyExists = Test-Path $absolutePath
                if(!$alreadyExists)
                {       
                    Write-Host "Absolute path doesn't exist creating..."
                    New-Item -ItemType Directory -Path $absolutePath -Force
                    Write-Host "All directories in path for Absolute Path created:"$absolutePath
                }
                Write-Host "Directory for"$directory.Name "already exists as it is part of the Absolute Path:" $absolutePath
            }else{
                Write-Host "Joining path with absolute path"
                $path = Join-Path $absolutePath $directory.Name
                Write-Host "Joined path:"$path
    
                Write-Host "Does joined path exist:"$path
                $alreadyExists = Test-Path $path
                if(!$alreadyExists)
                {       
                    Write-Host "Joined path doesn't exist creating..."
                    New-Item -ItemType Directory -Path $path -Force
                    Write-Host "Created new directory:" $path
                }
                Write-Host "Directory for"$path "already exists."
            }
            Write-Host "Creating files found in:" $directory
            Create-Files -currentPath $directory -pathTo $path
        }
    }
    Write-Host "Starting Copying Foundation Files"
    Copy-Assets -directoryBase $foundationDirectory
    Write-Host "Starting Copying Feature Files"
    Copy-Assets -directoryBase $featureDirectory