Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spiking filesystem changes #1258

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using Calamari.Common.Commands;
using Calamari.Common.FeatureToggles;
using Calamari.Common.Plumbing.Extensions;
using Calamari.Common.Plumbing.FileSystem;
using Calamari.Common.Plumbing.Logging;
using Calamari.Common.Plumbing.Pipeline;
using Calamari.Common.Plumbing.Variables;
Expand All @@ -33,7 +34,8 @@ internal class AzureAppServiceZipDeployBehaviour : IDeployBehaviour
{
static readonly TimeSpan PollingTimeout = TimeSpan.FromMinutes(3);
static readonly AsyncTimeoutPolicy<HttpResponseMessage> AsyncZipDeployTimeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(PollingTimeout, TimeoutStrategy.Optimistic);

static readonly ICalamariFileSystem CalamariFileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem();

public AzureAppServiceZipDeployBehaviour(ILog log)
{
Log = log;
Expand Down Expand Up @@ -354,16 +356,16 @@ await RetryPolicies.TransientHttpErrorsPolicy
static void CleanupUploadFile(string? uploadPath)
{
Policy.Handle<IOException>()
.WaitAndRetry(
5,
i => TimeSpan.FromMilliseconds(200))
.Execute(() =>
{
if (File.Exists(uploadPath))
{
File.Delete(uploadPath!);
}
});
.WaitAndRetry(
5,
i => TimeSpan.FromMilliseconds(200))
.Execute(() =>
{
if (CalamariFileSystem.FileExists(uploadPath))
{
CalamariFileSystem.DeleteFile(uploadPath!);
}
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public CommandResult ExecuteScript(Script script, ScriptSyntax scriptSyntax, ICo
destinationFile = Path.Combine(workingDirectory, copyScriptFile);
}

File.Copy(scriptFile, destinationFile, true);
fileSystem.CopyFile(scriptFile, destinationFile);
}

using (var contextScriptFile = new TemporaryFile(scriptFile))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System;
using System.IO;
using Calamari.Common.Plumbing;
using Calamari.Common.Plumbing.FileSystem;
using SharpCompress.Archives.Zip;

namespace Calamari.Common.Features.Packages.NuGet
Expand All @@ -14,6 +15,7 @@ public class LocalNuGetPackage
{
readonly string filePath;
readonly Lazy<ManifestMetadata> metadata;
static readonly ICalamariFileSystem CalamariFileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem();

public LocalNuGetPackage(string filePath)
{
Expand All @@ -30,15 +32,15 @@ public LocalNuGetPackage(string filePath)

public void GetStream(Action<Stream> process)
{
using (var fileStream = File.OpenRead(filePath))
using (var fileStream = CalamariFileSystem.OpenFile(filePath, FileAccess.Read))
{
process(fileStream);
}
}

static ManifestMetadata ReadMetadata(string filePath)
{
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (var fileStream = CalamariFileSystem.OpenFile(filePath, FileMode.Open, FileAccess.Read))
using (var archive = ZipArchive.Open(fileStream))
{
foreach (var entry in archive.Entries)
Expand Down
48 changes: 48 additions & 0 deletions source/Calamari.Common/Plumbing/FileSystem/FileAccess.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using Calamari.Common.Plumbing.Logging;
using Polly;

namespace Calamari.Common.Plumbing.FileSystem
{
public static class FileAccessChecker
{
public static T IsFileLocked<T>(Func<T> accessFile)
{
try
{
Policy.Handle<IOException>()
.WaitAndRetry(
3,
i => TimeSpan.FromMilliseconds(200))
.Execute(accessFile);
}
catch (Exception e)
{
var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
var isLocked = errorCode == 32 || errorCode == 33;
Log.Error($"File is {isLocked}, threw with error code {errorCode}");
throw e;
}

return accessFile();
}

public static void IsFileLocked(Action accessFile)
{
try
{
accessFile();
}
catch (Exception e)
{
var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
var isLocked = errorCode == 32 || errorCode == 33;
Log.Warn($"File is {isLocked}, threw with error code {errorCode}");
Log.Warn(e.Message);
throw e;
}
}
}
}
78 changes: 39 additions & 39 deletions source/Calamari.Common/Plumbing/FileSystem/FileOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,94 +40,94 @@ public class StandardFile : IFile
{
public void Delete(string path)
{
File.Delete(path);
FileAccessChecker.IsFileLocked(() => File.Delete(path));
}

public bool Exists(string? path)
{
return File.Exists(path);
return FileAccessChecker.IsFileLocked(() => File.Exists(path));
}

public byte[] ReadAllBytes(string path)
{
return File.ReadAllBytes(path);
return FileAccessChecker.IsFileLocked(() => File.ReadAllBytes(path));
}

public void WriteAllBytes(string path, byte[] bytes)
{
File.WriteAllBytes(path, bytes);
FileAccessChecker.IsFileLocked(() => File.WriteAllBytes(path, bytes));
}

public void Move(string source, string destination)
{
File.Move(source, destination);
FileAccessChecker.IsFileLocked(() => File.Move(source, destination));
}

public void SetAttributes(string path, FileAttributes fileAttributes)
{
File.SetAttributes(path, fileAttributes);
FileAccessChecker.IsFileLocked(() => File.SetAttributes(path, fileAttributes));
}

public DateTime GetCreationTime(string path)
{
return File.GetCreationTime(path);
return FileAccessChecker.IsFileLocked<DateTime>(() => File.GetCreationTime(path));
}

public Stream Open(string path, FileMode mode, FileAccess access, FileShare share)
{
return File.Open(path, mode, access, share);
return FileAccessChecker.IsFileLocked<Stream>(() => File.Open(path, mode, access, share));
}

public void Copy(string source, string destination, bool overwrite)
{
File.Copy(source, destination, overwrite);
FileAccessChecker.IsFileLocked(() => File.Copy(source, destination, overwrite));
}
}

public class StandardDirectory : IDirectory
{
public void CreateDirectory(string path)
{
Directory.CreateDirectory(path);
FileAccessChecker.IsFileLocked(() => Directory.CreateDirectory(path));
}

public void Delete(string path, bool recursive)
{
Directory.Delete(path, recursive);
FileAccessChecker.IsFileLocked(() => Directory.Delete(path, recursive));
}

public bool Exists(string? path)
{
return Directory.Exists(path);
return FileAccessChecker.IsFileLocked(() => Directory.Exists(path));
}

public string[] GetFileSystemEntries(string path)
{
return Directory.GetFileSystemEntries(path);
return FileAccessChecker.IsFileLocked(() => Directory.GetFileSystemEntries(path));
}

public IEnumerable<string> EnumerateDirectories(string path)
{
return Directory.EnumerateDirectories(path);
return FileAccessChecker.IsFileLocked(() => Directory.EnumerateDirectories(path));
}

public IEnumerable<string> EnumerateDirectoriesRecursively(string path)
{
return Directory.EnumerateDirectories(path, "*", SearchOption.AllDirectories);
return FileAccessChecker.IsFileLocked(() => Directory.EnumerateDirectories(path, "*", SearchOption.AllDirectories));
}

public virtual IEnumerable<string> EnumerateFiles(
string parentDirectoryPath,
params string[] searchPatterns)
{
return EnumerateFiles(parentDirectoryPath, SearchOption.TopDirectoryOnly, searchPatterns);
return FileAccessChecker.IsFileLocked(() => EnumerateFiles(parentDirectoryPath, SearchOption.TopDirectoryOnly, searchPatterns));
}

public virtual IEnumerable<string> EnumerateFilesRecursively(
string parentDirectoryPath,
params string[] searchPatterns)
{
return EnumerateFiles(parentDirectoryPath, SearchOption.AllDirectories, searchPatterns);
return FileAccessChecker.IsFileLocked(() => EnumerateFiles(parentDirectoryPath, SearchOption.AllDirectories, searchPatterns));
}

private IEnumerable<string> EnumerateFiles(
Expand All @@ -136,24 +136,24 @@ private IEnumerable<string> EnumerateFiles(
string[] searchPatterns)
{
return searchPatterns.Length == 0
? Directory.EnumerateFiles(parentDirectoryPath, "*", searchOption)
? FileAccessChecker.IsFileLocked(() => Directory.EnumerateFiles(parentDirectoryPath, "*", searchOption))
: searchPatterns.SelectMany(pattern =>
Directory.EnumerateFiles(parentDirectoryPath, pattern, searchOption)).Distinct();
FileAccessChecker.IsFileLocked(() => Directory.EnumerateFiles(parentDirectoryPath, pattern, searchOption)).Distinct());
}

public IEnumerable<string> GetFiles(string path, string searchPattern)
{
return Directory.GetFiles(path, searchPattern);
return FileAccessChecker.IsFileLocked(() => Directory.GetFiles(path, searchPattern));
}

public IEnumerable<string> GetDirectories(string path)
{
return Directory.GetDirectories(path);
return FileAccessChecker.IsFileLocked(() => Directory.GetDirectories(path));
}

public string GetCurrentDirectory()
{
return Directory.GetCurrentDirectory();
return FileAccessChecker.IsFileLocked(() => Directory.GetCurrentDirectory());
}
}

Expand All @@ -162,90 +162,90 @@ public class LongPathsFile : IFile
{
public void Delete(string path)
{
Alphaleonis.Win32.Filesystem.File.Delete(path);
FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.File.Delete(path));
}

public bool Exists(string? path)
{
return Alphaleonis.Win32.Filesystem.File.Exists(path);
return FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.File.Exists(path));
}

public byte[] ReadAllBytes(string path)
{
return Alphaleonis.Win32.Filesystem.File.ReadAllBytes(path);
return FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.File.ReadAllBytes(path));
}

public void WriteAllBytes(string path, byte[] bytes)
{
Alphaleonis.Win32.Filesystem.File.WriteAllBytes(path, bytes);
FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.File.WriteAllBytes(path, bytes));
}

public void Move(string source, string destination)
{
Alphaleonis.Win32.Filesystem.File.Move(source, destination);
FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.File.Move(source, destination));
}

public void SetAttributes(string path, FileAttributes fileAttributes)
{
Alphaleonis.Win32.Filesystem.File.SetAttributes(path, fileAttributes);
FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.File.SetAttributes(path, fileAttributes));
}

public DateTime GetCreationTime(string path)
{
return Alphaleonis.Win32.Filesystem.File.GetCreationTime(path);
return FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.File.GetCreationTime(path));
}

public Stream Open(string path, FileMode mode, FileAccess access, FileShare share)
{
return Alphaleonis.Win32.Filesystem.File.Open(path, mode, access, share);
return FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.File.Open(path, mode, access, share));
}

public void Copy(string source, string destination, bool overwrite)
{
Alphaleonis.Win32.Filesystem.File.Copy(source, destination, overwrite);
FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.File.Copy(source, destination, overwrite));
}
}

