protected bool TryDownloadCommit( string commitId, GVFSEnlistment enlistment, GitObjectsHttpRequestor objectRequestor, GVFSGitObjects gitObjects, GitRepo repo, out string error) { if (!repo.CommitAndRootTreeExists(commitId)) { if (!gitObjects.TryDownloadCommit(commitId)) { error = "Could not download commit " + commitId + " from: " + Uri.EscapeUriString(objectRequestor.CacheServer.ObjectsEndpointUrl); return(false); } } error = null; return(true); }
private GVFltCallbacks CreateGVFltCallbacks() { string error; if (!RepoMetadata.TryInitialize(this.Context.Tracer, this.Enlistment.DotGVFSRoot, out error)) { throw new InvalidRepoException(error); } CacheServerInfo cacheServer = new CacheServerInfo(this.Context.Enlistment.RepoUrl, "None"); GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor( this.Context.Tracer, this.Context.Enlistment, cacheServer, new RetryConfig()); GVFSGitObjects gitObjects = new GVFSGitObjects(this.Context, objectRequestor); return(new GVFltCallbacks(this.Context, gitObjects, RepoMetadata.Instance)); }
private bool TryDownloadGitObjects(ITracer tracer, GVFSEnlistment enlistment, RetryConfig retryConfig) { string errorMessage = null; if (!this.ShowStatusWhileRunning( () => { CacheServerInfo cacheServer = new CacheServerInfo(enlistment.RepoUrl, null); using (GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig)) { PhysicalFileSystem fileSystem = new PhysicalFileSystem(); GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem); GVFSGitObjects gitObjects = new GVFSGitObjects(new GVFSContext(tracer, fileSystem, gitRepo, enlistment), objectRequestor); GitProcess.Result revParseResult = enlistment.CreateGitProcess().RevParse("HEAD"); if (revParseResult.HasErrors) { errorMessage = "Unable to determine HEAD commit id: " + revParseResult.Errors; return(false); } string headCommit = revParseResult.Output.TrimEnd('\n'); if (!this.TryDownloadCommit(headCommit, enlistment, objectRequestor, gitObjects, gitRepo, out errorMessage) || !this.TryDownloadRootGitAttributes(enlistment, gitObjects, gitRepo, out errorMessage)) { return(false); } } return(true); }, "Downloading git objects", suppressGvfsLogMessage: true)) { this.WriteMessage(tracer, errorMessage); return(false); } return(true); }
public FetchHelper( ITracer tracer, Enlistment enlistment, int chunkSize, int searchThreadCount, int downloadThreadCount, int indexThreadCount) { this.SearchThreadCount = searchThreadCount; this.DownloadThreadCount = downloadThreadCount; this.IndexThreadCount = indexThreadCount; this.ChunkSize = chunkSize; this.Tracer = tracer; this.Enlistment = enlistment; this.ObjectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, downloadThreadCount); this.GitObjects = new GitObjects(tracer, enlistment, this.ObjectRequestor); this.PathWhitelist = new List <string>(); // We never want to update config settings for a GVFSEnlistment this.SkipConfigUpdate = enlistment is GVFSEnlistment; }
private void PrefetchCommits(ITracer tracer, GVFSEnlistment enlistment, GitObjectsHttpRequestor objectRequestor, CacheServerInfo cacheServer) { bool success; string error = string.Empty; if (this.Verbose) { success = this.TryPrefetchCommitsAndTrees(tracer, enlistment, objectRequestor, out error); } else { success = this.ShowStatusWhileRunning( () => { return(this.TryPrefetchCommitsAndTrees(tracer, enlistment, objectRequestor, out error)); }, "Fetching commits and trees " + this.GetCacheServerDisplay(cacheServer)); } if (!success) { this.ReportErrorAndExit(tracer, "Prefetching commits and trees failed: " + error); } }
private void InitializeServerConnection( ITracer tracer, GVFSEnlistment enlistment, string cacheServerUrl, out GitObjectsHttpRequestor objectRequestor, out CacheServerInfo cacheServer) { RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); cacheServer = this.ResolvedCacheServer; ServerGVFSConfig serverGVFSConfig = this.ServerGVFSConfig; if (!this.SkipVersionCheck) { string authErrorMessage; if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage)) { this.ReportErrorAndExit(tracer, "Unable to prefetch because authentication failed: " + authErrorMessage); } if (serverGVFSConfig == null) { serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig); } if (cacheServer == null) { CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerUrl, serverGVFSConfig); } this.ValidateClientVersions(tracer, enlistment, serverGVFSConfig, showWarnings: false); // this.Output.WriteLine("Configured cache server: " + cacheServer); } this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGVFSConfig, cacheServer); objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig); }
public BatchObjectDownloadJob( int maxParallel, int chunkSize, BlockingCollection <string> inputQueue, BlockingCollection <string> availableBlobs, ITracer tracer, Enlistment enlistment, GitObjectsHttpRequestor objectRequestor, GitObjects gitObjects) : base(maxParallel) { this.tracer = tracer.StartActivity(AreaPath, EventLevel.Informational, Keywords.Telemetry, metadata: null); this.inputQueue = new BlockingAggregator <string, BlobDownloadRequest>(inputQueue, chunkSize, objectIds => new BlobDownloadRequest(objectIds)); this.enlistment = enlistment; this.objectRequestor = objectRequestor; this.gitObjects = gitObjects; this.AvailablePacks = new BlockingCollection <IndexPackRequest>(); this.AvailableObjects = availableBlobs; }
public CheckoutPrefetcher( ITracer tracer, Enlistment enlistment, GitObjectsHttpRequestor objectRequestor, int chunkSize, int searchThreadCount, int downloadThreadCount, int indexThreadCount, int checkoutThreadCount, bool allowIndexMetadataUpdateFromWorkingTree, bool forceCheckout) : base( tracer, enlistment, objectRequestor, chunkSize, searchThreadCount, downloadThreadCount, indexThreadCount) { this.checkoutThreadCount = checkoutThreadCount; this.allowIndexMetadataUpdateFromWorkingTree = allowIndexMetadataUpdateFromWorkingTree; this.forceCheckout = forceCheckout; }
public BlobPrefetcher( ITracer tracer, Enlistment enlistment, GitObjectsHttpRequestor objectRequestor, int chunkSize, int searchThreadCount, int downloadThreadCount, int indexThreadCount) { this.SearchThreadCount = searchThreadCount; this.DownloadThreadCount = downloadThreadCount; this.IndexThreadCount = indexThreadCount; this.ChunkSize = chunkSize; this.Tracer = tracer; this.Enlistment = enlistment; this.ObjectRequestor = objectRequestor; this.GitObjects = new PrefetchGitObjects(tracer, enlistment, this.ObjectRequestor); this.FileList = new List <string>(); this.FolderList = new List <string>(); // We never want to update config settings for a GVFSEnlistment this.SkipConfigUpdate = enlistment is GVFSEnlistment; }
private void PrefetchBlobs( ITracer tracer, GVFSEnlistment enlistment, string headCommitId, List <string> filesList, List <string> foldersList, FileBasedDictionary <string, string> lastPrefetchArgs, GitObjectsHttpRequestor objectRequestor, CacheServerInfo cacheServer) { BlobPrefetcher blobPrefetcher = new BlobPrefetcher( tracer, enlistment, objectRequestor, filesList, foldersList, lastPrefetchArgs, ChunkSize, SearchThreadCount, DownloadThreadCount, IndexThreadCount); if (blobPrefetcher.FolderList.Count == 0 && blobPrefetcher.FileList.Count == 0) { this.ReportErrorAndExit(tracer, "Did you mean to fetch all blobs? If so, specify `--files '*'` to confirm."); } if (this.HydrateFiles) { if (!this.CheckIsMounted(verbose: true)) { this.ReportErrorAndExit("You can only specify --hydrate if the repo is mounted. Run 'gvfs mount' and try again."); } } int matchedBlobCount = 0; int downloadedBlobCount = 0; int hydratedFileCount = 0; Func <bool> doPrefetch = () => { try { blobPrefetcher.PrefetchWithStats( headCommitId, isBranch: false, hydrateFilesAfterDownload: this.HydrateFiles, matchedBlobCount: out matchedBlobCount, downloadedBlobCount: out downloadedBlobCount, hydratedFileCount: out hydratedFileCount); return(!blobPrefetcher.HasFailures); } catch (BlobPrefetcher.FetchException e) { tracer.RelatedError(e.Message); return(false); } }; if (this.Verbose) { doPrefetch(); } else { string message = this.HydrateFiles ? "Fetching blobs and hydrating files " : "Fetching blobs "; this.ShowStatusWhileRunning(doPrefetch, message + this.GetCacheServerDisplay(cacheServer, enlistment.RepoUrl)); } if (blobPrefetcher.HasFailures) { Environment.ExitCode = 1; } else { Console.WriteLine(); Console.WriteLine("Stats:"); Console.WriteLine(" Matched blobs: " + matchedBlobCount); Console.WriteLine(" Already cached: " + (matchedBlobCount - downloadedBlobCount)); Console.WriteLine(" Downloaded: " + downloadedBlobCount); if (this.HydrateFiles) { Console.WriteLine(" Hydrated files: " + hydratedFileCount); } } }
private Result DoClone(string fullEnlistmentRootPathParameter, string normalizedEnlistmentRootPath) { Result cloneResult = null; cloneResult = this.TryCreateEnlistment(fullEnlistmentRootPathParameter, normalizedEnlistmentRootPath, out this.enlistment); if (!cloneResult.Success) { this.tracer.RelatedError($"Error while creating enlistment: {cloneResult.ErrorMessage}"); return(cloneResult); } this.tracer.AddLogFileEventListener( ScalarEnlistment.GetNewScalarLogFileName(this.enlistment.ScalarLogsRoot, ScalarConstants.LogFileTypes.Clone), EventLevel.Informational, Keywords.Any); this.tracer.WriteStartEvent( this.enlistment.EnlistmentRoot, this.enlistment.RepoUrl, this.CacheServerUrl, this.AddVerbDataToMetadata(new EventMetadata { { nameof(this.Branch), this.Branch }, { nameof(this.LocalCacheRoot), this.LocalCacheRoot }, { nameof(this.SingleBranch), this.SingleBranch }, { nameof(this.FullClone), this.FullClone }, { nameof(this.NoFetchCommitsAndTrees), this.NoFetchCommitsAndTrees }, { nameof(this.Unattended), this.Unattended }, { nameof(ScalarPlatform.Instance.IsElevated), ScalarPlatform.Instance.IsElevated() }, { "ProcessID", Process.GetCurrentProcess().Id }, { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter }, { nameof(fullEnlistmentRootPathParameter), fullEnlistmentRootPathParameter }, })); this.cacheServerResolver = new CacheServerResolver(this.tracer, this.enlistment); this.cacheServer = this.cacheServerResolver.ParseUrlOrFriendlyName(this.CacheServerUrl); string resolvedLocalCacheRoot; if (string.IsNullOrWhiteSpace(this.LocalCacheRoot)) { if (!LocalCacheResolver.TryGetDefaultLocalCacheRoot(this.enlistment, out resolvedLocalCacheRoot, out string localCacheRootError)) { this.ReportErrorAndExit( this.tracer, $"Failed to determine the default location for the local Scalar cache: `{localCacheRootError}`"); } } else { resolvedLocalCacheRoot = Path.GetFullPath(this.LocalCacheRoot); } this.Output.WriteLine("Clone parameters:"); this.Output.WriteLine(" Repo URL: " + this.enlistment.RepoUrl); this.Output.WriteLine(" Branch: " + (string.IsNullOrWhiteSpace(this.Branch) ? "Default" : this.Branch)); this.Output.WriteLine(" Cache Server: " + this.cacheServer); this.Output.WriteLine(" Local Cache: " + resolvedLocalCacheRoot); this.Output.WriteLine(" Destination: " + this.enlistment.EnlistmentRoot); this.Output.WriteLine(" FullClone: " + this.FullClone); string authErrorMessage; if (!this.TryAuthenticate(this.tracer, this.enlistment, out authErrorMessage)) { this.ReportErrorAndExit(this.tracer, "Cannot clone because authentication failed: " + authErrorMessage); } this.retryConfig = this.GetRetryConfig(this.tracer, this.enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); this.serverScalarConfig = this.QueryScalarConfig(this.tracer, this.enlistment, this.retryConfig); this.cacheServer = this.ResolveCacheServer(this.tracer, this.cacheServer, this.cacheServerResolver, this.serverScalarConfig); this.ValidateClientVersions(this.tracer, this.enlistment, this.serverScalarConfig, showWarnings: true); using (this.objectRequestor = new GitObjectsHttpRequestor(this.tracer, this.enlistment, this.cacheServer, this.retryConfig)) { cloneResult = this.CreateScalarDirctories(resolvedLocalCacheRoot); if (!cloneResult.Success) { this.tracer.RelatedError(cloneResult.ErrorMessage); return(cloneResult); } this.ShowStatusWhileRunning( () => { cloneResult = this.CreateClone(); return(cloneResult.Success); }, "Cloning"); if (!cloneResult.Success) { this.tracer.RelatedError(cloneResult.ErrorMessage); return(cloneResult); } if (!this.NoFetchCommitsAndTrees) { ReturnCode result = this.Execute <RunVerb>( this.enlistment, verb => { verb.MaintenanceTask = ScalarConstants.VerbParameters.Maintenance.FetchTaskName; verb.SkipVersionCheck = true; verb.ResolvedCacheServer = this.cacheServer; verb.ServerScalarConfig = this.serverScalarConfig; }); if (result != ReturnCode.Success) { this.Output.WriteLine("\r\nError while fetching commits and trees @ {0}", fullEnlistmentRootPathParameter); return(cloneResult); } } this.ShowStatusWhileRunning( () => { cloneResult = this.CheckoutRepo(); return(cloneResult.Success); }, "Populating working directory"); } if (cloneResult.Success) { cloneResult = this.TryRegisterRepo(); } return(cloneResult); }
protected override void Execute(GVFSEnlistment enlistment) { using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "Prefetch")) { if (this.Verbose) { tracer.AddDiagnosticConsoleEventListener(EventLevel.Informational, Keywords.Any); } else { tracer.AddPrettyConsoleEventListener(EventLevel.Error, Keywords.Any); } tracer.AddLogFileEventListener( GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Prefetch), EventLevel.Informational, Keywords.Any); RetryConfig retryConfig; string error; if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error)) { tracer.RelatedError("Failed to determine GVFS timeout and max retries: " + error); Environment.Exit((int)ReturnCode.GenericError); } retryConfig.Timeout = TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes); CacheServerInfo cache; if (!CacheServerInfo.TryDetermineCacheServer(null, tracer, enlistment, retryConfig, out cache, out error)) { tracer.RelatedError(error); Environment.ExitCode = (int)ReturnCode.GenericError; return; } tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, cache.Url); try { EventMetadata metadata = new EventMetadata(); metadata.Add("Commits", this.Commits); metadata.Add("PathWhitelist", this.PathWhitelist); metadata.Add("PathWhitelistFile", this.PathWhitelistFile); tracer.RelatedEvent(EventLevel.Informational, "PerformPrefetch", metadata); GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cache, retryConfig); if (this.Commits) { this.PrefetchCommits(tracer, enlistment, objectRequestor); } else { this.PrefetchBlobs(tracer, enlistment, objectRequestor); } } catch (VerbAbortedException) { throw; } catch (AggregateException aggregateException) { this.Output.WriteLine( "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(enlistment.EnlistmentRoot), enlistment.EnlistmentRoot); foreach (Exception innerException in aggregateException.Flatten().InnerExceptions) { tracer.RelatedError( new EventMetadata { { "Verb", typeof(PrefetchVerb).Name }, { "ErrorMessage", $"Unhandled {innerException.GetType().Name}: {innerException.Message}" }, { "Exception", innerException.ToString() } }); } Environment.ExitCode = (int)ReturnCode.GenericError; } catch (Exception e) { this.Output.WriteLine( "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(enlistment.EnlistmentRoot), enlistment.EnlistmentRoot); tracer.RelatedError( new EventMetadata { { "Verb", typeof(PrefetchVerb).Name }, { "ErrorMessage", $"Unhandled {e.GetType().Name}: {e.Message}" }, { "Exception", e.ToString() } }); } } }
private bool TryPrefetchCommitsAndTrees(ITracer tracer, GVFSEnlistment enlistment, GitObjectsHttpRequestor objectRequestor) { GitObjects gitObjects = new GitObjects(tracer, enlistment, objectRequestor); string[] packs = gitObjects.ReadPackFileNames(GVFSConstants.PrefetchPackPrefix); long max = -1; foreach (string pack in packs) { long?timestamp = this.GetTimestamp(pack); if (timestamp.HasValue && timestamp > max) { max = timestamp.Value; } } return(gitObjects.TryDownloadPrefetchPacks(max)); }
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 GVFSGitObjects(GVFSContext context, GitObjectsHttpRequestor objectRequestor) : base(context.Tracer, context.Enlistment, objectRequestor, context.FileSystem) { this.Context = context; this.objectNegativeCache = new ConcurrentDictionary <string, DateTime>(StringComparer.OrdinalIgnoreCase); }
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); } }
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(); }
public MockGVFSGitObjects(GVFSContext context, GitObjectsHttpRequestor httpGitObjects) : base(context, httpGitObjects) { this.context = context; }
public MockPhysicalGitObjects(ITracer tracer, PhysicalFileSystem fileSystem, Enlistment enlistment, GitObjectsHttpRequestor objectRequestor) : base(tracer, enlistment, objectRequestor, fileSystem) { }
public GitObjects(ITracer tracer, Enlistment enlistment, GitObjectsHttpRequestor objectRequestor) { this.Tracer = tracer; this.Enlistment = enlistment; this.GitObjectRequestor = objectRequestor; }
public PrefetchGitObjects(ITracer tracer, Enlistment enlistment, GitObjectsHttpRequestor objectRequestor, PhysicalFileSystem fileSystem = null) : base(tracer, enlistment, objectRequestor, fileSystem) { }
public MockPhysicalGitObjects(ITracer tracer, Enlistment enlistment, GitObjectsHttpRequestor objectRequestor) : base(tracer, enlistment, objectRequestor) { }
public CloneHelper(ITracer tracer, GVFSEnlistment enlistment, GitObjectsHttpRequestor objectRequestor) { this.tracer = tracer; this.enlistment = enlistment; this.objectRequestor = objectRequestor; }
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)); }
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)); }
private Result CreateClone( ITracer tracer, GSDEnlistment 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); GSDContext context = new GSDContext(tracer, fileSystem, gitRepo, enlistment); GSDGitObjects gitObjects = new GSDGitObjects(context, objectRequestor); if (!this.TryDownloadCommit( refs.GetTipCommitId(branch), enlistment, objectRequestor, gitObjects, gitRepo, out errorMessage)) { return(new Result(errorMessage)); } if (!GSDVerb.TrySetRequiredGitConfigSettings(enlistment) || !GSDVerb.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.WorkingDirectoryBackingRoot, GSDConstants.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)); } // TODO: Move this to be after the mount? 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 (!RepoMetadata.TryInitialize(tracer, enlistment.DotGSDRoot, 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(); } return(new Result(true)); }
protected override void Execute(GVFSEnlistment enlistment) { using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "Prefetch")) { if (this.Verbose) { tracer.AddDiagnosticConsoleEventListener(EventLevel.Informational, Keywords.Any); } string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment); tracer.AddLogFileEventListener( GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Prefetch), EventLevel.Informational, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, cacheServerUrl); RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); CacheServerInfo cacheServer = this.ResolvedCacheServer; GVFSConfig gvfsConfig = this.GVFSConfig; if (!this.SkipVersionCheck) { string authErrorMessage; if (!this.ShowStatusWhileRunning( () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage), "Authenticating")) { this.ReportErrorAndExit(tracer, "Unable to prefetch because authentication failed"); } if (gvfsConfig == null) { gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig); } if (cacheServer == null) { CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerUrl, gvfsConfig); } this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: false); this.Output.WriteLine("Configured cache server: " + cacheServer); } this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, gvfsConfig, cacheServer); try { EventMetadata metadata = new EventMetadata(); metadata.Add("Commits", this.Commits); metadata.Add("Files", this.Files); metadata.Add("Folders", this.Folders); metadata.Add("FoldersListFile", this.FoldersListFile); metadata.Add("HydrateFiles", this.HydrateFiles); tracer.RelatedEvent(EventLevel.Informational, "PerformPrefetch", metadata); GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig); if (this.Commits) { if (!string.IsNullOrWhiteSpace(this.Files) || !string.IsNullOrWhiteSpace(this.Folders) || !string.IsNullOrWhiteSpace(this.FoldersListFile)) { this.ReportErrorAndExit(tracer, "You cannot prefetch commits and blobs at the same time."); } if (this.HydrateFiles) { this.ReportErrorAndExit(tracer, "You can only specify --hydrate with --files or --folders"); } PhysicalFileSystem fileSystem = new PhysicalFileSystem(); using (FileBasedLock prefetchLock = new FileBasedLock( fileSystem, tracer, Path.Combine(enlistment.GitPackRoot, PrefetchCommitsAndTreesLock), enlistment.EnlistmentRoot, overwriteExistingLock: true)) { this.WaitUntilLockIsAcquired(tracer, prefetchLock); this.PrefetchCommits(tracer, enlistment, objectRequestor, cacheServer); } } else { this.PrefetchBlobs(tracer, enlistment, objectRequestor, cacheServer); } } catch (VerbAbortedException) { throw; } catch (AggregateException aggregateException) { this.Output.WriteLine( "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(enlistment.EnlistmentRoot), enlistment.EnlistmentRoot); foreach (Exception innerException in aggregateException.Flatten().InnerExceptions) { tracer.RelatedError( new EventMetadata { { "Verb", typeof(PrefetchVerb).Name }, { "Exception", innerException.ToString() } }, $"Unhandled {innerException.GetType().Name}: {innerException.Message}"); } Environment.ExitCode = (int)ReturnCode.GenericError; } catch (Exception e) { this.Output.WriteLine( "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(enlistment.EnlistmentRoot), enlistment.EnlistmentRoot); tracer.RelatedError( new EventMetadata { { "Verb", typeof(PrefetchVerb).Name }, { "Exception", e.ToString() } }, $"Unhandled {e.GetType().Name}: {e.Message}"); Environment.ExitCode = (int)ReturnCode.GenericError; } } }
private Result TryClone(JsonEtwTracer tracer, GVFSEnlistment enlistment) { this.CheckVolumeSupportsDeleteNotifications(tracer, enlistment); this.CheckGitVersion(enlistment); Result pipeResult; using (NamedPipeServer pipeServer = this.StartNamedPipe(tracer, enlistment, out pipeResult)) { if (!pipeResult.Success) { return(pipeResult); } using (ConfigHttpRequestor configRequestor = new ConfigHttpRequestor(tracer, enlistment)) { GVFSConfig config = configRequestor.QueryGVFSConfig(); this.ValidateGVFSVersion(enlistment, config, tracer); } using (GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment)) { GitRefs refs = objectRequestor.QueryInfoRefs(this.SingleBranch ? this.Branch : null); if (refs == null) { return(new Result("Could not query info/refs from: " + Uri.EscapeUriString(enlistment.RepoUrl))); } if (this.Branch == null) { this.Branch = refs.GetDefaultBranch(); EventMetadata metadata = new EventMetadata(); metadata.Add("Branch", this.Branch); tracer.RelatedEvent(EventLevel.Informational, "CloneDefaultRemoteBranch", metadata); } else { if (!refs.HasBranch(this.Branch)) { EventMetadata metadata = new EventMetadata(); metadata.Add("Branch", this.Branch); tracer.RelatedEvent(EventLevel.Warning, "CloneBranchDoesNotExist", metadata); string errorMessage = string.Format("Remote branch {0} not found in upstream origin", this.Branch); return(new Result(errorMessage)); } } if (!enlistment.TryCreateEnlistmentFolders()) { string error = "Could not create enlistment directory"; tracer.RelatedError(error); return(new Result(error)); } CloneHelper cloneHelper = new CloneHelper(tracer, enlistment, objectRequestor); return(cloneHelper.CreateClone(refs, this.Branch)); } } }
private void PrefetchBlobs(ITracer tracer, GVFSEnlistment enlistment, GitObjectsHttpRequestor blobRequestor, CacheServerInfo cacheServer) { PrefetchHelper fetchHelper = new PrefetchHelper( tracer, enlistment, blobRequestor, ChunkSize, SearchThreadCount, DownloadThreadCount, IndexThreadCount); string error; if (!PrefetchHelper.TryLoadFolderList(enlistment, this.Folders, this.FoldersListFile, fetchHelper.FolderList, out error)) { this.ReportErrorAndExit(tracer, error); } if (!PrefetchHelper.TryLoadFileList(enlistment, this.Files, fetchHelper.FileList, out error)) { this.ReportErrorAndExit(tracer, error); } if (fetchHelper.FolderList.Count == 0 && fetchHelper.FileList.Count == 0) { this.ReportErrorAndExit(tracer, "Did you mean to fetch all blobs? If so, specify `--files *` to confirm."); } if (this.HydrateFiles) { if (!this.CheckIsMounted(verbose: true)) { this.ReportErrorAndExit("You can only specify --hydrate if the repo is mounted. Run 'gvfs mount' and try again."); } } GitProcess gitProcess = new GitProcess(enlistment); GitProcess.Result result = gitProcess.RevParse(GVFSConstants.DotGit.HeadName); if (result.HasErrors) { tracer.RelatedError(result.Errors); this.Output.WriteLine(result.Errors); Environment.ExitCode = (int)ReturnCode.GenericError; return; } int matchedBlobCount = 0; int downloadedBlobCount = 0; int readFileCount = 0; string headCommitId = result.Output; Func <bool> doPrefetch = () => { try { fetchHelper.PrefetchWithStats( headCommitId.Trim(), isBranch: false, readFilesAfterDownload: this.HydrateFiles, matchedBlobCount: out matchedBlobCount, downloadedBlobCount: out downloadedBlobCount, readFileCount: out readFileCount); return(!fetchHelper.HasFailures); } catch (PrefetchHelper.FetchException e) { tracer.RelatedError(e.Message); return(false); } }; if (this.Verbose) { doPrefetch(); } else { string message = this.HydrateFiles ? "Fetching blobs and hydrating files " : "Fetching blobs "; this.ShowStatusWhileRunning(doPrefetch, message + this.GetCacheServerDisplay(cacheServer)); } if (fetchHelper.HasFailures) { Environment.ExitCode = 1; } else { Console.WriteLine(); Console.WriteLine("Stats:"); Console.WriteLine(" Matched blobs: " + matchedBlobCount); Console.WriteLine(" Already cached: " + (matchedBlobCount - downloadedBlobCount)); Console.WriteLine(" Downloaded: " + downloadedBlobCount); if (this.HydrateFiles) { Console.WriteLine(" Hydrated files: " + readFileCount); } } }
private Result TryClone( JsonTracer tracer, GVFSEnlistment enlistment, CacheServerInfo cacheServer, RetryConfig retryConfig, ServerGVFSConfig serverGVFSConfig, string resolvedLocalCacheRoot) { Result pipeResult; using (NamedPipeServer pipeServer = this.StartNamedPipe(tracer, enlistment, out pipeResult)) { if (!pipeResult.Success) { return(pipeResult); } using (GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig)) { GitRefs refs = objectRequestor.QueryInfoRefs(this.SingleBranch ? this.Branch : null); if (refs == null) { return(new Result("Could not query info/refs from: " + Uri.EscapeUriString(enlistment.RepoUrl))); } if (this.Branch == null) { this.Branch = refs.GetDefaultBranch(); EventMetadata metadata = new EventMetadata(); metadata.Add("Branch", this.Branch); tracer.RelatedEvent(EventLevel.Informational, "CloneDefaultRemoteBranch", metadata); } else { if (!refs.HasBranch(this.Branch)) { EventMetadata metadata = new EventMetadata(); metadata.Add("Branch", this.Branch); tracer.RelatedEvent(EventLevel.Warning, "CloneBranchDoesNotExist", metadata); string errorMessage = string.Format("Remote branch {0} not found in upstream origin", this.Branch); return(new Result(errorMessage)); } } if (!enlistment.TryCreateEnlistmentFolders()) { string error = "Could not create enlistment directory"; tracer.RelatedError(error); return(new Result(error)); } string localCacheError; if (!this.TryDetermineLocalCacheAndInitializePaths(tracer, enlistment, serverGVFSConfig, cacheServer, resolvedLocalCacheRoot, out localCacheError)) { tracer.RelatedError(localCacheError); return(new Result(localCacheError)); } Directory.CreateDirectory(enlistment.GitObjectsRoot); Directory.CreateDirectory(enlistment.GitPackRoot); Directory.CreateDirectory(enlistment.BlobSizesRoot); return(this.CreateClone(tracer, enlistment, objectRequestor, refs, this.Branch)); } } }