public bool TryResolveUrlFromRemote( string cacheServerName, GVFSConfig gvfsConfig, out CacheServerInfo cacheServer, out string error) { if (string.IsNullOrWhiteSpace(cacheServerName)) { throw new InvalidOperationException("An empty name is not supported"); } cacheServer = null; error = null; if (cacheServerName.Equals(CacheServerInfo.ReservedNames.Default, StringComparison.OrdinalIgnoreCase)) { cacheServer = gvfsConfig.CacheServers.FirstOrDefault(cache => cache.GlobalDefault) ?? this.CreateNone(); } else { cacheServer = gvfsConfig.CacheServers.FirstOrDefault(cache => cache.Name.Equals(cacheServerName, StringComparison.OrdinalIgnoreCase)); if (cacheServer == null) { error = "No cache server found with name " + cacheServerName; return(false); } } return(true); }
protected CacheServerInfo ResolveCacheServer( ITracer tracer, CacheServerInfo cacheServer, CacheServerResolver cacheServerResolver, GVFSConfig gvfsConfig) { CacheServerInfo resolvedCacheServer = cacheServer; if (cacheServer.Url == null) { string cacheServerName = cacheServer.Name; string error = null; if (!cacheServerResolver.TryResolveUrlFromRemote( cacheServerName, gvfsConfig, out resolvedCacheServer, out error)) { this.ReportErrorAndExit(tracer, error); } } else if (cacheServer.Name.Equals(CacheServerInfo.ReservedNames.UserDefined)) { resolvedCacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, gvfsConfig); } this.Output.WriteLine("Using cache server: " + resolvedCacheServer); return(resolvedCacheServer); }
protected CacheServerInfo ResolveCacheServerUrlIfNeeded( ITracer tracer, CacheServerInfo cacheServer, CacheServerResolver cacheServerResolver, GVFSConfig gvfsConfig) { CacheServerInfo resolvedCacheServer = cacheServer; if (cacheServer.Url == null) { string cacheServerName = cacheServer.Name; string error = null; if (!cacheServerResolver.TryResolveUrlFromRemote( cacheServerName, gvfsConfig, out resolvedCacheServer, out error)) { this.ReportErrorAndExit(tracer, error); } } this.Output.WriteLine("Using cache server: " + resolvedCacheServer); return(resolvedCacheServer); }
protected void ValidateGVFSVersion(GVFSEnlistment enlistment, GVFSConfig config, ITracer tracer) { using (ITracer activity = tracer.StartActivity("ValidateGVFSVersion", EventLevel.Informational)) { Version currentVersion = new Version(ProcessHelper.GetCurrentProcessVersion()); IEnumerable <GVFSConfig.VersionRange> allowedGvfsClientVersions = config != null ? config.AllowedGVFSClientVersions : null; if (allowedGvfsClientVersions == null || !allowedGvfsClientVersions.Any()) { string errorMessage = string.Empty; if (config == null) { errorMessage = "Could not query valid GVFS versions from: " + Uri.EscapeUriString(enlistment.RepoUrl); } else { errorMessage = "Server not configured to provide supported GVFS versions"; } EventMetadata metadata = new EventMetadata(); metadata.Add("ErrorMessage", errorMessage); tracer.RelatedError(metadata, Keywords.Network); this.Output.WriteLine(); this.Output.WriteLine("WARNING: Unable to validate your GVFS version"); this.Output.WriteLine(); return; } foreach (GVFSConfig.VersionRange versionRange in config.AllowedGVFSClientVersions) { if (currentVersion >= versionRange.Min && (versionRange.Max == null || currentVersion <= versionRange.Max)) { activity.RelatedEvent( EventLevel.Informational, "GVFSVersionValidated", new EventMetadata { { "SupportedVersionRange", versionRange }, }); return; } } activity.RelatedError("GVFS version {0} is not supported", currentVersion); } this.ReportErrorAndExit("\r\nERROR: Your GVFS version is no longer supported. Install the latest and try again.\r\n"); }
protected override void Execute(GVFSEnlistment enlistment) { this.BlockEmptyCacheServerUrl(this.CacheToSet); RetryConfig retryConfig = new RetryConfig(RetryConfig.DefaultMaxRetries, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); using (ITracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "CacheVerb")) { GVFSConfig gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); string error = null; if (this.CacheToSet != null) { CacheServerInfo cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheToSet); cacheServer = this.ResolveCacheServer(tracer, cacheServer, cacheServerResolver, gvfsConfig); if (!cacheServerResolver.TrySaveUrlToLocalConfig(cacheServer, out error)) { this.ReportErrorAndExit("Failed to save cache to config: " + error); } this.Output.WriteLine("You must remount GVFS for this to take effect."); } else if (this.ListCacheServers) { List <CacheServerInfo> cacheServers = gvfsConfig.CacheServers.ToList(); if (cacheServers != null && cacheServers.Any()) { this.Output.WriteLine(); this.Output.WriteLine("Available cache servers for: " + enlistment.RepoUrl); foreach (CacheServerInfo cacheServer in cacheServers) { this.Output.WriteLine(cacheServer); } } else { this.Output.WriteLine("There are no available cache servers for: " + enlistment.RepoUrl); } } else { string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment); CacheServerInfo cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerUrl, gvfsConfig); this.Output.WriteLine("Using cache server: " + cacheServer); } } }
public GVFSConfig QueryGVFSConfig() { Uri gvfsConfigEndpoint; string gvfsConfigEndpointString = this.repoUrl + GVFSConstants.Endpoints.GVFSConfig; try { gvfsConfigEndpoint = new Uri(gvfsConfigEndpointString); } catch (UriFormatException e) { EventMetadata metadata = new EventMetadata(); metadata.Add("Method", nameof(this.QueryGVFSConfig)); metadata.Add("ErrorMessage", e); metadata.Add("Url", gvfsConfigEndpointString); this.Tracer.RelatedError(metadata, Keywords.Network); return(null); } long requestId = HttpRequestor.GetNewRequestId(); RetryWrapper <GVFSConfig> retrier = new RetryWrapper <GVFSConfig>(this.RetryConfig.MaxAttempts); retrier.OnFailure += RetryWrapper <GVFSConfig> .StandardErrorHandler(this.Tracer, requestId, "QueryGvfsConfig"); RetryWrapper <GVFSConfig> .InvocationResult output = retrier.Invoke( tryCount => { GitEndPointResponseData response = this.SendRequest(requestId, gvfsConfigEndpoint, HttpMethod.Get, null); if (response.HasErrors) { return(new RetryWrapper <GVFSConfig> .CallbackResult(response.Error, response.ShouldRetry)); } try { using (StreamReader reader = new StreamReader(response.Stream)) { string configString = reader.RetryableReadToEnd(); GVFSConfig config = JsonConvert.DeserializeObject <GVFSConfig>(configString); return(new RetryWrapper <GVFSConfig> .CallbackResult(config)); } } catch (JsonReaderException e) { return(new RetryWrapper <GVFSConfig> .CallbackResult(e, false)); } }); return(output.Result); }
public CacheServerInfo ResolveNameFromRemote( string cacheServerUrl, GVFSConfig gvfsConfig) { if (string.IsNullOrWhiteSpace(cacheServerUrl)) { throw new InvalidOperationException("An empty url is not supported"); } if (cacheServerUrl.Equals(this.enlistment.RepoUrl, StringComparison.OrdinalIgnoreCase)) { return(this.CreateNone()); } return (gvfsConfig.CacheServers.FirstOrDefault(cache => cache.Url.Equals(cacheServerUrl, StringComparison.OrdinalIgnoreCase)) ?? new CacheServerInfo(cacheServerUrl, CacheServerInfo.ReservedNames.UserDefined)); }
public static bool TryDetermineCacheServer( string userUrlish, ITracer tracer, Enlistment enlistment, RetryConfig retryConfig, out CacheServerInfo cache, out string error) { using (ConfigHttpRequestor configRequestor = new ConfigHttpRequestor(tracer, enlistment, retryConfig)) { GVFSConfig config = configRequestor.QueryGVFSConfig(); if (!CacheServerInfo.TryDetermineCacheServer(userUrlish, enlistment, config.CacheServers, out cache, out error)) { return(false); } } return(true); }
protected GVFSConfig QueryGVFSConfig(ITracer tracer, GVFSEnlistment enlistment, RetryConfig retryConfig) { GVFSConfig gvfsConfig = null; if (!this.ShowStatusWhileRunning( () => { using (ConfigHttpRequestor configRequestor = new ConfigHttpRequestor(tracer, enlistment, retryConfig)) { return(configRequestor.TryQueryGVFSConfig(out gvfsConfig)); } }, "Querying remote for config", suppressGvfsLogMessage: true)) { this.ReportErrorAndExit(tracer, "Unable to query /gvfs/config"); } return(gvfsConfig); }
private bool TryDetermineLocalCacheAndInitializePaths( ITracer tracer, GVFSEnlistment enlistment, GVFSConfig gvfsConfig, CacheServerInfo currentCacheServer, string localCacheRoot, out string errorMessage) { errorMessage = null; LocalCacheResolver localCacheResolver = new LocalCacheResolver(enlistment); string error; string localCacheKey; if (!localCacheResolver.TryGetLocalCacheKeyFromLocalConfigOrRemoteCacheServers( tracer, gvfsConfig, currentCacheServer, localCacheRoot, localCacheKey: out localCacheKey, errorMessage: out error)) { errorMessage = "Error determining local cache key: " + error; return(false); } EventMetadata metadata = new EventMetadata(); metadata.Add("localCacheRoot", localCacheRoot); metadata.Add("localCacheKey", localCacheKey); metadata.Add(TracingConstants.MessageKey.InfoMessage, "Initializing cache paths"); tracer.RelatedEvent(EventLevel.Informational, "CloneVerb_TryDetermineLocalCacheAndInitializePaths", metadata); enlistment.InitializeCachePathsFromKey(localCacheRoot, localCacheKey); return(true); }
private bool RequestMount(GVFSEnlistment enlistment, out string errorMessage) { this.CheckGitVersion(enlistment); this.CheckGVFSHooksVersion(enlistment, null); if (!this.SkipVersionCheck) { using (ITracer mountTracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "Mount")) { this.CheckVolumeSupportsDeleteNotifications(mountTracer, enlistment); using (ConfigHttpRequestor configRequestor = new ConfigHttpRequestor(mountTracer, enlistment)) { GVFSConfig config = configRequestor.QueryGVFSConfig(); this.ValidateGVFSVersion(enlistment, config, mountTracer); } } } // We have to parse these parameters here to make sure they are valid before // handing them to the background process which cannot tell the user when they are bad EventLevel verbosity; Keywords keywords; this.ParseEnumArgs(out verbosity, out keywords); GitProcess git = new GitProcess(enlistment); if (!git.IsValidRepo()) { errorMessage = "The physical git repo is missing or invalid"; return(false); } this.SetGitConfigSettings(git); return(this.SendMountRequest(enlistment, verbosity, keywords, out errorMessage)); }
protected void InitializeLocalCacheAndObjectsPaths( ITracer tracer, GVFSEnlistment enlistment, RetryConfig retryConfig, GVFSConfig gvfsConfig, CacheServerInfo cacheServer) { string error; if (!RepoMetadata.TryInitialize(tracer, Path.Combine(enlistment.EnlistmentRoot, GVFSConstants.DotGVFS.Root), out error)) { this.ReportErrorAndExit(tracer, "Failed to initialize repo metadata: " + error); } this.InitializeCachePathsFromRepoMetadata(tracer, enlistment); // Note: Repos cloned with a version of GVFS that predates the local cache will not have a local cache configured if (!string.IsNullOrWhiteSpace(enlistment.LocalCacheRoot)) { this.EnsureLocalCacheIsHealthy(tracer, enlistment, retryConfig, gvfsConfig, cacheServer); } RepoMetadata.Shutdown(); }
private bool TryValidateGVFSVersion(GVFSEnlistment enlistment, ITracer tracer, GVFSConfig config, out string errorMessage, out bool errorIsFatal) { errorMessage = null; errorIsFatal = false; using (ITracer activity = tracer.StartActivity("ValidateGVFSVersion", EventLevel.Informational)) { Version currentVersion = new Version(ProcessHelper.GetCurrentProcessVersion()); IEnumerable <GVFSConfig.VersionRange> allowedGvfsClientVersions = config != null ? config.AllowedGVFSClientVersions : null; if (allowedGvfsClientVersions == null || !allowedGvfsClientVersions.Any()) { errorMessage = "WARNING: Unable to validate your GVFS version" + Environment.NewLine; if (config == null) { errorMessage += "Could not query valid GVFS versions from: " + Uri.EscapeUriString(enlistment.RepoUrl); } else { errorMessage += "Server not configured to provide supported GVFS versions"; } EventMetadata metadata = new EventMetadata(); tracer.RelatedError(metadata, errorMessage, Keywords.Network); return(false); } foreach (GVFSConfig.VersionRange versionRange in config.AllowedGVFSClientVersions) { if (currentVersion >= versionRange.Min && (versionRange.Max == null || currentVersion <= versionRange.Max)) { activity.RelatedEvent( EventLevel.Informational, "GVFSVersionValidated", new EventMetadata { { "SupportedVersionRange", versionRange }, }); enlistment.SetGVFSVersion(currentVersion.ToString()); return(true); } } activity.RelatedError("GVFS version {0} is not supported", currentVersion); } errorMessage = "ERROR: Your GVFS version is no longer supported. Install the latest and try again."; errorIsFatal = true; return(false); }
protected void ValidateClientVersions(ITracer tracer, GVFSEnlistment enlistment, GVFSConfig gvfsConfig, bool showWarnings) { this.CheckGitVersion(tracer, enlistment); this.GetGVFSHooksPathAndCheckVersion(tracer); this.CheckVolumeSupportsDeleteNotifications(tracer, enlistment); string errorMessage = null; bool errorIsFatal = false; if (!this.TryValidateGVFSVersion(enlistment, tracer, gvfsConfig, out errorMessage, out errorIsFatal)) { if (errorIsFatal) { this.ReportErrorAndExit(tracer, errorMessage); } else if (showWarnings) { this.Output.WriteLine(); this.Output.WriteLine(errorMessage); this.Output.WriteLine(); } } }
protected void ValidateClientVersions(ITracer tracer, GVFSEnlistment enlistment, GVFSConfig gvfsConfig, bool showWarnings) { if (!GVFSPlatform.Instance.IsUnderConstruction) { this.CheckGitVersion(tracer, enlistment, out string gitVersion); enlistment.SetGitVersion(gitVersion); } this.GetGVFSHooksPathAndCheckVersion(tracer, out string hooksVersion); enlistment.SetGVFSHooksVersion(hooksVersion); this.CheckFileSystemSupportsRequiredFeatures(tracer, enlistment); string errorMessage = null; bool errorIsFatal = false; if (!this.TryValidateGVFSVersion(enlistment, tracer, gvfsConfig, out errorMessage, out errorIsFatal)) { if (errorIsFatal) { this.ReportErrorAndExit(tracer, errorMessage); } else if (showWarnings) { this.Output.WriteLine(); this.Output.WriteLine(errorMessage); this.Output.WriteLine(); } } }
public override void Execute() { int exitCode = 0; this.EnlistmentRootPath = this.GetCloneRoot(); this.CheckGVFltHealthy(); this.CheckNotInsideExistingRepo(); this.BlockEmptyCacheServerUrl(this.CacheServerUrl); try { GVFSEnlistment enlistment; Result cloneResult = new Result(false); CacheServerInfo cacheServer = null; using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "GVFSClone")) { cloneResult = this.TryCreateEnlistment(out enlistment); if (cloneResult.Success) { tracer.AddLogFileEventListener( GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Clone), EventLevel.Informational, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, this.CacheServerUrl, enlistment.GitObjectsRoot, new EventMetadata { { "Branch", this.Branch }, { "SingleBranch", this.SingleBranch }, { "NoMount", this.NoMount }, { "NoPrefetch", this.NoPrefetch }, { "Unattended", this.Unattended }, { "IsElevated", ProcessHelper.IsAdminElevated() }, }); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheServerUrl); this.Output.WriteLine("Clone parameters:"); this.Output.WriteLine(" Repo URL: " + enlistment.RepoUrl); this.Output.WriteLine(" Cache Server: " + cacheServer); this.Output.WriteLine(" Destination: " + enlistment.EnlistmentRoot); string authErrorMessage = null; if (!this.ShowStatusWhileRunning( () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage), "Authenticating")) { this.ReportErrorAndExit(tracer, "Unable to clone because authentication failed"); } RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); GVFSConfig gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig); cacheServer = this.ResolveCacheServerUrlIfNeeded(tracer, cacheServer, cacheServerResolver, gvfsConfig); this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: true); this.ShowStatusWhileRunning( () => { cloneResult = this.TryClone(tracer, enlistment, cacheServer, retryConfig); return(cloneResult.Success); }, "Cloning"); } if (!cloneResult.Success) { tracer.RelatedError(cloneResult.ErrorMessage); } } if (cloneResult.Success) { if (!this.NoPrefetch) { this.Execute <PrefetchVerb>( this.EnlistmentRootPath, verb => { verb.Commits = true; verb.SkipVersionCheck = true; verb.ResolvedCacheServer = cacheServer; }); } if (this.NoMount) { this.Output.WriteLine("\r\nIn order to mount, first cd to within your enlistment, then call: "); this.Output.WriteLine("gvfs mount"); } else { this.Execute <MountVerb>( this.EnlistmentRootPath, verb => { verb.SkipMountedCheck = true; verb.SkipVersionCheck = true; }); } } else { this.Output.WriteLine("\r\nCannot clone @ {0}", this.EnlistmentRootPath); this.Output.WriteLine("Error: {0}", cloneResult.ErrorMessage); exitCode = (int)ReturnCode.GenericError; } } catch (AggregateException e) { this.Output.WriteLine("Cannot clone @ {0}:", this.EnlistmentRootPath); foreach (Exception ex in e.Flatten().InnerExceptions) { this.Output.WriteLine("Exception: {0}", ex.ToString()); } exitCode = (int)ReturnCode.GenericError; } catch (VerbAbortedException) { throw; } catch (Exception e) { this.ReportErrorAndExit("Cannot clone @ {0}: {1}", this.EnlistmentRootPath, e.ToString()); } Environment.Exit(exitCode); }
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)); } } }
protected override void Execute(GVFSEnlistment enlistment) { string errorMessage = null; if (!HooksInstaller.InstallHooks(enlistment, out errorMessage)) { this.ReportErrorAndExit("Error installing hooks: " + errorMessage); } string mountExeLocation = null; using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "PreMount")) { CacheServerInfo cacheServer = this.ResolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment); tracer.AddLogFileEventListener( GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.MountVerb), EventLevel.Verbose, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, cacheServer.Url, new EventMetadata { { "Unattended", this.Unattended }, { "IsElevated", ProcessHelper.IsAdminElevated() }, }); // TODO 1050199: Once the service is an optional component, GVFS should only attempt to attach // the filter via the service if the service is present\enabled if (!ProjFSFilter.IsServiceRunning(tracer) || !ProjFSFilter.IsNativeLibInstalled(tracer, new PhysicalFileSystem()) || !ProjFSFilter.TryAttach(tracer, enlistment.EnlistmentRoot, out errorMessage)) { tracer.RelatedInfo($"{nameof(MountVerb)}.{nameof(this.Execute)}: Enabling and attaching ProjFS through service"); if (!this.ShowStatusWhileRunning( () => { return(this.TryEnableAndAttachGvFltThroughService(enlistment.EnlistmentRoot, out errorMessage)); }, $"Attaching {ProjFSFilter.ServiceName} to volume")) { this.ReportErrorAndExit(tracer, ReturnCode.FilterError, errorMessage); } } RetryConfig retryConfig = null; GVFSConfig gvfsConfig = this.DownloadedGVFSConfig; if (!this.SkipVersionCheck) { string authErrorMessage = null; if (!this.ShowStatusWhileRunning( () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage), "Authenticating")) { this.Output.WriteLine(" WARNING: " + authErrorMessage); this.Output.WriteLine(" Mount will proceed, but new files cannot be accessed until GVFS can authenticate."); } if (gvfsConfig == null) { if (retryConfig == null) { retryConfig = this.GetRetryConfig(tracer, enlistment); } gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig); } this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: true); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, gvfsConfig); this.Output.WriteLine("Configured cache server: " + cacheServer); } this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, gvfsConfig, cacheServer); if (!this.ShowStatusWhileRunning( () => { return(this.PerformPreMountValidation(tracer, enlistment, out mountExeLocation, out errorMessage)); }, "Validating repo")) { this.ReportErrorAndExit(tracer, errorMessage); } if (!this.SkipVersionCheck) { string error; if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGVFSRoot, out error)) { this.ReportErrorAndExit(tracer, error); } try { EventMetadata metadata = new EventMetadata(); metadata.Add(nameof(RepoMetadata.Instance.EnlistmentId), RepoMetadata.Instance.EnlistmentId); metadata.Add("Enlistment", enlistment); tracer.RelatedEvent(EventLevel.Informational, "EnlistmentInfo", metadata, Keywords.Telemetry); GitProcess git = new GitProcess(enlistment, new PhysicalFileSystem()); GitProcess.Result configResult = git.SetInLocalConfig(GVFSConstants.GitConfig.EnlistmentId, RepoMetadata.Instance.EnlistmentId, replaceAll: true); if (configResult.HasErrors) { error = "Could not update config with enlistment id, error: " + configResult.Errors; tracer.RelatedWarning(error); } } finally { RepoMetadata.Shutdown(); } } } if (!this.ShowStatusWhileRunning( () => { return(this.TryMount(enlistment, mountExeLocation, out errorMessage)); }, "Mounting")) { this.ReportErrorAndExit(errorMessage); } if (!this.Unattended) { if (!this.ShowStatusWhileRunning( () => { return(this.RegisterMount(enlistment, out errorMessage)); }, "Registering for automount")) { this.Output.WriteLine(" WARNING: " + errorMessage); } } }
public override void Execute() { int exitCode = 0; // TODO(Mac): limit the length of the enlistment root based on the length constraints imposed by named pipes this.ValidatePathParameter(this.EnlistmentRootPathParameter); this.ValidatePathParameter(this.LocalCacheRoot); string fullEnlistmentRootPathParameter; string normalizedEnlistmentRootPath = this.GetCloneRoot(out fullEnlistmentRootPathParameter); if (!string.IsNullOrWhiteSpace(this.LocalCacheRoot)) { string fullLocalCacheRootPath = Path.GetFullPath(this.LocalCacheRoot); string errorMessage; string normalizedLocalCacheRootPath; if (!GVFSPlatform.Instance.FileSystem.TryGetNormalizedPath(fullLocalCacheRootPath, out normalizedLocalCacheRootPath, out errorMessage)) { this.ReportErrorAndExit($"Failed to determine normalized path for '--local-cache-path' path {fullLocalCacheRootPath}: {errorMessage}"); } if (normalizedLocalCacheRootPath.StartsWith( Path.Combine(normalizedEnlistmentRootPath, GVFSConstants.WorkingDirectoryRootName), StringComparison.OrdinalIgnoreCase)) { this.ReportErrorAndExit("'--local-cache-path' cannot be inside the src folder"); } } this.CheckKernelDriverSupported(normalizedEnlistmentRootPath); this.CheckNotInsideExistingRepo(normalizedEnlistmentRootPath); this.BlockEmptyCacheServerUrl(this.CacheServerUrl); try { GVFSEnlistment enlistment; Result cloneResult = new Result(false); CacheServerInfo cacheServer = null; GVFSConfig gvfsConfig = null; using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "GVFSClone")) { cloneResult = this.TryCreateEnlistment(fullEnlistmentRootPathParameter, normalizedEnlistmentRootPath, out enlistment); if (cloneResult.Success) { tracer.AddLogFileEventListener( GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Clone), EventLevel.Informational, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, this.CacheServerUrl, new EventMetadata { { "Branch", this.Branch }, { "LocalCacheRoot", this.LocalCacheRoot }, { "SingleBranch", this.SingleBranch }, { "NoMount", this.NoMount }, { "NoPrefetch", this.NoPrefetch }, { "Unattended", this.Unattended }, { "IsElevated", GVFSPlatform.Instance.IsElevated() }, { "NamedPipeName", enlistment.NamedPipeName }, { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter }, { nameof(fullEnlistmentRootPathParameter), fullEnlistmentRootPathParameter }, }); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheServerUrl); string resolvedLocalCacheRoot; if (string.IsNullOrWhiteSpace(this.LocalCacheRoot)) { resolvedLocalCacheRoot = LocalCacheResolver.GetDefaultLocalCacheRoot(enlistment); } else { resolvedLocalCacheRoot = Path.GetFullPath(this.LocalCacheRoot); } this.Output.WriteLine("Clone parameters:"); this.Output.WriteLine(" Repo URL: " + enlistment.RepoUrl); this.Output.WriteLine(" Branch: " + (string.IsNullOrWhiteSpace(this.Branch) ? "Default" : this.Branch)); this.Output.WriteLine(" Cache Server: " + cacheServer); this.Output.WriteLine(" Local Cache: " + resolvedLocalCacheRoot); this.Output.WriteLine(" Destination: " + enlistment.EnlistmentRoot); string authErrorMessage = null; if (!this.ShowStatusWhileRunning( () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage), "Authenticating", normalizedEnlistmentRootPath)) { this.ReportErrorAndExit(tracer, "Cannot clone because authentication failed"); } RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig); cacheServer = this.ResolveCacheServer(tracer, cacheServer, cacheServerResolver, gvfsConfig); if (!GVFSPlatform.Instance.IsUnderConstruction) { this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: true); } this.ShowStatusWhileRunning( () => { cloneResult = this.TryClone(tracer, enlistment, cacheServer, retryConfig, gvfsConfig, resolvedLocalCacheRoot); return(cloneResult.Success); }, "Cloning", normalizedEnlistmentRootPath); } if (!cloneResult.Success) { tracer.RelatedError(cloneResult.ErrorMessage); } } if (cloneResult.Success) { if (!this.NoPrefetch) { ReturnCode result = this.Execute <PrefetchVerb>( fullEnlistmentRootPathParameter, verb => { verb.Commits = true; verb.SkipVersionCheck = true; verb.ResolvedCacheServer = cacheServer; verb.GVFSConfig = gvfsConfig; }); if (result != ReturnCode.Success) { this.Output.WriteLine("\r\nError during prefetch @ {0}", fullEnlistmentRootPathParameter); exitCode = (int)result; } } if (this.NoMount) { this.Output.WriteLine("\r\nIn order to mount, first cd to within your enlistment, then call: "); this.Output.WriteLine("gvfs mount"); } else { this.Execute <MountVerb>( fullEnlistmentRootPathParameter, verb => { verb.SkipMountedCheck = true; verb.SkipVersionCheck = true; verb.ResolvedCacheServer = cacheServer; verb.DownloadedGVFSConfig = gvfsConfig; }); } } else { this.Output.WriteLine("\r\nCannot clone @ {0}", fullEnlistmentRootPathParameter); this.Output.WriteLine("Error: {0}", cloneResult.ErrorMessage); exitCode = (int)ReturnCode.GenericError; } } catch (AggregateException e) { this.Output.WriteLine("Cannot clone @ {0}:", fullEnlistmentRootPathParameter); foreach (Exception ex in e.Flatten().InnerExceptions) { this.Output.WriteLine("Exception: {0}", ex.ToString()); } exitCode = (int)ReturnCode.GenericError; } catch (VerbAbortedException) { throw; } catch (Exception e) { this.ReportErrorAndExit("Cannot clone @ {0}: {1}", fullEnlistmentRootPathParameter, e.ToString()); } Environment.Exit(exitCode); }
public bool TryQueryGVFSConfig(out GVFSConfig gvfsConfig) { gvfsConfig = null; Uri gvfsConfigEndpoint; string gvfsConfigEndpointString = this.repoUrl + GVFSConstants.Endpoints.GVFSConfig; try { gvfsConfigEndpoint = new Uri(gvfsConfigEndpointString); } catch (UriFormatException e) { EventMetadata metadata = new EventMetadata(); metadata.Add("Method", nameof(this.TryQueryGVFSConfig)); metadata.Add("Exception", e.ToString()); metadata.Add("Url", gvfsConfigEndpointString); this.Tracer.RelatedError(metadata, "UriFormatException when constructing Uri", Keywords.Network); return(false); } long requestId = HttpRequestor.GetNewRequestId(); RetryWrapper <GVFSConfig> retrier = new RetryWrapper <GVFSConfig>(this.RetryConfig.MaxAttempts, CancellationToken.None); retrier.OnFailure += RetryWrapper <GVFSConfig> .StandardErrorHandler(this.Tracer, requestId, "QueryGvfsConfig"); RetryWrapper <GVFSConfig> .InvocationResult output = retrier.Invoke( tryCount => { using (GitEndPointResponseData response = this.SendRequest( requestId, gvfsConfigEndpoint, HttpMethod.Get, requestContent: null, cancellationToken: CancellationToken.None)) { if (response.HasErrors) { return(new RetryWrapper <GVFSConfig> .CallbackResult(response.Error, response.ShouldRetry)); } try { string configString = response.RetryableReadToEnd(); GVFSConfig config = JsonConvert.DeserializeObject <GVFSConfig>(configString); return(new RetryWrapper <GVFSConfig> .CallbackResult(config)); } catch (JsonReaderException e) { return(new RetryWrapper <GVFSConfig> .CallbackResult(e, shouldRetry: false)); } } }); if (output.Succeeded) { gvfsConfig = output.Result; return(true); } return(false); }
private Result TryClone( JsonTracer tracer, GVFSEnlistment enlistment, CacheServerInfo cacheServer, RetryConfig retryConfig, GVFSConfig gvfsConfig, 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, gvfsConfig, 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)); } } }
private void EnsureLocalCacheIsHealthy( ITracer tracer, GVFSEnlistment enlistment, RetryConfig retryConfig, GVFSConfig gvfsConfig, CacheServerInfo cacheServer) { if (!Directory.Exists(enlistment.LocalCacheRoot)) { try { tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Local cache root: {enlistment.LocalCacheRoot} missing, recreating it"); Directory.CreateDirectory(enlistment.LocalCacheRoot); } catch (Exception e) { EventMetadata metadata = new EventMetadata(); metadata.Add("Exception", e.ToString()); metadata.Add("enlistment.LocalCacheRoot", enlistment.LocalCacheRoot); tracer.RelatedError(metadata, $"{nameof(this.EnsureLocalCacheIsHealthy)}: Exception while trying to create local cache root"); this.ReportErrorAndExit(tracer, "Failed to create local cache: " + enlistment.LocalCacheRoot); } } // Validate that the GitObjectsRoot directory is on disk, and that the GVFS repo is configured to use it. // If the directory is missing (and cannot be found in the mapping file) a new key for the repo will be added // to the mapping file and used for BOTH the GitObjectsRoot and BlobSizesRoot PhysicalFileSystem fileSystem = new PhysicalFileSystem(); if (Directory.Exists(enlistment.GitObjectsRoot)) { bool gitObjectsRootInAlternates = false; string alternatesFilePath = this.GetAlternatesPath(enlistment); if (File.Exists(alternatesFilePath)) { try { using (Stream stream = fileSystem.OpenFileStream( alternatesFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, callFlushFileBuffers: false)) { using (StreamReader reader = new StreamReader(stream)) { while (!reader.EndOfStream) { string alternatesLine = reader.ReadLine(); if (string.Equals(alternatesLine, enlistment.GitObjectsRoot, StringComparison.OrdinalIgnoreCase)) { gitObjectsRootInAlternates = true; } } } } } catch (Exception e) { EventMetadata exceptionMetadata = new EventMetadata(); exceptionMetadata.Add("Exception", e.ToString()); tracer.RelatedError(exceptionMetadata, $"{nameof(this.EnsureLocalCacheIsHealthy)}: Exception while trying to validate alternates file"); this.ReportErrorAndExit(tracer, $"Failed to validate that alternates file includes git objects root: {e.Message}"); } } else { tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Alternates file not found"); } if (!gitObjectsRootInAlternates) { tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: GitObjectsRoot ({enlistment.GitObjectsRoot}) missing from alternates files, recreating alternates"); string error; if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out error)) { this.ReportErrorAndExit(tracer, $"Failed to update alternates file to include git objects root: {error}"); } } } else { tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: GitObjectsRoot ({enlistment.GitObjectsRoot}) missing, determining new root"); if (cacheServer == null) { cacheServer = CacheServerResolver.GetCacheServerFromConfig(enlistment); } string error; if (gvfsConfig == null) { if (retryConfig == null) { if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error)) { this.ReportErrorAndExit(tracer, "Failed to determine GVFS timeout and max retries: " + error); } } gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig); } string localCacheKey; LocalCacheResolver localCacheResolver = new LocalCacheResolver(enlistment); if (!localCacheResolver.TryGetLocalCacheKeyFromLocalConfigOrRemoteCacheServers( tracer, gvfsConfig, cacheServer, enlistment.LocalCacheRoot, localCacheKey: out localCacheKey, errorMessage: out error)) { this.ReportErrorAndExit(tracer, $"Previous git objects root ({enlistment.GitObjectsRoot}) not found, and failed to determine new local cache key: {error}"); } EventMetadata metadata = new EventMetadata(); metadata.Add("localCacheRoot", enlistment.LocalCacheRoot); metadata.Add("localCacheKey", localCacheKey); metadata.Add(TracingConstants.MessageKey.InfoMessage, "Initializing and persisting updated paths"); tracer.RelatedEvent(EventLevel.Informational, "GVFSVerb_EnsureLocalCacheIsHealthy_InitializePathsFromKey", metadata); enlistment.InitializeCachePathsFromKey(enlistment.LocalCacheRoot, localCacheKey); tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Creating GitObjectsRoot ({enlistment.GitObjectsRoot}), GitPackRoot ({enlistment.GitPackRoot}), and BlobSizesRoot ({enlistment.BlobSizesRoot})"); try { Directory.CreateDirectory(enlistment.GitObjectsRoot); Directory.CreateDirectory(enlistment.GitPackRoot); } catch (Exception e) { EventMetadata exceptionMetadata = new EventMetadata(); exceptionMetadata.Add("Exception", e.ToString()); exceptionMetadata.Add("enlistment.LocalCacheRoot", enlistment.LocalCacheRoot); exceptionMetadata.Add("enlistment.GitObjectsRoot", enlistment.GitObjectsRoot); exceptionMetadata.Add("enlistment.GitPackRoot", enlistment.GitPackRoot); exceptionMetadata.Add("enlistment.BlobSizesRoot", enlistment.BlobSizesRoot); tracer.RelatedError(exceptionMetadata, $"{nameof(this.InitializeLocalCacheAndObjectsPaths)}: Exception while trying to create objects, pack, and sizes folders"); this.ReportErrorAndExit(tracer, "Failed to create objects, pack, and sizes folders"); } tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Creating new alternates file"); if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out error)) { this.ReportErrorAndExit(tracer, $"Failed to update alterates file with new objects path: {error}"); } tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Saving git objects root ({enlistment.GitObjectsRoot}) in repo metadata"); RepoMetadata.Instance.SetGitObjectsRoot(enlistment.GitObjectsRoot); tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Saving blob sizes root ({enlistment.BlobSizesRoot}) in repo metadata"); RepoMetadata.Instance.SetBlobSizesRoot(enlistment.BlobSizesRoot); } // Validate that the BlobSizesRoot folder is on disk. // Note that if a user performed an action that resulted in the entire .gvfscache being deleted, the code above // for validating GitObjectsRoot will have already taken care of generating a new key and setting a new enlistment.BlobSizesRoot path if (!Directory.Exists(enlistment.BlobSizesRoot)) { tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: BlobSizesRoot ({enlistment.BlobSizesRoot}) not found, re-creating"); try { Directory.CreateDirectory(enlistment.BlobSizesRoot); } catch (Exception e) { EventMetadata exceptionMetadata = new EventMetadata(); exceptionMetadata.Add("Exception", e.ToString()); exceptionMetadata.Add("enlistment.BlobSizesRoot", enlistment.BlobSizesRoot); tracer.RelatedError(exceptionMetadata, $"{nameof(this.InitializeLocalCacheAndObjectsPaths)}: Exception while trying to create blob sizes folder"); this.ReportErrorAndExit(tracer, "Failed to create blob sizes folder"); } } }
private bool RequestMount(GVFSEnlistment enlistment, out string errorMessage) { this.CheckGitVersion(enlistment); this.CheckGVFSHooksVersion(enlistment, null); this.CheckAntiVirusExclusion(enlistment); string mountExeLocation = Path.Combine(ProcessHelper.GetCurrentProcessLocation(), MountExeName); if (!File.Exists(mountExeLocation)) { errorMessage = "Could not find GVFS.Mount.exe. You may need to reinstall GVFS."; return(false); } if (!this.SkipVersionCheck) { using (ITracer mountTracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "Mount")) { this.CheckVolumeSupportsDeleteNotifications(mountTracer, enlistment); using (ConfigHttpRequestor configRequestor = new ConfigHttpRequestor(mountTracer, enlistment)) { GVFSConfig config = configRequestor.QueryGVFSConfig(); this.ValidateGVFSVersion(enlistment, config, mountTracer); } } } // We have to parse these parameters here to make sure they are valid before // handing them to the background process which cannot tell the user when they are bad EventLevel verbosity; Keywords keywords; this.ParseEnumArgs(out verbosity, out keywords); GitProcess git = new GitProcess(enlistment); if (!git.IsValidRepo()) { errorMessage = "The physical git repo is missing or invalid"; return(false); } this.SetGitConfigSettings(git); const string ParamPrefix = "--"; ProcessHelper.StartBackgroundProcess( mountExeLocation, string.Join( " ", enlistment.EnlistmentRoot, ParamPrefix + MountParameters.Verbosity, this.Verbosity, ParamPrefix + MountParameters.Keywords, this.KeywordsCsv, this.ShowDebugWindow ? ParamPrefix + MountParameters.DebugWindow : string.Empty), createWindow: this.ShowDebugWindow); return(this.WaitForMountToComplete(enlistment, out errorMessage)); }
protected override void Execute(GVFSEnlistment enlistment) { string errorMessage = null; if (!HooksInstaller.InstallHooks(enlistment, out errorMessage)) { this.ReportErrorAndExit("Error installing hooks: " + errorMessage); } string mountExeLocation = null; using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "PreMount")) { CacheServerInfo cacheServer = this.ResolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment); tracer.AddLogFileEventListener( GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.MountVerb), EventLevel.Verbose, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, cacheServer.Url, new EventMetadata { { "Unattended", this.Unattended }, { "IsElevated", ProcessHelper.IsAdminElevated() }, }); // TODO 1050199: Once the service is an optional component, GVFS should only attempt to attach // GvFlt via the service if the service is present\enabled if (!GvFltFilter.TryAttach(tracer, enlistment.EnlistmentRoot, out errorMessage)) { if (!this.ShowStatusWhileRunning( () => { return(this.AttachGvFltThroughService(enlistment, out errorMessage)); }, "Attaching GvFlt to volume")) { this.ReportErrorAndExit(tracer, errorMessage); } } RetryConfig retryConfig = null; GVFSConfig gvfsConfig = this.DownloadedGVFSConfig; if (!this.SkipVersionCheck) { string authErrorMessage = null; if (!this.ShowStatusWhileRunning( () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage), "Authenticating")) { this.Output.WriteLine(" WARNING: " + authErrorMessage); this.Output.WriteLine(" Mount will proceed, but new files cannot be accessed until GVFS can authenticate."); } if (gvfsConfig == null) { if (retryConfig == null) { retryConfig = this.GetRetryConfig(tracer, enlistment); } gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig); } this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: true); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, gvfsConfig); this.Output.WriteLine("Configured cache server: " + cacheServer); } this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, gvfsConfig, cacheServer); if (!this.ShowStatusWhileRunning( () => { return(this.PerformPreMountValidation(tracer, enlistment, out mountExeLocation, out errorMessage)); }, "Validating repo")) { this.ReportErrorAndExit(tracer, errorMessage); } } if (!this.ShowStatusWhileRunning( () => { return(this.TryMount(enlistment, mountExeLocation, out errorMessage)); }, "Mounting")) { this.ReportErrorAndExit(errorMessage); } if (!this.Unattended) { if (!this.ShowStatusWhileRunning( () => { return(this.RegisterMount(enlistment, out errorMessage)); }, "Registering for automount")) { this.Output.WriteLine(" WARNING: " + errorMessage); } } }
protected void ValidateClientVersions(ITracer tracer, GVFSEnlistment enlistment, GVFSConfig gvfsConfig) { this.CheckGitVersion(enlistment); this.GetGVFSHooksPathAndCheckVersion(); this.CheckVolumeSupportsDeleteNotifications(tracer, enlistment); string errorMessage = null; bool errorIsFatal = false; if (!this.ShowStatusWhileRunning( () => this.TryValidateGVFSVersion(enlistment, tracer, gvfsConfig, out errorMessage, out errorIsFatal), "Validating client version", suppressGvfsLogMessage: true)) { if (errorIsFatal) { this.ReportErrorAndExit(errorMessage); } else { this.Output.WriteLine(); this.Output.WriteLine(errorMessage); this.Output.WriteLine(); } } }
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; } } }
protected override void Execute(GVFSEnlistment enlistment) { string errorMessage = null; string mountExecutableLocation = null; using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "PreMount")) { PhysicalFileSystem fileSystem = new PhysicalFileSystem(); GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem); GVFSContext context = new GVFSContext(tracer, fileSystem, gitRepo, enlistment); if (!HooksInstaller.InstallHooks(context, out errorMessage)) { this.ReportErrorAndExit("Error installing hooks: " + errorMessage); } CacheServerInfo cacheServer = this.ResolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment); tracer.AddLogFileEventListener( GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.MountVerb), EventLevel.Verbose, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, cacheServer.Url, new EventMetadata { { "Unattended", this.Unattended }, { "IsElevated", GVFSPlatform.Instance.IsElevated() }, { "NamedPipeName", enlistment.NamedPipeName }, { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter }, }); if (!GVFSPlatform.Instance.KernelDriver.IsReady(tracer, enlistment.EnlistmentRoot, out errorMessage)) { tracer.RelatedInfo($"{nameof(MountVerb)}.{nameof(this.Execute)}: Enabling and attaching ProjFS through service"); if (!this.ShowStatusWhileRunning( () => { return(this.TryEnableAndAttachPrjFltThroughService(enlistment.EnlistmentRoot, out errorMessage)); }, $"Attaching ProjFS to volume")) { this.ReportErrorAndExit(tracer, ReturnCode.FilterError, errorMessage); } } RetryConfig retryConfig = null; GVFSConfig gvfsConfig = this.DownloadedGVFSConfig; if (!this.SkipVersionCheck) { string authErrorMessage = null; if (!this.ShowStatusWhileRunning( () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage), "Authenticating")) { this.Output.WriteLine(" WARNING: " + authErrorMessage); this.Output.WriteLine(" Mount will proceed, but new files cannot be accessed until GVFS can authenticate."); } if (gvfsConfig == null) { if (retryConfig == null) { retryConfig = this.GetRetryConfig(tracer, enlistment); } gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig); } this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: true); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, gvfsConfig); this.Output.WriteLine("Configured cache server: " + cacheServer); } this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, gvfsConfig, cacheServer); if (!this.ShowStatusWhileRunning( () => { return(this.PerformPreMountValidation(tracer, enlistment, out mountExecutableLocation, out errorMessage)); }, "Validating repo")) { this.ReportErrorAndExit(tracer, errorMessage); } if (!this.SkipVersionCheck) { string error; if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGVFSRoot, out error)) { this.ReportErrorAndExit(tracer, error); } try { GitProcess git = new GitProcess(enlistment); this.LogEnlistmentInfoAndSetConfigValues(tracer, git, enlistment); } finally { RepoMetadata.Shutdown(); } } } if (!this.ShowStatusWhileRunning( () => { return(this.TryMount(enlistment, mountExecutableLocation, out errorMessage)); }, "Mounting")) { this.ReportErrorAndExit(errorMessage); } if (!this.Unattended && GVFSPlatform.Instance.SupportsGVFSService) { if (!this.ShowStatusWhileRunning( () => { return(this.RegisterMount(enlistment, out errorMessage)); }, "Registering for automount")) { this.Output.WriteLine(" WARNING: " + errorMessage); } } }