msbuild include / copy from subdirectory to root directory - possible? - visual-studio-2010

Can I include a file from a subdirectory, but have it placed in the root directory of the bulid instead of its original sub directory?
Example: We have multiple robots.txt files for different release configurations. The files are in the solution as \IncludeTest\Development\robots.txt and \IncludeTest\Production\robots.txt
I can dynamically grab them appropriately using something like:
<ItemGroup Condition=" '$(Configuration)' == 'Development' ">
<Content Include="IncludeTest\Development\robots.txt">
<SubType>Designer</SubType>
</Content>
</ItemGroup>
but when I do that, I maintain the \IncludeTest\Development\ (or \IncludeTest\Production) directory. Any way to just include it in the root directory, where robots.txt is supposed to be?

The above still did not work for me entirely, but I was able to find a work around based on how you set up the itemgroup:
Including the file in the solution as a link puts it in the root directory. And with your $(Configuration) hint, I was able to do this, and just include it dynamically as a link, rather than copy it over to the root.
<Content Include="..\Robots_Source\$(Configuration)\robots.txt">
<Link>robots.txt</Link>
</Content>

Not sure I got your question right, let me know whether this work as you expected:
<ItemGroup>
<Content Include = "IncludeTest\$(Configuration)\robots.txt">
<SubType>Designer</SubType>
</Content>
</ItemGroup>
Copy to root:
<Copy SourceFiles="#(Content)"
DestinationFiles="#(Content ->'..\%(RecursiveDir)%(Filename)%(Extension)')" />
EDIT: It could be problem when files are in nested directories, so try out:
<Copy SourceFiles="#(Content)"
DestinationFiles="#(Content ->'$(MSBuildProjectDirectory)..\%(RecursiveDir)%(Filename)%(Extension)')" />

Related

Change LibSassBuilder output directory

I'm using LibSassBuilder in a Blazor project. I have read the docs and it's unclear to me if the package's config allows you to specify an output directory. I'd prefer to keep my .scss files outside of wwwroot and just place the compiled .css files there-- but I don't see if there's a way to do this. If not, is there a way to specify a file move to wwwroot in the Visual Studio build pipeline?
I'm also developing a Blazor project using LibSassBuilder. This is how I got it to work in my .csproj file:
<PropertyGroup>
<LibSassOutputStyle>compressed</LibSassOutputStyle>
<LibSassOutputStyle Condition="'$(Configuration)' == 'Debug'">expanded</LibSassOutputStyle>
</PropertyGroup>
<ItemGroup>
<CSSFiles Include="**/*.css" />
</ItemGroup>
<Target Name="MoveCSS" AfterTargets="Build">
<Move SourceFiles="#(CSSFiles)" DestinationFolder="wwwroot/css" />
</Target>

msbuild task that works from publish profile to remove specific file

Have 3 json files in my project. For a specific publish profile, using a FileSystem publish and I'm trying to find a way to have a specific file NOT be published to the target folder. This is for a .net core console app.
This is my publish profile, but the file Im trying to restrict from being published is still published to the target folder.
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Debug</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp3.0</TargetFramework>
<PublishDir>D:\projects\test_publish</PublishDir>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<DeleteExistingFiles>false</DeleteExistingFiles>
<ExcludeFilesFromDeployment>appsettings.Test.json</ExcludeFilesFromDeployment>
</PropertyGroup>
</Project>
Note: project file includes these files so they will be in the build output. Might this prevent the appsettings.Test.json from being deleted and hence still get copied over to the publish dir?
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="appsettings.Local.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="appsettings.Test.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
The work-around solution I have come up with is similar to another project I have. It involves taping into the build system and add some extra bits into the csproj file.
So the csproj file would now look like this. It eliminates the file you dont need, and you only need to add a corresponding build config entry and this uses the VS build system to determine which of these json file(s) get output.
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="appsettings.Local.json" Condition=" '$(Configuration)' == 'Debug' " >
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="appsettings.Test.json" Condition=" '$(Configuration)' == 'Test' " >
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
This is my publish profile, but the file Im trying to restrict from
being published is still published to the target folder.
I test it in my local machine and reproduce same issue. Also I find if I use this element in web application like asp.net, it always works. So I assume this element is not supported for publishing .net core console application.
What role does that file play in your project?
1.If your application don't need it in build output directory and publish directory, you can set the Copy to Output Directory to Do not copy.
And then clean your publish folder and publish again to check if it helps.
2.And if you have specific reason that you need the file in build, but need to exclude it from publish folder, trying adding this script into your xx.csproj(Delete Task):
<Target Name="CustomTarget" AfterTargets="_PublishNoBuildAlternative">
<Delete Files="$(PublishDir)\appsettings.Test.json"/>
<!--<Delete Files="$(PublishDir)\appsettings.xxx.json"/>-->
</Target>
You can add MSbuild Conditions like Condition="$(Configuration)=='xxx'" to the targets to make it more flexible.

What is the value of MSBuildThisFileDirectory?

