Exemple #1
0
        private static bool TryFindUpgrade(JsonTracer tracer, string enlistmentRoot, out DiskLayoutUpgrade upgrade)
        {
            int majorVersion;
            int minorVersion;

            string error;

            if (!TryGetDiskLayoutVersion(tracer, enlistmentRoot, out majorVersion, out minorVersion, out error))
            {
                StartLogFile(enlistmentRoot, tracer);
                tracer.RelatedError(error);
                upgrade = null;
                return(false);
            }

            Dictionary <int, MinorUpgrade> minorVersionUpgradesForCurrentMajorVersion;

            if (minorVersionUpgrades.TryGetValue(majorVersion, out minorVersionUpgradesForCurrentMajorVersion))
            {
                MinorUpgrade minorUpgrade;
                if (minorVersionUpgradesForCurrentMajorVersion.TryGetValue(minorVersion, out minorUpgrade))
                {
                    StartLogFile(enlistmentRoot, tracer);
                    tracer.RelatedInfo(
                        "Upgrading from disk layout {0}.{1} to {0}.{2}",
                        majorVersion,
                        minorVersion,
                        minorVersion + 1);

                    upgrade = minorUpgrade;
                    return(true);
                }
            }

            MajorUpgrade majorUpgrade;

            if (majorVersionUpgrades.TryGetValue(majorVersion, out majorUpgrade))
            {
                StartLogFile(enlistmentRoot, tracer);
                tracer.RelatedInfo("Upgrading from disk layout {0} to {1}", majorVersion, majorVersion + 1);

                upgrade = majorUpgrade;
                return(true);
            }

            // return true to indicate that we succeeded, and no upgrader was found
            upgrade = null;
            return(true);
        }
Exemple #2
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, SparseVerbName))
            {
                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Sparse),
                    EventLevel.Informational,
                    Keywords.Any);

                bool needToChangeProjection = false;
                using (GVFSDatabase database = new GVFSDatabase(new PhysicalFileSystem(), enlistment.EnlistmentRoot, new SqliteDatabase()))
                {
                    SparseTable      sparseTable = new SparseTable(database);
                    HashSet <string> directories = sparseTable.GetAll();

                    string[] foldersToRemove = this.ParseFolderList(this.Remove);
                    string[] foldersToAdd    = this.ParseFolderList(this.Add);

                    if (this.List || (foldersToAdd.Length == 0 && foldersToRemove.Length == 0))
                    {
                        if (directories.Count == 0)
                        {
                            this.Output.WriteLine("No folders in sparse list. When the sparse list is empty, all folders are projected.");
                        }
                        else
                        {
                            foreach (string directory in directories)
                            {
                                this.Output.WriteLine(directory);
                            }
                        }

                        return;
                    }

                    foreach (string folder in foldersToRemove)
                    {
                        if (directories.Contains(folder))
                        {
                            needToChangeProjection = true;
                            break;
                        }
                    }

                    if (!needToChangeProjection)
                    {
                        foreach (string folder in foldersToAdd)
                        {
                            if (!directories.Contains(folder))
                            {
                                needToChangeProjection = true;
                                break;
                            }
                        }
                    }

                    if (needToChangeProjection)
                    {
                        // Make sure there is a clean git status before allowing sparse set to change
                        this.CheckGitStatus(tracer, enlistment);
                        if (!this.ShowStatusWhileRunning(
                                () =>
                        {
                            foreach (string directoryPath in foldersToRemove)
                            {
                                tracer.RelatedInfo($"Removing '{directoryPath}' from sparse folders.");
                                sparseTable.Remove(directoryPath);
                            }

                            foreach (string directoryPath in foldersToAdd)
                            {
                                tracer.RelatedInfo($"Adding '{directoryPath}' to sparse folders.");
                                sparseTable.Add(directoryPath);
                            }

                            return(true);
                        },
                                "Updating sparse folder set",
                                suppressGvfsLogMessage: true))
                        {
                            this.ReportErrorAndExit(tracer, "Failed to update sparse folder set.");
                        }
                    }
                }

                if (needToChangeProjection)
                {
                    // Force a projection update to get the current inclusion set
                    this.ForceProjectionChange(tracer, enlistment);
                    tracer.RelatedInfo("Projection updated after adding or removing folders.");
                }
                else
                {
                    this.WriteMessage(tracer, "No folders to update in sparse set.");
                }
            }
        }
