TeamCity.CSharpInteractive/FilePathResolver.cs (90 lines of code) (raw):
// ReSharper disable ClassNeverInstantiated.Global
namespace TeamCity.CSharpInteractive;
internal class FilePathResolver : IFilePathResolver
{
private readonly ILog<FilePathResolver> _log;
private readonly IEnvironment _environment;
private readonly IFileSystem _fileSystem;
public FilePathResolver(
ILog<FilePathResolver> log,
IEnvironment environment,
IFileSystem fileSystem)
{
_log = log;
_environment = environment;
_fileSystem = fileSystem;
}
public bool TryResolve(string? fileOrDirectoryPath, out string fullScriptPath)
{
var state = State.Unknown;
fullScriptPath = string.Empty;
if (!string.IsNullOrWhiteSpace(fileOrDirectoryPath))
{
if (_fileSystem.IsPathRooted(fileOrDirectoryPath))
{
state = TryResolveFullPath(fileOrDirectoryPath, fileOrDirectoryPath, out fullScriptPath);
if (state == State.NotFound)
{
return false;
}
}
else
{
foreach (var path in GetPaths().Distinct())
{
fullScriptPath = Path.Combine(path, fileOrDirectoryPath);
state = TryResolveFullPath(path, fullScriptPath, out fullScriptPath);
if (state is State.Found or State.Error)
{
break;
}
}
}
}
if (state is State.NotFound)
{
_log.Error(ErrorId.CannotFind, $"Cannot find \"{fileOrDirectoryPath}\".");
}
return state == State.Found;
}
private State TryResolveFullPath(string basePath, string fullPath, out string fullScriptPath)
{
fullScriptPath = string.Empty;
var isFileExist = _fileSystem.IsFileExist(fullPath);
_log.Trace(() => new[] {new Text($"Try to find file \"{fullPath}\" in \"{basePath}\": {isFileExist}.")});
if (isFileExist)
{
fullScriptPath = fullPath;
return State.Found;
}
var isDirectoryExist = _fileSystem.IsDirectoryExist(fullPath);
_log.Trace(() => new[] {new Text($"Try to find directory \"{fullPath}\" in \"{basePath}\": {isDirectoryExist}.")});
if (isDirectoryExist)
{
var scripts = _fileSystem.EnumerateFileSystemEntries(fullPath, "*.csx", SearchOption.TopDirectoryOnly).ToList();
switch (scripts.Count)
{
case 1:
fullScriptPath = scripts[0];
return State.Found;
case > 1:
_log.Error(ErrorId.CannotFind, new Text($"Specify which script file to use because the folder \"{fullPath}\" contains more than one script file."));
return State.Error;
default:
return State.Unknown;
}
}
return State.NotFound;
}
private enum State
{
Unknown,
Found,
Error,
NotFound
}
private IEnumerable<string> GetPaths()
{
yield return _environment.GetPath(SpecialFolder.Script);
yield return _environment.GetPath(SpecialFolder.Working);
}
}