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

Replaced FileNotFoundException with log instead (#199) #200

Open
wants to merge 2 commits into
base: develop
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
5 changes: 2 additions & 3 deletions Nuget.config
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="AspNetCiDev" value="https://www.myget.org/F/aspnetcidev/api/v3/index.json" />
<add key="XUnitDev" value="https://www.myget.org/F/xunit/api/v3/index.json" />
</packageSources>
</configuration>
</configuration>
15 changes: 10 additions & 5 deletions src/Smidge.Core/Cache/PhysicalFileCacheFileSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Smidge.Hashing;
using Smidge.Models;
using System;
Expand All @@ -13,7 +14,8 @@ public class PhysicalFileCacheFileSystem : ICacheFileSystem
public static PhysicalFileCacheFileSystem CreatePhysicalFileCacheFileSystem(
IHasher hasher,
ISmidgeConfig config,
IHostEnvironment hosting)
IHostEnvironment hosting,
ILogger logger)
{
var cacheFolder = Path.Combine(hosting.ContentRootPath, config.DataFolder, "Cache", Environment.MachineName.ReplaceNonAlphanumericChars('-'));

Expand All @@ -22,18 +24,21 @@ public static PhysicalFileCacheFileSystem CreatePhysicalFileCacheFileSystem(

var cacheFileProvider = new PhysicalFileProvider(cacheFolder);

return new PhysicalFileCacheFileSystem(cacheFileProvider, hasher);
return new PhysicalFileCacheFileSystem(cacheFileProvider, hasher, logger);
}

private readonly IHasher _hasher;
private readonly PhysicalFileProvider _fileProvider;
private readonly ILogger _logger;

public PhysicalFileCacheFileSystem(
PhysicalFileProvider cacheFileProvider,
IHasher hasher)
IHasher hasher,
ILogger logger)
{
_fileProvider = cacheFileProvider;
_hasher = hasher;
_logger = logger;
}

public IFileInfo GetRequiredFileInfo(string filePath)
Expand All @@ -42,7 +47,7 @@ public IFileInfo GetRequiredFileInfo(string filePath)

if (!fileInfo.Exists)
{
throw new FileNotFoundException($"No such file exists {fileInfo.PhysicalPath ?? fileInfo.Name} (mapped from {filePath})", fileInfo.PhysicalPath ?? fileInfo.Name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be handled differently, now fileInfo is returned even when its useless (also in MemoryCacheFileSystem).

Copy link
Author

@LennardF1989 LennardF1989 Dec 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which is as intended, as other parts of the logic will check for .Exists, which is precisely what a FileInfo is for (a cheap wrapper to tell you if a file exists before attempting to open it). You also annotated the old code :)

Returning null here would mean a lot more code has to be touched and double-checked.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which is as intended, as other parts of the logic will check for .Exists, which is precisely what a FileInfo is for (a cheap wrapper to tell you if a file exists before attempting to open it). You also annotated the old code :)

Returning null here would mean a lot more code has to be touched and double-checked.

It's already documented that GetRequiredFileInfo throws:

/// Throws an exception if the file doesn't exist

So this would be breaking anyway.

Not all other paths check if the file exists (only SmidgeController does):

var sourceFile = new Lazy<IFileInfo>(() => _fileSystem.GetRequiredFileInfo(file), LazyThreadSafetyMode.None);

var filePath = _fileSystem.GetRequiredFileInfo(path);

This would also apply to other people using the library, now it doesn't throw anymore and you need to handle it differently.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark about breaking change is fair, the other ones are easily "fixed" by reintroducing the exception right after retrieving the IFileInfo. I will push that in a second.

The two locations you pointed out are literally the only 2 places where something is done with GetRequiredFileInfo. They are also only called in very specific situations: @import in CSS and during bundle creation, both of which cannot be directly manipulated by malicious users (only malicious developers :P). That said, bundle creation would also need some love as I pointed out, but for another PR.

Copy link
Contributor

@PhyxionNL PhyxionNL Dec 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark about breaking change is fair, the other ones are easily "fixed" by reintroducing the exception right after retrieving the IFileInfo.

Not everyone uses Smidge as-is, some have custom implementations around it. I don't mind fixing this at all, but let's try to get consistent behavior ☺️

I think it's fine not to throw anymore; then PreProcessManager can bail out, and CssImportProcessor can continue with the others.

Alternatively, SmidgeController could swallow the exception. This would be the least breaking change.
@Shazwazza what would you prefer?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, i don't think we should change the behavior of this method since the meaning is in the name 'GetRequired...' ... which indicates that it will throw.

