| File: Helpers.cs | Web Access |
| Project: src\arcade\src\Common\Microsoft.Arcade.Common\Microsoft.Arcade.Common.csproj (Microsoft.Arcade.Common) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Microsoft.Arcade.Common { public class Helpers : IHelpers { private static readonly char[] s_slashes = [ '/', '\\' ]; public string RemoveTrailingSlash(string directoryPath) { return directoryPath.TrimEnd(s_slashes); } public string ComputeSha256Hash(string normalizedPath) { using (var hasher = SHA256.Create()) { var dirHash = Convert.ToBase64String(hasher.ComputeHash(Encoding.UTF8.GetBytes(normalizedPath))); dirHash = dirHash.TrimEnd('='); // base64 url encode it. dirHash = dirHash.Replace('+', '-'); dirHash = dirHash.Replace('/', '_'); return dirHash; } } public T MutexExec<T>(Func<T> function, string mutexName) { using var mutex = new Mutex(false, mutexName); bool hasMutex = false; try { try { mutex.WaitOne(); } catch (AbandonedMutexException) { } hasMutex = true; return function(); } finally { if (hasMutex) { mutex.ReleaseMutex(); } } } public T MutexExec<T>(Func<Task<T>> function, string mutexName) => MutexExec(() => function().GetAwaiter().GetResult(), mutexName); // Can't await because of mutex // This overload is here so that async Actions don't get routed to MutexExec<T>(Func<T> function, string path) public void MutexExec(Func<Task> function, string mutexName) => MutexExec(() => { function().GetAwaiter().GetResult(); return true; }, mutexName); public T DirectoryMutexExec<T>(Func<T> function, string path) => MutexExec(function, $"Global\\{ComputeSha256Hash(path)}"); public T DirectoryMutexExec<T>(Func<Task<T>> function, string path) => DirectoryMutexExec(() => function().GetAwaiter().GetResult(), path); // Can't await because of mutex // This overload is here so that async Actions don't get routed to DirectoryMutexExec<T>(Func<T> function, string path) public void DirectoryMutexExec(Func<Task> function, string path) => DirectoryMutexExec(() => { function().GetAwaiter().GetResult(); return true; }, path); } public static class KeyValuePairExtensions { public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> pair, out TKey key, out TValue value) { key = pair.Key; value = pair.Value; } } }