Exemple #3
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            string errorMessage            = null;
            string mountExecutableLocation = null;

            using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "ExecuteMount"))
            {
                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, this.Output, out errorMessage))
                {
                    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);
                    }
                }

                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(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");
                    }
                }
            }
        }
        protected override void Execute(GVFSEnlistment enlistment)
        {
            if (this.List || (
                    !this.Prune &&
                    !this.Disable &&
                    string.IsNullOrEmpty(this.Add) &&
                    string.IsNullOrEmpty(this.Remove) &&
                    string.IsNullOrEmpty(this.Set) &&
                    string.IsNullOrEmpty(this.File)))
            {
                this.ListSparseFolders(enlistment.EnlistmentRoot);
                return;
            }

            this.CheckOptions();

            using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, SparseVerbName))
            {
                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Sparse),
                    EventLevel.Informational,
                    Keywords.Any);

                EventMetadata metadata = new EventMetadata();
                metadata.Add(nameof(this.Set), this.Set);
                metadata.Add(nameof(this.File), this.File);
                metadata.Add(nameof(this.Add), this.Add);
                metadata.Add(nameof(this.Remove), this.Remove);
                metadata.Add(nameof(this.Prune), this.Prune);
                metadata.Add(nameof(this.Disable), this.Disable);
                tracer.RelatedInfo(metadata, $"Running sparse");

                HashSet <string> directories;
                bool             needToChangeProjection = false;
                using (GVFSDatabase database = new GVFSDatabase(new PhysicalFileSystem(), enlistment.EnlistmentRoot, new SqliteDatabase()))
                {
                    SparseTable sparseTable = new SparseTable(database);
                    directories = sparseTable.GetAll();

                    List <string> foldersToRemove = new List <string>();
                    List <string> foldersToAdd    = new List <string>();

                    if (this.Disable)
                    {
                        if (directories.Count > 0)
                        {
                            this.WriteMessage(tracer, "Removing all folders from sparse list. When the sparse list is empty, all folders are projected.");
                            needToChangeProjection = true;
                            foldersToRemove.AddRange(directories);
                            directories.Clear();
                        }
                        else
                        {
                            return;
                        }
                    }
                    else if (!string.IsNullOrEmpty(this.Set) || !string.IsNullOrEmpty(this.File))
                    {
                        IEnumerable <string> folders = null;
                        if (!string.IsNullOrEmpty(this.Set))
                        {
                            folders = this.ParseFolderList(this.Set);
                        }
                        else if (!string.IsNullOrEmpty(this.File))
                        {
                            PhysicalFileSystem fileSystem = new PhysicalFileSystem();
                            folders = this.ParseFolderList(fileSystem.ReadAllText(this.File), folderSeparator: Environment.NewLine);
                        }
                        else
                        {
                            this.WriteMessage(tracer, "Invalid options specified.");
                            throw new InvalidOperationException();
                        }

                        foreach (string folder in folders)
                        {
                            if (!directories.Contains(folder))
                            {
                                needToChangeProjection = true;
                                foldersToAdd.Add(folder);
                            }
                            else
                            {
                                // Remove from directories so that the only directories left in the directories collection
                                // will be the ones that will need to be removed from sparse set
                                directories.Remove(folder);
                            }
                        }

                        if (directories.Count > 0)
                        {
                            needToChangeProjection = true;
                            foldersToRemove.AddRange(directories);
                            directories.Clear();
                        }

                        // Need to add folders that will be in the projection back into directories for the status check
                        foreach (string folder in folders)
                        {
                            directories.Add(folder);
                        }
                    }
                    else
                    { // Process adds and removes
                        foreach (string folder in this.ParseFolderList(this.Remove))
                        {
                            if (directories.Contains(folder))
                            {
                                needToChangeProjection = true;
                                directories.Remove(folder);
                                foldersToRemove.Add(folder);
                            }
                        }

                        foreach (string folder in this.ParseFolderList(this.Add))
                        {
                            if (!directories.Contains(folder))
                            {
                                needToChangeProjection = true;
                                directories.Add(folder);
                                foldersToAdd.Add(folder);
                            }
                        }
                    }

                    if (needToChangeProjection || this.Prune)
                    {
                        if (directories.Count > 0)
                        {
                            // Make sure there is a clean git status before allowing sparse set to change
                            this.CheckGitStatus(tracer, enlistment, directories);
                        }

                        this.UpdateSparseFolders(tracer, sparseTable, foldersToRemove, foldersToAdd);
                    }

                    if (needToChangeProjection)
                    {
                        // Force a projection update to get the current inclusion set
                        this.ForceProjectionChange(tracer, enlistment);
                        tracer.RelatedInfo("Projection updated after adding or removing folders.");
                    }
                    else
                    {
                        this.WriteMessage(tracer, "No folders to update in sparse set.");
                    }

                    if (this.Prune && directories.Count > 0)
                    {
                        this.PruneFoldersOutsideSparse(tracer, enlistment, sparseTable);
                    }
                }
            }
        }