public class LongPathsDirectory : IDirectory
{
public void CreateDirectory(string path)
{
Alphaleonis.Win32.Filesystem.Directory.CreateDirectory(path);
FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.Directory.CreateDirectory(path));
}

public void Delete(string path, bool recursive)
{
Alphaleonis.Win32.Filesystem.Directory.Delete(path, recursive);
FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.Directory.Delete(path, recursive));
}

public bool Exists(string? path)
{
return Alphaleonis.Win32.Filesystem.Directory.Exists(path);
return FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.Directory.Exists(path));
}

public string[] GetFileSystemEntries(string path)
{
return Alphaleonis.Win32.Filesystem.Directory.GetFileSystemEntries(path);
return FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.Directory.GetFileSystemEntries(path));
}

public IEnumerable<string> EnumerateDirectories(string path)
{
return Alphaleonis.Win32.Filesystem.Directory.EnumerateDirectories(path);
return FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.Directory.EnumerateDirectories(path));
}

public IEnumerable<string> EnumerateDirectoriesRecursively(string path)
{
return Alphaleonis.Win32.Filesystem.Directory.EnumerateDirectories(path, "*", SearchOption.AllDirectories);
return FileAccessChecker.IsFileLocked(() => Alphaleonis.Win32.Filesystem.Directory.EnumerateDirectories(path, "*", SearchOption.AllDirectories));
}

public IEnumerable<string> EnumerateFiles(string parentDirectoryPath, params string[] searchPatterns)
{
return EnumerateFiles(parentDirectoryPath, SearchOption.TopDirectoryOnly, searchPatterns);
return FileAccessChecker.IsFileLocked(() => EnumerateFiles(parentDirectoryPath, SearchOption.TopDirectoryOnly, searchPatterns));
}

public IEnumerable<string> EnumerateFilesRecursively(string parentDirectoryPath, params string[] searchPatterns)
{
return EnumerateFiles(parentDirectoryPath, SearchOption.AllDirectories, searchPatterns);
return FileAccessChecker.IsFileLocked(() => EnumerateFiles(parentDirectoryPath, SearchOption.AllDirectories, searchPatterns));
}

private IEnumerable<string> EnumerateFiles(
Expand Down
Loading