I'm using MSBuild, FLAC and LAME to manage my MP3 collection, but it fails when it encounters a file with a non-ASCII character in the filename.
The following, cut down, project file shows the problem:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0" DefaultTargets="Default">
<PropertyGroup>
<FLAC>"C:\Program Files (x86)\Flac\bin\flac.exe"</FLAC>
</PropertyGroup>
<ItemGroup>
<Decode
Include="D:\Music\Artists\Kruder Dorfmeister\The K&D Sessions\**" />
</ItemGroup>
<Target Name="Default" Inputs="#(Decode)" Outputs="%(Identity).always">
<Exec Command="$(FLAC) --decode "#(Decode)"" />
</Target>
</Project>
When this gets to "D:\Music\Artists\Kruder Dorfmeister\The K&D Sessions\Part One\02 - Jazz Master (K&D Session™).flac", it fails with the following error message:
Default:
"C:\Program Files (x86)\Flac\bin\flac.exe" --decode "D:\Music\Artists\Kruder Dorfmeister\The K&D Sessions\Part One\02
- Jazz Master (K&D SessionT).flac"
02 - Jazz Master (K&D SessionT).flac: ERROR initializing decoder
init status = FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE
An error occurred opening the input file; it is likely that it does not exist
or is not readable.
As you can see, something is munging the "™" and converting it to "T".
But what? And how can I fix this?
The built-in MSBuild Exec task writes the given command to a batch file and then runs it with cmd /c /q. Unfortunately, it writes the batch file with the OEM code page.
This means that Unicode filenames are mangled.
You'll have to write your own Exec (or Pipe, or even ConvertMusic) task instead.
Related
I am trying to build a pair of WiX patch projects (the Patch Creation ones..) in parallel however my 64-bit configuration one always fails with PatchWiz errors:
INFO: Passed all of the main control parameter validation to PatchWiz, now calling the next 5 phases.
INFO: Phase I: Entered validation and processing phase.
ERROR: Internal PatchWiz Error occurred.
ERROR: The Last Error Received is: 0x20 (32)
INFO: Temporary folder is about to be cleaned out and deleted: C:\Users\TestUser\AppData\Local\Temp\~pcw_tmp.tmp
ERROR: Internal PatchWiz Error occurred.
ERROR: The Last Error Received is: 0x91 (145)
ERROR: During cleanup, could not delete the temporary folder: C:\Users\TestUser\AppData\Local\Temp\~pcw_tmp.tmp.
ERROR: The Last Error Received is: 0x91 (145)
I tried:
cleaning temp folder before running.
switching the configuration order.
adding a sleep/timeout between executions
with no luck.
Here is my build.proj I am executing:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\MSBuild.Extension.Pack.1.8.0\build\net40\MSBuild.Extension.Pack.targets" Condition="Exists('packages\MSBuild.Extension.Pack.1.8.0\build\net40\MSBuild.Extension.Pack.targets')" />
<PropertyGroup>
<ProductVersion>1.1.2</ProductVersion>
</PropertyGroup>
<Target Name="Compile32">
<MSBuild Targets="Build" Projects="Hotfix_Patch.wixproj"
Properties="Configuration=Debug;Platform=x86;ProductVersion=$(ProductVersion)" />
</Target>
<Target Name="Compile64">
<MSBuild Targets="Build" Projects="Hotfix_Patch.wixproj"
Properties="Configuration=Debug;Platform=x64;ProductVersion=$(ProductVersion)" />
</Target>
<Target Name="Build" >
<MSBuild.ExtensionPack.Framework.Parallel TaskAction="BuildTargetsInParallel" Targets="Compile64;Compile32"/>
</Target>
</Project>
Am I at the mercy of PatchWiz? Or is there something I might be doing wrong? Any hack ideas? (and don't say I'm doing it wrong by Patching/MSP in the first place! I realize that! Aside from this I'm a Major Upgrade MSI kind of guy).
The second patch creation process is trying to trample over the first's temp files luckily C:\Users\TestUser\AppData\Local\Temp\~pcw_tmp.tmp. is just a default. You can to specify another buildarch specific temp folder:-
If using MSIMSP.exe use /f on your cmd line
see msimsp.exe docs here
If using patchwiz directly, it's a parameter of UICreatePatchPackage see PatchWiz docs here
p.s. Was a good day when I found this out :)
I'm trying to use a build script to run the dotless.compiler.exe to compile my .less files into .min.css on build:
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/MsBuild/2003">
<!--
This MSBuild Script will compile all [*.less] files in the /CSS folder to their [*.min.css] counterparts.
-->
<ItemGroup>
<LessFiles Include="Styles\*.less" />
</ItemGroup>
<Target Name="CompileDotlessCss" AfterTargets="AfterBuild">
<ItemGroup>
<Binaries Include="*.dll;*.exe"/>
</ItemGroup>
<!-- Compile dotLess CSS into minified full CSS -->
<Exec Command="[MSBuild]\dotless.compiler.exe -m %(LessFiles.FullPath) $([System.String]::Copy('%(LessFiles.FullPath)').Replace('.less','.min.css'))" />
</Target>
</Project>
But when I build I get:
The command "[MSBuild]\dotless.compiler.exe -m C:\Source Control\MyProject\MyProject.Web\Styles\main.less C:\Source Control\MyProject\MyProject.Web\Styles\main.min.css" exited with code -1.
I suspect it has to do either with my project being under source control or simply the fact that the file path has a space in the "Source Control" folder.
How can I wrap the path in quotes (since the command itself is in quote)?
If it's the source control factor and it fails because the files are locked (I tried building with the file checked in).. how do I deal with this? I obviously want to keep my project under source control.
You can use "" and '' interchangeably in MSBuild files, inc. for paths with spaces, worst cases might require XML escapes like ". For better output beyond exit code try to up verbosity to detailed or diagnostic, may be it's something to do with [MSBuild], shouldn't it be a $() property?
I am executing MSBuild from a batch file. The MSBuild script is in a different directory than the directory I want MSBuild to consider the working directory when running the script. When invoking MSBuild.exe, how do I change its working directory?
Edit: More details
Let's say I have an MSBuild script located on some other server. I want to run a command thusly:
msbuild.exe \\my_server\c$\My\Path\To\Scripts\TestScript.msbuild
I run that command with my command prompt at c:\temp. Let's say my TestScript.msbuild has a task to create a file. The file has no path just a filename. I would expect that the file gets created inside c:\temp. But it doesn't it gets created next to the msbuild file that is sitting on the server. This is the behavior I want to change.
Edit #2
Here is the script I'm using in my test:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Files Include="HelloWorld.txt" />
</ItemGroup>
<Target Name="TouchFiles">
<Touch Files="#(Files)" AlwaysCreate="True" />
</Target>
</Project>
I am going into a command shell CDing into c:\temp and then executing the script. With or without the /p:OutDir switch that #Nick Nieslanik mentions, the HelloWorld.txt file appears in the folder where the *.msbuild file is and not c:\temp.
I ran across this while looking for a solution to my problem. Here's my solution (build script):
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Default">
<Exec Command="build.bat" WorkingDirectory="..\[your dir]\" />
</Target>
</Project>
I believe that's more what you were originally looking for?
My problem was that my batch file called another that it expected to be in the same directory, but since my ms build script was being run elsewhere, the batch file failed to find the second batch file.
#jkohlhepp - I see now. You are doing the opposite of what I described in my comment to some degree.
MSBuild common targets use the MSBuildProjectDirectory to determine the output folder unless you override that. So in your case, you could run
msbuild.exe \\my_server\c$\My\Pat\To\Scripts\TestScript.msbuild /p:OutDir=c:\temp
to force the output to be dropped in that location.
EDIT:
Given the project file above, you'd need to edit it to do something like the following for this to work:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutDir Condition=" '$(OutDir)' == '' ">bin\debug\</OutDir>
</PropertyGroup>
<ItemGroup>
<!-- Without prefacing files with paths, they are assumed relative to the proj file -->
<FilesToCreate Include="$(OutDir)HelloWorld.txt" />
</ItemGroup>
<Target Name="TouchFiles">
<Touch Files="#(FilesToCreate)" AlwaysCreate="True" />
</Target>
</Project>
In current versions of MSBuild the well-known property MSBuildStartupDirectory can be used in the msbuild file to retrieve the absolute path of the folder where MSBuild is called.
https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-reserved-and-well-known-properties?view=vs-2019
This option perhaps did not exist in msbuild around the time when the question was asked. I didn't want to spend too much time investigating it.
I am trying to specify some additional targets/tasks to an msbuild file by extending an existing msbuild file (a web applicartion .csproj file). The idea is to put configuration specific tasks in this "extended ms build file" and use this file in our build server (TeamCity). The way I tried to solve it at first was to add a folder "msbuildscripts" to my web project and put the extended ms build file there:
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<Import Project="../My.Web.csproj" />
...more stuff...
</Project>
and then build this file using something like:
c:\myweb\msbuild.exe msbuildscripts/extended.msbuild.file.xml
Now, this wont work because when importing the original ms build file, that csproj file will be "executed" in the "wrong" folder (msbuildscripts), and the csproj-build-file wont find any of its referenced folders/items.
Is there any way to tell msbuild.exe to use a specific working directory? I know it is possible to solve this problem using an execute task, but that doesnt seem like a good solution.
Use MSBuild task like this:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="MyBuild">
<ItemGroup>
<ProjectToBuild Include="../My.Web.csproj" />
</ItemGroup>
<Target Name="MyBuild">
<MSBuild Targets="Build" Projects="#(ProjectToBuild)"></MSBuild>
</Target>
</Project>
I have Windows application in csproj in my solution, and I want generate Publish using command line (bat, cmd).
My script is (I put \r\n for better reading):
SET MSBUILD="%SystemRoot%\Microsoft.NET\Framework\v3.5\MSBuild.exe"
SET CARWIN="..\..\Security.CarWin.csproj"
rem msbuild para publish
%MSBUILD% /target:rebuild;publish %CARWIN%
/p:ApplicationVersion="1.0.0.0"
/p:Configuration=release
/p:PublishUrl="C:\ClickOnce\CarWin.WebInstall\Publicacion\"
/p:InstallUrl="http://desserver/carwinclickonce/Publicacion/"
/p:PublishDir="C:\ClickOnce\CarWin.WebInstall\Publicacion\"
note: I'll try too using /target:publish
But in path PublishDir or PublishUrl (C:\ClickOnce\CarWin.WebInstall\Publicacion) not generates any files.
I have seen many posts in this site and google but I not found any solution.
Use PublishDir instead of PublishUrl when running from command line.
msbuild /target:publish /p:Configuration=Release;PublishDir=c:\playground\
You can also change version, like ApplicationRevision=666;MinimumRequiredVersion=1.1
Take a look at this Stack Overflow question. Basically the PublishUrl property is ignored when running ClickOnce from the command line. But you can easily add the behaviour with an additional MSBuild-task.
I've created an additional MSBuild-File, for example a build.csproj. This contains a publish-task. This task first invokes the regular MS-Build of the target-project. Afterwards it copies the result to the publish-directory. Now I invoke the 'build.csproj' instead of the reguar project-file from the command-line:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Publish" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- project name-->
<ProjectName>MyExampleProject</ProjectName>
<!--properties for the project-build-->
<DefaultBuildProperties>Configuration=Release</DefaultBuildProperties>
<!-- location of the click-once stuff, relative to the project -->
<ProjectPublishLocation>.\bin\Release\app.publish</ProjectPublishLocation>
<!-- Location you want to copy the click-once-deployment. Here an windows-share-->
<ProjectClickOnceFolder>\\TargetServer\deployments</ProjectClickOnceFolder>
</PropertyGroup>
<Target Name="Publish" DependsOnTargets="Clean">
<Message Text="Publish-Build started for build no $(ApplicationRevision)" />
<!-- run the original build of the project -->
<MSBuild Projects="./$(ProjectName).csproj"
Properties="$(DefaultBuildProperties)"
Targets="Publish"/>
<!-- define the files required for click-once-->
<ItemGroup>
<SetupFiles Include="$(ProjectPublishLocation)\*.*"/>
<UpdateFiles Include="$(ProjectPublishLocation)\Application Files\**\*.*"/>
</ItemGroup>
<!-- and copy them -->
<Copy
SourceFiles="#(SetupFiles)"
DestinationFolder="$(ProjectClickOnceFolder)\"/>
<Copy
SourceFiles="#(UpdateFiles)"
DestinationFolder="$(ProjectClickOnceFolder)\Application Files\%(RecursiveDir)"/>
</Target>
<Target Name="Clean">
<Message Text="Clean project" />
<MSBuild Projects="./$(ProjectName).csproj"
Properties="$(DefaultBuildProperties)"
Targets="Clean"/>
</Target>
</Project>
I don't know if this is a problem, but I noticed that you pass the /target parameter twice?
you could you use a semi-colon delimited example:
/target:rebuild;publish
MSDN Documentation on command line parameters and MSBuild
If that also does not work you could perhaps try to debug it by passing
/verbosity:diag