Anicho
Anicho

Reputation: 2667

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>

Upvotes: 3

Views: 4216

Answers (2)

Anicho
Anicho

Reputation: 2667

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

Upvotes: 4

Leo Liu
Leo Liu

Reputation: 76760

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

It looks like impossible to use filter and merge in the internal double recursion.

As we all know, \**\*.* help to get files from all the folder. RecursiveDir help to put all the file in the respective folder. When you use **\App_Config\** to get your files from all the parent folder and sub folder, RecursiveDir will put all the file in the respective folder(parent folder and sub folder) by double recursion. We could not insert the filter and merge in the process of recursion. What can we do is publish all those files to a folder:

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

Not sure if this result is what you want, if you want to get all files without parent folder, it looks you should specify the parent folder when you get all files:

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

Upvotes: 0

Related Questions