One way to be less breaking would be to have an optional overload of this like bool throwIfNotFound = true

It is a binary breaking change, but all folks nowadays build their projects before deploying so I don't think it would cause any issues.

Else I'm fine with try/catch/swallow where necessary

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LennardF1989 just wanted to ping on this one?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I forgot that I did this xD I'll put it back on my list.

_logger.LogError("No such file exists {FileName} (mapped from {FilePath})", fileInfo.PhysicalPath ?? fileInfo.Name, filePath);
}

return fileInfo;
Expand Down
11 changes: 9 additions & 2 deletions src/Smidge.Core/FileProcessors/CssImportProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Smidge.Models;
using Smidge.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -48,6 +49,12 @@ public async Task ProcessAsync(FileProcessContext fileProcessContext, PreProcess
{
//it's internal (in theory)
var filePath = _fileSystem.GetRequiredFileInfo(path);

if (!filePath.Exists)
{
throw new FileNotFoundException(filePath.PhysicalPath ?? filePath.Name);
}

var content = await _fileSystem.ReadContentsAsync(filePath);

//This needs to be put back through the whole pre-processor pipeline before being added,
Expand Down Expand Up @@ -126,4 +133,4 @@ internal string ParseImportStatements(string content, out IEnumerable<string> im


}
}
}
16 changes: 13 additions & 3 deletions src/Smidge.Core/FileProcessors/PreProcessManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
Expand Down Expand Up @@ -76,7 +76,17 @@ private async Task ProcessFileImpl(IWebFile file, BundleOptions bundleOptions, B
var cacheBusterValue = bundleContext.CacheBusterValue;

//we're making this lazy since we don't always want to resolve it
var sourceFile = new Lazy<IFileInfo>(() => _fileSystem.GetRequiredFileInfo(file), LazyThreadSafetyMode.None);
var sourceFile = new Lazy<IFileInfo>(() =>
{
var fileInfo = _fileSystem.GetRequiredFileInfo(file);

if (!fileInfo.Exists)
{
throw new FileNotFoundException(fileInfo.PhysicalPath ?? fileInfo.Name);
}

return fileInfo;
}, LazyThreadSafetyMode.None);

var cacheFile = _fileSystem.CacheFileSystem.GetCacheFile(file, () => sourceFile.Value, fileWatchEnabled, extension, cacheBusterValue, out var filePath);

Expand Down Expand Up @@ -127,4 +137,4 @@ private static void FileModified(WatchedFile file)
file.BundleOptions.FileWatchOptions.Changed(new FileWatchEventArgs(file));
}
}
}
}
6 changes: 3 additions & 3 deletions src/Smidge.Core/ISmidgeFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ public interface ISmidgeFileSystem
/// <param name="webfile"></param>
/// <returns></returns>
/// <remarks>
/// Throws an exception if the file doesn't exist
/// Returns even if the file doesn't exist
/// </remarks>
IFileInfo GetRequiredFileInfo(IWebFile webfile);

/// <summary>
/// Get a required <see cref="IFileInfo"/>
/// </summary>
/// <param name="webfile"></param>
/// <param name="filePath"></param>
/// <returns></returns>
/// <remarks>
/// Throws an exception if the file doesn't exist
/// Returns even if the file doesn't exist
/// </remarks>
IFileInfo GetRequiredFileInfo(string filePath);

Expand Down
10 changes: 7 additions & 3 deletions src/Smidge.Core/SmidgeFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Smidge.Options;
using Smidge.Cache;
using System.Linq;
using Microsoft.Extensions.Logging;

namespace Smidge
{
Expand All @@ -21,17 +22,20 @@ public sealed class SmidgeFileSystem : ISmidgeFileSystem
private readonly IWebsiteInfo _siteInfo;
private readonly IFileProvider _sourceFileProvider;
private readonly IFileProviderFilter _fileProviderFilter;
private readonly ILogger _logger;

public SmidgeFileSystem(
IFileProvider sourceFileProvider,
IFileProviderFilter fileProviderFilter,
ICacheFileSystem cacheFileProvider,
IWebsiteInfo siteInfo)
IWebsiteInfo siteInfo,
ILogger logger)
{
_sourceFileProvider = sourceFileProvider;
_fileProviderFilter = fileProviderFilter;
CacheFileSystem = cacheFileProvider;
_siteInfo = siteInfo;
_logger = logger;
}

public ICacheFileSystem CacheFileSystem { get; }
Expand All @@ -43,7 +47,7 @@ public IFileInfo GetRequiredFileInfo(IWebFile webfile)

