// ReSharper disable ClassNeverInstantiated.Global namespace TeamCity.CSharpInteractive; using NuGet.Packaging; internal class ScriptContentReplacer : IScriptContentReplacer { private readonly INuGetReferenceResolver _nuGetReferenceResolver; private readonly ICommandFactory _commandFactory; private readonly IRuntimeExplorer _runtimeExplorer; private readonly ICommandsRunner _commandsRunner; private readonly IFileSystem _fileSystem; private readonly IUniqueNameGenerator _uniqueNameGenerator; private readonly IEnvironment _environment; private readonly Func _codeSourceFactory; public ScriptContentReplacer( INuGetReferenceResolver nuGetReferenceResolver, ICommandFactory commandFactory, IRuntimeExplorer runtimeExplorer, ICommandsRunner commandsRunner, IFileSystem fileSystem, IUniqueNameGenerator uniqueNameGenerator, IEnvironment environment, [Tag(typeof(LineCodeSource))] Func codeSourceFactory) { _nuGetReferenceResolver = nuGetReferenceResolver; _commandFactory = commandFactory; _runtimeExplorer = runtimeExplorer; _commandsRunner = commandsRunner; _fileSystem = fileSystem; _uniqueNameGenerator = uniqueNameGenerator; _environment = environment; _codeSourceFactory = codeSourceFactory; } public IEnumerable Replace(IEnumerable lines) { var allAssemblies = new HashSet(); var commandsToRun = new List(); foreach (var line in lines) { if (string.IsNullOrWhiteSpace(line)) { continue; } var assemblies = new HashSet(); var commands = _commandFactory.Create(_codeSourceFactory(line)).ToArray(); var repl = false; foreach (var command in commands) { switch (command) { case AddNuGetReferenceCommand referenceCommand: repl = true; if (_nuGetReferenceResolver.TryResolveAssemblies(referenceCommand.PackageId, referenceCommand.VersionRange, out var resolvedAssemblies)) { foreach (var assembly in resolvedAssemblies.Where(i => !allAssemblies.Contains(i.FilePath))) { // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression if (_runtimeExplorer.TryFindRuntimeAssembly(assembly.FilePath, out var runtimeAssemblyPath)) { assemblies.Add(runtimeAssemblyPath); } else { assemblies.Add(assembly.FilePath); } } } break; case ScriptCommand: case CodeCommand: break; default: repl = true; commandsToRun.Add(command); break; } } var newAssemblies = assemblies.Except(allAssemblies).ToArray(); if (!newAssemblies.Any()) { if (!repl) { yield return line; } } else { allAssemblies.AddRange(newAssemblies); var scriptFile = Path.Combine(_environment.GetPath(SpecialFolder.Temp), _uniqueNameGenerator.Generate()); _fileSystem.WriteAllLines(scriptFile, newAssemblies.Select(i => $"#r \"{i}\"")); yield return $"#load \"{scriptFile}\""; } } // ReSharper disable once ReturnValueOfPureMethodIsNotUsed _commandsRunner.Run(commandsToRun).ToArray(); } }