I am using TailwindCSS in my Blazor project and I want to automatically regenerate the CSS whenever a file changes.
I found that it's possible to call any command after a build using Targets in the .csproj file.
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="npx tailwindcss -i ./Styles/tailwind.css -o ./wwwroot/css/tailwind.css"/>
</Target>
However, this only works when building the project and not during a hot reload. How can I call this command during hot reload as well?
Related
I would like to perform postBuild action in MS Visual Studio 2022 / C# project.
The action is to copy the executable into a different folder. However the folder is not yet created so the copy instruction fails. How to use the copy instruction in a way it creates the required directory or something other like mkdir? Is anywhere a list of available commands?
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="MKDIR $(SolutionDir)Outputs
copy /Y $(TargetDir)$(TargetName).exe $(SolutionDir)Outputs\$(TargetName).exe" />
</Target>
I am trying to compile my .NET Core application where all the assemblies are as one .exe and certain .csv and .txt files remain in the output.
I am using this command to compile as one .exe: dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true
However, when I use this, my csv and txt files are not included in the output and my application does not work. I have tried setting their 'Copy to Output Directory' value as true, but this does not fix it.
How can I do this?
Answer found:
You must add the <ExcludeFromSingleFile>true</ExcludeFromSingleFile> tag to your project.csproj file items.
eg.
<None Update="additionaldata.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</None>
I generate a nuget package from a project with this command in the post-build event. the variable %conf% is set to the right configuration (debug or release) and %1 is the project name (e.g. "MyCompany.MyProject").
nuget pack -Prop Configuration=%conf% "%1.csproj" -exclude *.sql -IncludeReferencedProjects
This package is for our own usage only, it will never be published on nuget. It ends in our private repository.
In the project, there is a file that is set to generate action : content and copy local : always. (My Visual Studio is in French, so I'm not 100% sure of the translation). Let's name it importantfile.xml.
In the generated package, I end up with this structure :
- content
- importantfile.xml
- lib
-net45 (.NetFramework,Version=v4.5)
-MyCompany.MyProject.dll
Which is fine, I want importantfile.xml to be deployed in the package, because, well, this file is important!
When I install the package in another project, importantfile.xml is deployed at the root of the project. That's OK. But it is not set to copy local : always.
I need importantfile.xml to be copy local : always in this project where I install my package.
How can I achieve that?
Notes :
I can set copy local : always on the file just after installing the package, that's no big deal. I would live with it if later updates of the package would let this property as-is, which is not the case. When updating the package, copy local is reset to never (as stated here).
There's a nuspec file in the project's folder, here it is :
<?xml version="1.0"?>
<package >
<metadata>
<id>$id$</id>
<version>$version$</version>
<title>$title$</title>
<authors>$author$</authors>
<owners>$author$</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<copyright>Copyright 2014</copyright>
<tags>some random tags</tags>
</metadata>
</package>
Instead of using a PowerShell script another approach is to use an MSBuild targets or props file with the same name as the package id:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)importantfile.xml">
<Link>importantfile.xml</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
In the nuspec file then, instead of adding the required files to the Content directory, add them to the Build directory along with the targets file.
Build
importantfile.xml
MyPackage.targets
lib
net45
MyAssembly.dll
If you require different content for different architectures then you can add architecture folders under Build also each with their own targets file.
Benefits to using a targets file over the PowerShell script with NuGet Content directory:
required content files aren't shown in the project in Visual Studio
content files are linked to rather than copied into the directory of each project which references the NuGet package (preventing there being multiple copies and keeping behaviour the same as for assemblies / libraries from NuGet packages)
PowerShell scripts only work in Visual Studio and aren't run when NuGet is run from the commandline (build servers, other IDEs and other OS), this approach will work everywhere
PowerShell install scripts are not supported in NuGet 3.x project.json system.
I know you guys got a working solution to this but it didn't work for me so I'm going to share what I pulled out of the NLog.config NuGet package install.ps1 (github source here).
NOTE: this is not my code, this is the content of the install.ps1 from
the NLog.config nuget package just sharing the knowledge.
It seems a little more straight forward to me and just hoping to help others that will likely stumble upon this.
You can find the accepted int values for BuildAction here and the accepted values for CopyToOutputDirectory here.
if the link breaks again
Fields
prjBuildActionCompile 1
The file is compiled.
prjBuildActionContent 2
The file is included in the Content project output group (see Deploying Applications, Services, and Components)
prjBuildActionEmbeddedResource 3
The file is included in the main generated assembly or in a satellite assembly as a resource.
prjBuildActionNone 0
No action is taken.
param($installPath, $toolsPath, $package, $project)
$configItem = $project.ProjectItems.Item("NLog.config")
# set 'Copy To Output Directory' to 'Copy if newer'
$copyToOutput = $configItem.Properties.Item("CopyToOutputDirectory")
# Copy Always Always copyToOutput.Value = 1
# Copy if Newer copyToOutput.Value = 2
$copyToOutput.Value = 2
# set 'Build Action' to 'Content'
$buildAction = $configItem.Properties.Item("BuildAction")
$buildAction.Value = 2
I have made this which copies files from my build folder to the output folder (bin/debug or bin/release). Works like a charm for me.
Nuspec file:
<package>
<files>
<file src="\bin\Release\*.dll" target="lib" />
<file src="\bin\Release\x64\*.dll" target="build\x64" />
<file src="\bin\Release\x86\*.dll" target="build\x86" />
<file src="MyProject.targets" target="build\" />
</files>
</package>
MyProject.targets
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<NativeLibs Include="$(MSBuildThisFileDirectory)**\*.dll" />
<None Include="#(NativeLibs)">
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
You can use PowerShell and the Install.ps1 hook provided by NuGet.
See the documentation.
Via PowerShell you have to 'search' for the content element which includes your importantfile.xml in an attribute. When the script found it, it has to add <CopyToOutputDirectory>Always</CopyToOutputDirectory> as a child element.
<Content Include="importantfile.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
You can find some PowerShell snippets here. Just take a look at the .ps1 files.
You could try the following (not tested). The file has to be named Install.ps1 and copied into the tools folder:
param($installPath, $toolsPath, $package, $project)
# Load project XML.
$doc = New-Object System.Xml.XmlDocument
$doc.Load($project.FullName)
$namespace = 'http://schemas.microsoft.com/developer/msbuild/2003'
# Find the node containing the file. The tag "Content" may be replace by "None" depending of the case, check your .csproj file.
$xmlNode = Select-Xml "//msb:Project/msb:ItemGroup/msb:Content[#Include='importantfile.xml']" $doc -Namespace #{msb = $namespace}
#check if the node exists.
if($xmlNode -ne $null)
{
$nodeName = "CopyToOutputDirectory"
#Check if the property already exists, just in case.
$property = $xmlNode.Node.SelectSingleNode($nodeName)
if($property -eq $null)
{
$property = $doc.CreateElement($nodeName, $namespace)
$property.AppendChild($doc.CreateTextNode("Always"))
$xmlNode.Node.AppendChild($property)
# Save changes.
$doc.Save($project.FullName)
}
}
You should also check if everything is removed completely when uninstalling the package.
Note by Jonhhy5
When updating the package via update-package, Visual Studio warns that the project is modified "outside the environnment". That's caused by $doc.Save($project.FullName). If I click reload before the command is fully terminated, it sometimes causes errors. The trick is to leave the dialog there until the process finishes, and then reload the projects.
I have written a little tool called NuGetLib to automatically add files to the nuget package after build.
create a tools folder with your Install.ps1 script
build your nugetPackage
add the tools folder to the built nugetPackage
https://stackoverflow.com/a/47134733/6229375
I'm trying to remove a folder (well, actually I thought it was easier to remove the files inside it) from a build using MSBuild scripts.
I thought the way is removing them from the copy task itself, but what I was thinking it was going to see quite straightforward it's not working (I'm sure because I don't have much idea of this stuff, just read documentation yesterday and today). Here is how I'm trying to remove the folder (or the files inside it) ..App_Data/Email Templates with this space (does the space something to do?).
<ItemGroup>
<SourceRootFiles Include="$(BuildFolder)/**/*.*" Exclude="$(BuildFolder)/**/App_Data/Email Templates/*.*">
</SourceRootFiles>
</ItemGroup>
<Target Name="PrepareBuild" DependsOnTargets="CleanUp">
<Message Text="Preparing the build directory : $(LocalBuild)"></Message>
<MakeDir Directories="$(LocalBuild)" />
<Copy SourceFiles="#(SourceRootFiles)" DestinationFolder="$(LocalBuild)\%(RecursiveDir)">
</Copy>
<Exec Command="FOR /r "$(LocalBuild)" %%f IN (.svn) DO RD /s /q "%%f"" IgnoreExitCode="true" />
</Target>
<Target Name="Build" DependsOnTargets="PrepareBuild">
<MSBuild Projects="$(LocalBuild)\Getting.sln" />
</Target>
Update.
Jenkins is raising this error
:\Program Files\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets(1852,5): error : Copying file App_Data\Email Templates\BuyerRegistrationComplete.htm to obj\Latest\Package\PackageTmp\App_Data\Email Templates\BuyerRegistrationComplete.htm failed. Could not find a part of the path 'App_Data\Email Templates\BuyerRegistrationComplete.htm'. [C:\Builds\Getting\Latest\Build\Web\UI\UI.csproj]
Dont' really know if it's exluding it or not
On githup is a project named MsBuildTasks that contains all kind of custom-actions that you can easily integrate in your project
https://github.com/loresoft/msbuildtasks
From your update tells a "new" story.
In your project-file you reference files in the App_Data folder which WebDeployment wants to copy to deployment. Removing App_Data results in missing files and thus failure.
Either move those files to another location in your project or remove the references to those files.
My suggestion would be to make a separate folder for the templates, App_Data has a different purpose.
I run an ASP.NET website solution with a few other projects in it. I've known that MSBuild projects are capable of this, but is it the best way? Are they easy to create? Is nAnt, CruiseControl.NET or any other solution better?
When I build the site (using Web Deployment Projects), can I automate part of the build so that it does not copy certain folders from the project into the Release folder? For instance, I have folders with local search indexes, images and other content part of the folder, but I never need or upload those when deploying the project.
I'm also looking toward this type of solution to automatically increment build and version numbers.
Here's an example of a Web Deployment Project scripting this sort of task in the .wdproj file:
<Target Name="AfterBuild">
<!-- ============================ Script Compression============================ -->
<MakeDir Directories="$(OutputPath)\compressed" />
<Exec Command="java -jar c:\yuicompressor-2.2.5\build\yuicompressor-2.2.5.jar --charset UTF-8 styles.css -o compressed/styles.css" WorkingDirectory="$(OutputPath)" />
<Exec Command="move /Y .\compressed\* .\" WorkingDirectory="$(OutputPath)" />
<RemoveDir Directories="$(OutputPath)\sql" />
<Exec Command="c:\7zip-4.4.2\7za.exe a $(ZipName).zip $(OutputPath)\*" />
</Target>
This would allow you to delete a folder.
(I suspect that if you wanted to not have the folder copy over at all, the solution file would be the place to specify that, though I haven't had to use that.)
MaseBase, you can use Web Deployment Projects to build and package Web Sites. We do that all the time for projects with a web application aspect. After you assign a WDP to a Web Site, you can open up the .wdproj file as plain-text XML file. At the end is a commented section of MSBuild targets that represent the sequence of events that fire during a build process.
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.WebDeployment.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="BeforeMerge">
</Target>
<Target Name="AfterMerge">
</Target>
<Target Name="AfterBuild">
</Target>
-->
You can uncomment the targets you want (e.g. "AfterBuild") and insert the necessary tasks there to carry out your repeated post-build activities.
You can set the Build Action/Copy to Output Directory property on individual files (select the file and hit F4 to open the properties window) to control what happens to them during build, but not for folders. This could probably be automated with a (pre) build task if you don't want to do it manually.
Alternatively, you can exclude these folders from the project (right click and 'exclude from project'); they'll still be there ("show all files" in solution explorer), but they won't be included when building the project.
CruiseControl.NET solves a different problem (continuous integration) ... however, I've had great success with NAnt for specifically what you're asking. There's a learning curve, but once you get proficient you'll wonder how you ever got along w/o it.
In addition to #Fredrik's tip about setting project items to "Copy to Output Directory", you can also specify a post-build action in the project's properties in the Build tab and include CMD commands like copy.exe and move.exe.
We use FinalBuilder to automate a bunch of post build / pre build tasks. There's also a web interface so you can kick off builds (or push websites) by logging in to the web site and clicking a button.
http://www.finalbuilder.com/
Can't you edit the Web Deployment project's MSBuild file for it to do what you want?