Skip to content

Commit

Permalink
Tons of bug fixes for grace watch and grace rebase; added checkin…
Browse files Browse the repository at this point in the history
…g for Sha256Hash when creating a reference
  • Loading branch information
ScottArbeit committed Dec 26, 2023
1 parent 5dcfd1e commit 1a9b66a
Show file tree
Hide file tree
Showing 8 changed files with 477 additions and 370 deletions.
4 changes: 2 additions & 2 deletions src/Grace.Actors/Branch.Actor.fs
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ module Branch =
override this.OnPostActorMethodAsync(context) =
let duration_ms = (getCurrentInstant().Minus(actorStartTime).TotalMilliseconds).ToString("F3")
if String.IsNullOrEmpty(currentCommand) then
log.LogInformation("{CurrentInstant}: Finished {ActorName}.{MethodName}; Id: {Id}; Duration: {duration_ms}ms.", getCurrentInstantExtended(), actorName, context.MethodName, this.Id, duration_ms)
log.LogInformation("{CurrentInstant}: Finished {ActorName}.{MethodName}; Id: {Id}; Name: {Name}; Duration: {duration_ms}ms.", getCurrentInstantExtended(), actorName, context.MethodName, this.Id, branchDto.BranchName, duration_ms)
else
log.LogInformation("{CurrentInstant}: Finished {ActorName}.{MethodName}; Command: {Command}; Id: {Id}; Duration: {duration_ms}ms.", getCurrentInstantExtended(), actorName, context.MethodName, currentCommand, this.Id, duration_ms)
log.LogInformation("{CurrentInstant}: Finished {ActorName}.{MethodName}; Command: {Command}; Id: {Id}; Name: {Name}; Duration: {duration_ms}ms.", getCurrentInstantExtended(), actorName, context.MethodName, currentCommand, this.Id, branchDto.BranchName, duration_ms)
logScope.Dispose()
Task.CompletedTask

