83 lines
3.4 KiB
C#
83 lines
3.4 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.DotNet.Watcher.Internal;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Tools.Internal;
|
|
|
|
namespace Microsoft.DotNet.Watcher
|
|
{
|
|
public class DotNetWatcher
|
|
{
|
|
private readonly ILogger _logger;
|
|
private readonly ProcessRunner _processRunner;
|
|
|
|
public DotNetWatcher(ILogger logger)
|
|
{
|
|
Ensure.NotNull(logger, nameof(logger));
|
|
|
|
_logger = logger;
|
|
_processRunner = new ProcessRunner(logger);
|
|
}
|
|
|
|
public async Task WatchAsync(ProcessSpec processSpec, IFileSetFactory fileSetFactory, CancellationToken cancellationToken)
|
|
{
|
|
Ensure.NotNull(processSpec, nameof(processSpec));
|
|
|
|
var cancelledTaskSource = new TaskCompletionSource<object>();
|
|
cancellationToken.Register(state => ((TaskCompletionSource<object>)state).TrySetResult(null), cancelledTaskSource);
|
|
|
|
while (true)
|
|
{
|
|
var fileSet = await fileSetFactory.CreateAsync(cancellationToken);
|
|
if (cancellationToken.IsCancellationRequested)
|
|
{
|
|
return;
|
|
}
|
|
|
|
using (var currentRunCancellationSource = new CancellationTokenSource())
|
|
using (var combinedCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(
|
|
cancellationToken,
|
|
currentRunCancellationSource.Token))
|
|
using (var fileSetWatcher = new FileSetWatcher(fileSet))
|
|
{
|
|
var fileSetTask = fileSetWatcher.GetChangedFileAsync(combinedCancellationSource.Token);
|
|
var processTask = _processRunner.RunAsync(processSpec, combinedCancellationSource.Token);
|
|
|
|
_logger.LogInformation("Running {execName} with the following arguments: {args}",
|
|
processSpec.ShortDisplayName(),
|
|
ArgumentEscaper.EscapeAndConcatenate(processSpec.Arguments));
|
|
|
|
var finishedTask = await Task.WhenAny(processTask, fileSetTask, cancelledTaskSource.Task);
|
|
|
|
// Regardless of the which task finished first, make sure everything is cancelled
|
|
// and wait for dotnet to exit. We don't want orphan processes
|
|
currentRunCancellationSource.Cancel();
|
|
|
|
await Task.WhenAll(processTask, fileSetTask);
|
|
|
|
if (finishedTask == cancelledTaskSource.Task || cancellationToken.IsCancellationRequested)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (finishedTask == processTask)
|
|
{
|
|
_logger.LogInformation("Waiting for a file to change before restarting dotnet...");
|
|
|
|
// Now wait for a file to change before restarting process
|
|
await fileSetWatcher.GetChangedFileAsync(cancellationToken);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(fileSetTask.Result))
|
|
{
|
|
_logger.LogInformation($"File changed: {fileSetTask.Result}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|