Msdeploy not removing the NON-empty directory during deployment - msdeploy

I am getting following error during deployment when there was a folder recursively removed from code. As a workaround i had to manually delete the folder from destination path on server.
Error: (12/26/2018 4:32:27 AM) An error occurred when the request was processed on the remote computer.
Error: An error was encountered when processing operation 'Delete Directory' on 'C:\Alam\Test\MSF\Config'.
Error: The error code was 0x80070091.
Error: The directory is not empty.
at Microsoft.Web.Deployment.NativeMethods.RaiseIOExceptionFromErrorCode(Win32ErrorCode errorCode, String maybeFullPat
h)
at Microsoft.Web.Deployment.DirectoryEx.Delete(String path)
at Microsoft.Web.Deployment.DirPathProviderBase.Delete(Boolean whatIf)
Error count: 1.

I can confirm this bug.
If a file in a directory that should be deleted (i.e. that is not excluded) is excluded then the file does not get deleted and the following rmdir crashes MsDeploy.
Work around
You must exactly ensure that no file exclution rule happens to match to a sub folder that is not excluded.
To satify this condition all file exclution rules must match from the deploy root path only. Otherwise a file in a sub directory may not be deleted and the following directory removal fails.
It can be quite difficult to ensure this, because the initial part of the deploy path ist typically not predictable if you do not always deploy to only one directory on only one server.
Fortunately MsDeploy tends to use different path delimiters for the target directory and the sub directories, e.g.:
Default Web Site/VirtualPath\Folder\File. Note the forward slash and the backslash.
So it is possible to use the forward slash as indicator of the root path.
Example
<MsDeploySkipRules Include="CustomSkipFile">
<ObjectName>filePath</ObjectName>
<AbsolutePath>/[^\\]+\\Custom</AbsolutePath>
</MsDeploySkipRules>
<MsDeploySkipRules Include="CustomSkipFile">
<ObjectName>dirPath</ObjectName>
<AbsolutePath>/[^\\]+\\Custom</AbsolutePath>
</MsDeploySkipRules>
This will exclude all files starting with Custom in the top level and all directories starting with Custom in the top level.
But this will not exclude a file that starts with Custom in a sub directory that does not start with Custom like notCustomDir\Custom.csv.
The /[^\\]+\\ prefix ensures that the following part cannot match to a deeper path because the latter is not delimited with a forward slash.
I would not consider this a sophisticated solution. It is just the only one I got working.

Related

Why does `getResourceAsStream` sometimes load a resource even when there is a typo in the resource path?