Expand Down
3 changes: 2 additions & 1 deletion src/Grace.Actors/Services.Actor.fs
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,8 @@ module Services =
// Add the results to the list in the same order as the supplied referenceIds.
referenceIds |> Seq.iter (fun referenceId ->
if referenceId <> ReferenceId.Empty then
referenceDtos.Add(queryResults[referenceId])
if queryResults.ContainsKey(referenceId) then
referenceDtos.Add(queryResults[referenceId])
else
// In case the caller supplied an empty referenceId, add a default ReferenceDto.
referenceDtos.Add(ReferenceDto.Default))
Expand Down
761 changes: 415 additions & 346 deletions src/Grace.CLI/Command/Branch.CLI.fs

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions src/Grace.CLI/Command/Services.CLI.fs
Original file line number Diff line number Diff line change
Expand Up @@ -428,15 +428,17 @@ module Services =
| ObjectStorageProvider.Unknown ->
return Ok ()
| AzureBlobStorage ->
let anyErrors = files.ToArray()
let results = files.ToArray()
|> Array.where (fun f -> not <| File.Exists(f.FullObjectPath))
|> Array.Parallel.map (fun f ->
(task {
return! Storage.GetFileFromObjectStorage f.ToFileVersion correlationId
}).Result)
|> Array.exists (fun result -> match result with | Ok _ -> false | Error _ -> true)
if anyErrors then
return Error "Some files could not be downloaded from object storage."
let (results, errors) = results |> Array.partition (fun result -> match result with | Ok _ -> true | Error _ -> false)
if errors.Count() > 0 then
let sb = StringBuilder($"Some files could not be downloaded from object storage.{Environment.NewLine}")
errors |> Seq.iter(fun e -> match e with | Ok _ -> () | Error e -> sb.AppendLine(e.Error) |> ignore)
return Error (sb.ToString())
else
return Ok ()
| AWSS3 ->
Expand Down Expand Up @@ -540,7 +542,7 @@ module Services =
/// Gets a list of new or updated LocalDirectoryVersions that reflect changes in the working directory.
///
/// If an empty list of differences is passed in, returns the same GraceStatus that was passed in, and an empty list of LocalDirectoryVersions.
let getNewGraceStatusAndDirectoryVersions (previousGraceStatus: GraceStatus) (differences: List<FileSystemDifference>) =
let getNewGraceStatusAndDirectoryVersions (previousGraceStatus: GraceStatus) (differences: IEnumerable<FileSystemDifference>) =
task {
/// Holds DirectoryVersions that have already been changed, so we can make more changes to them if needed.
let changedDirectoryVersions = ConcurrentDictionary<RelativePath, LocalDirectoryVersion>()
Expand Down Expand Up @@ -862,7 +864,7 @@ module Services =
newGraceStatus

/// Gets the file name used to indicate to `grace watch` that updates are in progress from another Grace command, and that it should ignore them.
let getUpdateInProgressFileName() = getNativeFilePath (Path.Combine(Environment.GetEnvironmentVariable("temp"), $"grace-UpdatesInProgress.txt"))
let updateInProgressFileName = getNativeFilePath (Path.Combine(Path.GetTempPath(), "Grace", Constants.UpdateInProgressFileName))

/// Updates the working directory to match the contents of new DirectoryVersions.
///
Expand Down
50 changes: 39 additions & 11 deletions src/Grace.CLI/Command/Watch.CLI.fs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ module Watch =
logToConsole $"In Delete: filePath: {filePath}"

let isNotDirectory path = not <| Directory.Exists(path)
let updateInProgress() = File.Exists(getUpdateInProgressFileName())
let updateInProgress() = File.Exists(updateInProgressFileName)
let updateNotInProgress() = not <| updateInProgress()

let OnCreated (args: FileSystemEventArgs) =
Expand Down Expand Up @@ -118,9 +118,30 @@ module Watch =
let correlationId = Guid.NewGuid().ToString()
logToAnsiConsole Colors.Error $"I saw that the FileSystemWatcher threw an exception: {args.GetException().Message}. grace watch should be restarted."

/// Creates a FileSystemWatcher for the given root directory.
let createFileSystemWatcher rootDirectory =
let fileSystemWatcher = new FileSystemWatcher(rootDirectory)
let OnGraceUpdateInProgressCreated (args: FileSystemEventArgs) =
if args.FullPath = updateInProgressFileName then
if updateInProgress() then
logToAnsiConsole Colors.Important $"Update is in progress from another Grace instance."
else
logToAnsiConsole Colors.Important $"{updateInProgressFileName} should already exist, but it doesn't."

let OnGraceUpdateInProgressChanged (args: FileSystemEventArgs) =
if args.FullPath = updateInProgressFileName then
if updateInProgress() then
logToAnsiConsole Colors.Important $"Update is in progress from another Grace instance."
else
logToAnsiConsole Colors.Important $"{updateInProgressFileName} should already exist, but it doesn't."

let OnGraceUpdateInProgressDeleted (args: FileSystemEventArgs) =
if args.FullPath = updateInProgressFileName then
if updateNotInProgress() then
logToAnsiConsole Colors.Important $"Update has finished in another Grace instance."
else
logToAnsiConsole Colors.Important $"{updateInProgressFileName} should have been deleted, but it hasn't yet."

/// Creates a FileSystemWatcher for the given path.
let createFileSystemWatcher path =
let fileSystemWatcher = new FileSystemWatcher(path)
fileSystemWatcher.InternalBufferSize <- (64 * 1024) // Default is 4K, choosing maximum of 64K for safety.
fileSystemWatcher.IncludeSubdirectories <- true
fileSystemWatcher.NotifyFilter <- NotifyFilters.DirectoryName ||| NotifyFilters.FileName ||| NotifyFilters.LastWrite ||| NotifyFilters.Security
Expand Down Expand Up @@ -288,13 +309,19 @@ module Watch =
task {
try
// Create the FileSystemWatcher, but don't enable it yet.
use fileSystemWatcher = createFileSystemWatcher (Current().RootDirectory)
use created = Observable.FromEventPattern<FileSystemEventArgs>(fileSystemWatcher, "Created").Select(fun e -> e.EventArgs).Subscribe(OnCreated)
use changed = Observable.FromEventPattern<FileSystemEventArgs>(fileSystemWatcher, "Changed").Select(fun e -> e.EventArgs).Subscribe(OnChanged)
use deleted = Observable.FromEventPattern<FileSystemEventArgs>(fileSystemWatcher, "Deleted").Select(fun e -> e.EventArgs).Subscribe(OnDeleted)
use renamed = Observable.FromEventPattern<RenamedEventArgs>(fileSystemWatcher, "Renamed") .Select(fun e -> e.EventArgs).Subscribe(OnRenamed)
use errored = Observable.FromEventPattern<ErrorEventArgs>(fileSystemWatcher, "Error") .Select(fun e -> e.EventArgs).Subscribe(OnError) // I want all of the errors.
use rootDirectoryFileSystemWatcher = createFileSystemWatcher (Current().RootDirectory)
use created = Observable.FromEventPattern<FileSystemEventArgs>(rootDirectoryFileSystemWatcher, "Created").Select(fun e -> e.EventArgs).Subscribe(OnCreated)
use changed = Observable.FromEventPattern<FileSystemEventArgs>(rootDirectoryFileSystemWatcher, "Changed").Select(fun e -> e.EventArgs).Subscribe(OnChanged)
use deleted = Observable.FromEventPattern<FileSystemEventArgs>(rootDirectoryFileSystemWatcher, "Deleted").Select(fun e -> e.EventArgs).Subscribe(OnDeleted)
use renamed = Observable.FromEventPattern<RenamedEventArgs>(rootDirectoryFileSystemWatcher, "Renamed") .Select(fun e -> e.EventArgs).Subscribe(OnRenamed)
use errored = Observable.FromEventPattern<ErrorEventArgs>(rootDirectoryFileSystemWatcher, "Error") .Select(fun e -> e.EventArgs).Subscribe(OnError) // I want all of the errors.

Directory.CreateDirectory(Path.GetDirectoryName(updateInProgressFileName)) |> ignore
use updateInProgressFileSystemWatcher = createFileSystemWatcher (Path.GetDirectoryName(updateInProgressFileName))
use updateInProgressChanged = Observable.FromEventPattern<FileSystemEventArgs>(updateInProgressFileSystemWatcher, "Created").Select(fun e -> e.EventArgs).Subscribe(OnGraceUpdateInProgressCreated)
use updateInProgressChanged = Observable.FromEventPattern<FileSystemEventArgs>(updateInProgressFileSystemWatcher, "Changed").Select(fun e -> e.EventArgs).Subscribe(OnGraceUpdateInProgressChanged)
use updateInProgressDeleted = Observable.FromEventPattern<FileSystemEventArgs>(updateInProgressFileSystemWatcher, "Deleted").Select(fun e -> e.EventArgs).Subscribe(OnGraceUpdateInProgressDeleted)

// Load the Grace Index file.
let! status = readGraceStatusFile()
graceStatus <- status
Expand All @@ -303,7 +330,8 @@ module Watch =
do! updateGraceWatchInterprocessFile graceStatus

// Enable the FileSystemWatcher.
fileSystemWatcher.EnableRaisingEvents <- true
rootDirectoryFileSystemWatcher.EnableRaisingEvents <- true
updateInProgressFileSystemWatcher.EnableRaisingEvents <- true

let timerTimeSpan = TimeSpan.FromSeconds(1.0)
logToAnsiConsole Colors.Verbose $"The change processor timer will tick every {timerTimeSpan.TotalSeconds:F1} seconds."
Expand Down
10 changes: 6 additions & 4 deletions src/Grace.Server/Branch.Server.fs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ module Branch =
String.isValidGraceName parameters.BranchName InvalidBranchName
String.isNotEmpty parameters.Message MessageIsRequired
String.maxLength parameters.Message 2048 StringIsTooLong
String.isValidSha256Hash parameters.Sha256Hash Sha256HashIsRequired
Owner.ownerExists parameters.OwnerId parameters.OwnerName OwnerDoesNotExist
Organization.organizationExists parameters.OwnerId parameters.OwnerName parameters.OrganizationId parameters.OrganizationName OrganizationDoesNotExist
Repository.repositoryExists parameters.OwnerId parameters.OwnerName parameters.OrganizationId parameters.OrganizationName parameters.RepositoryId parameters.RepositoryName RepositoryDoesNotExist
Expand All @@ -231,6 +232,7 @@ module Branch =
String.isValidGraceName parameters.BranchName InvalidBranchName
String.isNotEmpty parameters.Message MessageIsRequired
String.maxLength parameters.Message 2048 StringIsTooLong
String.isValidSha256Hash parameters.Sha256Hash Sha256HashIsRequired
Owner.ownerExists parameters.OwnerId parameters.OwnerName OwnerDoesNotExist
Organization.organizationExists parameters.OwnerId parameters.OwnerName parameters.OrganizationId parameters.OrganizationName OrganizationDoesNotExist
Repository.repositoryExists parameters.OwnerId parameters.OwnerName parameters.OrganizationId parameters.OrganizationName parameters.RepositoryId parameters.RepositoryName RepositoryDoesNotExist
Expand All @@ -253,6 +255,7 @@ module Branch =
String.isValidGraceName parameters.BranchName InvalidBranchName
Input.eitherIdOrNameMustBeProvided parameters.BranchId parameters.BranchName EitherBranchIdOrBranchNameRequired
String.maxLength parameters.Message 2048 StringIsTooLong
String.isValidSha256Hash parameters.Sha256Hash Sha256HashIsRequired
Owner.ownerExists parameters.OwnerId parameters.OwnerName OwnerDoesNotExist
Organization.organizationExists parameters.OwnerId parameters.OwnerName parameters.OrganizationId parameters.OrganizationName OrganizationDoesNotExist
Repository.repositoryExists parameters.OwnerId parameters.OwnerName parameters.OrganizationId parameters.OrganizationName parameters.RepositoryId parameters.RepositoryName RepositoryDoesNotExist
Expand All @@ -275,6 +278,7 @@ module Branch =
String.isValidGraceName parameters.BranchName InvalidBranchName
Input.eitherIdOrNameMustBeProvided parameters.BranchId parameters.BranchName EitherBranchIdOrBranchNameRequired
String.maxLength parameters.Message 4096 StringIsTooLong
String.isValidSha256Hash parameters.Sha256Hash Sha256HashIsRequired
Owner.ownerExists parameters.OwnerId parameters.OwnerName OwnerDoesNotExist
Organization.organizationExists parameters.OwnerId parameters.OwnerName parameters.OrganizationId parameters.OrganizationName OrganizationDoesNotExist
Repository.repositoryExists parameters.OwnerId parameters.OwnerName parameters.OrganizationId parameters.OrganizationName parameters.RepositoryId parameters.RepositoryName RepositoryDoesNotExist
Expand All @@ -297,6 +301,7 @@ module Branch =
String.isValidGraceName parameters.BranchName InvalidBranchName
Input.eitherIdOrNameMustBeProvided parameters.BranchId parameters.BranchName EitherBranchIdOrBranchNameRequired
String.maxLength parameters.Message 2048 StringIsTooLong
String.isValidSha256Hash parameters.Sha256Hash Sha256HashIsRequired
Owner.ownerExists parameters.OwnerId parameters.OwnerName OwnerDoesNotExist
Organization.organizationExists parameters.OwnerId parameters.OwnerName parameters.OrganizationId parameters.OrganizationName OrganizationDoesNotExist
Repository.repositoryExists parameters.OwnerId parameters.OwnerName parameters.OrganizationId parameters.OrganizationName parameters.RepositoryId parameters.RepositoryName RepositoryDoesNotExist
Expand Down Expand Up @@ -832,10 +837,7 @@ module Branch =
let! latestReference = getLatestReference branchDto.BranchId
match latestReference with
| Some latestReference ->
let referenceActorId = Reference.GetActorId branchDto.LatestSave
let referenceActorProxy = actorProxyFactory.CreateActorProxy<IReferenceActor>(referenceActorId, ActorName.Reference)
let! referenceDto = referenceActorProxy.Get()
let directoryActorId = DirectoryVersion.GetActorId referenceDto.DirectoryId
let directoryActorId = DirectoryVersion.GetActorId latestReference.DirectoryId
let directoryActorProxy = actorProxyFactory.CreateActorProxy<IDirectoryVersionActor>(directoryActorId, ActorName.DirectoryVersion)
let! contents = directoryActorProxy.GetDirectoryVersionsRecursive(false)
return contents
Expand Down
3 changes: 3 additions & 0 deletions src/Grace.Shared/Constants.Shared.fs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ module Constants =
/// The name of the inter-process communication file used by grace watch to share status with other invocations of Grace.
let IpcFileName = "graceWatchStatus.json"

/// The name of the file to let `grace watch` know that `grace rebase` or `grace switch` is underway.
let UpdateInProgressFileName = "graceUpdateInProgress.txt"

/// The default expiration time for a cache entry.
let DefaultExpirationTime = TimeSpan.FromMinutes(5.0)

Expand Down
2 changes: 2 additions & 0 deletions src/Grace.Shared/Validation/Errors.Validation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ module Errors =
| RepositoryDoesNotExist
| SaveIsDisabled
| Sha256HashDoesNotExist
| Sha256HashIsRequired
| StringIsTooLong
| TagIsDisabled
| ValueMustBePositive
Expand Down Expand Up @@ -88,6 +89,7 @@ module Errors =
| RepositoryDoesNotExist -> getLocalizedString StringResourceName.RepositoryDoesNotExist
| SaveIsDisabled -> getLocalizedString StringResourceName.SaveIsDisabled
| Sha256HashDoesNotExist -> getLocalizedString StringResourceName.Sha256HashDoesNotExist
| Sha256HashIsRequired -> getLocalizedString StringResourceName.Sha256HashIsRequired
| StringIsTooLong -> getLocalizedString StringResourceName.StringIsTooLong
| TagIsDisabled -> getLocalizedString StringResourceName.TagIsDisabled
| ValueMustBePositive -> getLocalizedString StringResourceName.ValueMustBePositive
Expand Down

0 comments on commit 1a9b66a

Please sign in to comment.