/// <summary> /// Version 11 to 12 added the shared local git objects cache. /// </summary> public override bool TryUpgrade(ITracer tracer, string enlistmentRoot) { string dotGVFSPath = Path.Combine(enlistmentRoot, GVFSConstants.DotGVFS.Root); string error; if (!RepoMetadata.TryInitialize(tracer, dotGVFSPath, out error)) { tracer.RelatedError(nameof(this.TryUpgradeGitObjectPath) + ": Could not initialize repo metadata: " + error); return(false); } if (!this.TryUpgradeGitObjectPath(tracer, enlistmentRoot)) { return(false); } RepoMetadata.Instance.SetLocalCacheRoot(string.Empty); tracer.RelatedInfo("Set LocalCacheRoot to string.Empty"); if (!this.TryIncrementMajorVersion(tracer, enlistmentRoot)) { return(false); } return(true); }
private static bool TryGetDiskLayoutVersion( ITracer tracer, string enlistmentRoot, out int majorVersion, out int minorVersion, out string error) { majorVersion = 0; minorVersion = 0; string dotGVFSPath = Path.Combine(enlistmentRoot, GVFSPlatform.Instance.Constants.DotGVFSRoot); if (!GVFSPlatform.Instance.DiskLayoutUpgrade.TryParseLegacyDiskLayoutVersion(dotGVFSPath, out majorVersion)) { if (!RepoMetadata.TryInitialize(tracer, dotGVFSPath, out error)) { majorVersion = 0; return(false); } if (!RepoMetadata.Instance.TryGetOnDiskLayoutVersion(out majorVersion, out minorVersion, out error)) { return(false); } } error = null; return(true); }
/// <summary> /// Version 13 to 14 added the (shared) SQLite blob sizes database /// </summary> public override bool TryUpgrade(ITracer tracer, string enlistmentRoot) { string dotGVFSPath = Path.Combine(enlistmentRoot, GVFSPlatform.Instance.Constants.DotGVFSRoot); string error; if (!RepoMetadata.TryInitialize(tracer, dotGVFSPath, out error)) { tracer.RelatedError($"{nameof(DiskLayout13to14Upgrade_BlobSizes)}.{nameof(this.TryUpgrade)}: Could not initialize repo metadata: {error}"); return(false); } string newBlobSizesRoot; if (!this.TryFindNewBlobSizesRoot(tracer, enlistmentRoot, out newBlobSizesRoot)) { return(false); } this.MigrateBlobSizes(tracer, enlistmentRoot, newBlobSizesRoot); RepoMetadata.Instance.SetBlobSizesRoot(newBlobSizesRoot); tracer.RelatedInfo("Set BlobSizesRoot: " + newBlobSizesRoot); if (!this.TryIncrementMajorVersion(tracer, enlistmentRoot)) { return(false); } return(true); }
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); }
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(); } }
private FileSystemCallbacks CreateFileSystemCallbacks() { string error; if (!RepoMetadata.TryInitialize(this.Context.Tracer, this.Enlistment.DotGVFSRoot, out error)) { throw new InvalidRepoException(error); } string gitObjectsRoot; if (!RepoMetadata.Instance.TryGetGitObjectsRoot(out gitObjectsRoot, out error)) { throw new InvalidRepoException("Failed to determine git objects root from repo metadata: " + error); } string localCacheRoot; if (!RepoMetadata.Instance.TryGetLocalCacheRoot(out localCacheRoot, out error)) { throw new InvalidRepoException("Failed to determine local cache path from repo metadata: " + error); } string blobSizesRoot; if (!RepoMetadata.Instance.TryGetBlobSizesRoot(out blobSizesRoot, out error)) { throw new InvalidRepoException("Failed to determine blob sizes root from repo metadata: " + error); } this.Enlistment.InitializeCachePaths(localCacheRoot, gitObjectsRoot, blobSizesRoot); CacheServerInfo cacheServer = new CacheServerInfo(this.Context.Enlistment.RepoUrl, "None"); GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor( this.Context.Tracer, this.Context.Enlistment, cacheServer, new RetryConfig()); this.gvfsDatabase = new GVFSDatabase(this.Context.FileSystem, this.Context.Enlistment.EnlistmentRoot, new SqliteDatabase()); GVFSGitObjects gitObjects = new GVFSGitObjects(this.Context, objectRequestor); return(new FileSystemCallbacks( this.Context, gitObjects, RepoMetadata.Instance, blobSizes: null, gitIndexProjection: null, backgroundFileSystemTaskRunner: null, fileSystemVirtualizer: null, placeholderDatabase: new PlaceholderTable(this.gvfsDatabase), sparseCollection: new SparseTable(this.gvfsDatabase), gitStatusCache: null)); }
public virtual void TestSetup() { this.Repo = new CommonRepoSetup(); string error; RepoMetadata.TryInitialize( new MockTracer(), this.Repo.Context.FileSystem, this.Repo.Context.Enlistment.DotGVFSRoot, out error); }
public override IssueType HasIssue(List <string> messages) { string error; if (!RepoMetadata.TryInitialize(this.Tracer, this.Enlistment.DotGVFSRoot, out error)) { messages.Add("Could not open repo metadata: " + error); return(IssueType.CantFix); } return(IssueType.None); }
private bool UpdateRepoMetadata(ITracer tracer, string dotGVFSRoot) { string esentRepoMetadata = Path.Combine(dotGVFSRoot, WindowsDiskLayoutUpgradeData.EsentRepoMetadataName); if (Directory.Exists(esentRepoMetadata)) { try { using (PersistentDictionary <string, string> oldMetadata = new PersistentDictionary <string, string>(esentRepoMetadata)) { string error; if (!RepoMetadata.TryInitialize(tracer, dotGVFSRoot, out error)) { tracer.RelatedError("Could not initialize RepoMetadata: " + error); return(false); } foreach (KeyValuePair <string, string> kvp in oldMetadata) { tracer.RelatedInfo("Copying ESENT entry: {0} = {1}", kvp.Key, kvp.Value); RepoMetadata.Instance.SetEntry(kvp.Key, kvp.Value); } } } catch (IOException ex) { tracer.RelatedError("Could not write to new repo metadata: " + ex.Message); return(false); } catch (EsentException ex) { tracer.RelatedError("RepoMetadata appears to be from an older version of GVFS and corrupted: " + ex.Message); return(false); } string backupName; if (this.TryRenameFolderForDelete(tracer, esentRepoMetadata, out backupName)) { // If this fails, we leave behind cruft, but there's no harm because we renamed. this.TryDeleteFolder(tracer, backupName); return(true); } else { // To avoid double upgrading, we should rollback if we can't rename the old data this.TryDeleteFile(tracer, RepoMetadata.Instance.DataFilePath); return(false); } } return(true); }
private static bool TryGetDiskLayoutVersion( ITracer tracer, string enlistmentRoot, out int majorVersion, out int minorVersion, out string error) { majorVersion = 0; minorVersion = 0; string dotGVFSPath = Path.Combine(enlistmentRoot, GVFSConstants.DotGVFS.Root); string repoMetadataPath = Path.Combine(dotGVFSPath, EsentRepoMetadataName); if (Directory.Exists(repoMetadataPath)) { try { using (PersistentDictionary <string, string> oldMetadata = new PersistentDictionary <string, string>(repoMetadataPath)) { string versionString = oldMetadata[DiskLayoutEsentVersionKey]; if (!int.TryParse(versionString, out majorVersion)) { error = "Could not parse version string as integer: " + versionString; return(false); } } } catch (Exception e) { majorVersion = 0; error = e.ToString(); return(false); } } else { if (!RepoMetadata.TryInitialize(tracer, dotGVFSPath, out error)) { majorVersion = 0; return(false); } if (!RepoMetadata.Instance.TryGetOnDiskLayoutVersion(out majorVersion, out minorVersion, out error)) { return(false); } } error = null; return(true); }
protected bool TryIncrementDiskLayoutVersion(ITracer tracer, string enlistmentRoot, DiskLayoutUpgrade upgrade) { string newVersion = (upgrade.SourceLayoutVersion + 1).ToString(); string dotGVFSPath = Path.Combine(enlistmentRoot, GVFSConstants.DotGVFS.Root); string error; if (!RepoMetadata.TryInitialize(tracer, dotGVFSPath, out error)) { tracer.RelatedError("Could not initialize repo metadata: " + error); return(false); } RepoMetadata.Instance.SetEntry(RepoMetadata.Keys.DiskLayoutVersion, newVersion); tracer.RelatedInfo("Disk layout version is now: " + newVersion); return(true); }
public void Mount(EventLevel verbosity, Keywords keywords) { this.currentState = MountState.Mounting; // We must initialize repo metadata before starting the pipe server so it // can immediately handle status requests string error; if (!RepoMetadata.TryInitialize(this.tracer, this.enlistment.DotGVFSRoot, out error)) { this.FailMountAndExit("Failed to load repo metadata: {0}", error); } using (NamedPipeServer pipeServer = this.StartNamedPipe()) { GVFSContext context = this.CreateContext(); if (context.Unattended) { this.tracer.RelatedEvent(EventLevel.Critical, GVFSConstants.UnattendedEnvironmentVariable, null); } this.ValidateMountPoints(); this.UpdateHooks(); this.SetVisualStudioRegistryKey(); this.gvfsLock = context.Repository.GVFSLock; this.MountAndStartWorkingDirectoryCallbacks(context, this.cacheServer); Console.Title = "GVFS " + ProcessHelper.GetCurrentProcessVersion() + " - " + this.enlistment.EnlistmentRoot; this.tracer.RelatedEvent( EventLevel.Critical, "Mount", new EventMetadata { // Use TracingConstants.MessageKey.InfoMessage rather than TracingConstants.MessageKey.CriticalMessage // as this message should not appear as an error { TracingConstants.MessageKey.InfoMessage, "Virtual repo is ready" }, }); this.currentState = MountState.Ready; this.unmountEvent.WaitOne(); } }
protected bool TryIncrementMinorVersion(ITracer tracer, string enlistmentRoot) { string newMinorVersion = (this.SourceMinorVersion + 1).ToString(); string dotGVFSPath = Path.Combine(enlistmentRoot, GVFSPlatform.Instance.Constants.DotGVFSRoot); string error; if (!RepoMetadata.TryInitialize(tracer, dotGVFSPath, out error)) { tracer.RelatedError("Could not initialize repo metadata: " + error); return(false); } RepoMetadata.Instance.SetEntry(RepoMetadata.Keys.DiskLayoutMinorVersion, newMinorVersion); tracer.RelatedInfo("Disk layout version is now: {0}.{1}", this.SourceMajorVersion, newMinorVersion); return(true); }
private FileSystemCallbacks CreateFileSystemCallbacks() { string error; if (!RepoMetadata.TryInitialize(this.Context.Tracer, this.Enlistment.DotGVFSRoot, out error)) { throw new InvalidRepoException(error); } string gitObjectsRoot; if (!RepoMetadata.Instance.TryGetGitObjectsRoot(out gitObjectsRoot, out error)) { throw new InvalidRepoException("Failed to determine git objects root from repo metadata: " + error); } string localCacheRoot; if (!RepoMetadata.Instance.TryGetLocalCacheRoot(out localCacheRoot, out error)) { throw new InvalidRepoException("Failed to determine local cache path from repo metadata: " + error); } string blobSizesRoot; if (!RepoMetadata.Instance.TryGetBlobSizesRoot(out blobSizesRoot, out error)) { throw new InvalidRepoException("Failed to determine blob sizes root from repo metadata: " + error); } this.Enlistment.InitializeCachePaths(localCacheRoot, gitObjectsRoot, blobSizesRoot); 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 FileSystemCallbacks(this.Context, gitObjects, RepoMetadata.Instance, fileSystemVirtualizer: null)); }
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)); }
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(); }
public void Mount(EventLevel verbosity, Keywords keywords) { this.currentState = MountState.Mounting; // We must initialize repo metadata before starting the pipe server so it // can immediately handle status requests string error; if (!RepoMetadata.TryInitialize(this.tracer, this.enlistment.DotGVFSRoot, out error)) { this.FailMountAndExit("Failed to load repo metadata: " + error); } string gitObjectsRoot; if (!RepoMetadata.Instance.TryGetGitObjectsRoot(out gitObjectsRoot, out error)) { this.FailMountAndExit("Failed to determine git objects root from repo metadata: " + error); } string localCacheRoot; if (!RepoMetadata.Instance.TryGetLocalCacheRoot(out localCacheRoot, out error)) { this.FailMountAndExit("Failed to determine local cache path from repo metadata: " + error); } string blobSizesRoot; if (!RepoMetadata.Instance.TryGetBlobSizesRoot(out blobSizesRoot, out error)) { this.FailMountAndExit("Failed to determine blob sizes root from repo metadata: " + error); } this.tracer.RelatedEvent( EventLevel.Informational, "CachePathsLoaded", new EventMetadata { { "gitObjectsRoot", gitObjectsRoot }, { "localCacheRoot", localCacheRoot }, { "blobSizesRoot", blobSizesRoot }, }); this.enlistment.InitializeCachePaths(localCacheRoot, gitObjectsRoot, blobSizesRoot); using (NamedPipeServer pipeServer = this.StartNamedPipe()) { this.tracer.RelatedEvent( EventLevel.Informational, $"{nameof(this.Mount)}_StartedNamedPipe", new EventMetadata { { "NamedPipeName", this.enlistment.NamedPipeName } }); this.context = this.CreateContext(); if (this.context.Unattended) { this.tracer.RelatedEvent(EventLevel.Critical, GVFSConstants.UnattendedEnvironmentVariable, null); } this.ValidateMountPoints(); string errorMessage; if (!HooksInstaller.TryUpdateHooks(this.context, out errorMessage)) { this.FailMountAndExit(errorMessage); } GVFSPlatform.Instance.ConfigureVisualStudio(this.enlistment.GitBinPath, this.tracer); this.MountAndStartWorkingDirectoryCallbacks(this.cacheServer); Console.Title = "GVFS " + ProcessHelper.GetCurrentProcessVersion() + " - " + this.enlistment.EnlistmentRoot; this.tracer.RelatedEvent( EventLevel.Informational, "Mount", new EventMetadata { // Use TracingConstants.MessageKey.InfoMessage rather than TracingConstants.MessageKey.CriticalMessage // as this message should not appear as an error { TracingConstants.MessageKey.InfoMessage, "Virtual repo is ready" }, }, Keywords.Telemetry); this.currentState = MountState.Ready; this.unmountEvent.WaitOne(); } }
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); } } }
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)); }
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(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); } } }
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)); }