I have a Jar (we'll call it a.jar) with a resource in it at path foo/bar.txt and a function as follows:
object FooBarLoader {
fun loadFooBarText() = javaClass.getResourceAsStream("foo//bar.txt")
?.bufferedReader()
?.readLines()
?.joinToString("\n")
}
When I test the function in a unit test (JUnit 4, running with Gradle 6), it loads the text from the resource file despite the obvious typo (the // in the middle of the resource path).
I also have a CLI application (in b.jar) that has a dependency on a.jar. When the CLI application calls loadFooBarText(), it got a null result due to the resource not being found. This was fixed by fixing the typo (// -> /) in the function in a.jar. No other changes were needed to fix it.
So, my question is why did the wrong path work in one situation (unit tests of a.jar) and not the other (call from b.jar)?
How do you run the unit test with a.jar ? Just run it in your IDE or use command java -jar a.jar ?
If you ran it just in IDE,I think difference is the search path between local files and zip files .
Your first application searches the file in your target directory and the second application searches it in the jar which is a compressed file.
When searching files in local path, command will be changed to right one by system.
The two commands below are the same in both Windows/Linux.
cd work//abc/ddd
cd work/abc/ddd
But when searching files in a jar file which is actually compressed zip file, path should be a restrict written or else the program will find nothing.

MSdeploy skip particular file type

I am trying to skip a sub folder and certain file types while deploying a webapp. I tried the below
Test.deploy.cmd /T /M:test.noreply.com /
P:a /G:False "-skip:Directory="Config\\Testdata\\Resx" -skip:filePath,absolutePath="Config\\Testdata\\*.xml""
The above is not working for some reason, am i missing something?
i think below worked for me
-skip:file="Config\\Testdata\\.*\.xml"

Can't deploy precompiled, merged webapp to Azure

I'm trying to deploy an ASP.NET web application to Azure. It's hybrid Web Forms, MVC, and WebAPI, and there are a TON of aspx/ascx files, such that they really need to be precompiled or every deploy will render the site sluggish for awhile.
I am trying to deploy via SCM integration with GitHub via kudu, with precompiled views, all merged to a single assembly.
Note that:
Deploy works fine with precompilation disabled.
Deploy works fine from Visual Studio
Build works fine if I copy the msbuild command from the Azure log, replace the relevant paths, and run it locally on my Windows 8.1 machine.
I've set up the Advanced Precompile settings as:
Don't allow precompiled site to be udpatable
Don't emit debug information
Merge all pages and control outputs to a single assembly = AppViews.dll
Here's the .deployment file for Azure
[config]
project = WebSite/WebSite.csproj
SCM_BUILD_ARGS=/p:Configuration=Release;PublishProfile=azure-prod /v:n
You notice I'm sending the verbosity /v to "normal" for extra diagnostic information.
Here is info I get toward the tail of the deployment log:
AspNetPreCompile:
D:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe -v \ -p D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\Source -c D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\TempBuildDir
GenerateAssemblyInfoFromExistingAssembleInfo:
Creating directory "obj\Release\AssemblyInfo".
D:\Windows\Microsoft.NET\Framework\v4.0.30319\Csc.exe /out:obj\Release\AssemblyInfo\AssemblyInfo.dll /target:library Properties\AssemblyInfo.cs
AspNetMerge:
Running aspnet_merge.exe.
D:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\aspnet_merge.exe D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\TempBuildDir -w AppViews.dll -copyattrs obj\Release\AssemblyInfo\AssemblyInfo.dll -a
aspnet_merge : error 1003: The directory 'D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\TempBuildDir' does not exist. [D:\home\site\repository\WebSite\WebSite.csproj]
Done Building Project "D:\home\site\repository\WebSite\WebSite.csproj" (Build;pipelinePreDeployCopyAllFilesToOneFolder target(s)) -- FAILED.
Build FAILED.
It looks like aspnet_compiler.exe runs, but doesn't do what it's supposed to, which is why the TempBuildDir directory (supposed to be the output of the compiler) does not exist in time for the AspNetMerge target. Contrast that with my system, where that directory DOES in fact exist, containing the marker aspx/ascx/etc. files, static content, a PrecompiledApp.config file, and a whole mess of stuff in the bin directory.
aspnet_compiler.exe has an -errorstack flag but it's not clear to me how I could get MSBuild to add this just via the .deployment file, or even if that app is really even throwing an error.
I could just deploy via Visual Studio, but I would really like to take advantage of the SCM integration so I can just push to my prod branch and let it go. Any suggestions?
I replied on https://github.com/projectkudu/kudu/issues/1341, but copying my answer here in case someone lands here...
Way back, we had found that aspnet_compiler.exe was not working within Azure Websites due to how it dealt with the profile folder. We made a change at the time that's a bit of a hack but got us going: we turned it into a no-op, by pointing HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\aspnet_compiler.exe to our own dummy exe (D:\Program Files (x86)\aspnet_compiler\KuduAspNetCompiler.exe).
But trying it now, it appears to work correctly today, likely thanks to improvements in the Azure Websites hosting environment. So we will try getting rid of this hack and doing a full test pass to make sure it doesn't cause any major regressions. If all goes well, we can get that into production, which should enable those scenarios.
In the short term, you may be able to work around this by having your build script:
copy aspnet_compiler.exe from D:\Windows\Microsoft.NET\Framework\v4.0.30319 into your own site files, but under a different name (e.g. aspnet_compiler2.exe)
convince msbuild to use that one
Note: This GitHub issue on projectkudu will eventually make this solution obsolete, but for the meantime, that issue is filed as Backlog, and this works right now.
Thank you thank you David Ebbo. With this information, I was able to bootstrap my build to work for the short term.
First, I downloaded the aspnet_compiler.exe from the Azure instance using the Diagnostic Console available at https://{WEBSITE_NAME}.scm.azurewebsites.net/DebugConsole and added that to my own repository. This way there's no question about any difference between 32/64-bit, etc. I renamed it to azure_aspnet_compiler.exe in my repository.
Second, the AspNetCompiler task doesn't give you the option to change the tool name. It's hardcoded, but as a virtual property so it's overrideable. So I had to create my own task class, and package it in its own assembly, which I built in Release mode and also included in my repository.
public class AzureAspNetCompiler : Microsoft.Build.Tasks.AspNetCompiler
{
private string _toolName = "aspnet_compiler.exe";
protected override string ToolName
{
get { return _toolName; }
}
public string CustomToolName // Because ToolName cannot have a setter
{
get { return _toolName; }
set { _toolName = value; }
}
}
Next I needed to replace the AspNetPreCompile task in MSBuild, but I couldn't figure out how to do that directly. But that task wasn't doing anything anyway, so why not just run right after it?
I added this to the top of my Website.csproj file to import the DLL containing the AzureAspNetCompiler class. Note that the path is relative to the Website.csproj file I'm editing.
<UsingTask TaskName="AzureBuildTargets.AzureAspNetCompiler"
AssemblyFile="..\DeploymentTools\AzureBuildTargets.dll" />
Then I added this right below it, which is basically stealing the MSBuild target definition of AspNetPreCompile from C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Transform\Microsoft.Web.Publishing.AspNetCompileMerge.targets, with some of the property setting stuff near the top of it left out (because the original task will do that for us anyway.) Just take note of the ToolPath and CustomToolName values at the bottom of the (renamed) AzureAspNetCompiler element.
<PropertyGroup>
<!--Relative to solution root apparently-->
<LocalRepoDeploymentTools>.\DeploymentTools</LocalRepoDeploymentTools>
<AzureAspnetCompilerPath>$([System.IO.Path]::GetFullPath($(LocalRepoDeploymentTools)))</AzureAspnetCompilerPath>
</PropertyGroup>
<Target Name="NoReallyAspNetPreCompile" AfterTargets="AspNetPreCompile">
<AzureAspNetCompiler
PhysicalPath="$(_PreAspnetCompileMergeSingleTargetFolderFullPath)"
TargetPath="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)"
VirtualPath="$(_AspNetCompilerVirtualPath)"
Force="$(_AspNetCompilerForce)"
Debug="$(DebugSymbols)"
Updateable="$(EnableUpdateable)"
KeyFile="$(_AspNetCompileMergeKeyFile)"
KeyContainer="$(_AspNetCompileMergeKeyContainer)"
DelaySign="$(DelaySign)"
AllowPartiallyTrustedCallers="$(AllowPartiallyTrustedCallers)"
FixedNames="$(_AspNetCompilerFixedNames)"
Clean="$(Clean)"
MetabasePath="$(_AspNetCompilerMetabasePath)"
ToolPath="$(AzureAspnetCompilerPath)"
CustomToolName="azure_aspnet_compiler.exe"
/>
<!--
Removing APP_DATA is done here so that the output groups reflect the fact that App_data is
not present
-->
<RemoveDir Condition="'$(DeleteAppDataFolder)' == 'true' And Exists('$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\App_Data')"
Directories="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\App_Data" />
<CollectFilesinFolder Condition="'$(UseMerge)' != 'true'"
RootPath="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)" >
<Output TaskParameter="Result" ItemName="_AspnetCompileMergePrecompiledOutputNoMetadata" />
</CollectFilesinFolder>
<ItemGroup Condition="'$(UseMerge)' != 'true'">
<FileWrites Include="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\**"/>
</ItemGroup>
With this in place, everything works as I would expect it to.

chef copying a directory

I'm trying to copy a directory from one folder to another folder like so:
directory "C:\\test\\go" do
recursive true
action :create
end
cookbook_file "C:\\Automation" do
source "C:\\Automation"
path "C:\\test\\go"
action :create_if_missing
end
It creates the target folder C:\test\go but does not copy anything.
The documentation says that it should also handle directories so any ideas why it does not?
I've also tried a wildcard source "C:\Automation\*" and also tried forward slashed...
Here is the solution:
ruby_block "get the windows resources" do
block do
FileUtils.mkdir_p mod_path
FileUtils.cp_r(Dir["#{RESOURCE_DIR}/*.exe"], Chef::Config[:file_cache_path])
end
end

Can't Delete file with File.Delete(path)

I'm unable to delete file with this command ..
Exception Details: System.IO.DirectoryNotFoundException: Could not find a part of the path
Im getting the above error ..
However Im able to download file with the very same path..
Additional Details: I've have File path saved in the DataBase..
and files are in the ~\Upload\ folder ..
Path like this "~\Upload\ folder" are virtual paths. You need to convert them to physical path to delete them.
If you are in web context then use the following code to get physical path and then delete them.
var physicalPath = HttpContext.Current.Server.MapPath("~/Upload/folder/file.html"); //to get the physical path
File.Delete(physicalPath);
Ensure that you are escaping any backslashes/forward, and just generally check that your path is complete with no small errors.
Failing that make sure your program has the correct privileges to delete the file.
Sorry I can't be more specific but you have not shown your code.

Resources