Skip to content
Merged
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
8 changes: 5 additions & 3 deletions Arcade.sln
Original file line number Diff line number Diff line change
Expand Up @@ -897,18 +897,20 @@ Global
{3CCA947D-B466-4481-BC78-43CE98A8A3A7} = {80888CDA-37DC-4061-AF5F-7237BF16A320}
{86D901E6-C054-445B-92EC-E267EBB16278} = {80888CDA-37DC-4061-AF5F-7237BF16A320}
{4626A7D1-7AC0-4E21-9FED-083EF2A8194C} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{036A1269-EA1B-457A-8447-D90AEF80BAF9} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{41F3EF12-6062-44CE-A1DB-1DCA76122AF8} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{6E19C6B6-4ADF-4DD6-86CC-6C1624BCDB71} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{3376C769-211F-4537-A156-5F841FF7840B} = {6BE49638-F842-4329-BE8A-30C0F30CCAA5}
{03390E61-9DC1-4893-93A4-193D76C16034} = {6BE49638-F842-4329-BE8A-30C0F30CCAA5}
{3376C769-211F-4537-A156-5F841FF7840B} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{03390E61-9DC1-4893-93A4-193D76C16034} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{D6AC20A4-1719-49FE-B112-B2AB564496F8} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{61041759-64FE-425F-8984-BA876428A595} = {E41E23C4-5CB0-4C61-9E05-EEFFEC4B356D}
{61041759-64FE-425F-8984-BA876428A595} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{52E92416-5E5F-4A62-A837-9D8554DD2805} = {6F517597-E9E2-43B2-B7E2-757132EA525C}
{6F517597-E9E2-43B2-B7E2-757132EA525C} = {E41E23C4-5CB0-4C61-9E05-EEFFEC4B356D}
{1CC55B23-6212-4120-BF52-8DED9CFF9FBC} = {6F517597-E9E2-43B2-B7E2-757132EA525C}
{CE5278A3-2442-4309-A543-5BA5C1C76A2A} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{E941EDE6-3FFB-4776-A4CE-750755D57817} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{6CA09DC9-E654-4906-A977-1279F6EDC109} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{8BBF14AC-48F0-4282-910E-48E816021660} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{B5E9D9D8-59E0-49F8-9C3C-75138A2D452C} = {C53DD924-C212-49EA-9BC4-1827421361EF}
{0B5D3C20-EB58-4A82-A3AA-2E626A17B35D} = {C53DD924-C212-49EA-9BC4-1827421361EF}
EndGlobalSection
Expand Down
32 changes: 20 additions & 12 deletions src/Common/Microsoft.Arcade.Common/FileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,38 @@

using System.IO;

#nullable enable
namespace Microsoft.Arcade.Common
{
public class FileSystem : IFileSystem
{
public void CreateDirectory(string path)
{
Directory.CreateDirectory(path);
}
public void CreateDirectory(string path) => Directory.CreateDirectory(path);

public bool DirectoryExists(string path)
{
return Directory.Exists(path);
}
public bool DirectoryExists(string path) => Directory.Exists(path);

public bool FileExists(string path)
{
return File.Exists(path);
}
public bool FileExists(string path) => File.Exists(path);

public void DeleteFile(string path) => File.Delete(path);

public string? GetDirectoryName(string? path) => Path.GetDirectoryName(path);

public string? GetFileName(string? path) => Path.GetFileName(path);

public string? GetFileNameWithoutExtension(string? path) => Path.GetFileNameWithoutExtension(path);

public string? GetExtension(string? path) => Path.GetExtension(path);

public string PathCombine(string path1, string path2) => Path.Combine(path1, path2);

public void WriteToFile(string path, string content)
{
string dirPath = Path.GetDirectoryName(path);
Directory.CreateDirectory(dirPath);
File.WriteAllText(path, content);
}

public void FileCopy(string sourceFileName, string destFileName) => File.Copy(sourceFileName, destFileName);

public Stream GetFileStream(string path, FileMode mode, FileAccess access) => new FileStream(path, mode, access);
}
}
19 changes: 19 additions & 0 deletions src/Common/Microsoft.Arcade.Common/IFileSystem.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable enable
using System.IO;

