public override void Execute() { PhysicalFileSystem fileSystem = new PhysicalFileSystem(); this.ValidatePathParameter(this.EnlistmentRootPathParameter); ScalarEnlistment enlistment = this.CreateEnlistment(this.EnlistmentRootPathParameter ?? Directory.GetCurrentDirectory(), null); using (JsonTracer tracer = new JsonTracer(ScalarConstants.ScalarEtwProviderName, RegisterVerb.RegisterVerbName)) { if (this.TryRegisterRepo(tracer, enlistment, fileSystem, out string error)) { this.Output.WriteLine($"Successfully registered repo at '{enlistment.EnlistmentRoot}'"); } else { string message = $"Failed to register repo: {error}"; tracer.RelatedError(message); this.ReportErrorAndExit(message); return; } ScalarContext context = new ScalarContext(tracer, fileSystem, enlistment); new ConfigStep(context).Execute(); } }
private void TestSetup() { ITracer tracer = new MockTracer(); ScalarEnlistment enlistment = new MockScalarEnlistment(); PhysicalFileSystem fileSystem = new MockFileSystem(new MockDirectory(enlistment.EnlistmentRoot, null, null)); this.context = new ScalarContext(tracer, fileSystem, enlistment); }
public LooseObjectsStep( ScalarContext context, bool requireCacheLock = true, bool forceRun = false, GitProcessChecker gitProcessChecker = null) : base(context, requireCacheLock, gitProcessChecker) { this.forceRun = forceRun; }
public FetchStep( ScalarContext context, GitObjects gitObjects, bool requireCacheLock = true, bool forceRun = false) : base(context, requireCacheLock) { this.GitObjects = gitObjects; this.forceRun = forceRun; }
public PackfileMaintenanceStep( ScalarContext context, bool requireObjectCacheLock = true, bool forceRun = false, string batchSize = null, GitProcessChecker gitProcessChecker = null) : base(context, requireObjectCacheLock, gitProcessChecker) { this.forceRun = forceRun; this.batchSize = batchSize ?? DefaultBatchSizeBytes.ToString(); }
private void TestSetup() { this.gitProcess = new MockGitProcess(); // Create enlistment using git process ScalarEnlistment enlistment = new MockScalarEnlistment(this.gitProcess); PhysicalFileSystem fileSystem = new MockFileSystem(new MockDirectory(enlistment.EnlistmentRoot, null, null)); // Create and return Context this.tracer = new MockTracer(); this.context = new ScalarContext(this.tracer, fileSystem, enlistment: enlistment); }
public static bool EnlistmentRootReady(ScalarContext context) { // If a user locks their drive or disconnects an external drive while the process // is running, then it will appear as if the directories below do not exist or throw // a "Device is not ready" error. try { return(context.FileSystem.DirectoryExists(context.Enlistment.EnlistmentRoot) && context.FileSystem.DirectoryExists(context.Enlistment.GitObjectsRoot)); } catch (IOException) { return(false); } }
public ConfigStep(ScalarContext context, bool?useGvfsProtocol = null) : base(context, requireObjectCacheLock: false) { this.UseGvfsProtocol = useGvfsProtocol; }
private Result CreateClone() { Result initRepoResult = this.TryInitRepo(); if (!initRepoResult.Success) { return(initRepoResult); } string errorMessage; if (!this.TrySetObjectCacheLocation(this.fileSystem, this.enlistment, out errorMessage)) { return(new Result("Error configuring alternate: " + errorMessage)); } this.context = new ScalarContext(this.tracer, this.fileSystem, this.enlistment); // Set required and optional config. // Explicitly pass useGvfsProtocol: true as the enlistment can not discover that setting from // Git config yet. Other verbs will discover this automatically from the config we set now. ConfigStep configStep = new ConfigStep(context, useGvfsProtocol: true); if (!configStep.TrySetConfig(out string configError)) { return(new Result($"Failed to set initial config: {configError}")); } CacheServerResolver cacheServerResolver = new CacheServerResolver(this.tracer, this.enlistment); if (!cacheServerResolver.TrySaveUrlToLocalConfig(this.cacheServer, out errorMessage)) { return(new Result("Unable to configure cache server: " + errorMessage)); } if (!this.TryDownloadCommit( this.refs.GetTipCommitId(this.Branch), this.enlistment, out errorMessage)) { return(new Result(errorMessage)); } this.git = new GitProcess(this.enlistment); string originBranchName = "origin/" + this.Branch; GitProcess.Result createBranchResult = this.git.CreateBranchWithUpstream(this.Branch, originBranchName); if (createBranchResult.ExitCodeIsFailure) { return(new Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output)); } File.WriteAllText( Path.Combine(this.enlistment.WorkingDirectoryRoot, ScalarConstants.DotGit.Head), "ref: refs/heads/" + this.Branch); try { this.LogEnlistmentInfoAndSetConfigValues(this.tracer, this.git, this.enlistment); } catch (Exception e) { this.tracer.RelatedError(e.ToString()); return(new Result(e.Message)); } return(new Result(true)); }
private void TestSetup(DateTime lastRun) { string lastRunTime = EpochConverter.ToUnixEpochSeconds(lastRun).ToString(); // Create GitProcess this.gitProcess = new MockGitProcess(); this.gitProcess.SetExpectedCommandResult( PrunePackedCommand, () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode)); // Create enlistment using git process ScalarEnlistment enlistment = new MockScalarEnlistment(this.gitProcess); string packPrefix = Path.Combine(enlistment.GitPackRoot, "from-loose"); this.packCommand = $"pack-objects {packPrefix} --non-empty --window=0 --depth=0 -q"; this.gitProcess.SetExpectedCommandResult( this.packCommand, () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode)); // Create a last run time file MockFile timeFile = new MockFile(Path.Combine(enlistment.GitObjectsRoot, "info", LooseObjectsStep.LooseObjectsLastRunFileName), lastRunTime); // Create info directory to hold last run time file MockDirectory infoRoot = new MockDirectory(Path.Combine(enlistment.GitObjectsRoot, "info"), null, new List <MockFile>() { timeFile }); // Create Hex Folder 1 with 1 File MockDirectory hex1 = new MockDirectory( Path.Combine(enlistment.GitObjectsRoot, "AA"), null, new List <MockFile>() { new MockFile(Path.Combine(enlistment.GitObjectsRoot, "AA", "1156f4f2b850673090c285289ea8475d629fe1"), "one") }); // Create Hex Folder 2 with 2 Files MockDirectory hex2 = new MockDirectory( Path.Combine(enlistment.GitObjectsRoot, "F1"), null, new List <MockFile>() { new MockFile(Path.Combine(enlistment.GitObjectsRoot, "F1", "1156f4f2b850673090c285289ea8475d629fe2"), "two"), new MockFile(Path.Combine(enlistment.GitObjectsRoot, "F1", "1156f4f2b850673090c285289ea8475d629fe3"), "three") }); // Create NonHex Folder with 4 Files MockDirectory nonhex = new MockDirectory( Path.Combine(enlistment.GitObjectsRoot, "ZZ"), null, new List <MockFile>() { new MockFile(Path.Combine(enlistment.GitObjectsRoot, "ZZ", "1156f4f2b850673090c285289ea8475d629fe4"), "4"), new MockFile(Path.Combine(enlistment.GitObjectsRoot, "ZZ", "1156f4f2b850673090c285289ea8475d629fe5"), "5"), new MockFile(Path.Combine(enlistment.GitObjectsRoot, "ZZ", "1156f4f2b850673090c285289ea8475d629fe6"), "6"), new MockFile(Path.Combine(enlistment.GitObjectsRoot, "ZZ", "1156f4f2b850673090c285289ea8475d629fe7"), "7") }); MockDirectory pack = new MockDirectory( enlistment.GitPackRoot, null, new List <MockFile>()); // Create git objects directory MockDirectory gitObjectsRoot = new MockDirectory(enlistment.GitObjectsRoot, new List <MockDirectory>() { infoRoot, hex1, hex2, nonhex, pack }, null); // Add object directory to file System List <MockDirectory> directories = new List <MockDirectory>() { gitObjectsRoot }; PhysicalFileSystem fileSystem = new MockFileSystem(new MockDirectory(enlistment.EnlistmentRoot, directories, null)); // Create and return Context this.tracer = new MockTracer(); this.context = new ScalarContext(this.tracer, fileSystem, enlistment: enlistment); }
private Result GitClone() { string gitBinPath = ScalarPlatform.Instance.GitInstallation.GetInstalledGitBinPath(); if (string.IsNullOrWhiteSpace(gitBinPath)) { return(new Result(ScalarConstants.GitIsNotInstalledError)); } GitProcess git = new GitProcess(this.enlistment); // protocol.version=2 is broken right now. git.SetInLocalConfig("protocol.version", "1"); git.SetInLocalConfig("remote.origin.url", this.RepositoryURL); git.SetInLocalConfig("remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*"); git.SetInLocalConfig("remote.origin.promisor", "true"); git.SetInLocalConfig("remote.origin.partialCloneFilter", "blob:none"); string branch = this.Branch ?? "master"; git.SetInLocalConfig($"branch.{branch}.remote", "origin"); git.SetInLocalConfig($"branch.{branch}.merge", $"refs/heads/{branch}"); if (!this.FullClone) { GitProcess.SparseCheckoutInit(this.enlistment); } this.context = new ScalarContext(this.tracer, this.fileSystem, this.enlistment); // Set required and optional config. // Explicitly pass useGvfsProtocol: true as the enlistment can not discover that setting from // Git config yet. Other verbs will discover this automatically from the config we set now. ConfigStep configStep = new ConfigStep(this.context, useGvfsProtocol: false); if (!configStep.TrySetConfig(out string configError)) { return(new Result($"Failed to set initial config: {configError}")); } GitProcess.Result fetchResult = null; if (!this.ShowStatusWhileRunning(() => { using (ITracer activity = this.tracer.StartActivity("git-fetch-partial", EventLevel.LogAlways)) { fetchResult = git.ForegroundFetch("origin"); return(fetchResult.ExitCodeIsSuccess); } }, "Fetching objects from remote")) { if (!fetchResult.Errors.Contains("filtering not recognized by server")) { return(new Result($"Failed to complete regular clone: {fetchResult?.Errors}")); } } if (fetchResult.ExitCodeIsFailure && !this.ShowStatusWhileRunning(() => { using (ITracer activity = this.tracer.StartActivity("git-fetch", EventLevel.LogAlways)) { git.DeleteFromLocalConfig("remote.origin.promisor"); git.DeleteFromLocalConfig("remote.origin.partialCloneFilter"); fetchResult = git.ForegroundFetch("origin"); return(fetchResult.ExitCodeIsSuccess); } }, "Fetching objects from remote")) { return(new Result($"Failed to complete regular clone: {fetchResult?.Errors}")); } GitProcess.Result checkoutResult = null; if (!this.ShowStatusWhileRunning(() => { using (ITracer activity = this.tracer.StartActivity("git-checkout", EventLevel.LogAlways)) { checkoutResult = git.ForceCheckout(branch); return(checkoutResult.ExitCodeIsSuccess); } }, $"Checking out '{branch}'")) { return(new Result($"Failed to complete regular clone: {checkoutResult?.Errors}")); } return(new Result(true)); }
private void TestSetup(DateTime lastRun, bool failOnVerify = false) { string lastRunTime = EpochConverter.ToUnixEpochSeconds(lastRun).ToString(); this.gitProcess = new MockGitProcess(); // Create enlistment using git process ScalarEnlistment enlistment = new MockScalarEnlistment(this.gitProcess); // Create a last run time file MockFile timeFile = new MockFile(Path.Combine(enlistment.GitObjectsRoot, "info", PackfileMaintenanceStep.PackfileLastRunFileName), lastRunTime); // Create info directory to hold last run time file MockDirectory info = new MockDirectory( Path.Combine(enlistment.GitObjectsRoot, "info"), null, new List <MockFile>() { timeFile }); // Create pack info MockDirectory pack = new MockDirectory( enlistment.GitPackRoot, null, new List <MockFile>() { new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-1.pack"), "one"), new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-1.idx"), "1"), new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-2.pack"), "two"), new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-2.idx"), "2"), new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-3.pack"), "three"), new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-3.idx"), "3"), new MockFile(Path.Combine(enlistment.GitPackRoot, KeepName), string.Empty), new MockFile(Path.Combine(enlistment.GitPackRoot, StaleIdxName), "4"), }); // Create git objects directory MockDirectory gitObjectsRoot = new MockDirectory(enlistment.GitObjectsRoot, new List <MockDirectory>() { info, pack }, null); // Add object directory to file System List <MockDirectory> directories = new List <MockDirectory>() { gitObjectsRoot }; PhysicalFileSystem fileSystem = new MockFileSystem(new MockDirectory(enlistment.EnlistmentRoot, directories, null)); // Create and return Context this.tracer = new MockTracer(); this.context = new ScalarContext(this.tracer, fileSystem, enlistment); this.gitProcess.SetExpectedCommandResult( this.WriteCommand, () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode)); this.gitProcess.SetExpectedCommandResult( this.ExpireCommand, () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode)); this.gitProcess.SetExpectedCommandResult( this.VerifyCommand, () => new GitProcess.Result(string.Empty, string.Empty, failOnVerify ? GitProcess.Result.GenericFailureCode : GitProcess.Result.SuccessCode)); this.gitProcess.SetExpectedCommandResult( this.RepackCommand, () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode)); }
public GitMaintenanceStep(ScalarContext context, bool requireObjectCacheLock, GitProcessChecker gitProcessChecker = null) { this.Context = context; this.RequireObjectCacheLock = requireObjectCacheLock; this.GitProcessChecker = gitProcessChecker ?? new GitProcessChecker(); }
protected override void Execute(ScalarEnlistment enlistment) { using (JsonTracer tracer = new JsonTracer(ScalarConstants.ScalarEtwProviderName, RunVerbName)) { string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment); string logFileName = ScalarEnlistment.GetNewScalarLogFileName( enlistment.ScalarLogsRoot, ScalarConstants.LogFileTypes.Maintenance, logId: this.StartedByService ? "service" : null); List <GitMaintenanceStep> steps = new List <GitMaintenanceStep>(); tracer.AddLogFileEventListener( logFileName, EventLevel.Informational, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, cacheServerUrl, this.AddVerbDataToMetadata( new EventMetadata { { nameof(this.MaintenanceTask), this.MaintenanceTask }, { nameof(this.PackfileMaintenanceBatchSize), this.PackfileMaintenanceBatchSize }, { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter }, { nameof(this.StartedByService), this.StartedByService }, })); this.InitializeCachePaths(tracer, enlistment); PhysicalFileSystem fileSystem = new PhysicalFileSystem(); using (ScalarContext context = new ScalarContext(tracer, fileSystem, 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); steps.Add(new LooseObjectsStep(context, forceRun: !this.StartedByService)); break; case ScalarConstants.VerbParameters.Maintenance.PackFilesTaskName: 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.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); steps.Add(new CommitGraphStep(context, requireObjectCacheLock: false)); break; case ScalarConstants.VerbParameters.Maintenance.ConfigTaskName: this.FailIfBatchSizeSet(tracer); 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) { throw; } catch (AggregateException aggregateException) { string error = $"AggregateException thrown while running '{this.MaintenanceTask}' task: {aggregateException.Message}"; tracer.RelatedError(this.CreateEventMetadata(aggregateException), error); foreach (Exception innerException in aggregateException.Flatten().InnerExceptions) { tracer.RelatedError( this.CreateEventMetadata(innerException), $"Unhandled {innerException.GetType().Name}: {innerException.Message}"); } this.ReportErrorAndExit(tracer, ReturnCode.GenericError, error); } catch (Exception e) { string error = $"Exception thrown while running '{this.MaintenanceTask}' task: {e.Message}"; tracer.RelatedError(this.CreateEventMetadata(e), error); this.ReportErrorAndExit(tracer, ReturnCode.GenericError, error); } } } }
public CommitGraphStep(ScalarContext context, bool requireObjectCacheLock = true) : base(context, requireObjectCacheLock) { }
public CheckMethodStep(ScalarContext context, WhenToStop when) : base(context, requireObjectCacheLock: true) { this.when = when; }