protected bool TryDownloadRootGitAttributes(GVFSEnlistment enlistment, GVFSGitObjects gitObjects, GitRepo repo, out string error) { List <DiffTreeResult> rootEntries = new List <DiffTreeResult>(); GitProcess git = new GitProcess(enlistment); GitProcess.Result result = git.LsTree( GVFSConstants.DotGit.HeadName, line => rootEntries.Add(DiffTreeResult.ParseFromLsTreeLine(line, repoRoot: string.Empty)), recursive: false); if (result.ExitCodeIsFailure) { error = "Error returned from ls-tree to find " + GVFSConstants.SpecialGitFiles.GitAttributes + " file: " + result.Errors; return(false); } DiffTreeResult gitAttributes = rootEntries.FirstOrDefault(entry => entry.TargetPath.Equals(GVFSConstants.SpecialGitFiles.GitAttributes)); if (gitAttributes == null) { error = "This branch does not contain a " + GVFSConstants.SpecialGitFiles.GitAttributes + " file in the root folder. This file is required by GVFS clone"; return(false); } if (!repo.ObjectExists(gitAttributes.TargetSha)) { if (gitObjects.TryDownloadAndSaveObject(gitAttributes.TargetSha, GVFSGitObjects.RequestSource.GVFSVerb) != GitObjects.DownloadAndSaveObjectResult.Success) { error = "Could not download " + GVFSConstants.SpecialGitFiles.GitAttributes + " file"; return(false); } } error = null; return(true); }
public MacFileSystemVirtualizer(GVFSContext context, GVFSGitObjects gitObjects) : this(context, gitObjects, virtualizationInstance : null) { }
private void PrefetchCommits(ITracer tracer, GVFSEnlistment enlistment, GitObjectsHttpRequestor objectRequestor, CacheServerInfo cacheServer) { bool success; string error = string.Empty; PhysicalFileSystem fileSystem = new PhysicalFileSystem(); GitRepo repo = new GitRepo(tracer, enlistment, fileSystem); GVFSContext context = new GVFSContext(tracer, fileSystem, repo, enlistment); GitObjects gitObjects = new GVFSGitObjects(context, objectRequestor); List <string> packIndexes = null; if (this.Verbose) { success = this.TryPrefetchCommitsAndTrees(tracer, enlistment, fileSystem, gitObjects, out error, out packIndexes); } else { success = this.ShowStatusWhileRunning( () => this.TryPrefetchCommitsAndTrees(tracer, enlistment, fileSystem, gitObjects, out error, out packIndexes), "Fetching commits and trees " + this.GetCacheServerDisplay(cacheServer)); } if (success) { if (packIndexes.Count == 0) { return; } // We make a best-effort request to run MIDX and commit-graph writes using (NamedPipeClient pipeClient = new NamedPipeClient(enlistment.NamedPipeName)) { if (!pipeClient.Connect()) { tracer.RelatedWarning( metadata: null, message: "Failed to connect to GVFS. Skipping post-fetch job request.", keywords: Keywords.Telemetry); return; } NamedPipeMessages.RunPostFetchJob.Request request = new NamedPipeMessages.RunPostFetchJob.Request(packIndexes); if (pipeClient.TrySendRequest(request.CreateMessage())) { NamedPipeMessages.Message response; if (pipeClient.TryReadResponse(out response)) { tracer.RelatedInfo("Requested post-fetch job with resonse '{0}'", response.Header); } else { tracer.RelatedWarning( metadata: null, message: "Requested post-fetch job failed to respond", keywords: Keywords.Telemetry); } } else { tracer.RelatedWarning( metadata: null, message: "Message to named pipe failed to send, skipping post-fetch job request.", keywords: Keywords.Telemetry); } } } else { this.ReportErrorAndExit(tracer, "Prefetching commits and trees failed: " + error); } }
protected FileSystemVirtualizer(GVFSContext context, GVFSGitObjects gvfsGitObjects) : this(context, gvfsGitObjects, FileSystemVirtualizer.DefaultNumWorkerThreads) { }
private void MountAndStartWorkingDirectoryCallbacks(CacheServerInfo cache) { string error; if (!this.context.Enlistment.Authentication.TryInitialize(this.context.Tracer, this.context.Enlistment, out error)) { this.FailMountAndExit("Failed to obtain git credentials: " + error); } GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(this.context.Tracer, this.context.Enlistment, cache, this.retryConfig); this.gitObjects = new GVFSGitObjects(this.context, objectRequestor); FileSystemVirtualizer virtualizer = this.CreateOrReportAndExit(() => GVFSPlatformLoader.CreateFileSystemVirtualizer(this.context, this.gitObjects), "Failed to create src folder virtualizer"); GitStatusCache gitStatusCache = (!this.context.Unattended && GVFSPlatform.Instance.IsGitStatusCacheSupported()) ? new GitStatusCache(this.context, this.gitStatusCacheConfig) : null; if (gitStatusCache != null) { this.tracer.RelatedInfo("Git status cache enabled. Backoff time: {0}ms", this.gitStatusCacheConfig.BackoffTime.TotalMilliseconds); } else { this.tracer.RelatedInfo("Git status cache is not enabled"); } this.gvfsDatabase = this.CreateOrReportAndExit(() => new GVFSDatabase(this.context.FileSystem, this.context.Enlistment.EnlistmentRoot, new SqliteDatabase()), "Failed to create database connection"); this.fileSystemCallbacks = this.CreateOrReportAndExit( () => { return(new FileSystemCallbacks( this.context, this.gitObjects, RepoMetadata.Instance, blobSizes: null, gitIndexProjection: null, backgroundFileSystemTaskRunner: null, fileSystemVirtualizer: virtualizer, placeholderDatabase: new PlaceholderTable(this.gvfsDatabase), gitStatusCache: gitStatusCache)); }, "Failed to create src folder callback listener"); this.maintenanceScheduler = this.CreateOrReportAndExit(() => new GitMaintenanceScheduler(this.context, this.gitObjects), "Failed to start maintenance scheduler"); int majorVersion; int minorVersion; if (!RepoMetadata.Instance.TryGetOnDiskLayoutVersion(out majorVersion, out minorVersion, out error)) { this.FailMountAndExit("Error: {0}", error); } if (majorVersion != GVFSPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion) { this.FailMountAndExit( "Error: On disk version ({0}) does not match current version ({1})", majorVersion, GVFSPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion); } try { if (!this.fileSystemCallbacks.TryStart(out error)) { this.FailMountAndExit("Error: {0}. \r\nPlease confirm that gvfs clone completed without error.", error); } } catch (Exception e) { this.FailMountAndExit("Failed to initialize src folder callbacks. {0}", e.ToString()); } this.heartbeat = new HeartbeatThread(this.tracer, this.fileSystemCallbacks); this.heartbeat.Start(); }
private Result CreateClone( ITracer tracer, GVFSEnlistment enlistment, GitObjectsHttpRequestor objectRequestor, GitRefs refs, string branch) { Result initRepoResult = this.TryInitRepo(tracer, refs, enlistment); if (!initRepoResult.Success) { return(initRepoResult); } PhysicalFileSystem fileSystem = new PhysicalFileSystem(); string errorMessage; if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out errorMessage)) { return(new Result("Error configuring alternate: " + errorMessage)); } GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem); GVFSContext context = new GVFSContext(tracer, fileSystem, gitRepo, enlistment); GVFSGitObjects gitObjects = new GVFSGitObjects(context, objectRequestor); if (!this.TryDownloadCommit( refs.GetTipCommitId(branch), enlistment, objectRequestor, gitObjects, gitRepo, out errorMessage)) { return(new Result(errorMessage)); } if (!GVFSVerb.TrySetRequiredGitConfigSettings(enlistment) || !GVFSVerb.TrySetOptionalGitConfigSettings(enlistment)) { return(new Result("Unable to configure git repo")); } CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); if (!cacheServerResolver.TrySaveUrlToLocalConfig(objectRequestor.CacheServer, out errorMessage)) { return(new Result("Unable to configure cache server: " + errorMessage)); } GitProcess git = new GitProcess(enlistment); string originBranchName = "origin/" + branch; GitProcess.Result createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName); if (createBranchResult.ExitCodeIsFailure) { return(new Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output)); } File.WriteAllText( Path.Combine(enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Head), "ref: refs/heads/" + branch); if (!this.TryDownloadRootGitAttributes(enlistment, gitObjects, gitRepo, out errorMessage)) { return(new Result(errorMessage)); } this.CreateGitScript(enlistment); string installHooksError; if (!HooksInstaller.InstallHooks(context, out installHooksError)) { tracer.RelatedError(installHooksError); return(new Result(installHooksError)); } GitProcess.Result forceCheckoutResult = git.ForceCheckout(branch); if (forceCheckoutResult.ExitCodeIsFailure && forceCheckoutResult.Errors.IndexOf("unable to read tree") > 0) { // It is possible to have the above TryDownloadCommit() fail because we // already have the commit and root tree we intend to check out, but // don't have a tree further down the working directory. If we fail // checkout here, its' because we don't have these trees and the // read-object hook is not available yet. Force downloading the commit // again and retry the checkout. if (!this.TryDownloadCommit( refs.GetTipCommitId(branch), enlistment, objectRequestor, gitObjects, gitRepo, out errorMessage, checkLocalObjectCache: false)) { return(new Result(errorMessage)); } forceCheckoutResult = git.ForceCheckout(branch); } if (forceCheckoutResult.ExitCodeIsFailure) { string[] errorLines = forceCheckoutResult.Errors.Split('\n'); StringBuilder checkoutErrors = new StringBuilder(); foreach (string gitError in errorLines) { if (IsForceCheckoutErrorCloneFailure(gitError)) { checkoutErrors.AppendLine(gitError); } } if (checkoutErrors.Length > 0) { string error = "Could not complete checkout of branch: " + branch + ", " + checkoutErrors.ToString(); tracer.RelatedError(error); return(new Result(error)); } } if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGVFSRoot, out errorMessage)) { tracer.RelatedError(errorMessage); return(new Result(errorMessage)); } try { RepoMetadata.Instance.SaveCloneMetadata(tracer, enlistment); this.LogEnlistmentInfoAndSetConfigValues(tracer, git, enlistment); } catch (Exception e) { tracer.RelatedError(e.ToString()); return(new Result(e.Message)); } finally { RepoMetadata.Shutdown(); } // Prepare the working directory folder for GVFS last to ensure that gvfs mount will fail if gvfs clone has failed Exception exception; string prepFileSystemError; if (!GVFSPlatform.Instance.KernelDriver.TryPrepareFolderForCallbacks(enlistment.WorkingDirectoryRoot, out prepFileSystemError, out exception)) { EventMetadata metadata = new EventMetadata(); metadata.Add(nameof(prepFileSystemError), prepFileSystemError); if (exception != null) { metadata.Add("Exception", exception.ToString()); } tracer.RelatedError(metadata, $"{nameof(this.CreateClone)}: TryPrepareFolderForCallbacks failed"); return(new Result(prepFileSystemError)); } return(new Result(true)); }
public FileSystemCallbacks( GVFSContext context, GVFSGitObjects gitObjects, RepoMetadata repoMetadata, BlobSizes blobSizes, GitIndexProjection gitIndexProjection, BackgroundFileSystemTaskRunner backgroundFileSystemTaskRunner, FileSystemVirtualizer fileSystemVirtualizer, GitStatusCache gitStatusCache = null) { this.logsHeadFileProperties = null; this.postFetchJobLock = new object(); this.context = context; this.gitObjects = gitObjects; this.fileSystemVirtualizer = fileSystemVirtualizer; this.placeHolderCreationCount = new ConcurrentDictionary <string, PlaceHolderCreateCounter>(StringComparer.OrdinalIgnoreCase); this.newlyCreatedFileAndFolderPaths = new ConcurrentHashSet <string>(StringComparer.OrdinalIgnoreCase); string error; if (!ModifiedPathsDatabase.TryLoadOrCreate( this.context.Tracer, Path.Combine(this.context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.ModifiedPaths), this.context.FileSystem, out this.modifiedPaths, out error)) { throw new InvalidRepoException(error); } this.BlobSizes = blobSizes; this.BlobSizes.Initialize(); PlaceholderListDatabase placeholders; if (!PlaceholderListDatabase.TryCreate( this.context.Tracer, Path.Combine(this.context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.PlaceholderList), this.context.FileSystem, out placeholders, out error)) { throw new InvalidRepoException(error); } this.GitIndexProjection = gitIndexProjection ?? new GitIndexProjection( context, gitObjects, this.BlobSizes, repoMetadata, fileSystemVirtualizer, placeholders, this.modifiedPaths); if (backgroundFileSystemTaskRunner != null) { this.backgroundFileSystemTaskRunner = backgroundFileSystemTaskRunner; this.backgroundFileSystemTaskRunner.SetCallbacks( this.PreBackgroundOperation, this.ExecuteBackgroundOperation, this.PostBackgroundOperation); } else { this.backgroundFileSystemTaskRunner = new BackgroundFileSystemTaskRunner( this.context, this.PreBackgroundOperation, this.ExecuteBackgroundOperation, this.PostBackgroundOperation, Path.Combine(context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.BackgroundFileSystemTasks)); } this.enableGitStatusCache = gitStatusCache != null; // If the status cache is not enabled, create a dummy GitStatusCache that will never be initialized // This lets us from having to add null checks to callsites into GitStatusCache. this.gitStatusCache = gitStatusCache ?? new GitStatusCache(context, TimeSpan.Zero); this.logsHeadPath = Path.Combine(this.context.Enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Logs.Head); EventMetadata metadata = new EventMetadata(); metadata.Add("placeholders.Count", placeholders.EstimatedCount); metadata.Add("background.Count", this.backgroundFileSystemTaskRunner.Count); metadata.Add(TracingConstants.MessageKey.InfoMessage, $"{nameof(FileSystemCallbacks)} created"); this.context.Tracer.RelatedEvent(EventLevel.Informational, $"{nameof(FileSystemCallbacks)}_Constructor", metadata); }
private Result CreateClone( ITracer tracer, GVFSEnlistment enlistment, GitObjectsHttpRequestor objectRequestor, GitRefs refs, string branch) { Result initRepoResult = this.TryInitRepo(tracer, refs, enlistment); if (!initRepoResult.Success) { return(initRepoResult); } PhysicalFileSystem fileSystem = new PhysicalFileSystem(); string errorMessage; if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out errorMessage)) { return(new Result("Error configuring alternate: " + errorMessage)); } GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem); GVFSContext context = new GVFSContext(tracer, fileSystem, gitRepo, enlistment); GVFSGitObjects gitObjects = new GVFSGitObjects(context, objectRequestor); if (!this.TryDownloadCommit( refs.GetTipCommitId(branch), enlistment, objectRequestor, gitObjects, gitRepo, out errorMessage)) { return(new Result(errorMessage)); } if (!GVFSVerb.TrySetRequiredGitConfigSettings(enlistment) || !GVFSVerb.TrySetOptionalGitConfigSettings(enlistment)) { return(new Result("Unable to configure git repo")); } CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); if (!cacheServerResolver.TrySaveUrlToLocalConfig(objectRequestor.CacheServer, out errorMessage)) { return(new Result("Unable to configure cache server: " + errorMessage)); } GitProcess git = new GitProcess(enlistment); string originBranchName = "origin/" + branch; GitProcess.Result createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName); if (createBranchResult.HasErrors) { return(new Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output)); } File.WriteAllText( Path.Combine(enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Head), "ref: refs/heads/" + branch); File.AppendAllText( Path.Combine(enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Info.SparseCheckoutPath), GVFSConstants.GitPathSeparatorString + GVFSConstants.SpecialGitFiles.GitAttributes + "\n"); if (!this.TryDownloadRootGitAttributes(enlistment, gitObjects, gitRepo, out errorMessage)) { return(new Result(errorMessage)); } this.CreateGitScript(enlistment); string installHooksError; if (!HooksInstaller.InstallHooks(context, out installHooksError)) { tracer.RelatedError(installHooksError); return(new Result(installHooksError)); } GitProcess.Result forceCheckoutResult = git.ForceCheckout(branch); if (forceCheckoutResult.HasErrors) { string[] errorLines = forceCheckoutResult.Errors.Split('\n'); StringBuilder checkoutErrors = new StringBuilder(); foreach (string gitError in errorLines) { if (IsForceCheckoutErrorCloneFailure(gitError)) { checkoutErrors.AppendLine(gitError); } } if (checkoutErrors.Length > 0) { string error = "Could not complete checkout of branch: " + branch + ", " + checkoutErrors.ToString(); tracer.RelatedError(error); return(new Result(error)); } } if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGVFSRoot, out errorMessage)) { tracer.RelatedError(errorMessage); return(new Result(errorMessage)); } try { RepoMetadata.Instance.SaveCloneMetadata(tracer, enlistment); this.LogEnlistmentInfoAndSetConfigValues(tracer, git, enlistment); } catch (Exception e) { tracer.RelatedError(e.ToString()); return(new Result(e.Message)); } finally { RepoMetadata.Shutdown(); } // Prepare the working directory folder for GVFS last to ensure that gvfs mount will fail if gvfs clone has failed string prepFileSystemError; if (!GVFSPlatform.Instance.KernelDriver.TryPrepareFolderForCallbacks(enlistment.WorkingDirectoryRoot, out prepFileSystemError)) { tracer.RelatedError(prepFileSystemError); return(new Result(prepFileSystemError)); } return(new Result(true)); }
public static FileSystemVirtualizer CreateFileSystemVirtualizer(GVFSContext context, GVFSGitObjects gitObjects) { return(new WindowsFileSystemVirtualizer(context, gitObjects)); }
public MockFileSystemVirtualizer(GVFSContext context, GVFSGitObjects gvfsGitObjects) : base(context, gvfsGitObjects) { }
private bool TryPrefetchCommitsAndTrees(ITracer tracer, GVFSEnlistment enlistment, GitObjectsHttpRequestor objectRequestor, out string error) { error = null; PhysicalFileSystem fileSystem = new PhysicalFileSystem(); GitRepo repo = new GitRepo(tracer, enlistment, fileSystem); GVFSContext context = new GVFSContext(tracer, fileSystem, repo, enlistment); GitObjects gitObjects = new GVFSGitObjects(context, objectRequestor); gitObjects.DeleteStaleTempPrefetchPackAndIdxs(); string[] packs = gitObjects.ReadPackFileNames(enlistment.GitPackRoot, GVFSConstants.PrefetchPackPrefix); List <PrefetchPackInfo> orderedPacks = packs .Where(pack => this.GetTimestamp(pack).HasValue) .Select(pack => new PrefetchPackInfo(this.GetTimestamp(pack).Value, pack)) .OrderBy(packInfo => packInfo.Timestamp) .ToList(); long maxGood = -1; int firstBadPack = -1; for (int i = 0; i < orderedPacks.Count; ++i) { long timestamp = orderedPacks[i].Timestamp; string packPath = orderedPacks[i].Path; string idxPath = Path.ChangeExtension(packPath, ".idx"); if (!fileSystem.FileExists(idxPath)) { EventMetadata metadata = new EventMetadata(); metadata.Add("pack", packPath); metadata.Add("idxPath", idxPath); metadata.Add("timestamp", timestamp); GitProcess.Result indexResult = gitObjects.IndexPackFile(packPath); if (indexResult.HasErrors) { firstBadPack = i; metadata.Add("Errors", indexResult.Errors); tracer.RelatedWarning(metadata, $"{nameof(this.TryPrefetchCommitsAndTrees)}: Found pack file that's missing idx file, and failed to regenerate idx"); break; } else { maxGood = timestamp; metadata.Add(TracingConstants.MessageKey.InfoMessage, $"{nameof(this.TryPrefetchCommitsAndTrees)}: Found pack file that's missing idx file, and regenerated idx"); tracer.RelatedEvent(EventLevel.Informational, $"{nameof(this.TryPrefetchCommitsAndTrees)}_RebuildIdx", metadata); } } else { maxGood = timestamp; } } if (firstBadPack != -1) { const int MaxDeleteRetries = 200; // 200 * IoFailureRetryDelayMS (50ms) = 10 seconds const int RetryLoggingThreshold = 40; // 40 * IoFailureRetryDelayMS (50ms) = 2 seconds // Delete packs and indexes in reverse order so that if prefetch is killed, subseqeuent prefetch commands will // find the right starting spot. for (int i = orderedPacks.Count - 1; i >= firstBadPack; --i) { string packPath = orderedPacks[i].Path; string idxPath = Path.ChangeExtension(packPath, ".idx"); EventMetadata metadata = new EventMetadata(); metadata.Add("path", idxPath); metadata.Add(TracingConstants.MessageKey.InfoMessage, $"{nameof(this.TryPrefetchCommitsAndTrees)} deleting bad idx file"); tracer.RelatedEvent(EventLevel.Informational, $"{nameof(this.TryPrefetchCommitsAndTrees)}_DeleteBadIdx", metadata); if (!fileSystem.TryWaitForDelete(tracer, idxPath, IoFailureRetryDelayMS, MaxDeleteRetries, RetryLoggingThreshold)) { error = $"Unable to delete {idxPath}"; return(false); } metadata = new EventMetadata(); metadata.Add("path", packPath); metadata.Add(TracingConstants.MessageKey.InfoMessage, $"{nameof(this.TryPrefetchCommitsAndTrees)} deleting bad pack file"); tracer.RelatedEvent(EventLevel.Informational, $"{nameof(this.TryPrefetchCommitsAndTrees)}_DeleteBadPack", metadata); if (!fileSystem.TryWaitForDelete(tracer, packPath, IoFailureRetryDelayMS, MaxDeleteRetries, RetryLoggingThreshold)) { error = $"Unable to delete {packPath}"; return(false); } } } if (!gitObjects.TryDownloadPrefetchPacks(maxGood)) { error = "Failed to download prefetch packs"; return(false); } return(true); }
public FileSystemCallbacks( GVFSContext context, GVFSGitObjects gitObjects, RepoMetadata repoMetadata, BlobSizes blobSizes, GitIndexProjection gitIndexProjection, BackgroundFileSystemTaskRunner backgroundFileSystemTaskRunner, FileSystemVirtualizer fileSystemVirtualizer) { this.logsHeadFileProperties = null; this.postFetchJobLock = new object(); this.context = context; this.gitObjects = gitObjects; this.fileSystemVirtualizer = fileSystemVirtualizer; this.placeHolderCreationCount = new ConcurrentDictionary <string, PlaceHolderCreateCounter>(StringComparer.OrdinalIgnoreCase); string error; if (!ModifiedPathsDatabase.TryLoadOrCreate( this.context.Tracer, Path.Combine(this.context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.ModifiedPaths), this.context.FileSystem, out this.modifiedPaths, out error)) { throw new InvalidRepoException(error); } this.BlobSizes = blobSizes; this.BlobSizes.Initialize(); PlaceholderListDatabase placeholders; if (!PlaceholderListDatabase.TryCreate( this.context.Tracer, Path.Combine(this.context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.PlaceholderList), this.context.FileSystem, out placeholders, out error)) { throw new InvalidRepoException(error); } this.GitIndexProjection = gitIndexProjection ?? new GitIndexProjection( context, gitObjects, this.BlobSizes, repoMetadata, fileSystemVirtualizer, placeholders, this.modifiedPaths); this.backgroundFileSystemTaskRunner = backgroundFileSystemTaskRunner ?? new BackgroundFileSystemTaskRunner( this.context, this.PreBackgroundOperation, this.ExecuteBackgroundOperation, this.PostBackgroundOperation, Path.Combine(context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.BackgroundFileSystemTasks)); this.logsHeadPath = Path.Combine(this.context.Enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Logs.Head); EventMetadata metadata = new EventMetadata(); metadata.Add("placeholders.Count", placeholders.EstimatedCount); metadata.Add("background.Count", this.backgroundFileSystemTaskRunner.Count); metadata.Add(TracingConstants.MessageKey.InfoMessage, $"{nameof(FileSystemCallbacks)} created"); this.context.Tracer.RelatedEvent(EventLevel.Informational, $"{nameof(FileSystemCallbacks)}_Constructor", metadata); }
public CloneVerb.Result CreateClone(GitRefs refs, string branch) { CloneVerb.Result initRepoResult = this.TryInitRepo(refs, this.enlistment); if (!initRepoResult.Success) { return(initRepoResult); } string errorMessage; if (!this.enlistment.TryConfigureAlternate(out errorMessage)) { return(new CloneVerb.Result("Error configuring alternate: " + errorMessage)); } PhysicalFileSystem fileSystem = new PhysicalFileSystem(); GitRepo gitRepo = new GitRepo(this.tracer, this.enlistment, fileSystem); GVFSGitObjects gitObjects = new GVFSGitObjects(new GVFSContext(this.tracer, fileSystem, gitRepo, this.enlistment), this.objectRequestor); if (!gitObjects.TryEnsureCommitIsLocal(refs.GetTipCommitId(branch), commitDepth: 2)) { return(new CloneVerb.Result("Could not download tip commits from: " + Uri.EscapeUriString(this.objectRequestor.CacheServer.ObjectsEndpointUrl))); } if (!GVFSVerb.TrySetGitConfigSettings(this.enlistment)) { return(new CloneVerb.Result("Unable to configure git repo")); } CacheServerResolver cacheServerResolver = new CacheServerResolver(this.tracer, this.enlistment); if (!cacheServerResolver.TrySaveUrlToLocalConfig(this.objectRequestor.CacheServer, out errorMessage)) { return(new CloneVerb.Result("Unable to configure cache server: " + errorMessage)); } GitProcess git = new GitProcess(this.enlistment); string originBranchName = "origin/" + branch; GitProcess.Result createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName); if (createBranchResult.HasErrors) { return(new CloneVerb.Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output)); } File.WriteAllText( Path.Combine(this.enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Head), "ref: refs/heads/" + branch); File.AppendAllText( Path.Combine(this.enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Info.SparseCheckoutPath), GVFSConstants.GitPathSeparatorString + GVFSConstants.SpecialGitFiles.GitAttributes + "\n"); CloneVerb.Result hydrateResult = this.HydrateRootGitAttributes(gitObjects, gitRepo, branch); if (!hydrateResult.Success) { return(hydrateResult); } this.CreateGitScript(); GitProcess.Result forceCheckoutResult = git.ForceCheckout(branch); if (forceCheckoutResult.HasErrors) { string[] errorLines = forceCheckoutResult.Errors.Split('\n'); StringBuilder checkoutErrors = new StringBuilder(); foreach (string gitError in errorLines) { if (IsForceCheckoutErrorCloneFailure(gitError)) { checkoutErrors.AppendLine(gitError); } } if (checkoutErrors.Length > 0) { string error = "Could not complete checkout of branch: " + branch + ", " + checkoutErrors.ToString(); this.tracer.RelatedError(error); return(new CloneVerb.Result(error)); } } GitProcess.Result updateIndexresult = git.UpdateIndexVersion4(); if (updateIndexresult.HasErrors) { string error = "Could not update index, error: " + updateIndexresult.Errors; this.tracer.RelatedError(error); return(new CloneVerb.Result(error)); } string installHooksError; if (!HooksInstaller.InstallHooks(this.enlistment, out installHooksError)) { this.tracer.RelatedError(installHooksError); return(new CloneVerb.Result(installHooksError)); } if (!RepoMetadata.TryInitialize(this.tracer, this.enlistment.DotGVFSRoot, out errorMessage)) { this.tracer.RelatedError(errorMessage); return(new CloneVerb.Result(errorMessage)); } try { RepoMetadata.Instance.SaveCurrentDiskLayoutVersion(); } catch (Exception e) { this.tracer.RelatedError(e.ToString()); return(new CloneVerb.Result(e.Message)); } finally { RepoMetadata.Shutdown(); } // Prepare the working directory folder for GVFS last to ensure that gvfs mount will fail if gvfs clone has failed string prepGVFltError; if (!GVFltCallbacks.TryPrepareFolderForGVFltCallbacks(this.enlistment.WorkingDirectoryRoot, out prepGVFltError)) { this.tracer.RelatedError(prepGVFltError); return(new CloneVerb.Result(prepGVFltError)); } return(new CloneVerb.Result(true)); }