namespace Microsoft.Arcade.Common
{
public interface IFileSystem
Expand All @@ -12,5 +15,21 @@ public interface IFileSystem
bool DirectoryExists(string path);

void CreateDirectory(string path);

string? GetFileName(string? path);

string? GetDirectoryName(string? path);

string? GetFileNameWithoutExtension(string? path);

string? GetExtension(string? path);

string PathCombine(string path1, string path2);

void DeleteFile(string path);

void FileCopy(string sourceFileName, string destFileName);

Stream GetFileStream(string path, FileMode mode, FileAccess access);
}
}
34 changes: 34 additions & 0 deletions src/Common/Microsoft.Arcade.Common/IZipArchiveManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Threading.Tasks;

namespace Microsoft.Arcade.Common
{
public interface IZipArchiveManager
{
/// <summary>
/// Loads an embedded resource and adds it to a target archive.
/// </summary>
/// <typeparam name="TAssembly">Type from the assembly where the resource is embedded (usually the caller)</typeparam>
/// <param name="archivePath">Path to the archive where the file will be added</param>
/// <param name="resourceName">Name of the embedded resource</param>
/// <param name="targetFileName">New name of the file in the archive</param>
Task AddResourceFileToArchive<TAssembly>(string archivePath, string resourceName, string targetFileName = null);

/// <summary>
/// Compresses a directory into an archive on a given path.
/// </summary>
/// <param name="directoryPath">The directory to archive</param>
/// <param name="archivePath">Path where to create the archive</param>
/// <param name="includeBaseDirectory">When true, includes top-level directory in the archive</param>
void ArchiveDirectory(string directoryPath, string archivePath, bool includeBaseDirectory);

/// <summary>
/// Creates a new archive containing given file.
/// </summary>
/// <param name="filePath">File to archive</param>
/// <param name="archivePath">Path where to create the archive</param>
void ArchiveFile(string filePath, string archivePath);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@
<Compile Remove="MSBuildTaskBase.Desktop.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
<Reference Include="System.IO.Compression" />
</ItemGroup>

</Project>
48 changes: 48 additions & 0 deletions src/Common/Microsoft.Arcade.Common/ZipArchiveManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Threading.Tasks;

namespace Microsoft.Arcade.Common
{
public class ZipArchiveManager : IZipArchiveManager
{
public async Task AddResourceFileToArchive<TAssembly>(string archivePath, string resourceName, string targetFileName = null)
{
using Stream fileStream = GetResourceFileContent<TAssembly>(resourceName);
await AddContentToArchive(archivePath, targetFileName ?? resourceName, fileStream);
}

public void ArchiveDirectory(string directoryPath, string archivePath, bool includeBaseDirectory)
{
ZipFile.CreateFromDirectory(directoryPath, archivePath, CompressionLevel.Fastest, includeBaseDirectory);
}

public void ArchiveFile(string filePath, string archivePath)
{
using (FileStream fs = File.OpenWrite(archivePath))
using (var zip = new ZipArchive(fs, ZipArchiveMode.Create, false))
{
zip.CreateEntryFromFile(filePath, Path.GetFileName(filePath));
}
}

private async Task AddContentToArchive(string archivePath, string targetFilename, Stream content)
{
using FileStream archiveStream = new FileStream(archivePath, FileMode.Open);
using ZipArchive archive = new ZipArchive(archiveStream, ZipArchiveMode.Update);
ZipArchiveEntry entry = archive.CreateEntry(targetFilename);
using Stream targetStream = entry.Open();
await content.CopyToAsync(targetStream);
}

private static Stream GetResourceFileContent<TAssembly>(string resourceFileName)
{
Assembly assembly = typeof(TAssembly).Assembly;
return assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{resourceFileName}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.DotNet.Build.Tasks.Feed.Tests.TestDoubles
namespace Microsoft.DotNet.Arcade.Test.Common
{
public static class FakeHttpClient
{
public static HttpClient WithResponse(HttpResponseMessage response)
=> WithResponses(new[] { response });

public static HttpClient WithResponses(IEnumerable<HttpResponseMessage> responses)
public static HttpClient WithResponses(params HttpResponseMessage[] responses)
=> new HttpClient(
new FakeHttpMessageHandler(responses));

Expand Down Expand Up @@ -44,5 +41,4 @@ protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage reques
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,12 @@
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(MicrosoftBuildTasksCoreVersion)" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
<Reference Include="System.Net.Http" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.Arcade.Common\Microsoft.Arcade.Common.csproj" />
</ItemGroup>

</Project>
93 changes: 93 additions & 0 deletions src/Common/Microsoft.Arcade.Test.Common/MockFileSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.IO;
using Microsoft.Arcade.Common;

#nullable enable
namespace Microsoft.Arcade.Test.Common
{
public class MockFileSystem : IFileSystem
{
#region File system state

public HashSet<string> Directories { get; }

public Dictionary<string, string> Files { get; }

public List<string> RemovedFiles { get; } = new();

#endregion

public MockFileSystem(
Dictionary<string, string>? files = null,
IEnumerable<string>? directories = null)
{
Directories = new(directories ?? new string[0]);
Files = files ?? new();
}

#region IFileSystem implementation

public void CreateDirectory(string path) => Directories.Add(path);

public bool DirectoryExists(string path) => Directories.Contains(path);

public bool FileExists(string path) => Files.ContainsKey(path);

public void DeleteFile(string path)
{
Files.Remove(path);
RemovedFiles.Add(path);
}

public string? GetDirectoryName(string? path) => Path.GetDirectoryName(path);

public string? GetFileName(string? path) => Path.GetFileName(path);

public string? GetFileNameWithoutExtension(string? path) => Path.GetFileNameWithoutExtension(path);

public string? GetExtension(string? path) => Path.GetExtension(path);

public string PathCombine(string path1, string path2) => path1 + "/" + path2;

public void WriteToFile(string path, string content) => Files[path] = content;

public void FileCopy(string sourceFileName, string destFileName) => Files[destFileName] = Files[sourceFileName];

public Stream GetFileStream(string path, FileMode mode, FileAccess access)
=> FileExists(path) ? new MemoryStream() : new MockFileStream(this, path);

#endregion

/// <summary>
/// Allows to write to a stream that will end up in the MockFileSystem.
/// </summary>
private class MockFileStream : MemoryStream
{
private readonly MockFileSystem _fileSystem;
private readonly string _path;
private bool _disposed = false;

public MockFileStream(MockFileSystem fileSystem, string path)
: base(fileSystem.FileExists(path) ? System.Text.Encoding.UTF8.GetBytes(fileSystem.Files[path]) : new byte[2048])
{
_fileSystem = fileSystem;
_path = path;
}

protected override void Dispose(bool disposing)
{
// flush file to our system
if (!_disposed)
{
_disposed = true;
using var sr = new StreamReader(this);
Seek(0, SeekOrigin.Begin);
_fileSystem.WriteToFile(_path, sr.ReadToEnd().Replace("\0", ""));
}
}
}
}
}
5 changes: 3 additions & 2 deletions src/Microsoft.DotNet.Build.Tasks.Feed.Tests/GeneralTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Xunit;
using static Microsoft.DotNet.Build.Tasks.Feed.GeneralUtils;
using FluentAssertions;
using Microsoft.DotNet.Arcade.Test.Common;

namespace Microsoft.DotNet.Build.Tasks.Feed.Tests
{
Expand Down Expand Up @@ -55,7 +56,7 @@ public async Task IsFeedPublicShouldCorrectlyInterpretFeedResponseStatusCode(
HttpStatusCode feedResponseStatusCode,
bool? expectedResult)
{
using var httpClient = FakeHttpClient.WithResponse(
using var httpClient = FakeHttpClient.WithResponses(
new HttpResponseMessage(feedResponseStatusCode));
var retryHandler = new MockRetryHandler();

Expand Down Expand Up @@ -117,7 +118,7 @@ public async Task CompareLocalPackageToFeedPackageShouldCorrectlyInterpretFeedRe
response.Content = new ByteArrayContent(content);
};

var httpClient = FakeHttpClient.WithResponse(response);
var httpClient = FakeHttpClient.WithResponses(response);

var result = await GeneralUtils.CompareLocalPackageToFeedPackage(
localPackagePath,
Expand Down
Loading