if (!fileInfo.Exists)
{
throw new FileNotFoundException($"No such file exists {fileInfo.PhysicalPath ?? fileInfo.Name} (mapped from {path})", fileInfo.PhysicalPath ?? fileInfo.Name);
_logger.LogError("No such file exists {FileName} (mapped from {FilePath})", fileInfo.PhysicalPath ?? fileInfo.Name, path);
}

return fileInfo;
Expand All @@ -56,7 +60,7 @@ public IFileInfo GetRequiredFileInfo(string filePath)

if (!fileInfo.Exists)
{
throw new FileNotFoundException($"No such file exists {fileInfo.PhysicalPath ?? fileInfo.Name} (mapped from {filePath})", fileInfo.PhysicalPath ?? fileInfo.Name);
_logger.LogError("No such file exists {FileName} (mapped from {FilePath})", fileInfo.PhysicalPath ?? fileInfo.Name, filePath);
}

return fileInfo;
Expand Down
12 changes: 9 additions & 3 deletions src/Smidge.InMemory/ConfiguredCacheFileSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
Expand All @@ -10,6 +10,7 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace Smidge.InMemory
{
Expand All @@ -31,14 +32,19 @@ public ConfiguredCacheFileSystem(IOptions<SmidgeOptions> options, IServiceProvid

if (_options.CacheOptions.UseInMemoryCache)
{
_wrapped = new MemoryCacheFileSystem(hasher);
var logger = services.GetRequiredService<ILogger<MemoryCacheFileSystem>>();

_wrapped = new MemoryCacheFileSystem(hasher, logger);
}
else
{
var logger = services.GetRequiredService<ILogger<PhysicalFileCacheFileSystem>>();

_wrapped = PhysicalFileCacheFileSystem.CreatePhysicalFileCacheFileSystem(
hasher,
services.GetRequiredService<ISmidgeConfig>(),
services.GetRequiredService<IHostEnvironment>());
services.GetRequiredService<IHostEnvironment>(),
logger);
}
}

Expand Down
9 changes: 6 additions & 3 deletions src/Smidge.InMemory/MemoryCacheFileSystem.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using Dazinator.Extensions.FileProviders;
using Dazinator.Extensions.FileProviders;
using Dazinator.Extensions.FileProviders.InMemory;
using Dazinator.Extensions.FileProviders.InMemory.Directory;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Smidge.Cache;
using Smidge.Hashing;
using Smidge.Models;
Expand All @@ -17,12 +18,14 @@ public class MemoryCacheFileSystem : ICacheFileSystem
private readonly IDirectory _directory;
private readonly IHasher _hasher;
private readonly IFileProvider _fileProvider;
private readonly ILogger _logger;

public MemoryCacheFileSystem(IHasher hasher)
public MemoryCacheFileSystem(IHasher hasher, ILogger logger)
{
_directory = new InMemoryDirectory();
_fileProvider = new InMemoryFileProvider(_directory);
_hasher = hasher;
_logger = logger;
}

public IFileInfo GetRequiredFileInfo(string filePath)
Expand All @@ -31,7 +34,7 @@ public IFileInfo GetRequiredFileInfo(string filePath)

if (!fileInfo.Exists)
{
throw new FileNotFoundException($"No such file exists {fileInfo.PhysicalPath ?? fileInfo.Name} (mapped from {filePath})", fileInfo.PhysicalPath ?? fileInfo.Name);
_logger.LogError("No such file exists {FileName} (mapped from {FilePath})", fileInfo.PhysicalPath ?? fileInfo.Name, filePath);
}

return fileInfo;
Expand Down
10 changes: 7 additions & 3 deletions src/Smidge/SmidgeStartup.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
Expand All @@ -17,6 +17,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Microsoft.Extensions.Logging;

[assembly: InternalsVisibleTo("Smidge.Tests")]

Expand Down Expand Up @@ -47,20 +48,23 @@ public static IServiceCollection AddSmidge(this IServiceCollection services, ICo
services.AddSingleton<ISmidgeFileSystem>(p =>
{
var hosting = p.GetRequiredService<IWebHostEnvironment>();
var logger = p.GetRequiredService<ILogger<SmidgeFileSystem>>();

//resolve the ISmidgeFileProvider if there is one
var provider = p.GetService<ISmidgeFileProvider>() ?? hosting.WebRootFileProvider;
return new SmidgeFileSystem(
provider,
p.GetRequiredService<IFileProviderFilter>(),
p.GetRequiredService<ICacheFileSystem>(),
p.GetRequiredService<IWebsiteInfo>());
p.GetRequiredService<IWebsiteInfo>(),
logger);
});

