diff --git a/Scalar.Common/Maintenance/CommitGraphStep.cs b/Scalar.Common/Maintenance/CommitGraphStep.cs index f03175097d..69c68af4bb 100644 --- a/Scalar.Common/Maintenance/CommitGraphStep.cs +++ b/Scalar.Common/Maintenance/CommitGraphStep.cs @@ -17,6 +17,8 @@ public CommitGraphStep(ScalarContext context, bool requireObjectCacheLock = true public override string Area => "CommitGraphStep"; + public override string ProgressMessage => "Updating commit-graph"; + protected override void PerformMaintenance() { using (ITracer activity = this.Context.Tracer.StartActivity("TryWriteGitCommitGraph", EventLevel.Informational)) diff --git a/Scalar.Common/Maintenance/ConfigStep.cs b/Scalar.Common/Maintenance/ConfigStep.cs index 90a99ba171..cd2946ca0a 100644 --- a/Scalar.Common/Maintenance/ConfigStep.cs +++ b/Scalar.Common/Maintenance/ConfigStep.cs @@ -71,6 +71,8 @@ public ConfigStep(ScalarContext context, bool? useGvfsProtocol = null) : base(co this.UseGvfsProtocol = useGvfsProtocol; } + public override string ProgressMessage => "Setting recommended config settings"; + public bool TrySetConfig(out string error) { string coreGVFSFlags = Convert.ToInt32( diff --git a/Scalar.Common/Maintenance/FetchStep.cs b/Scalar.Common/Maintenance/FetchStep.cs index 7c248a42a2..298e7d66d7 100644 --- a/Scalar.Common/Maintenance/FetchStep.cs +++ b/Scalar.Common/Maintenance/FetchStep.cs @@ -33,6 +33,25 @@ public FetchStep( public override string Area => "FetchCommitsAndTreesStep"; + public override string ProgressMessage + { + get + { + if (!this.Context.Enlistment.UsesGvfsProtocol) + { + return "Fetching from remotes"; + } + else if (this.GitObjects.IsUsingCacheServer()) + { + return "Fetching from cache server"; + } + else + { + return "Fetching from origin (no cache server)"; + } + } + } + // Used only for vanilla Git repos protected override TimeSpan TimeBetweenRuns => this.timeBetweenFetches; diff --git a/Scalar.Common/Maintenance/GitMaintenanceStep.cs b/Scalar.Common/Maintenance/GitMaintenanceStep.cs index 515bab283a..e0a107345b 100644 --- a/Scalar.Common/Maintenance/GitMaintenanceStep.cs +++ b/Scalar.Common/Maintenance/GitMaintenanceStep.cs @@ -19,6 +19,9 @@ public GitMaintenanceStep(ScalarContext context, bool requireObjectCacheLock, Gi } public abstract string Area { get; } + + public abstract string ProgressMessage { get; } + protected virtual TimeSpan TimeBetweenRuns { get; } protected virtual string LastRunTimeFilePath { get; set; } protected ScalarContext Context { get; } diff --git a/Scalar.Common/Maintenance/LooseObjectsStep.cs b/Scalar.Common/Maintenance/LooseObjectsStep.cs index 0efd9b6f06..f28a952670 100644 --- a/Scalar.Common/Maintenance/LooseObjectsStep.cs +++ b/Scalar.Common/Maintenance/LooseObjectsStep.cs @@ -41,6 +41,8 @@ public enum CreatePackResult protected override string LastRunTimeFilePath => Path.Combine(this.Context.Enlistment.GitObjectsRoot, "info", LooseObjectsLastRunFileName); protected override TimeSpan TimeBetweenRuns => TimeSpan.FromDays(1); + public override string ProgressMessage => "Cleaning up loose objects"; + public void CountLooseObjects(out int count, out long size) { count = 0; diff --git a/Scalar.Common/Maintenance/PackfileMaintenanceStep.cs b/Scalar.Common/Maintenance/PackfileMaintenanceStep.cs index 6064013f12..4f9849ba7f 100644 --- a/Scalar.Common/Maintenance/PackfileMaintenanceStep.cs +++ b/Scalar.Common/Maintenance/PackfileMaintenanceStep.cs @@ -45,6 +45,9 @@ public PackfileMaintenanceStep( } public override string Area => nameof(PackfileMaintenanceStep); + + public override string ProgressMessage => "Cleaning up pack-files"; + protected override string LastRunTimeFilePath => Path.Combine(this.Context.Enlistment.GitObjectsRoot, "info", PackfileLastRunFileName); protected override TimeSpan TimeBetweenRuns => TimeSpan.FromDays(1); diff --git a/Scalar.Common/ScalarConstants.cs b/Scalar.Common/ScalarConstants.cs index 5dd2d8693b..f1f6afde19 100644 --- a/Scalar.Common/ScalarConstants.cs +++ b/Scalar.Common/ScalarConstants.cs @@ -198,11 +198,12 @@ public static class Unmount public static class Maintenance { + public const string AllTasksName = "all"; + public const string ConfigTaskName = "config"; + public const string CommitGraphTaskName = "commit-graph"; public const string FetchTaskName = "fetch"; public const string LooseObjectsTaskName = "loose-objects"; public const string PackFilesTaskName = "pack-files"; - public const string CommitGraphTaskName = "commit-graph"; - public const string ConfigTaskName = "config"; public const string BatchSizeOptionName = "batch-size"; } diff --git a/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/CommitGraphStepTests.cs b/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/CommitGraphStepTests.cs index 6d067db264..67d425a69a 100644 --- a/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/CommitGraphStepTests.cs +++ b/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/CommitGraphStepTests.cs @@ -29,7 +29,7 @@ public void CreateCommitGraphWhenMissing() { RepositoryHelpers.DeleteTestDirectory(this.CommitGraphsRoot); - this.Enlistment.CommitGraphStep(); + this.Enlistment.RunVerb("commit-graph"); this.fileSystem .FileExists(this.CommitGraphsChain) @@ -58,7 +58,7 @@ public void CleansUpOphanedLockFiles() this.fileSystem.CreateEmptyFile(graphLockPath); - this.Enlistment.CommitGraphStep(); + this.Enlistment.RunVerb("commit-graph"); this.fileSystem.FileExists(graphLockPath).ShouldBeFalse(nameof(graphLockPath)); this.fileSystem.FileExists(this.CommitGraphsChain).ShouldBeTrue(nameof(this.CommitGraphsChain)); diff --git a/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/FetchStepTests.cs b/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/FetchStepTests.cs index f818b40f14..e9115e67a7 100644 --- a/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/FetchStepTests.cs +++ b/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/FetchStepTests.cs @@ -26,7 +26,7 @@ public FetchStepTests() [Category(Categories.MacTODO.TestNeedsToLockFile)] public void FetchStepCleansUpStaleFetchLock() { - this.Enlistment.FetchStep(); + this.Enlistment.RunVerb("fetch"); string fetchCommitsLockFile = Path.Combine( ScalarHelpers.GetObjectsRootFromGitConfig(this.Enlistment.RepoRoot), "pack", @@ -42,7 +42,7 @@ public void FetchStepCleansUpStaleFetchLock() .Count() .ShouldEqual(1, "Incorrect number of .keep files in pack directory"); - this.Enlistment.FetchStep(); + this.Enlistment.RunVerb("fetch"); fetchCommitsLockFile.ShouldNotExistOnDisk(this.fileSystem); } } diff --git a/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/FetchStepWithoutSharedCacheTests.cs b/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/FetchStepWithoutSharedCacheTests.cs index e7de931454..adc1f5b07b 100644 --- a/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/FetchStepWithoutSharedCacheTests.cs +++ b/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/FetchStepWithoutSharedCacheTests.cs @@ -43,7 +43,7 @@ private string TempPackRoot [TestCase, Order(1)] public void FetchStepCommitsToEmptyCache() { - this.Enlistment.FetchStep(); + this.Enlistment.RunVerb("fetch"); // Verify prefetch pack(s) are in packs folder and have matching idx file string[] prefetchPacks = this.ReadPrefetchPackFileNames(); @@ -66,7 +66,7 @@ public void FetchStepBuildsIdxWhenMissingFromPrefetchPack() idxPath.ShouldNotExistOnDisk(this.fileSystem); // fetch should rebuild the missing idx - this.Enlistment.FetchStep(); + this.Enlistment.RunVerb("fetch"); idxPath.ShouldBeAFile(this.fileSystem); @@ -90,7 +90,7 @@ public void FetchStepCleansUpBadPrefetchPack() badPackPath.ShouldBeAFile(this.fileSystem).WithContents(badContents); // fetch should delete the bad pack - this.Enlistment.FetchStep(); + this.Enlistment.RunVerb("fetch"); badPackPath.ShouldNotExistOnDisk(this.fileSystem); @@ -119,12 +119,12 @@ public void FetchStepFailsWhenItCannotRemoveABadPrefetchPack() // Open a handle to the bad pack that will prevent fetch-commits-and-trees from being able to delete it using (FileStream stream = new FileStream(badPackPath, FileMode.Open, FileAccess.Read, FileShare.None)) { - string output = this.Enlistment.FetchStep(failOnError: false); + string output = this.Enlistment.RunVerb("fetch", failOnError: false); output.ShouldContain($"Unable to delete {badPackPath}"); } // After handle is closed fetching commits and trees should succeed - this.Enlistment.FetchStep(); + this.Enlistment.RunVerb("fetch"); badPackPath.ShouldNotExistOnDisk(this.fileSystem); @@ -164,7 +164,7 @@ public void FetchCommitsAndTreesCleansUpStaleTempPrefetchPacks() this.fileSystem.WriteAllText(otherFilePath, otherFileContents); otherFilePath.ShouldBeAFile(this.fileSystem).WithContents(otherFileContents); - this.Enlistment.FetchStep(); + this.Enlistment.RunVerb("fetch"); // Validate stale prefetch packs are cleaned up Directory.GetFiles(this.TempPackRoot, $"{PrefetchPackPrefix}*.pack").ShouldBeEmpty("There should be no .pack files in the tempPack folder"); diff --git a/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/LooseObjectStepTests.cs b/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/LooseObjectStepTests.cs index 052453bb91..81d128beb1 100644 --- a/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/LooseObjectStepTests.cs +++ b/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/LooseObjectStepTests.cs @@ -38,7 +38,7 @@ public void NoLooseObjectsDoesNothing() this.GetLooseObjectFiles().Count.ShouldEqual(0); int startingPackFileCount = this.CountPackFiles(); - this.Enlistment.LooseObjectStep(); + this.Enlistment.RunVerb("loose-objects"); this.GetLooseObjectFiles().Count.ShouldEqual(0); this.CountPackFiles().ShouldEqual(startingPackFileCount); @@ -56,7 +56,7 @@ public void RemoveLooseObjectsInPackFiles() this.CountPackFiles().ShouldEqual(1); // Cleanup should delete all loose objects, since they are in the packfile - this.Enlistment.LooseObjectStep(); + this.Enlistment.RunVerb("loose-objects"); this.GetLooseObjectFiles().Count.ShouldEqual(0); this.CountPackFiles().ShouldEqual(1); @@ -76,13 +76,13 @@ public void PutLooseObjectsInPackFiles() looseObjectCount.ShouldBeAtLeast(1); // This step should put the loose objects into a packfile - this.Enlistment.LooseObjectStep(); + this.Enlistment.RunVerb("loose-objects"); this.GetLooseObjectFiles().Count.ShouldEqual(looseObjectCount); this.CountPackFiles().ShouldEqual(1); // Running the step a second time should remove the loose obects and keep the pack file - this.Enlistment.LooseObjectStep(); + this.Enlistment.RunVerb("loose-objects"); this.GetLooseObjectFiles().Count.ShouldEqual(0); this.CountPackFiles().ShouldEqual(1); @@ -110,7 +110,7 @@ public void CorruptLooseObjectIsDeleted() // This step should fail to place the objects, but // succeed in deleting the given file. - this.Enlistment.LooseObjectStep(); + this.Enlistment.RunVerb("loose-objects"); this.fileSystem.FileExists(fakeBlob).ShouldBeFalse( "Step failed to delete corrupt blob"); @@ -120,13 +120,13 @@ public void CorruptLooseObjectIsDeleted() "unexpected number of loose objects after step"); // This step should create a pack. - this.Enlistment.LooseObjectStep(); + this.Enlistment.RunVerb("loose-objects"); this.CountPackFiles().ShouldEqual(1, "Incorrect number of packs after second loose object step"); this.GetLooseObjectFiles().Count.ShouldEqual(looseObjectCount); // This step should delete the loose objects - this.Enlistment.LooseObjectStep(); + this.Enlistment.RunVerb("loose-objects"); this.GetLooseObjectFiles().Count.ShouldEqual(0, "Incorrect number of loose objects after third loose object step"); } diff --git a/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/PackfileMaintenanceStepTests.cs b/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/PackfileMaintenanceStepTests.cs index 98ee3a0c42..ec540700ea 100644 --- a/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/PackfileMaintenanceStepTests.cs +++ b/Scalar.FunctionalTests/Tests/EnlistmentPerFixture/PackfileMaintenanceStepTests.cs @@ -45,7 +45,7 @@ public void RepackAllToOnePack() // Run the step to ensure we don't have any packs that will be expired during the repack step. // Use a non-standard, but large batchSize to avoid logic that resizes the batchSize. - this.Enlistment.PackfileMaintenanceStep(batchSize: BatchSizeForNoRepack); + this.Enlistment.RunVerb("pack-files", batchSize: BatchSizeForNoRepack); this.GetPackSizes(out int afterPrefetchPackCount, out maxSize, out minSize, out totalSize); @@ -53,7 +53,7 @@ public void RepackAllToOnePack() afterPrefetchPackCount.ShouldBeAtLeast(2); // Batch size 0 tells Git to repack everything into a single pack! - this.Enlistment.PackfileMaintenanceStep(batchSize: 0); + this.Enlistment.RunVerb("pack-files", batchSize: 0); this.GetPackSizes(out int packCount, out maxSize, out minSize, out totalSize); // We should not have expired any packs, but created a new one with repack @@ -70,8 +70,8 @@ public void ExpireAllButOneAndKeep() // We should expire all packs except the one we just created, // and the prefetch pack which is marked as ".keep" - this.Enlistment.PackfileMaintenanceStep(batchSize: BatchSizeForNoRepack); - + this.Enlistment.RunVerb("pack-files", batchSize: BatchSizeForNoRepack); + List packsAfter = this.GetPackfiles(); packsAfter.Count.ShouldEqual(2, $"incorrect number of packs after final expire step: {packsAfter.Count}"); diff --git a/Scalar.FunctionalTests/Tests/GitRepoPerFixture/RunVerbTests.cs b/Scalar.FunctionalTests/Tests/GitRepoPerFixture/RunVerbTests.cs index 4d5020d6b2..265a70d8a8 100644 --- a/Scalar.FunctionalTests/Tests/GitRepoPerFixture/RunVerbTests.cs +++ b/Scalar.FunctionalTests/Tests/GitRepoPerFixture/RunVerbTests.cs @@ -28,7 +28,7 @@ public RunVerbTests() public void CommitGraphStep() { this.fileSystem.FileExists(CommitGraphChain).ShouldBeFalse(); - this.Enlistment.CommitGraphStep(); + this.Enlistment.RunVerb("commit-graph"); this.fileSystem.FileExists(CommitGraphChain).ShouldBeTrue(); } @@ -47,7 +47,7 @@ public void PackfileMaintenanceStep() minSize.ShouldNotEqual(0, "min size means empty pack-file?"); this.Enlistment - .PackfileMaintenanceStep(batchSize: totalSize - minSize + 1) + .RunVerb("pack-files", batchSize: totalSize - minSize + 1) .ShouldNotContain(false, "Skipping pack maintenance due to no .keep file."); this.GetPackSizes(out int countAfterStep, out maxSize, out minSize, out totalSize); @@ -56,7 +56,7 @@ public void PackfileMaintenanceStep() countAfterStep.ShouldEqual(countAfterRepack + 1, nameof(countAfterStep)); this.Enlistment - .PackfileMaintenanceStep(batchSize: totalSize - minSize + 1) + .RunVerb("pack-files", batchSize: totalSize - minSize + 1) .ShouldNotContain(false, "Skipping pack maintenance due to no .keep file."); this.GetPackSizes(out int countAfterStep2, out maxSize, out minSize, out totalSize); @@ -76,14 +76,14 @@ public void LooseObjectsStep() minSize.ShouldNotEqual(0, "min size means empty pack-file?"); // This step packs the loose object into a pack. - this.Enlistment.LooseObjectStep(); + this.Enlistment.RunVerb("loose-objects"); this.GetPackSizes(out int countAfterStep1, out _, out minSize, out _); minSize.ShouldNotEqual(0, "min size means empty pack-file?"); this.GetLooseObjectFiles().Count.ShouldBeAtLeast(1); countAfterStep1.ShouldEqual(countBeforeStep + 1, "First step should create a pack"); // This step deletes the loose object that is already in a pack - this.Enlistment.LooseObjectStep(); + this.Enlistment.RunVerb("loose-objects"); this.GetPackSizes(out int countAfterStep2, out _, out minSize, out _); minSize.ShouldNotEqual(0, "min size means empty pack-file?"); this.GetLooseObjectFiles().Count.ShouldEqual(0); @@ -104,7 +104,7 @@ public void FetchStep() this.fileSystem.DeleteDirectory(refsRemotes); this.fileSystem.DeleteDirectory(this.PackRoot); - this.Enlistment.FetchStep(); + this.Enlistment.RunVerb("fetch"); this.GetPackSizes(out int countAfterFetch, out _, out _, out _); @@ -114,7 +114,7 @@ public void FetchStep() this.fileSystem.DirectoryExists(refsHeads).ShouldBeFalse("background fetch should not have created refs/heads/*"); this.fileSystem.DirectoryExists(refsRemotes).ShouldBeFalse("background fetch should not have created refs/remotes/*"); - this.Enlistment.FetchStep(); + this.Enlistment.RunVerb("fetch"); this.fileSystem.DirectoryExists(refsHeads).ShouldBeFalse("background fetch should not have created refs/heads/*"); this.fileSystem.DirectoryExists(refsRemotes).ShouldBeFalse("background fetch should not have created refs/remotes/*"); @@ -123,6 +123,14 @@ public void FetchStep() countAfterFetch2.ShouldEqual(1, "sceond fetch should not download a pack"); } + + [TestCase] + [Order(5)] + public void AllSteps() + { + this.Enlistment.RunVerb("all"); + } + private List GetPackfiles() { return Directory.GetFiles(this.PackRoot, "*.pack").ToList(); diff --git a/Scalar.FunctionalTests/Tools/ScalarFunctionalTestEnlistment.cs b/Scalar.FunctionalTests/Tools/ScalarFunctionalTestEnlistment.cs index 57e69c08d8..5ca877c59d 100644 --- a/Scalar.FunctionalTests/Tools/ScalarFunctionalTestEnlistment.cs +++ b/Scalar.FunctionalTests/Tools/ScalarFunctionalTestEnlistment.cs @@ -187,9 +187,9 @@ public void CloneGitRepo() this.InitializeConfig(); } - public string FetchStep(bool failOnError = true, string standardInput = null) + public string RunVerb(string task, long? batchSize = null, bool failOnError = true) { - return this.scalarProcess.FetchStep(failOnError, standardInput); + return this.scalarProcess.RunVerb(task, batchSize, failOnError); } public void Unregister() @@ -207,21 +207,6 @@ public string Diagnose() return this.scalarProcess.Diagnose(); } - public string CommitGraphStep() - { - return this.scalarProcess.CommitGraphStep(); - } - - public string LooseObjectStep() - { - return this.scalarProcess.LooseObjectStep(); - } - - public string PackfileMaintenanceStep(long? batchSize = null) - { - return this.scalarProcess.PackfileMaintenanceStep(batchSize); - } - public string Status(string trace = null) { return this.scalarProcess.Status(trace); diff --git a/Scalar.FunctionalTests/Tools/ScalarProcess.cs b/Scalar.FunctionalTests/Tools/ScalarProcess.cs index dbf982638d..4687246495 100644 --- a/Scalar.FunctionalTests/Tools/ScalarProcess.cs +++ b/Scalar.FunctionalTests/Tools/ScalarProcess.cs @@ -56,12 +56,16 @@ public bool TryMount(out string output) return this.IsEnlistmentMounted(); } - public string FetchStep(bool failOnError, string standardInput = null) + public string RunVerb(string task, long? batchSize = null, bool failOnError = true) { + string batchArg = batchSize == null + ? string.Empty + : $"--batch-size={batchSize}"; + return this.CallScalar( - $"run fetch \"{this.enlistmentRoot}\"", + $"run {task} \"{this.enlistmentRoot}\" {batchArg}", failOnError ? SuccessExitCode : DoNotCheckExitCode, - standardInput: standardInput); + standardInput: null); } public void Repair(bool confirm) @@ -72,28 +76,6 @@ public void Repair(bool confirm) expectedExitCode: SuccessExitCode); } - public string CommitGraphStep() - { - return this.CallScalar( - $"run commit-graph \"{this.enlistmentRoot}\"", - expectedExitCode: SuccessExitCode); - } - - public string LooseObjectStep() - { - return this.CallScalar( - $"run loose-objects \"{this.enlistmentRoot}\"", - expectedExitCode: SuccessExitCode); - } - - public string PackfileMaintenanceStep(long? batchSize) - { - string sizeString = batchSize.HasValue ? $"--batch-size {batchSize.Value}" : string.Empty; - return this.CallScalar( - $"run pack-files \"{this.enlistmentRoot}\" {sizeString}", - expectedExitCode: SuccessExitCode); - } - public string Register(string enlistmentRoot) { return this.CallScalar($"register", expectedExitCode: SuccessExitCode, workingDirectory: enlistmentRoot); diff --git a/Scalar.UnitTests/Maintenance/GitMaintenanceStepTests.cs b/Scalar.UnitTests/Maintenance/GitMaintenanceStepTests.cs index a9e2c6762d..6929b2bcaf 100644 --- a/Scalar.UnitTests/Maintenance/GitMaintenanceStepTests.cs +++ b/Scalar.UnitTests/Maintenance/GitMaintenanceStepTests.cs @@ -100,6 +100,8 @@ public CheckMethodStep(ScalarContext context, WhenToStop when) public override string Area => "CheckMethodStep"; + public override string ProgressMessage => throw new System.NotImplementedException(); + protected override void PerformMaintenance() { if (this.when == WhenToStop.BeforeGitCommand) diff --git a/Scalar/CommandLine/RunVerb.cs b/Scalar/CommandLine/RunVerb.cs index 9a889da074..ffc9cdfb0f 100644 --- a/Scalar/CommandLine/RunVerb.cs +++ b/Scalar/CommandLine/RunVerb.cs @@ -6,6 +6,7 @@ using Scalar.Common.Maintenance; using Scalar.Common.Tracing; using System; +using System.Collections.Generic; namespace Scalar.CommandLine { @@ -20,9 +21,12 @@ public class RunVerb : ScalarVerb.ForExistingEnlistment MetaName = "Task", Default = "", HelpText = "Maintenance task to run. Allowed values are '" + + ScalarConstants.VerbParameters.Maintenance.AllTasksName + "', '" + + ScalarConstants.VerbParameters.Maintenance.ConfigTaskName + "', '" + + ScalarConstants.VerbParameters.Maintenance.CommitGraphTaskName + "', '" + + ScalarConstants.VerbParameters.Maintenance.FetchTaskName + "', '" + ScalarConstants.VerbParameters.Maintenance.LooseObjectsTaskName + "', '" - + ScalarConstants.VerbParameters.Maintenance.PackFilesTaskName + "', '" - + ScalarConstants.VerbParameters.Maintenance.CommitGraphTaskName + "'")] + + ScalarConstants.VerbParameters.Maintenance.PackFilesTaskName + "'")] public string MaintenanceTask { get; set; } [Option( @@ -52,6 +56,8 @@ protected override void Execute(ScalarEnlistment enlistment) ScalarConstants.LogFileTypes.Maintenance, logId: this.StartedByService ? "service" : null); + List steps = new List(); + tracer.AddLogFileEventListener( logFileName, EventLevel.Informational, @@ -75,41 +81,67 @@ protected override void Execute(ScalarEnlistment enlistment) { try { + GitObjectsHttpRequestor objectRequestor = null; + CacheServerInfo cacheServer; + GitObjects gitObjects; + switch (this.MaintenanceTask) { + case ScalarConstants.VerbParameters.Maintenance.AllTasksName: + steps.Add(new ConfigStep(context)); + this.InitializeServerConnection(tracer, enlistment, cacheServerUrl, out objectRequestor, out cacheServer); + gitObjects = new GitObjects(tracer, enlistment, objectRequestor, fileSystem); + steps.Add(new FetchStep(context, gitObjects, requireCacheLock: false, forceRun: !this.StartedByService)); + steps.Add(new CommitGraphStep(context, requireObjectCacheLock: false)); + steps.Add(new LooseObjectsStep(context, forceRun: !this.StartedByService)); + steps.Add(new PackfileMaintenanceStep( + context, + forceRun: !this.StartedByService, + batchSize: string.IsNullOrWhiteSpace(this.PackfileMaintenanceBatchSize) ? + PackfileMaintenanceStep.DefaultBatchSizeBytes.ToString() : + this.PackfileMaintenanceBatchSize)); + break; + case ScalarConstants.VerbParameters.Maintenance.LooseObjectsTaskName: this.FailIfBatchSizeSet(tracer); - (new LooseObjectsStep(context, forceRun: true)).Execute(); - return; + steps.Add(new LooseObjectsStep(context, forceRun: !this.StartedByService)); + break; case ScalarConstants.VerbParameters.Maintenance.PackFilesTaskName: - (new PackfileMaintenanceStep( - context, - forceRun: true, - batchSize: string.IsNullOrWhiteSpace(this.PackfileMaintenanceBatchSize) ? - PackfileMaintenanceStep.DefaultBatchSizeBytes.ToString() : - this.PackfileMaintenanceBatchSize)).Execute(); - return; + steps.Add(new PackfileMaintenanceStep( + context, + forceRun: !this.StartedByService, + batchSize: string.IsNullOrWhiteSpace(this.PackfileMaintenanceBatchSize) ? + PackfileMaintenanceStep.DefaultBatchSizeBytes.ToString() : + this.PackfileMaintenanceBatchSize)); + break; case ScalarConstants.VerbParameters.Maintenance.FetchTaskName: this.FailIfBatchSizeSet(tracer); - this.FetchCommitsAndTrees(tracer, enlistment, cacheServerUrl); - return; + this.InitializeServerConnection(tracer, enlistment, cacheServerUrl, out objectRequestor, out cacheServer); + gitObjects = new GitObjects(tracer, enlistment, objectRequestor, fileSystem); + steps.Add(new FetchStep(context, gitObjects, requireCacheLock: false, forceRun: !this.StartedByService)); + break; case ScalarConstants.VerbParameters.Maintenance.CommitGraphTaskName: this.FailIfBatchSizeSet(tracer); - (new CommitGraphStep(context, requireObjectCacheLock: false)).Execute(); - return; + steps.Add(new CommitGraphStep(context, requireObjectCacheLock: false)); + break; case ScalarConstants.VerbParameters.Maintenance.ConfigTaskName: this.FailIfBatchSizeSet(tracer); - (new ConfigStep(context)).Execute(); - return; + steps.Add(new ConfigStep(context)); + break; default: this.ReportErrorAndExit($"Unknown maintenance task requested: '{this.MaintenanceTask}'"); break; } + + foreach (GitMaintenanceStep step in steps) + { + this.ShowStatusWhileRunning(() => { step.Execute(); return true; }, step.ProgressMessage); + } } catch (VerbAbortedException) { @@ -138,24 +170,6 @@ protected override void Execute(ScalarEnlistment enlistment) } } - private void FetchCommitsAndTrees(ITracer tracer, ScalarEnlistment enlistment, string cacheServerUrl) - { - GitObjectsHttpRequestor objectRequestor = null; - CacheServerInfo cacheServer = null; - - if (enlistment.UsesGvfsProtocol) - { - this.InitializeServerConnection( - tracer, - enlistment, - cacheServerUrl, - out objectRequestor, - out cacheServer); - } - - this.RunFetchStep(tracer, enlistment, objectRequestor, cacheServer); - } - private void FailIfBatchSizeSet(ITracer tracer) { if (!string.IsNullOrWhiteSpace(this.PackfileMaintenanceBatchSize)) @@ -174,6 +188,13 @@ private void InitializeServerConnection( out GitObjectsHttpRequestor objectRequestor, out CacheServerInfo cacheServer) { + if (!enlistment.UsesGvfsProtocol) + { + objectRequestor = null; + cacheServer = null; + return; + } + RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); cacheServer = this.ResolvedCacheServer; @@ -205,38 +226,5 @@ private void InitializeServerConnection( this.InitializeCachePaths(tracer, enlistment); objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig); } - - private void RunFetchStep(ITracer tracer, ScalarEnlistment enlistment, GitObjectsHttpRequestor objectRequestor, CacheServerInfo cacheServer) - { - bool success; - string error = string.Empty; - PhysicalFileSystem fileSystem = new PhysicalFileSystem(); - ScalarContext context = new ScalarContext(tracer, fileSystem, enlistment); - GitObjects gitObjects = new GitObjects(tracer, enlistment, objectRequestor, fileSystem); - - success = this.ShowStatusWhileRunning( - () => new FetchStep(context, gitObjects, requireCacheLock: false, forceRun: !this.StartedByService).TryFetch(out error), - "Fetching " + this.GetCacheServerDisplay(cacheServer, enlistment.RepoUrl)); - - if (!success) - { - this.ReportErrorAndExit(tracer, ReturnCode.GenericError, "Fetch failed: " + error); - } - } - - private string GetCacheServerDisplay(CacheServerInfo cacheServer, string repoUrl) - { - if (cacheServer == null) - { - return "from remotes"; - } - - if (!cacheServer.IsNone(repoUrl)) - { - return "from cache server"; - } - - return "from origin (no cache server)"; - } } } diff --git a/docs/advanced.md b/docs/advanced.md index 6e9ea027b6..c6b1f6087f 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -9,6 +9,12 @@ chose to run those maintenance steps yourself by running `scalar run [`. These tasks are: +* `config`: Set recommended Git config settings. These are all intended + to improve performance in large repos. If the repo was cloned by Scalar, + then most of these settings will overwrite any existing settings. Otherwise, + Scalar will not override a local config value that disagrees with the + recommendation. + * `commit-graph`: Update the Git commit-graph to include all reachable commits. After writing a new file, verify the file was computed successfully. This drastically improves the performance of commands like `git log --graph`. @@ -38,6 +44,15 @@ tasks are: batch-size is "2g" for two gigabytes. This batch size signifies the goal size of a repacked pack-file. +* `all`: This task runs all of the above steps in the following order: + 1. `config` ensures our recommended values are set for the remaining steps. + 2. `fetch` downloads the latest data from the remotes. + 3. `commit-graph` updates based on the newly fetched data. + 4. `loose-objects` cleans up loose objects. When using the GVFS protocol, + the previous steps may have downloaded new loose objects. + 5. `pack-files` cleans up the pack-files, including those downloaed in + previous steps. + Controlling Background Maintenance ----------------------------------