If I have a project structure like this:
\MySolution
\MyProject
ReadMe.md
\build
MyProject.targets
What would the value of $(MSBuildThisFileDirectory) be when used in the MyProject.targets file?
Assuming my solution folder is in the root of C: drive, would it be?..
c:\MySolution\MyProject\build\
In the MyProject.targets file, how would I reference the ReadMe.md file using the $(MSBuildThisFileDirectory)?
Additional information:
MyProject.targets looks like:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)\xxx\ReadMe.md">
<Link>FrameworkTests.feature</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CustomToolNamespace></CustomToolNamespace>
</None>
</ItemGroup>
</Project>
What is the value of MSBuildThisFileDirectory?
It depends on your MyProject.targets. According to the literal meaning of this variable, you could to know ThisFileDirectory means "This File Directory".
Since you have use this argument in the file MyProject.targets, the path should be related to the location of the "this file" MyProject.targets. So the value of this argument should be the directory of this file MyProject.targets.
After install the nuget, the file MyProject.targets should be added to the path:
c:\MySolution\packages\MyProject.1.0.0<YouPackagefolder>\build
You can use a target to output that value in your project file, to accomplish this, unload your project. Then at the very end of the project, just before the end-tag </project>, place below scripts:
<Target Name="TestValue" AfterTargets="build">
<Message Text="#(none)">
</Message>
</Target>

Copy DLL files to bin directory after one-click publishing in VS2010

I have a web application in VS2010 which has a number of DLLs that need to be copied into the bin directory after doing a publish in VS2010.
I've tried putting the following into my .csproj file (which sits in the root folder of the web applications) but it doesn't seem to work:
<Target Name="AfterBuild">
<ItemGroup>
<_CircularDependencies Include="DLLs\Circular\Dependencies\*.dll" />
</ItemGroup>
<Copy
SourceFiles="#(_CircularDependencies)"
DestinationFiles="#(_CircularDependencies->'bin\%(Filename)%(Extension)')"
SkipUnchangedFiles="true" />
</Target>
For bonus points, I have another set of DLLs copied to be copied post-publish, but I want to use one set when doing a debug publish (for Win32) and a different set when doing a release publish (x86).
Thanks!
OK, I've managed to get this working fully. Thanks to the answers provided above, I've been able to add some MS Build commands to the .csproj file to copy the appropriate DLLs from various folders into the bin folder based on the current build configuration. However as these are unmanaged DLLs (i.e. not .NET) I can't create normal references to them and they fail to be copied during the publish. I got around this by dynamically adding the files to the project as 'content'.
The solution came in three parts. Firstly, create an item group for the files near the top of the .csproj file (I've tried to use generic filenames here to make it clearer), with conditions based on the current build configuration:
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<_UnmanagedDLLs Include="Win32DLLs\*.dll" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<_UnmanagedDLLs Include="x64DLLs\*.dll" />
</ItemGroup>
Then add another item group to include these DLLs (as content, not references) in the build:
<ItemGroup>
<Content Include="#(_UnmanagedDLLs->'bin\%(Filename)%(Extension)')" />
</ItemGroup>
Finally, at the bottom of the .csproj file, I do the copy on the AfterBuild target:
<Target Name="AfterBuild">
<Copy SourceFiles="#(_UnmanagedDLLs)" DestinationFiles="#(_UnmanagedDLLs->'bin\%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
</Target>
It means I can do a debug publish for my windows 32 staging box and a release publish for my x64 production box while keeping my bin folder out of SVN.
Once you get the copy working, separate sets for debug/release is easy with a condition:
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<_CircularDependencies Include="DLLs\Circular\Dependencies\*.dll" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<_CircularDependencies Include="DebugDLLs\Circular\Dependencies\*.dll" />
<_CircularDependencies Include="DebugDLLs\Circular\Dependencies\*.pdb" />
</ItemGroup>
If you want your copy to happen after publish, not after build you need to change your target from:
<Target Name="AfterBuild">
to
<Target Name="AfterPublish">

msbuild custom task

I have a custom MSBuild task that takes in a set of JavaScript files, minifies them, and outputs them, with the extension .min.js. When I do a normal build through Visual Studio, it works perfectly and the .min.js files are output to the same directory as the original files. When I try to deploy using the Publish feature in Visual Studio, only the original .js files make it to the publish directory.... How can I get the output of my task to be counted as "content" so that it will end up in the published folder?
EDIT:
I was able to figure it out by adding the Output tag inside my task and then creating an ItemGroup around that:
<Target Name="AfterBuild">
<ItemGroup>
<JavaScriptFiles Include="Scripts\*.js" Exclude="Scripts\*.min.js" />
</ItemGroup>
<JsCompress Files="#(JavaScriptFiles)" OutputPath="Scripts">
<Output TaskParameter="CompressedFiles" ItemName="CompressedFiles" />
</JsCompress>
<ItemGroup>
<Content Include="#(CompressedFiles)" />
</ItemGroup>
</Target>
Build and Publish are separate targets. Add a target to your project, abstract your minification to its own target, then make the AfterBuild and Publish target depend on the minification target. Something like this:
<Target Name="AfterBuild" DependsOnTargets="Build;Minify">
</Target>
<Target Name="Publish" DependsOnTargets="Build;Minify">
</Target>
<Target Name="Minify" DependsOnTargets="Build">
<ItemGroup>
<JavaScriptFiles Include="Scripts\*.js" Exclude="Scripts\*.min.js" />
</ItemGroup>
<JsCompress Files="#(JavaScriptFiles)" OutputPath="Scripts">
<Output TaskParameter="CompressedFiles" ItemName="CompressedFiles" />
</JsCompress>
<ItemGroup>
<Content Include="#(CompressedFiles)" />
</ItemGroup>
</Target>
This snippet, of course, means you have to have a build target, which may or not be the case. For that reason you may need to modify this. Hope this helps!
Change the file properties. Check the Build Action and Copy to Output Directory properties for those files.

Resources