private void GetLocalCachePaths(GVFSEnlistment enlistment, out string localCacheRoot, out string gitObjectsRoot) { localCacheRoot = null; gitObjectsRoot = null; try { using (ITracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "DiagnoseVerb")) { string error; if (RepoMetadata.TryInitialize(tracer, Path.Combine(enlistment.EnlistmentRoot, GVFSConstants.DotGVFS.Root), out error)) { RepoMetadata.Instance.TryGetLocalCacheRoot(out localCacheRoot, out error); RepoMetadata.Instance.TryGetGitObjectsRoot(out gitObjectsRoot, out error); } else { this.WriteMessage("Failed to determine local cache path and git objects root, RepoMetadata error: " + error); } } } catch (Exception e) { this.WriteMessage(string.Format("Failed to determine local cache path and git objects root, Exception: {0}", e)); } finally { RepoMetadata.Shutdown(); } }
public override IssueType HasIssue(List <string> messages) { string error; try { if (!RepoMetadata.TryInitialize(this.Tracer, this.Enlistment.DotGVFSRoot, out error)) { messages.Add("Could not open repo metadata: " + error); return(IssueType.CantFix); } if (!RepoMetadata.Instance.TryGetBlobSizesRoot(out this.blobSizeRoot, out error)) { messages.Add("Could not find blob sizes root in repo metadata: " + error); return(IssueType.CantFix); } } finally { RepoMetadata.Shutdown(); } string blobsizesDatabasePath = Path.Combine(this.blobSizeRoot, BlobSizes.DatabaseName); if (SqliteDatabase.HasIssue(blobsizesDatabasePath, new PhysicalFileSystem(), out error)) { messages.Add("Could not load blob size database: " + error); return(IssueType.Fixable); } return(IssueType.None); }
public virtual void TestTearDown() { if (this.Repo != null) { this.Repo.Dispose(); } RepoMetadata.Shutdown(); }
public static bool TryCheckDiskLayoutVersion(ITracer tracer, string enlistmentRoot, out string error) { error = string.Empty; int majorVersion; int minorVersion; try { if (TryGetDiskLayoutVersion(tracer, enlistmentRoot, out majorVersion, out minorVersion, out error)) { if (majorVersion < GVFSPlatform.Instance.DiskLayoutUpgrade.Version.MinimumSupportedMajorVersion) { error = string.Format( "Breaking change to GVFS disk layout has been made since cloning. \r\nEnlistment disk layout version: {0} \r\nGVFS disk layout version: {1} \r\nMinimum supported version: {2}", majorVersion, GVFSPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion, GVFSPlatform.Instance.DiskLayoutUpgrade.Version.MinimumSupportedMajorVersion); return(false); } else if (majorVersion > GVFSPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion) { error = string.Format( "Changes to GVFS disk layout do not allow mounting after downgrade. Try mounting again using a more recent version of GVFS. \r\nEnlistment disk layout version: {0} \r\nGVFS disk layout version: {1}", majorVersion, GVFSPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion); return(false); } else if (majorVersion != GVFSPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion) { error = string.Format( "GVFS disk layout version doesn't match current version. Try running 'gvfs mount' to upgrade. \r\nEnlistment disk layout version: {0}.{1} \r\nGVFS disk layout version: {2}.{3}", majorVersion, minorVersion, GVFSPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion, GVFSPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMinorVersion); return(false); } return(true); } } finally { RepoMetadata.Shutdown(); } error = "Failed to read disk layout version. " + ConsoleHelper.GetGVFSLogMessage(enlistmentRoot); return(false); }
public static bool TryCheckDiskLayoutVersion(ITracer tracer, string enlistmentRoot, out string error) { error = string.Empty; int persistedVersionNumber; try { if (TryGetDiskLayoutVersion(tracer, enlistmentRoot, out persistedVersionNumber, out error)) { if (persistedVersionNumber < RepoMetadata.DiskLayoutVersion.MinDiskLayoutVersion) { error = string.Format( "Breaking change to GVFS disk layout has been made since cloning. \r\nEnlistment disk layout version: {0} \r\nGVFS disk layout version: {1} \r\nMinimum supported version: {2}", persistedVersionNumber, RepoMetadata.DiskLayoutVersion.CurrentDiskLayoutVersion, RepoMetadata.DiskLayoutVersion.MinDiskLayoutVersion); return(false); } else if (persistedVersionNumber > RepoMetadata.DiskLayoutVersion.MaxDiskLayoutVersion) { error = string.Format( "Changes to GVFS disk layout do not allow mounting after downgrade. Try mounting again using a more recent version of GVFS. \r\nEnlistment disk layout version: {0} \r\nGVFS disk layout version: {1}", persistedVersionNumber, RepoMetadata.DiskLayoutVersion.CurrentDiskLayoutVersion); return(false); } else if (persistedVersionNumber != RepoMetadata.DiskLayoutVersion.CurrentDiskLayoutVersion) { error = string.Format( "GVFS disk layout version doesn't match current version. Try running 'gvfs mount' to upgrade. \r\nEnlistment disk layout version: {0} \r\nGVFS disk layout version: {1}", persistedVersionNumber, RepoMetadata.DiskLayoutVersion.CurrentDiskLayoutVersion); return(false); } return(true); } } finally { RepoMetadata.Shutdown(); } error = "Failed to read disk layout version. " + ConsoleHelper.GetGVFSLogMessage(enlistmentRoot); return(false); }
public static bool TryRunAllUpgrades(string enlistmentRoot) { majorVersionUpgrades = new Dictionary <int, MajorUpgrade>(); minorVersionUpgrades = new Dictionary <int, Dictionary <int, MinorUpgrade> >(); foreach (DiskLayoutUpgrade upgrade in GVFSPlatform.Instance.DiskLayoutUpgrade.Upgrades) { RegisterUpgrade(upgrade); } using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "DiskLayoutUpgrade")) { try { DiskLayoutUpgrade upgrade = null; while (TryFindUpgrade(tracer, enlistmentRoot, out upgrade)) { if (upgrade == null) { return(true); } if (!upgrade.TryUpgrade(tracer, enlistmentRoot)) { return(false); } if (!CheckLayoutVersionWasIncremented(tracer, enlistmentRoot, upgrade)) { return(false); } } return(false); } catch (Exception e) { StartLogFile(enlistmentRoot, tracer); tracer.RelatedError(e.ToString()); return(false); } finally { RepoMetadata.Shutdown(); } } }
public override IssueType HasIssue(List <string> messages) { string error; try { if (!RepoMetadata.TryInitialize(this.Tracer, this.Enlistment.DotGSDRoot, out error)) { messages.Add("Could not open repo metadata: " + error); return(IssueType.CantFix); } } finally { RepoMetadata.Shutdown(); } return(IssueType.None); }
public static bool TryRunAllUpgrades(string enlistmentRoot) { using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "DiskLayoutUpgrade")) { try { DiskLayoutUpgrade upgrade = null; while (TryFindUpgrade(tracer, enlistmentRoot, out upgrade)) { if (upgrade == null) { return(true); } if (!upgrade.TryUpgrade(tracer, enlistmentRoot)) { return(false); } if (!CheckLayoutVersionWasIncremented(tracer, enlistmentRoot, upgrade)) { return(false); } } return(false); } catch (Exception e) { StartLogFile(enlistmentRoot, tracer); tracer.RelatedError(e.ToString()); return(false); } finally { RepoMetadata.Shutdown(); } } }
protected void InitializeLocalCacheAndObjectsPaths( ITracer tracer, GVFSEnlistment enlistment, RetryConfig retryConfig, ServerGVFSConfig serverGVFSConfig, 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, serverGVFSConfig, cacheServer); } RepoMetadata.Shutdown(); }
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)) { if (GVFSPlatform.Instance.UnderConstruction.SupportsGVFSService) { tracer.RelatedEvent( EventLevel.Informational, $"{nameof(MountVerb)}_{nameof(this.Execute)}_EnablingKernelDriverViaService", new EventMetadata { { "KernelDriver.IsReady_Error", errorMessage }, { TracingConstants.MessageKey.InfoMessage, "Service will retry" } }); if (!this.ShowStatusWhileRunning( () => { return(this.TryEnableAndAttachPrjFltThroughService(enlistment.EnlistmentRoot, out errorMessage)); }, $"Attaching ProjFS to volume")) { this.ReportErrorAndExit(tracer, ReturnCode.FilterError, errorMessage); } } else { tracer.RelatedEvent( EventLevel.Informational, $"{nameof(MountVerb)}_{nameof(this.Execute)}", new EventMetadata { { "KernelDriver.IsReady_Error", errorMessage }, }); this.ReportErrorAndExit(tracer, ReturnCode.FilterError, errorMessage); } } RetryConfig retryConfig = null; ServerGVFSConfig serverGVFSConfig = this.DownloadedGVFSConfig; if (!this.SkipVersionCheck) { string authErrorMessage; if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage)) { this.Output.WriteLine(" WARNING: " + authErrorMessage); this.Output.WriteLine(" Mount will proceed, but new files cannot be accessed until GVFS can authenticate."); } if (serverGVFSConfig == null) { if (retryConfig == null) { retryConfig = this.GetRetryConfig(tracer, enlistment); } serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig); } this.ValidateClientVersions(tracer, enlistment, serverGVFSConfig, showWarnings: true); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, serverGVFSConfig); this.Output.WriteLine("Configured cache server: " + cacheServer); } this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGVFSConfig, 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(tracer, enlistment, mountExecutableLocation, out errorMessage)); }, "Mounting")) { this.ReportErrorAndExit(errorMessage); } } if (!this.Unattended && GVFSPlatform.Instance.UnderConstruction.SupportsGVFSService) { if (!this.ShowStatusWhileRunning( () => { return(this.RegisterMount(enlistment, out errorMessage)); }, "Registering for automount")) { this.Output.WriteLine(" WARNING: " + errorMessage); } } }
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)); }
protected override void Execute(GSDEnlistment enlistment) { string errorMessage = null; string mountExecutableLocation = null; using (JsonTracer tracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "ExecuteMount")) { PhysicalFileSystem fileSystem = new PhysicalFileSystem(); GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem); GSDContext context = new GSDContext(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( GSDEnlistment.GetNewGSDLogFileName(enlistment.GSDLogsRoot, GSDConstants.LogFileTypes.MountVerb), EventLevel.Verbose, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, cacheServer.Url, new EventMetadata { { "Unattended", this.Unattended }, { "IsElevated", GSDPlatform.Instance.IsElevated() }, { "NamedPipeName", enlistment.NamedPipeName }, { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter }, }); RetryConfig retryConfig = null; ServerGSDConfig serverGSDConfig = this.DownloadedGSDConfig; if (!this.SkipVersionCheck) { string authErrorMessage; if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage)) { this.Output.WriteLine(" WARNING: " + authErrorMessage); this.Output.WriteLine(" Mount will proceed, but new files cannot be accessed until GSD can authenticate."); } if (serverGSDConfig == null) { if (retryConfig == null) { retryConfig = this.GetRetryConfig(tracer, enlistment); } serverGSDConfig = this.QueryGSDConfig(tracer, enlistment, retryConfig); } this.ValidateClientVersions(tracer, enlistment, serverGSDConfig, showWarnings: true); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, serverGSDConfig); this.Output.WriteLine("Configured cache server: " + cacheServer); } this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGSDConfig, 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.DotGSDRoot, 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(tracer, enlistment, mountExecutableLocation, out errorMessage)); }, "Mounting")) { this.ReportErrorAndExit(tracer, errorMessage); } if (!this.Unattended) { tracer.RelatedInfo($"{nameof(this.Execute)}: Registering for automount"); if (this.ShowStatusWhileRunning( () => { return(this.RegisterMount(enlistment, out errorMessage)); }, "Registering for automount")) { tracer.RelatedInfo($"{nameof(this.Execute)}: Registered for automount"); } else { this.Output.WriteLine(" WARNING: " + errorMessage); tracer.RelatedInfo($"{nameof(this.Execute)}: Failed to register for automount"); } } } }
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) { 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 CloneVerb.Result CreateClone(GitRefs refs, string branch) { CloneVerb.Result initRepoResult = this.TryInitRepo(refs, this.enlistment); if (!initRepoResult.Success) { return(initRepoResult); } string errorMessage; if (!this.enlistment.TryConfigureAlternate(out errorMessage)) { return(new CloneVerb.Result("Error configuring alternate: " + errorMessage)); } PhysicalFileSystem fileSystem = new PhysicalFileSystem(); GitRepo gitRepo = new GitRepo(this.tracer, this.enlistment, fileSystem); GVFSGitObjects gitObjects = new GVFSGitObjects(new GVFSContext(this.tracer, fileSystem, gitRepo, this.enlistment), this.objectRequestor); if (!gitObjects.TryEnsureCommitIsLocal(refs.GetTipCommitId(branch), commitDepth: 2)) { return(new CloneVerb.Result("Could not download tip commits from: " + Uri.EscapeUriString(this.objectRequestor.CacheServer.ObjectsEndpointUrl))); } if (!GVFSVerb.TrySetGitConfigSettings(this.enlistment)) { return(new CloneVerb.Result("Unable to configure git repo")); } CacheServerResolver cacheServerResolver = new CacheServerResolver(this.tracer, this.enlistment); if (!cacheServerResolver.TrySaveUrlToLocalConfig(this.objectRequestor.CacheServer, out errorMessage)) { return(new CloneVerb.Result("Unable to configure cache server: " + errorMessage)); } GitProcess git = new GitProcess(this.enlistment); string originBranchName = "origin/" + branch; GitProcess.Result createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName); if (createBranchResult.HasErrors) { return(new CloneVerb.Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output)); } File.WriteAllText( Path.Combine(this.enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Head), "ref: refs/heads/" + branch); File.AppendAllText( Path.Combine(this.enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Info.SparseCheckoutPath), GVFSConstants.GitPathSeparatorString + GVFSConstants.SpecialGitFiles.GitAttributes + "\n"); CloneVerb.Result hydrateResult = this.HydrateRootGitAttributes(gitObjects, gitRepo, branch); if (!hydrateResult.Success) { return(hydrateResult); } this.CreateGitScript(); GitProcess.Result forceCheckoutResult = git.ForceCheckout(branch); if (forceCheckoutResult.HasErrors) { string[] errorLines = forceCheckoutResult.Errors.Split('\n'); StringBuilder checkoutErrors = new StringBuilder(); foreach (string gitError in errorLines) { if (IsForceCheckoutErrorCloneFailure(gitError)) { checkoutErrors.AppendLine(gitError); } } if (checkoutErrors.Length > 0) { string error = "Could not complete checkout of branch: " + branch + ", " + checkoutErrors.ToString(); this.tracer.RelatedError(error); return(new CloneVerb.Result(error)); } } GitProcess.Result updateIndexresult = git.UpdateIndexVersion4(); if (updateIndexresult.HasErrors) { string error = "Could not update index, error: " + updateIndexresult.Errors; this.tracer.RelatedError(error); return(new CloneVerb.Result(error)); } string installHooksError; if (!HooksInstaller.InstallHooks(this.enlistment, out installHooksError)) { this.tracer.RelatedError(installHooksError); return(new CloneVerb.Result(installHooksError)); } if (!RepoMetadata.TryInitialize(this.tracer, this.enlistment.DotGVFSRoot, out errorMessage)) { this.tracer.RelatedError(errorMessage); return(new CloneVerb.Result(errorMessage)); } try { RepoMetadata.Instance.SaveCurrentDiskLayoutVersion(); } catch (Exception e) { this.tracer.RelatedError(e.ToString()); return(new CloneVerb.Result(e.Message)); } finally { RepoMetadata.Shutdown(); } // Prepare the working directory folder for GVFS last to ensure that gvfs mount will fail if gvfs clone has failed string prepGVFltError; if (!GVFltCallbacks.TryPrepareFolderForGVFltCallbacks(this.enlistment.WorkingDirectoryRoot, out prepGVFltError)) { this.tracer.RelatedError(prepGVFltError); return(new CloneVerb.Result(prepGVFltError)); } return(new CloneVerb.Result(true)); }