services.AddSingleton<ICacheFileSystem>(p => PhysicalFileCacheFileSystem.CreatePhysicalFileCacheFileSystem(
p.GetRequiredService<IHasher>(),
p.GetRequiredService<ISmidgeConfig>(),
p.GetRequiredService<IHostEnvironment>()));
p.GetRequiredService<IHostEnvironment>(),
p.GetRequiredService<ILogger<PhysicalFileCacheFileSystem>>()));

services.AddSingleton<ISmidgeConfig>((p) =>
{
Expand Down
10 changes: 7 additions & 3 deletions test/Smidge.Tests/BundleFileSetGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Smidge.Hashing;
using Smidge.Options;
using System.Linq;
using Microsoft.Extensions.Logging;
using Smidge.FileProcessors;
using Microsoft.Extensions.Options;
using Smidge.Cache;
Expand All @@ -28,9 +29,10 @@ public void Get_Ordered_File_Set_No_Duplicates()

var fileProvider = new Mock<IFileProvider>();
var cacheProvider = new Mock<ICacheFileSystem>();
var logger = new Mock<ILogger>();
var fileProviderFilter = new DefaultFileProviderFilter();

var fileSystemHelper = new SmidgeFileSystem(fileProvider.Object, fileProviderFilter, cacheProvider.Object, Mock.Of<IWebsiteInfo>());
var fileSystemHelper = new SmidgeFileSystem(fileProvider.Object, fileProviderFilter, cacheProvider.Object, Mock.Of<IWebsiteInfo>(), logger.Object);
var pipeline = new PreProcessPipeline(Enumerable.Empty<IPreProcessor>());
var smidgeOptions = new Mock<IOptions<SmidgeOptions>>();
smidgeOptions.Setup(opt => opt.Value).Returns(new SmidgeOptions());
Expand Down Expand Up @@ -58,9 +60,10 @@ public void Get_Ordered_File_External_Set()

var fileProvider = new Mock<IFileProvider>();
var cacheProvider = new Mock<ICacheFileSystem>();
var logger = new Mock<ILogger>();
var fileProviderFilter = new DefaultFileProviderFilter();

var fileSystemHelper = new SmidgeFileSystem(fileProvider.Object, fileProviderFilter, cacheProvider.Object, Mock.Of<IWebsiteInfo>());
var fileSystemHelper = new SmidgeFileSystem(fileProvider.Object, fileProviderFilter, cacheProvider.Object, Mock.Of<IWebsiteInfo>(), logger.Object);
var pipeline = new PreProcessPipeline(Enumerable.Empty<IPreProcessor>());
var smidgeOptions = new Mock<IOptions<SmidgeOptions>>();
smidgeOptions.Setup(opt => opt.Value).Returns(new SmidgeOptions());
Expand Down Expand Up @@ -89,9 +92,10 @@ public void Get_Ordered_File_Set_Correct_Order()

var fileProvider = new Mock<IFileProvider>();
var cacheProvider = new Mock<ICacheFileSystem>();
var logger = new Mock<ILogger>();
var fileProviderFilter = new DefaultFileProviderFilter();

var fileSystemHelper = new SmidgeFileSystem(fileProvider.Object, fileProviderFilter, cacheProvider.Object, Mock.Of<IWebsiteInfo>());
var fileSystemHelper = new SmidgeFileSystem(fileProvider.Object, fileProviderFilter, cacheProvider.Object, Mock.Of<IWebsiteInfo>(), logger.Object);
var pipeline = new PreProcessPipeline(Enumerable.Empty<IPreProcessor>());
var smidgeOptions = new Mock<IOptions<SmidgeOptions>>();
smidgeOptions.Setup(opt => opt.Value).Returns(new SmidgeOptions());
Expand Down
8 changes: 5 additions & 3 deletions test/Smidge.Tests/CssImportProcessorTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Moq;
using Smidge.Cache;
using Smidge.FileProcessors;
Expand Down Expand Up @@ -69,7 +70,8 @@ private ISmidgeFileSystem GetFileSystem()
Mock.Of<IFileProvider>(),
Mock.Of<IFileProviderFilter>(),
Mock.Of<ICacheFileSystem>(),
Mock.Of<IWebsiteInfo>());
Mock.Of<IWebsiteInfo>(),
Mock.Of<ILogger>());
return fileSystem;
}

Expand All @@ -81,4 +83,4 @@ private IWebsiteInfo GetWebsiteInfo()
return websiteInfo.Object;
}
}
}
}
Loading