.NET 7 + Spring Cleaning (#1677)

* Updated to net7.0

* Updated GA to .net 7

* Updated System.IO.Abstractions to use New factory.

* Converted Regex into SourceGenerator in Parser.

* Updated more regex to source generators.

* Enabled Nullability and more regex changes throughout codebase.

* Parser is 100% GeneratedRegexified

* Lots of nullability code

* Enabled nullability for all repositories.

* Fixed another unit test

* Refactored some code around and took care of some todos.

* Updating code for nullability and cleaning up methods that aren't used anymore. Refctored all uses of Parser.Normalize() to use new extension

* More nullability exercises. 500 warnings to go.

* Fixed a bug where custom file uploads for entities wouldn't save in webP.

* Nullability is done for all DTOs

* Fixed all unit tests and nullability for the project. Only OPDS is left which will be done with an upcoming OPDS enhancement.

* Use localization in book service after validating

* Code smells

* Switched to preview build of swashbuckle for .net7 support

* Fixed up merge issues

* Disable emulate comic book when on single page reader

* Fixed a regression where double page renderer wouldn't layout the images correctly

* Updated to swashbuckle which support .net 7

* Fixed a bad GA action

* Some code cleanup

* More code smells

* Took care of most of nullable issues

* Fixed a broken test due to having more than one test run in parallel

* I'm really not sure why the unit tests are failing or are so extremely slow on .net 7

* Updated all dependencies

* Fixed up build and removed hardcoded framework from build scripts. (this merge removes Regex Source generators). Unit tests are completely busted.

* Unit tests and code cleanup. Needs shakeout now.

* Adjusted Series model since a few fields are not-nullable. Removed dead imports on the project.

* Refactored to use Builder pattern for all unit tests.

* Switched nullability down to warnings. It wasn't possible to switch due to constraint issues in DB Migration.
This commit is contained in:
Joe Milazzo 2023-03-05 14:55:13 -06:00 committed by GitHub
parent 76fe3fd64a
commit 5d1dd7b3f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
283 changed files with 4221 additions and 4593 deletions

View file

@ -1,17 +1,14 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using API.DTOs.System;
using API.Entities.Enums;
using API.Extensions;
using Kavita.Common.Helpers;
using Microsoft.Extensions.FileSystemGlobbing;
using Microsoft.Extensions.Logging;
namespace API.Services;
@ -47,33 +44,25 @@ public interface IDirectoryService
void ClearDirectory(string directoryPath);
void ClearAndDeleteDirectory(string directoryPath);
string[] GetFilesWithExtension(string path, string searchPatternExpression = "");
bool CopyDirectoryToDirectory(string sourceDirName, string destDirName, string searchPattern = "");
bool CopyDirectoryToDirectory(string? sourceDirName, string destDirName, string searchPattern = "");
Dictionary<string, string> FindHighestDirectoriesFromFiles(IEnumerable<string> libraryFolders,
IList<string> filePaths);
IEnumerable<string> GetFoldersTillRoot(string rootPath, string fullPath);
IEnumerable<string> GetFiles(string path, string fileNameRegex = "", SearchOption searchOption = SearchOption.TopDirectoryOnly);
bool ExistOrCreate(string directoryPath);
void DeleteFiles(IEnumerable<string> files);
void RemoveNonImages(string directoryName);
void Flatten(string directoryName);
Task<bool> CheckWriteAccess(string directoryName);
IEnumerable<string> GetFilesWithCertainExtensions(string path,
string searchPatternExpression = "",
SearchOption searchOption = SearchOption.TopDirectoryOnly);
IEnumerable<string> GetDirectories(string folderPath);
IEnumerable<string> GetDirectories(string folderPath, GlobMatcher matcher);
IEnumerable<string> GetDirectories(string folderPath, GlobMatcher? matcher);
string GetParentDirectoryName(string fileOrFolder);
#nullable enable
IList<string> ScanFiles(string folderPath, GlobMatcher? matcher = null);
DateTime GetLastWriteTime(string folderPath);
GlobMatcher CreateMatcherFromFile(string filePath);
#nullable disable
GlobMatcher? CreateMatcherFromFile(string filePath);
}
public class DirectoryService : IDirectoryService
{
@ -87,6 +76,16 @@ public class DirectoryService : IDirectoryService
public string BookmarkDirectory { get; }
public string SiteThemeDirectory { get; }
private readonly ILogger<DirectoryService> _logger;
private const int RegexTimeoutMs = 5000000;
private const RegexOptions MatchOptions = RegexOptions.Compiled | RegexOptions.IgnoreCase;
// [GeneratedRegex(@"@eaDir|\.DS_Store|\.qpkg|__MACOSX|@Recently-Snapshot|@recycle",
// MatchOptions, matchTimeoutMilliseconds: RegexTimeoutMs)]
// private static partial Regex ExcludeDirectoriesRegex();
//
// [GeneratedRegex(@"\(\d+\)",
// MatchOptions, matchTimeoutMilliseconds: RegexTimeoutMs)]
// private static partial Regex FileCopyAppendRegex();
private static readonly Regex ExcludeDirectories = new Regex(
@"@eaDir|\.DS_Store|\.qpkg|__MACOSX|@Recently-Snapshot|@recycle|\.@__thumb",
@ -130,7 +129,7 @@ public class DirectoryService : IDirectoryService
SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
if (!FileSystem.Directory.Exists(path)) return ImmutableList<string>.Empty;
var reSearchPattern = new Regex(searchPatternExpression, RegexOptions.IgnoreCase);
var reSearchPattern = new Regex(searchPatternExpression, RegexOptions.IgnoreCase, Tasks.Scanner.Parser.Parser.RegexTimeout);
return FileSystem.Directory.EnumerateFiles(path, "*", searchOption)
.Where(file =>
@ -172,7 +171,7 @@ public class DirectoryService : IDirectoryService
while (FileSystem.Path.GetDirectoryName(path) != Path.GetDirectoryName(root))
{
var folder = FileSystem.DirectoryInfo.FromDirectoryName(path).Name;
var folder = FileSystem.DirectoryInfo.New(path).Name;
paths.Add(folder);
path = path.Substring(0, path.LastIndexOf(separator));
}
@ -187,7 +186,7 @@ public class DirectoryService : IDirectoryService
/// <returns></returns>
public bool Exists(string directory)
{
var di = FileSystem.DirectoryInfo.FromDirectoryName(directory);
var di = FileSystem.DirectoryInfo.New(directory);
return di.Exists;
}
@ -230,7 +229,7 @@ public class DirectoryService : IDirectoryService
{
try
{
var fileInfo = FileSystem.FileInfo.FromFileName(fullFilePath);
var fileInfo = FileSystem.FileInfo.New(fullFilePath);
if (!fileInfo.Exists) return;
ExistOrCreate(targetDirectory);
@ -250,12 +249,12 @@ public class DirectoryService : IDirectoryService
/// <param name="searchPattern">Defaults to all files</param>
/// <returns>If was successful</returns>
/// <exception cref="DirectoryNotFoundException">Thrown when source directory does not exist</exception>
public bool CopyDirectoryToDirectory(string sourceDirName, string destDirName, string searchPattern = "")
public bool CopyDirectoryToDirectory(string? sourceDirName, string destDirName, string searchPattern = "")
{
if (string.IsNullOrEmpty(sourceDirName)) return false;
// Get the subdirectories for the specified directory.
var dir = FileSystem.DirectoryInfo.FromDirectoryName(sourceDirName);
var dir = FileSystem.DirectoryInfo.New(sourceDirName);
if (!dir.Exists)
{
@ -270,7 +269,7 @@ public class DirectoryService : IDirectoryService
ExistOrCreate(destDirName);
// Get the files in the directory and copy them to the new location.
var files = GetFilesWithExtension(dir.FullName, searchPattern).Select(n => FileSystem.FileInfo.FromFileName(n));
var files = GetFilesWithExtension(dir.FullName, searchPattern).Select(n => FileSystem.FileInfo.New(n));
foreach (var file in files)
{
var tempPath = FileSystem.Path.Combine(destDirName, file.Name);
@ -294,7 +293,7 @@ public class DirectoryService : IDirectoryService
/// <returns></returns>
public bool IsDriveMounted(string path)
{
return FileSystem.DirectoryInfo.FromDirectoryName(FileSystem.Path.GetPathRoot(path) ?? string.Empty).Exists;
return FileSystem.DirectoryInfo.New(FileSystem.Path.GetPathRoot(path) ?? string.Empty).Exists;
}
@ -325,7 +324,7 @@ public class DirectoryService : IDirectoryService
/// <returns>Total bytes</returns>
public long GetTotalSize(IEnumerable<string> paths)
{
return paths.Sum(path => FileSystem.FileInfo.FromFileName(path).Length);
return paths.Sum(path => FileSystem.FileInfo.New(path).Length);
}
/// <summary>
@ -335,7 +334,7 @@ public class DirectoryService : IDirectoryService
/// <returns></returns>
public bool ExistOrCreate(string directoryPath)
{
var di = FileSystem.DirectoryInfo.FromDirectoryName(directoryPath);
var di = FileSystem.DirectoryInfo.New(directoryPath);
if (di.Exists) return true;
try
{
@ -356,7 +355,7 @@ public class DirectoryService : IDirectoryService
{
if (!FileSystem.Directory.Exists(directoryPath)) return;
var di = FileSystem.DirectoryInfo.FromDirectoryName(directoryPath);
var di = FileSystem.DirectoryInfo.New(directoryPath);
ClearDirectory(directoryPath);
@ -370,7 +369,7 @@ public class DirectoryService : IDirectoryService
/// <returns></returns>
public void ClearDirectory(string directoryPath)
{
var di = FileSystem.DirectoryInfo.FromDirectoryName(directoryPath);
var di = FileSystem.DirectoryInfo.New(directoryPath);
if (!di.Exists) return;
try
{
@ -401,7 +400,7 @@ public class DirectoryService : IDirectoryService
public bool CopyFilesToDirectory(IEnumerable<string> filePaths, string directoryPath, string prepend = "")
{
ExistOrCreate(directoryPath);
string currentFile = null;
string? currentFile = null;
try
{
foreach (var file in filePaths)
@ -413,8 +412,8 @@ public class DirectoryService : IDirectoryService
_logger.LogError("Unable to copy {File} to {DirectoryPath} as it doesn't exist", file, directoryPath);
continue;
}
var fileInfo = FileSystem.FileInfo.FromFileName(file);
var targetFile = FileSystem.FileInfo.FromFileName(RenameFileForCopy(file, directoryPath, prepend));
var fileInfo = FileSystem.FileInfo.New(file);
var targetFile = FileSystem.FileInfo.New(RenameFileForCopy(file, directoryPath, prepend));
fileInfo.CopyTo(FileSystem.Path.Join(directoryPath, targetFile.Name));
}
@ -439,7 +438,7 @@ public class DirectoryService : IDirectoryService
public bool CopyFilesToDirectory(IEnumerable<string> filePaths, string directoryPath, IList<string> newFilenames)
{
ExistOrCreate(directoryPath);
string currentFile = null;
string? currentFile = null;
var index = 0;
try
{
@ -452,8 +451,8 @@ public class DirectoryService : IDirectoryService
_logger.LogError("Unable to copy {File} to {DirectoryPath} as it doesn't exist", file, directoryPath);
continue;
}
var fileInfo = FileSystem.FileInfo.FromFileName(file);
var targetFile = FileSystem.FileInfo.FromFileName(RenameFileForCopy(newFilenames[index] + fileInfo.Extension, directoryPath));
var fileInfo = FileSystem.FileInfo.New(file);
var targetFile = FileSystem.FileInfo.New(RenameFileForCopy(newFilenames[index] + fileInfo.Extension, directoryPath));
fileInfo.CopyTo(FileSystem.Path.Join(directoryPath, targetFile.Name));
index++;
@ -480,18 +479,20 @@ public class DirectoryService : IDirectoryService
{
while (true)
{
var fileInfo = FileSystem.FileInfo.FromFileName(fileToCopy);
var fileInfo = FileSystem.FileInfo.New(fileToCopy);
var filename = prepend + fileInfo.Name;
var targetFile = FileSystem.FileInfo.FromFileName(FileSystem.Path.Join(directoryPath, filename));
var targetFile = FileSystem.FileInfo.New(FileSystem.Path.Join(directoryPath, filename));
if (!targetFile.Exists)
{
return targetFile.FullName;
}
var noExtension = FileSystem.Path.GetFileNameWithoutExtension(fileInfo.Name);
//if (FileCopyAppendRegex().IsMatch(noExtension))
if (FileCopyAppend.IsMatch(noExtension))
{
//var match = FileCopyAppendRegex().Match(noExtension).Value;
var match = FileCopyAppend.Match(noExtension).Value;
var matchNumber = match.Replace("(", string.Empty).Replace(")", string.Empty);
noExtension = noExtension.Replace(match, $"({int.Parse(matchNumber) + 1})");
@ -515,7 +516,7 @@ public class DirectoryService : IDirectoryService
{
if (!FileSystem.Directory.Exists(rootPath)) return ImmutableList<DirectoryDto>.Empty;
var di = FileSystem.DirectoryInfo.FromDirectoryName(rootPath);
var di = FileSystem.DirectoryInfo.New(rootPath);
var dirs = di.GetDirectories()
.Where(dir => !(dir.Attributes.HasFlag(FileAttributes.Hidden) || dir.Attributes.HasFlag(FileAttributes.System)))
.Select(d => new DirectoryDto()
@ -595,13 +596,13 @@ public class DirectoryService : IDirectoryService
/// <param name="folderPath"></param>
/// <param name="matcher">A set of glob rules that will filter directories out</param>
/// <returns>List of directory paths, empty if path doesn't exist</returns>
public IEnumerable<string> GetDirectories(string folderPath, GlobMatcher matcher)
public IEnumerable<string> GetDirectories(string folderPath, GlobMatcher? matcher)
{
if (matcher == null) return GetDirectories(folderPath);
return GetDirectories(folderPath)
.Where(folder => !matcher.ExcludeMatches(
$"{FileSystem.DirectoryInfo.FromDirectoryName(folder).Name}{FileSystem.Path.AltDirectorySeparatorChar}"));
$"{FileSystem.DirectoryInfo.New(folder).Name}{FileSystem.Path.AltDirectorySeparatorChar}"));
}
/// <summary>
@ -681,7 +682,7 @@ public class DirectoryService : IDirectoryService
{
var foundFiles = GetFilesWithCertainExtensions(folderPath,
Tasks.Scanner.Parser.Parser.SupportedExtensions)
.Where(file => !matcher.ExcludeMatches(FileSystem.FileInfo.FromFileName(file).Name));
.Where(file => !matcher.ExcludeMatches(FileSystem.FileInfo.New(file).Name));
files.AddRange(foundFiles);
}
@ -707,7 +708,7 @@ public class DirectoryService : IDirectoryService
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public GlobMatcher CreateMatcherFromFile(string filePath)
public GlobMatcher? CreateMatcherFromFile(string filePath)
{
if (!FileSystem.File.Exists(filePath))
{
@ -831,7 +832,7 @@ public class DirectoryService : IDirectoryService
{
try
{
FileSystem.FileInfo.FromFileName(file).Delete();
FileSystem.FileInfo.New(file).Delete();
}
catch (Exception)
{
@ -934,7 +935,7 @@ public class DirectoryService : IDirectoryService
{
if (string.IsNullOrEmpty(directoryName) || !FileSystem.Directory.Exists(directoryName)) return;
var directory = FileSystem.DirectoryInfo.FromDirectoryName(directoryName);
var directory = FileSystem.DirectoryInfo.New(directoryName);
var index = 0;
FlattenDirectory(directory, directory, ref index);