示例#1
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "Dehydrate"))
            {
                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Dehydrate),
                    EventLevel.Informational,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    CacheServerResolver.GetUrlFromConfig(enlistment),
                    new EventMetadata
                {
                    { "Confirmed", this.Confirmed },
                    { "NoStatus", this.NoStatus },
                    { "NamedPipeName", enlistment.NamedPipeName },
                    { "Folders", this.Folders },
                    { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
                });

                // This is only intended to be run by functional tests
                if (this.MaintenanceJob != null)
                {
                    this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig: null, serverGVFSConfig: null, cacheServer: null);
                    PhysicalFileSystem fileSystem = new PhysicalFileSystem();
                    using (GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem))
                        using (GVFSContext context = new GVFSContext(tracer, fileSystem, gitRepo, enlistment))
                        {
                            switch (this.MaintenanceJob)
                            {
                            case "LooseObjects":
                                (new LooseObjectsStep(context, forceRun: true)).Execute();
                                return;

                            case "PackfileMaintenance":
                                (new PackfileMaintenanceStep(
                                     context,
                                     forceRun: true,
                                     batchSize: this.PackfileMaintenanceBatchSize ?? PackfileMaintenanceStep.DefaultBatchSize)).Execute();
                                return;

                            case "PostFetch":
                                (new PostFetchStep(context, new System.Collections.Generic.List <string>(), requireObjectCacheLock: false)).Execute();
                                return;

                            default:
                                this.ReportErrorAndExit($"Unknown maintenance job requested: {this.MaintenanceJob}");
                                break;
                            }
                        }
                }

                bool fullDehydrate = string.IsNullOrEmpty(this.Folders);

                if (!this.Confirmed && fullDehydrate)
                {
                    this.Output.WriteLine(
                        @"WARNING: THIS IS AN EXPERIMENTAL FEATURE

Dehydrate will back up your src folder, and then create a new, empty src folder 
with a fresh virtualization of the repo. All of your downloaded objects, branches, 
and siblings of the src folder will be preserved. Your modified working directory 
files will be moved to the backup, and your new working directory will not have 
any of your uncommitted changes.

Before you dehydrate, make sure you have committed any working directory changes 
you want to keep. If you choose not to, you can still find your uncommitted changes 
in the backup folder, but it will be harder to find them because 'git status' 
will not work in the backup.

To actually execute the dehydrate, run 'gvfs dehydrate --confirm' from the parent 
of your enlistment's src folder.
");

                    return;
                }
                else if (!this.Confirmed)
                {
                    this.Output.WriteLine(
                        @"WARNING: THIS IS AN EXPERIMENTAL FEATURE

All of your downloaded objects, branches, and siblings of the src folder
will be preserved.  This will remove the folders specified and any working directory
files and folders even if ignored by git similar to 'git clean -xdf <path>'.

Before you dehydrate, you will have to commit any working directory changes 
you want to keep and have a clean 'git status'.

To actually execute the dehydrate, run 'gvfs dehydrate --confirm --folders <folder list>'
from a parent of the folders list.
");

                    return;
                }

                if (this.NoStatus && !fullDehydrate)
                {
                    this.ReportErrorAndExit(tracer, "Dehydrate --no-status not valid with --folders");
                    return;
                }

                bool cleanStatus = this.StatusChecked || this.CheckGitStatus(tracer, enlistment, fullDehydrate);

                string backupRoot = Path.GetFullPath(Path.Combine(enlistment.EnlistmentRoot, "dehydrate_backup", DateTime.Now.ToString("yyyyMMdd_HHmmss")));
                this.Output.WriteLine();

                if (fullDehydrate)
                {
                    this.WriteMessage(tracer, $"Starting {this.RunningVerbName}. All of your existing files will be backed up in " + backupRoot);
                }

                this.WriteMessage(tracer, $"WARNING: If you abort the {this.RunningVerbName} after this point, the repo may become corrupt");

                this.Output.WriteLine();

                this.Unmount(tracer);

                string error;
                if (!DiskLayoutUpgrade.TryCheckDiskLayoutVersion(tracer, enlistment.EnlistmentRoot, out error))
                {
                    this.ReportErrorAndExit(tracer, error);
                }

                if (fullDehydrate)
                {
                    RetryConfig retryConfig;
                    if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error))
                    {
                        this.ReportErrorAndExit(tracer, "Failed to determine GVFS timeout and max retries: " + error);
                    }

                    string errorMessage;
                    if (!this.TryAuthenticate(tracer, enlistment, out errorMessage))
                    {
                        this.ReportErrorAndExit(tracer, errorMessage);
                    }

                    // Local cache and objects paths are required for TryDownloadGitObjects
                    this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGVFSConfig: null, cacheServer: null);

                    this.RunFullDehydrate(tracer, enlistment, backupRoot, retryConfig);
                }
                else
                {
                    string[] folders = this.Folders.Split(new[] { FolderListSeparator }, StringSplitOptions.RemoveEmptyEntries);

                    if (folders.Length > 0)
                    {
                        if (cleanStatus)
                        {
                            this.DehydrateFolders(tracer, enlistment, folders);
                        }
                        else
                        {
                            this.ReportErrorAndExit($"Cannot {this.ActionName}: must have a clean git status.");
                        }
                    }
                    else
                    {
                        this.ReportErrorAndExit($"No folders to {this.ActionName}.");
                    }
                }
            }
        }
示例#2
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "Dehydrate"))
            {
                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Dehydrate),
                    EventLevel.Informational,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    CacheServerResolver.GetUrlFromConfig(enlistment),
                    enlistment.GitObjectsRoot,
                    new EventMetadata
                {
                    { "Confirmed", this.Confirmed },
                    { "NoStatus", this.NoStatus },
                });

                if (!this.Confirmed)
                {
                    this.Output.WriteLine(
                        @"WARNING: THIS IS AN EXPERIMENTAL FEATURE

Dehydrate will back up your src folder, and then create a new, empty src folder 
with a fresh virtualization of the repo. All of your downloaded objects, branches, 
and siblings of the src folder will be preserved. Your modified working directory 
files will be moved to the backup, and your new working directory will not have 
any of your uncommitted changes.

Before you dehydrate, make sure you have committed any working directory changes 
you want to keep. If you choose not to, you can still find your uncommitted changes 
in the backup folder, but it will be harder to find them because 'git status' 
will not work in the backup.

To actually execute the dehydrate, run 'gvfs dehydrate --confirm'
");

                    return;
                }

                this.CheckGitStatus(tracer, enlistment);

                string backupRoot = Path.GetFullPath(Path.Combine(enlistment.EnlistmentRoot, "dehydrate_backup", DateTime.Now.ToString("yyyyMMdd_HHmmss")));
                this.Output.WriteLine();
                this.WriteMessage(tracer, "Starting dehydration. All of your existing files will be backed up in " + backupRoot);
                this.WriteMessage(tracer, "WARNING: If you abort the dehydrate after this point, the repo may become corrupt");
                this.Output.WriteLine();

                this.Unmount(tracer);

                string error;
                if (!DiskLayoutUpgrade.TryCheckDiskLayoutVersion(tracer, enlistment.EnlistmentRoot, out error))
                {
                    this.WriteErrorAndExit(tracer, error);
                }

                if (this.TryBackupFiles(tracer, enlistment, backupRoot) &&
                    this.TryRecreateIndex(tracer, enlistment))
                {
                    // Converting the src folder to partial must be the final step before mount
                    this.PrepareSrcFolder(tracer, enlistment);
                    this.Mount(tracer);

                    this.Output.WriteLine();
                    this.WriteMessage(tracer, "The repo was successfully dehydrated and remounted");
                }
                else
                {
                    this.Output.WriteLine();
                    this.WriteMessage(tracer, "ERROR: Backup failed. We will attempt to mount, but you may need to reclone if that fails");

                    this.Mount(tracer);
                    this.WriteMessage(tracer, "Dehydrate failed, but remounting succeeded");
                }
            }
        }
示例#3
0
        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, 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(errorMessage);
                }
            }

            if (!this.Unattended)
            {
                if (!this.ShowStatusWhileRunning(
                        () => { return(this.RegisterMount(enlistment, out errorMessage)); },
                        "Registering for automount"))
                {
                    this.Output.WriteLine("    WARNING: " + errorMessage);
                }
            }
        }
示例#4
0
        protected override void Execute(ScalarEnlistment enlistment)
        {
            string diagnosticsRoot = Path.Combine(enlistment.EnlistmentRoot, ".scalarDiagnostics");

            if (!Directory.Exists(diagnosticsRoot))
            {
                Directory.CreateDirectory(diagnosticsRoot);
            }

            string archiveFolderPath = Path.Combine(diagnosticsRoot, "scalar_" + DateTime.Now.ToString("yyyyMMdd_HHmmss"));

            Directory.CreateDirectory(archiveFolderPath);

            using (FileStream diagnosticLogFile = new FileStream(Path.Combine(archiveFolderPath, "diagnostics.log"), FileMode.CreateNew))
                using (this.diagnosticLogFileWriter = new StreamWriter(diagnosticLogFile))
                {
                    this.WriteMessage("Collecting diagnostic info into temp folder " + archiveFolderPath);

                    this.WriteMessage(string.Empty);
                    this.WriteMessage("scalar version " + ProcessHelper.GetCurrentProcessVersion());

                    GitVersion gitVersion = null;
                    string     error      = null;
                    if (!string.IsNullOrEmpty(enlistment.GitBinPath) && GitProcess.TryGetVersion(enlistment.GitBinPath, out gitVersion, out error))
                    {
                        this.WriteMessage("git version " + gitVersion.ToString());
                    }
                    else
                    {
                        this.WriteMessage("Could not determine git version. " + error);
                    }

                    this.WriteMessage(enlistment.GitBinPath);
                    this.WriteMessage(string.Empty);
                    this.WriteMessage("Enlistment root: " + enlistment.EnlistmentRoot);
                    this.WriteMessage("Cache Server: " + CacheServerResolver.GetCacheServerFromConfig(enlistment));

                    string localCacheRoot;
                    string gitObjectsRoot;
                    this.GetLocalCachePaths(enlistment, out localCacheRoot, out gitObjectsRoot);
                    string actualLocalCacheRoot = !string.IsNullOrWhiteSpace(localCacheRoot) ? localCacheRoot : gitObjectsRoot;
                    this.WriteMessage("Local Cache: " + actualLocalCacheRoot);
                    this.WriteMessage(string.Empty);

                    this.PrintDiskSpaceInfo(actualLocalCacheRoot, this.EnlistmentRootPathParameter);

                    this.RecordVersionInformation();

                    this.ShowStatusWhileRunning(
                        () =>
                    {
                        // .git
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, ScalarConstants.DotGit.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, ScalarConstants.DotGit.Hooks.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, ScalarConstants.DotGit.Info.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, ScalarConstants.DotGit.Logs.Root, copySubFolders: true);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, ScalarConstants.DotGit.Refs.Root, copySubFolders: true);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, ScalarConstants.DotGit.Objects.Info.Root, copySubFolders: false);
                        this.LogDirectoryEnumeration(enlistment.WorkingDirectoryRoot, Path.Combine(archiveFolderPath, ScalarConstants.DotGit.Objects.Root), ScalarConstants.DotGit.Objects.Pack.Root, "packs-local.txt");
                        this.LogLooseObjectCount(enlistment.WorkingDirectoryRoot, Path.Combine(archiveFolderPath, ScalarConstants.DotGit.Objects.Root), ScalarConstants.DotGit.Objects.Root, "objects-local.txt");

                        // local cache
                        this.CopyLocalCacheData(archiveFolderPath, gitObjectsRoot);

                        // service
                        string commonAppDataRoot = ScalarPlatform.Instance.GetCommonAppDataRootForScalar();
                        string secureDataRoot    = ScalarPlatform.Instance.GetSecureDataRootForScalar();

                        this.CopyAllFiles(
                            commonAppDataRoot,
                            archiveFolderPath,
                            this.ServiceName,
                            copySubFolders: true);

                        if (!commonAppDataRoot.Equals(secureDataRoot))
                        {
                            this.CopyAllFiles(
                                secureDataRoot,
                                archiveFolderPath,
                                this.ServiceName,
                                copySubFolders: true);
                        }

                        // service ui
                        this.CopyAllFiles(
                            ScalarPlatform.Instance.GetCommonAppDataRootForScalar(),
                            archiveFolderPath,
                            ScalarConstants.Service.UIName,
                            copySubFolders: true);

                        if (ScalarPlatform.Instance.UnderConstruction.SupportsScalarUpgrade)
                        {
                            // upgrader
                            this.CopyAllFiles(
                                ProductUpgraderInfo.GetParentLogDirectoryPath(),
                                archiveFolderPath,
                                DeprecatedUpgradeLogsDirectory,
                                copySubFolders: true,
                                targetFolderName: Path.Combine(ProductUpgraderInfo.UpgradeDirectoryName, DeprecatedUpgradeLogsDirectory));

                            this.CopyAllFiles(
                                ProductUpgraderInfo.GetParentLogDirectoryPath(),
                                archiveFolderPath,
                                ProductUpgraderInfo.LogDirectory,
                                copySubFolders: true,
                                targetFolderName: Path.Combine(ProductUpgraderInfo.UpgradeDirectoryName, ProductUpgraderInfo.LogDirectory));

                            this.LogDirectoryEnumeration(
                                ProductUpgraderInfo.GetUpgradeProtectedDataDirectory(),
                                Path.Combine(archiveFolderPath, ProductUpgraderInfo.UpgradeDirectoryName),
                                ProductUpgraderInfo.DownloadDirectory,
                                "downloaded-assets.txt");
                        }

                        if (ScalarPlatform.Instance.UnderConstruction.SupportsScalarConfig)
                        {
                            this.CopyFile(ScalarPlatform.Instance.GetSecureDataRootForScalar(), archiveFolderPath, LocalScalarConfig.FileName);
                        }

                        return(true);
                    },
                        "Copying logs");

                    this.CopyAllFiles(enlistment.DotGitRoot, archiveFolderPath, ScalarConstants.DotGit.Logs.Name, copySubFolders: false);
                }

            string zipFilePath = archiveFolderPath + ".zip";

            this.ShowStatusWhileRunning(
                () =>
            {
                ZipFile.CreateFromDirectory(archiveFolderPath, zipFilePath);
                this.fileSystem.DeleteDirectory(archiveFolderPath);

                return(true);
            },
                "Creating zip file");

            this.Output.WriteLine();
            this.Output.WriteLine("Diagnostics complete. All of the gathered info, as well as all of the output above, is captured in");
            this.Output.WriteLine(zipFilePath);
        }
示例#5
0
        private Result CreateClone()
        {
            Result initRepoResult = this.TryInitRepo();

            if (!initRepoResult.Success)
            {
                return(initRepoResult);
            }

            string errorMessage;

            if (!this.TrySetObjectCacheLocation(this.fileSystem, this.enlistment, out errorMessage))
            {
                return(new Result("Error configuring alternate: " + errorMessage));
            }

            this.context = new ScalarContext(this.tracer, this.fileSystem, this.enlistment);

            // Set required and optional config.
            // Explicitly pass useGvfsProtocol: true as the enlistment can not discover that setting from
            // Git config yet. Other verbs will discover this automatically from the config we set now.
            ConfigStep configStep = new ConfigStep(context, useGvfsProtocol: true);

            if (!configStep.TrySetConfig(out string configError))
            {
                return(new Result($"Failed to set initial config: {configError}"));
            }

            CacheServerResolver cacheServerResolver = new CacheServerResolver(this.tracer, this.enlistment);

            if (!cacheServerResolver.TrySaveUrlToLocalConfig(this.cacheServer, out errorMessage))
            {
                return(new Result("Unable to configure cache server: " + errorMessage));
            }

            if (!this.TryDownloadCommit(
                    this.refs.GetTipCommitId(this.Branch),
                    this.enlistment,
                    out errorMessage))
            {
                return(new Result(errorMessage));
            }

            this.git = new GitProcess(this.enlistment);
            string originBranchName = "origin/" + this.Branch;

            GitProcess.Result createBranchResult = this.git.CreateBranchWithUpstream(this.Branch, originBranchName);
            if (createBranchResult.ExitCodeIsFailure)
            {
                return(new Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output));
            }

            File.WriteAllText(
                Path.Combine(this.enlistment.WorkingDirectoryRoot, ScalarConstants.DotGit.Head),
                "ref: refs/heads/" + this.Branch);

            try
            {
                this.LogEnlistmentInfoAndSetConfigValues(this.tracer, this.git, this.enlistment);
            }
            catch (Exception e)
            {
                this.tracer.RelatedError(e.ToString());
                return(new Result(e.Message));
            }

            return(new Result(true));
        }
        protected override void Execute(GVFSEnlistment enlistment)
        {
            using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "Dehydrate"))
            {
                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Dehydrate),
                    EventLevel.Informational,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    CacheServerResolver.GetUrlFromConfig(enlistment),
                    new EventMetadata
                {
                    { "Confirmed", this.Confirmed },
                    { "NoStatus", this.NoStatus },
                    { "NamedPipeName", enlistment.NamedPipeName },
                    { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
                });

                // This is only intended to be run by functional tests
                if (this.MaintenanceJob != null)
                {
                    this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig: null, serverGVFSConfig: null, cacheServer: null);
                    PhysicalFileSystem fileSystem = new PhysicalFileSystem();
                    using (GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem))
                        using (GVFSContext context = new GVFSContext(tracer, fileSystem, gitRepo, enlistment))
                        {
                            switch (this.MaintenanceJob)
                            {
                            case "LooseObjects":
                                (new LooseObjectsStep(context, forceRun: true)).Execute();
                                return;

                            case "PackfileMaintenance":
                                (new PackfileMaintenanceStep(
                                     context,
                                     forceRun: true,
                                     batchSize: this.PackfileMaintenanceBatchSize ?? PackfileMaintenanceStep.DefaultBatchSize)).Execute();
                                return;

                            default:
                                this.ReportErrorAndExit($"Unknown maintenance job requested: {this.MaintenanceJob}");
                                break;
                            }
                        }
                }

                if (!this.Confirmed)
                {
                    this.Output.WriteLine(
                        @"WARNING: THIS IS AN EXPERIMENTAL FEATURE

Dehydrate will back up your src folder, and then create a new, empty src folder 
with a fresh virtualization of the repo. All of your downloaded objects, branches, 
and siblings of the src folder will be preserved. Your modified working directory 
files will be moved to the backup, and your new working directory will not have 
any of your uncommitted changes.

Before you dehydrate, make sure you have committed any working directory changes 
you want to keep. If you choose not to, you can still find your uncommitted changes 
in the backup folder, but it will be harder to find them because 'git status' 
will not work in the backup.

To actually execute the dehydrate, run 'gvfs dehydrate --confirm' from the parent 
of your enlistment's src folder.
");

                    return;
                }

                this.CheckGitStatus(tracer, enlistment);

                string backupRoot = Path.GetFullPath(Path.Combine(enlistment.EnlistmentRoot, "dehydrate_backup", DateTime.Now.ToString("yyyyMMdd_HHmmss")));
                this.Output.WriteLine();
                this.WriteMessage(tracer, "Starting dehydration. All of your existing files will be backed up in " + backupRoot);
                this.WriteMessage(tracer, "WARNING: If you abort the dehydrate after this point, the repo may become corrupt");
                this.Output.WriteLine();

                this.Unmount(tracer);

                string error;
                if (!DiskLayoutUpgrade.TryCheckDiskLayoutVersion(tracer, enlistment.EnlistmentRoot, out error))
                {
                    this.ReportErrorAndExit(tracer, error);
                }

                RetryConfig retryConfig;
                if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error))
                {
                    this.ReportErrorAndExit(tracer, "Failed to determine GVFS timeout and max retries: " + error);
                }

                string errorMessage;
                if (!this.TryAuthenticate(tracer, enlistment, out errorMessage))
                {
                    this.ReportErrorAndExit(tracer, errorMessage);
                }

                // Local cache and objects paths are required for TryDownloadGitObjects
                this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGVFSConfig: null, cacheServer: null);

                if (this.TryBackupFiles(tracer, enlistment, backupRoot))
                {
                    if (this.TryDownloadGitObjects(tracer, enlistment, retryConfig) &&
                        this.TryRecreateIndex(tracer, enlistment))
                    {
                        // Converting the src folder to partial must be the final step before mount
                        this.PrepareSrcFolder(tracer, enlistment);
                        this.Mount(tracer);

                        this.Output.WriteLine();
                        this.WriteMessage(tracer, "The repo was successfully dehydrated and remounted");
                    }
                }
                else
                {
                    this.Output.WriteLine();
                    this.WriteMessage(tracer, "ERROR: Backup failed. We will attempt to mount, but you may need to reclone if that fails");

                    this.Mount(tracer);
                    this.WriteMessage(tracer, "Dehydrate failed, but remounting succeeded");
                }
            }
        }
示例#7
0
            private void EnsureLocalCacheIsHealthy(
                ITracer tracer,
                GVFSEnlistment enlistment,
                RetryConfig retryConfig,
                ServerGVFSConfig serverGVFSConfig,
                CacheServerInfo cacheServer)
            {
                if (!Directory.Exists(enlistment.LocalCacheRoot))
                {
                    try
                    {
                        tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Local cache root: {enlistment.LocalCacheRoot} missing, recreating it");
                        Directory.CreateDirectory(enlistment.LocalCacheRoot);
                    }
                    catch (Exception e)
                    {
                        EventMetadata metadata = new EventMetadata();
                        metadata.Add("Exception", e.ToString());
                        metadata.Add("enlistment.LocalCacheRoot", enlistment.LocalCacheRoot);
                        tracer.RelatedError(metadata, $"{nameof(this.EnsureLocalCacheIsHealthy)}: Exception while trying to create local cache root");

                        this.ReportErrorAndExit(tracer, "Failed to create local cache: " + enlistment.LocalCacheRoot);
                    }
                }

                // Validate that the GitObjectsRoot directory is on disk, and that the GVFS repo is configured to use it.
                // If the directory is missing (and cannot be found in the mapping file) a new key for the repo will be added
                // to the mapping file and used for BOTH the GitObjectsRoot and BlobSizesRoot
                PhysicalFileSystem fileSystem = new PhysicalFileSystem();

                if (Directory.Exists(enlistment.GitObjectsRoot))
                {
                    bool gitObjectsRootInAlternates = false;

                    string alternatesFilePath = this.GetAlternatesPath(enlistment);
                    if (File.Exists(alternatesFilePath))
                    {
                        try
                        {
                            using (Stream stream = fileSystem.OpenFileStream(
                                       alternatesFilePath,
                                       FileMode.Open,
                                       FileAccess.Read,
                                       FileShare.ReadWrite,
                                       callFlushFileBuffers: false))
                            {
                                using (StreamReader reader = new StreamReader(stream))
                                {
                                    while (!reader.EndOfStream)
                                    {
                                        string alternatesLine = reader.ReadLine();
                                        if (string.Equals(alternatesLine, enlistment.GitObjectsRoot, StringComparison.OrdinalIgnoreCase))
                                        {
                                            gitObjectsRootInAlternates = true;
                                        }
                                    }
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            EventMetadata exceptionMetadata = new EventMetadata();
                            exceptionMetadata.Add("Exception", e.ToString());
                            tracer.RelatedError(exceptionMetadata, $"{nameof(this.EnsureLocalCacheIsHealthy)}: Exception while trying to validate alternates file");

                            this.ReportErrorAndExit(tracer, $"Failed to validate that alternates file includes git objects root: {e.Message}");
                        }
                    }
                    else
                    {
                        tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Alternates file not found");
                    }

                    if (!gitObjectsRootInAlternates)
                    {
                        tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: GitObjectsRoot ({enlistment.GitObjectsRoot}) missing from alternates files, recreating alternates");
                        string error;
                        if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out error))
                        {
                            this.ReportErrorAndExit(tracer, $"Failed to update alternates file to include git objects root: {error}");
                        }
                    }
                }
                else
                {
                    tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: GitObjectsRoot ({enlistment.GitObjectsRoot}) missing, determining new root");

                    if (cacheServer == null)
                    {
                        cacheServer = CacheServerResolver.GetCacheServerFromConfig(enlistment);
                    }

                    string error;
                    if (serverGVFSConfig == null)
                    {
                        if (retryConfig == null)
                        {
                            if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error))
                            {
                                this.ReportErrorAndExit(tracer, "Failed to determine GVFS timeout and max retries: " + error);
                            }
                        }

                        serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);
                    }

                    string             localCacheKey;
                    LocalCacheResolver localCacheResolver = new LocalCacheResolver(enlistment);
                    if (!localCacheResolver.TryGetLocalCacheKeyFromLocalConfigOrRemoteCacheServers(
                            tracer,
                            serverGVFSConfig,
                            cacheServer,
                            enlistment.LocalCacheRoot,
                            localCacheKey: out localCacheKey,
                            errorMessage: out error))
                    {
                        this.ReportErrorAndExit(tracer, $"Previous git objects root ({enlistment.GitObjectsRoot}) not found, and failed to determine new local cache key: {error}");
                    }

                    EventMetadata metadata = new EventMetadata();
                    metadata.Add("localCacheRoot", enlistment.LocalCacheRoot);
                    metadata.Add("localCacheKey", localCacheKey);
                    metadata.Add(TracingConstants.MessageKey.InfoMessage, "Initializing and persisting updated paths");
                    tracer.RelatedEvent(EventLevel.Informational, "GVFSVerb_EnsureLocalCacheIsHealthy_InitializePathsFromKey", metadata);
                    enlistment.InitializeCachePathsFromKey(enlistment.LocalCacheRoot, localCacheKey);

                    tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Creating GitObjectsRoot ({enlistment.GitObjectsRoot}), GitPackRoot ({enlistment.GitPackRoot}), and BlobSizesRoot ({enlistment.BlobSizesRoot})");
                    try
                    {
                        Directory.CreateDirectory(enlistment.GitObjectsRoot);
                        Directory.CreateDirectory(enlistment.GitPackRoot);
                    }
                    catch (Exception e)
                    {
                        EventMetadata exceptionMetadata = new EventMetadata();
                        exceptionMetadata.Add("Exception", e.ToString());
                        exceptionMetadata.Add("enlistment.LocalCacheRoot", enlistment.LocalCacheRoot);
                        exceptionMetadata.Add("enlistment.GitObjectsRoot", enlistment.GitObjectsRoot);
                        exceptionMetadata.Add("enlistment.GitPackRoot", enlistment.GitPackRoot);
                        exceptionMetadata.Add("enlistment.BlobSizesRoot", enlistment.BlobSizesRoot);
                        tracer.RelatedError(exceptionMetadata, $"{nameof(this.InitializeLocalCacheAndObjectsPaths)}: Exception while trying to create objects, pack, and sizes folders");

                        this.ReportErrorAndExit(tracer, "Failed to create objects, pack, and sizes folders");
                    }

                    tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Creating new alternates file");
                    if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out error))
                    {
                        this.ReportErrorAndExit(tracer, $"Failed to update alterates file with new objects path: {error}");
                    }

                    tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Saving git objects root ({enlistment.GitObjectsRoot}) in repo metadata");
                    RepoMetadata.Instance.SetGitObjectsRoot(enlistment.GitObjectsRoot);

                    tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Saving blob sizes root ({enlistment.BlobSizesRoot}) in repo metadata");
                    RepoMetadata.Instance.SetBlobSizesRoot(enlistment.BlobSizesRoot);
                }

                // Validate that the BlobSizesRoot folder is on disk.
                // Note that if a user performed an action that resulted in the entire .gvfscache being deleted, the code above
                // for validating GitObjectsRoot will have already taken care of generating a new key and setting a new enlistment.BlobSizesRoot path
                if (!Directory.Exists(enlistment.BlobSizesRoot))
                {
                    tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: BlobSizesRoot ({enlistment.BlobSizesRoot}) not found, re-creating");
                    try
                    {
                        Directory.CreateDirectory(enlistment.BlobSizesRoot);
                    }
                    catch (Exception e)
                    {
                        EventMetadata exceptionMetadata = new EventMetadata();
                        exceptionMetadata.Add("Exception", e.ToString());
                        exceptionMetadata.Add("enlistment.BlobSizesRoot", enlistment.BlobSizesRoot);
                        tracer.RelatedError(exceptionMetadata, $"{nameof(this.InitializeLocalCacheAndObjectsPaths)}: Exception while trying to create blob sizes folder");

                        this.ReportErrorAndExit(tracer, "Failed to create blob sizes folder");
                    }
                }
            }
示例#8
0
        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);
                }
            }
        }
        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.WorkingDirectoryBackingRoot, 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.WorkingDirectoryBackingRoot, 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));
        }
示例#10
0
        public override void Execute()
        {
            int exitCode = 0;

            this.EnlistmentRootPath = this.GetCloneRoot();

            this.CheckGVFltHealthy();
            this.CheckNotInsideExistingRepo();
            this.BlockEmptyCacheServerUrl(this.CacheServerUrl);

            try
            {
                GVFSEnlistment enlistment;
                Result         cloneResult = new Result(false);

                CacheServerInfo cacheServer = null;

                using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "GVFSClone"))
                {
                    cloneResult = this.TryCreateEnlistment(out enlistment);
                    if (cloneResult.Success)
                    {
                        tracer.AddLogFileEventListener(
                            GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Clone),
                            EventLevel.Informational,
                            Keywords.Any);
                        tracer.WriteStartEvent(
                            enlistment.EnlistmentRoot,
                            enlistment.RepoUrl,
                            this.CacheServerUrl,
                            enlistment.GitObjectsRoot,
                            new EventMetadata
                        {
                            { "Branch", this.Branch },
                            { "SingleBranch", this.SingleBranch },
                            { "NoMount", this.NoMount },
                            { "NoPrefetch", this.NoPrefetch },
                            { "Unattended", this.Unattended },
                            { "IsElevated", ProcessHelper.IsAdminElevated() },
                        });

                        CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);
                        cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheServerUrl);

                        this.Output.WriteLine("Clone parameters:");
                        this.Output.WriteLine("  Repo URL:     " + enlistment.RepoUrl);
                        this.Output.WriteLine("  Cache Server: " + cacheServer);
                        this.Output.WriteLine("  Destination:  " + enlistment.EnlistmentRoot);

                        string authErrorMessage = null;
                        if (!this.ShowStatusWhileRunning(
                                () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage),
                                "Authenticating"))
                        {
                            this.ReportErrorAndExit(tracer, "Unable to clone because authentication failed");
                        }

                        RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes));
                        GVFSConfig  gvfsConfig  = this.QueryGVFSConfig(tracer, enlistment, retryConfig);

                        cacheServer = this.ResolveCacheServerUrlIfNeeded(tracer, cacheServer, cacheServerResolver, gvfsConfig);
                        this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: true);

                        this.ShowStatusWhileRunning(
                            () =>
                        {
                            cloneResult = this.TryClone(tracer, enlistment, cacheServer, retryConfig);
                            return(cloneResult.Success);
                        },
                            "Cloning");
                    }

                    if (!cloneResult.Success)
                    {
                        tracer.RelatedError(cloneResult.ErrorMessage);
                    }
                }

                if (cloneResult.Success)
                {
                    if (!this.NoPrefetch)
                    {
                        this.Execute <PrefetchVerb>(
                            this.EnlistmentRootPath,
                            verb =>
                        {
                            verb.Commits             = true;
                            verb.SkipVersionCheck    = true;
                            verb.ResolvedCacheServer = cacheServer;
                        });
                    }

                    if (this.NoMount)
                    {
                        this.Output.WriteLine("\r\nIn order to mount, first cd to within your enlistment, then call: ");
                        this.Output.WriteLine("gvfs mount");
                    }
                    else
                    {
                        this.Execute <MountVerb>(
                            this.EnlistmentRootPath,
                            verb =>
                        {
                            verb.SkipMountedCheck = true;
                            verb.SkipVersionCheck = true;
                        });
                    }
                }
                else
                {
                    this.Output.WriteLine("\r\nCannot clone @ {0}", this.EnlistmentRootPath);
                    this.Output.WriteLine("Error: {0}", cloneResult.ErrorMessage);
                    exitCode = (int)ReturnCode.GenericError;
                }
            }
            catch (AggregateException e)
            {
                this.Output.WriteLine("Cannot clone @ {0}:", this.EnlistmentRootPath);
                foreach (Exception ex in e.Flatten().InnerExceptions)
                {
                    this.Output.WriteLine("Exception: {0}", ex.ToString());
                }

                exitCode = (int)ReturnCode.GenericError;
            }
            catch (VerbAbortedException)
            {
                throw;
            }
            catch (Exception e)
            {
                this.ReportErrorAndExit("Cannot clone @ {0}: {1}", this.EnlistmentRootPath, e.ToString());
            }

            Environment.Exit(exitCode);
        }
        public void Execute()
        {
            if (this.StartedByVerb)
            {
                // If this process was started by a verb it means that StartBackgroundVFS4GProcess was used
                // and we should be running in the background.  PrepareProcessToRunInBackground will perform
                // any platform specific preparation required to run as a background process.
                GSDPlatform.Instance.PrepareProcessToRunInBackground();
            }

            GSDEnlistment enlistment = this.CreateEnlistment(this.EnlistmentRootPathParameter);

            EventLevel verbosity;
            Keywords   keywords;

            this.ParseEnumArgs(out verbosity, out keywords);

            JsonTracer tracer = this.CreateTracer(enlistment, verbosity, keywords);

            CacheServerInfo cacheServer = CacheServerResolver.GetCacheServerFromConfig(enlistment);

            tracer.WriteStartEvent(
                enlistment.EnlistmentRoot,
                enlistment.RepoUrl,
                cacheServer.Url,
                new EventMetadata
            {
                { "IsElevated", GSDPlatform.Instance.IsElevated() },
                { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
                { nameof(this.StartedByService), this.StartedByService },
                { nameof(this.StartedByVerb), this.StartedByVerb },
            });

            AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) =>
            {
                this.UnhandledGSDExceptionHandler(tracer, sender, e);
            };

            string      error;
            RetryConfig retryConfig;

            if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error))
            {
                this.ReportErrorAndExit(tracer, "Failed to determine GSD timeout and max retries: " + error);
            }

            GitStatusCacheConfig gitStatusCacheConfig;

            if (!GitStatusCacheConfig.TryLoadFromGitConfig(tracer, enlistment, out gitStatusCacheConfig, out error))
            {
                tracer.RelatedWarning("Failed to determine GSD status cache backoff time: " + error);
                gitStatusCacheConfig = GitStatusCacheConfig.DefaultConfig;
            }

            InProcessMount mountHelper = new InProcessMount(tracer, enlistment, cacheServer, retryConfig, gitStatusCacheConfig, this.ShowDebugWindow);

            try
            {
                mountHelper.Mount(verbosity, keywords);
            }
            catch (Exception ex)
            {
                this.ReportErrorAndExit(tracer, "Failed to mount: {0}", ex.Message);
            }
        }
示例#12
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            string diagnosticsRoot = Path.Combine(enlistment.DotGVFSRoot, "diagnostics");

            if (!Directory.Exists(diagnosticsRoot))
            {
                Directory.CreateDirectory(diagnosticsRoot);
            }

            string archiveFolderPath = Path.Combine(diagnosticsRoot, "gvfs_" + DateTime.Now.ToString("yyyyMMdd_HHmmss"));

            Directory.CreateDirectory(archiveFolderPath);

            using (FileStream diagnosticLogFile = new FileStream(Path.Combine(archiveFolderPath, "diagnostics.log"), FileMode.CreateNew))
                using (this.diagnosticLogFileWriter = new StreamWriter(diagnosticLogFile))
                {
                    this.WriteMessage("Collecting diagnostic info into temp folder " + archiveFolderPath);

                    this.WriteMessage(string.Empty);
                    this.WriteMessage("gvfs version " + ProcessHelper.GetCurrentProcessVersion());
                    this.WriteMessage(GitProcess.Version(enlistment).Output);
                    this.WriteMessage(GVFSPlatform.Instance.GitInstallation.GetInstalledGitBinPath());
                    this.WriteMessage(string.Empty);
                    this.WriteMessage("Enlistment root: " + enlistment.EnlistmentRoot);
                    this.WriteMessage("Cache Server: " + CacheServerResolver.GetCacheServerFromConfig(enlistment));

                    string localCacheRoot;
                    string gitObjectsRoot;
                    this.GetLocalCachePaths(enlistment, out localCacheRoot, out gitObjectsRoot);
                    string actualLocalCacheRoot = !string.IsNullOrWhiteSpace(localCacheRoot) ? localCacheRoot : gitObjectsRoot;
                    this.WriteMessage("Local Cache: " + actualLocalCacheRoot);
                    this.WriteMessage(string.Empty);

                    this.PrintDiskSpaceInfo(actualLocalCacheRoot, this.EnlistmentRootPathParameter);

                    this.RecordVersionInformation();

                    this.ShowStatusWhileRunning(
                        () =>
                        this.RunAndRecordGVFSVerb <StatusVerb>(archiveFolderPath, "gvfs_status.txt") != ReturnCode.Success ||
                        this.RunAndRecordGVFSVerb <UnmountVerb>(archiveFolderPath, "gvfs_unmount.txt", verb => verb.SkipLock = true) == ReturnCode.Success,
                        "Unmounting",
                        suppressGvfsLogMessage: true);

                    this.ShowStatusWhileRunning(
                        () =>
                    {
                        // .gvfs
                        this.CopyAllFiles(enlistment.EnlistmentRoot, archiveFolderPath, GVFSConstants.DotGVFS.Root, copySubFolders: false);

                        // filter
                        this.FlushFilterLogBuffers();
                        string system32LogFilesPath = Environment.ExpandEnvironmentVariables(System32LogFilesRoot);

                        // This copy sometimes fails because the OS has an exclusive lock on the etl files. The error is not actionable
                        // for the user so we don't write the error message to stdout, just to our own log file.
                        this.CopyAllFiles(system32LogFilesPath, archiveFolderPath, GVFSPlatform.Instance.KernelDriver.DriverLogFolderName, copySubFolders: false, hideErrorsFromStdout: true);

                        // .git
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Hooks.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Info.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Logs.Root, copySubFolders: true);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Refs.Root, copySubFolders: true);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Objects.Info.Root, copySubFolders: false);
                        this.LogDirectoryEnumeration(enlistment.WorkingDirectoryRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGit.Objects.Root), GVFSConstants.DotGit.Objects.Pack.Root, "packs-local.txt");
                        this.LogLooseObjectCount(enlistment.WorkingDirectoryRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGit.Objects.Root), GVFSConstants.DotGit.Objects.Root, "objects-local.txt");

                        // databases
                        this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGVFS.Root), GVFSConstants.DotGVFS.Databases.Name, copySubFolders: false);

                        // local cache
                        this.CopyLocalCacheData(archiveFolderPath, localCacheRoot, gitObjectsRoot);

                        // corrupt objects
                        this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGVFS.Root), GVFSConstants.DotGVFS.CorruptObjectsName, copySubFolders: false);

                        // service
                        this.CopyAllFiles(
                            Paths.GetServiceDataRoot(string.Empty),
                            archiveFolderPath,
                            this.ServiceName,
                            copySubFolders: true);

                        return(true);
                    },
                        "Copying logs");

                    this.ShowStatusWhileRunning(
                        () => this.RunAndRecordGVFSVerb <MountVerb>(archiveFolderPath, "gvfs_mount.txt") == ReturnCode.Success,
                        "Mounting",
                        suppressGvfsLogMessage: true);

                    this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGVFS.Root), "logs", copySubFolders: false);
                }

            string zipFilePath = archiveFolderPath + ".zip";

            this.ShowStatusWhileRunning(
                () =>
            {
                ZipFile.CreateFromDirectory(archiveFolderPath, zipFilePath);
                PhysicalFileSystem.RecursiveDelete(archiveFolderPath);

                return(true);
            },
                "Creating zip file",
                suppressGvfsLogMessage: true);

            this.Output.WriteLine();
            this.Output.WriteLine("Diagnostics complete. All of the gathered info, as well as all of the output above, is captured in");
            this.Output.WriteLine(zipFilePath);
        }
示例#13
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            string diagnosticsRoot = Path.Combine(enlistment.DotGVFSRoot, "diagnostics");

            if (!Directory.Exists(diagnosticsRoot))
            {
                Directory.CreateDirectory(diagnosticsRoot);
            }

            string archiveFolderPath = Path.Combine(diagnosticsRoot, "gvfs_" + DateTime.Now.ToString("yyyyMMdd_HHmmss"));

            Directory.CreateDirectory(archiveFolderPath);

            using (FileStream diagnosticLogFile = new FileStream(Path.Combine(archiveFolderPath, "diagnostics.log"), FileMode.CreateNew))
                using (this.diagnosticLogFileWriter = new StreamWriter(diagnosticLogFile))
                {
                    this.WriteMessage("Collecting diagnostic info into temp folder " + archiveFolderPath);

                    this.WriteMessage(string.Empty);
                    this.WriteMessage("gvfs version " + ProcessHelper.GetCurrentProcessVersion());
                    this.WriteMessage(GitProcess.Version(enlistment).Output);
                    this.WriteMessage(GitProcess.GetInstalledGitBinPath());
                    this.WriteMessage(string.Empty);
                    this.WriteMessage("Enlistment root: " + enlistment.EnlistmentRoot);
                    this.WriteMessage("Repo URL: " + enlistment.RepoUrl);
                    this.WriteMessage("Cache Server: " + CacheServerResolver.GetUrlFromConfig(enlistment));

                    this.WriteMessage(string.Empty);

                    this.WriteAntiVirusExclusions(enlistment.EnlistmentRoot, archiveFolderPath, "DefenderExclusionInfo.txt");

                    this.ShowStatusWhileRunning(
                        () =>
                        this.RunAndRecordGVFSVerb <StatusVerb>(archiveFolderPath, "gvfs_status.txt") != ReturnCode.Success ||
                        this.RunAndRecordGVFSVerb <UnmountVerb>(archiveFolderPath, "gvfs_unmount.txt", verb => verb.SkipLock = true) == ReturnCode.Success,
                        "Unmounting",
                        suppressGvfsLogMessage: true);

                    this.ShowStatusWhileRunning(
                        () =>
                    {
                        // .gvfs
                        this.CopyAllFiles(enlistment.EnlistmentRoot, archiveFolderPath, GVFSConstants.DotGVFS.Root, copySubFolders: false);

                        // gvflt
                        this.FlushGvFltLogBuffers();
                        string system32LogFilesPath = Environment.ExpandEnvironmentVariables(System32LogFilesRoot);
                        this.CopyAllFiles(system32LogFilesPath, archiveFolderPath, GVFltLogFolderName, copySubFolders: false);

                        // .git
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Hooks.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Info.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Logs.Root, copySubFolders: true);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Refs.Root, copySubFolders: true);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Objects.Info.Root, copySubFolders: false);
                        this.LogDirectoryEnumeration(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Objects.Pack.Root, "packs-local.txt");
                        this.LogLooseObjectCount(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Objects.Root, "objects-local.txt");
                        this.LogDirectoryEnumeration(enlistment.GitObjectsRoot, archiveFolderPath, GVFSConstants.DotGit.Objects.Pack.Name, "packs-cached.txt");
                        this.LogLooseObjectCount(enlistment.GitObjectsRoot, archiveFolderPath, string.Empty, "objects-cached.txt");

                        // databases
                        this.CopyEsentDatabase <string, long>(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGVFS.Root), GVFSConstants.DotGVFS.BlobSizesName);
                        this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGVFS.Root), GVFSConstants.DotGVFS.Databases.Name, copySubFolders: false);

                        // corrupt objects
                        this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGVFS.Root), GVFSConstants.DotGVFS.CorruptObjectsName, copySubFolders: false);

                        // service
                        this.CopyAllFiles(
                            Paths.GetServiceDataRoot(string.Empty),
                            archiveFolderPath,
                            this.ServiceName,
                            copySubFolders: true);

                        return(true);
                    },
                        "Copying logs");

                    this.ShowStatusWhileRunning(
                        () => this.RunAndRecordGVFSVerb <MountVerb>(archiveFolderPath, "gvfs_mount.txt") == ReturnCode.Success,
                        "Mounting",
                        suppressGvfsLogMessage: true);

                    this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGVFS.Root), "logs", copySubFolders: false);
                }

            string zipFilePath = archiveFolderPath + ".zip";

            this.ShowStatusWhileRunning(
                () =>
            {
                ZipFile.CreateFromDirectory(archiveFolderPath, zipFilePath);
                PhysicalFileSystem.RecursiveDelete(archiveFolderPath);

                return(true);
            },
                "Creating zip file",
                suppressGvfsLogMessage: true);

            this.Output.WriteLine();
            this.Output.WriteLine("Diagnostics complete. All of the gathered info, as well as all of the output above, is captured in");
            this.Output.WriteLine(zipFilePath);
        }
示例#14
0
        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));
        }
示例#15
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "Prefetch"))
            {
                if (this.Verbose)
                {
                    tracer.AddDiagnosticConsoleEventListener(EventLevel.Informational, Keywords.Any);
                }

                string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment);

                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Prefetch),
                    EventLevel.Informational,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    cacheServerUrl);

                try
                {
                    EventMetadata metadata = new EventMetadata();
                    metadata.Add("Commits", this.Commits);
                    metadata.Add("Files", this.Files);
                    metadata.Add("Folders", this.Folders);
                    metadata.Add("FileListFile", this.FilesListFile);
                    metadata.Add("FoldersListFile", this.FoldersListFile);
                    metadata.Add("FilesFromStdIn", this.FilesFromStdIn);
                    metadata.Add("FoldersFromStdIn", this.FoldersFromStdIn);
                    metadata.Add("HydrateFiles", this.HydrateFiles);
                    tracer.RelatedEvent(EventLevel.Informational, "PerformPrefetch", metadata);

                    if (this.Commits)
                    {
                        if (!string.IsNullOrWhiteSpace(this.Files) ||
                            !string.IsNullOrWhiteSpace(this.Folders) ||
                            !string.IsNullOrWhiteSpace(this.FoldersListFile) ||
                            !string.IsNullOrWhiteSpace(this.FilesListFile) ||
                            this.FilesFromStdIn ||
                            this.FoldersFromStdIn)
                        {
                            this.ReportErrorAndExit(tracer, "You cannot prefetch commits and blobs at the same time.");
                        }

                        if (this.HydrateFiles)
                        {
                            this.ReportErrorAndExit(tracer, "You can only specify --hydrate with --files or --folders");
                        }

                        GitObjectsHttpRequestor objectRequestor;
                        CacheServerInfo         cacheServer;
                        this.InitializeServerConnection(
                            tracer,
                            enlistment,
                            cacheServerUrl,
                            out objectRequestor,
                            out cacheServer);
                        this.PrefetchCommits(tracer, enlistment, objectRequestor, cacheServer);
                    }
                    else
                    {
                        string        headCommitId;
                        List <string> filesList;
                        List <string> foldersList;
                        FileBasedDictionary <string, string> lastPrefetchArgs;

                        this.LoadBlobPrefetchArgs(tracer, enlistment, out headCommitId, out filesList, out foldersList, out lastPrefetchArgs);

                        if (BlobPrefetcher.IsNoopPrefetch(tracer, lastPrefetchArgs, headCommitId, filesList, foldersList, this.HydrateFiles))
                        {
                            Console.WriteLine("All requested files are already available. Nothing new to prefetch.");
                        }
                        else
                        {
                            GitObjectsHttpRequestor objectRequestor;
                            CacheServerInfo         cacheServer;
                            this.InitializeServerConnection(
                                tracer,
                                enlistment,
                                cacheServerUrl,
                                out objectRequestor,
                                out cacheServer);
                            this.PrefetchBlobs(tracer, enlistment, headCommitId, filesList, foldersList, lastPrefetchArgs, objectRequestor, cacheServer);
                        }
                    }
                }
                catch (VerbAbortedException)
                {
                    throw;
                }
                catch (AggregateException aggregateException)
                {
                    this.Output.WriteLine(
                        "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(enlistment.EnlistmentRoot),
                        enlistment.EnlistmentRoot);
                    foreach (Exception innerException in aggregateException.Flatten().InnerExceptions)
                    {
                        tracer.RelatedError(
                            new EventMetadata
                        {
                            { "Verb", typeof(PrefetchVerb).Name },
                            { "Exception", innerException.ToString() }
                        },
                            $"Unhandled {innerException.GetType().Name}: {innerException.Message}");
                    }

                    Environment.ExitCode = (int)ReturnCode.GenericError;
                }
                catch (Exception e)
                {
                    this.Output.WriteLine(
                        "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(enlistment.EnlistmentRoot),
                        enlistment.EnlistmentRoot);
                    tracer.RelatedError(
                        new EventMetadata
                    {
                        { "Verb", typeof(PrefetchVerb).Name },
                        { "Exception", e.ToString() }
                    },
                        $"Unhandled {e.GetType().Name}: {e.Message}");

                    Environment.ExitCode = (int)ReturnCode.GenericError;
                }
            }
        }
示例#16
0
        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);

            if (!GVFSPlatform.Instance.IsUnderConstruction)
            {
                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));
        }
示例#17
0
        protected override void Execute(ScalarEnlistment enlistment)
        {
            using (JsonTracer tracer = new JsonTracer(ScalarConstants.ScalarEtwProviderName, RunVerbName))
            {
                string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment);

                string logFileName = ScalarEnlistment.GetNewScalarLogFileName(
                    enlistment.ScalarLogsRoot,
                    ScalarConstants.LogFileTypes.Maintenance,
                    logId: this.StartedByService ? "service" : null);

                List <GitMaintenanceStep> steps = new List <GitMaintenanceStep>();

                tracer.AddLogFileEventListener(
                    logFileName,
                    EventLevel.Informational,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    cacheServerUrl,
                    this.AddVerbDataToMetadata(
                        new EventMetadata
                {
                    { nameof(this.MaintenanceTask), this.MaintenanceTask },
                    { nameof(this.PackfileMaintenanceBatchSize), this.PackfileMaintenanceBatchSize },
                    { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
                    { nameof(this.StartedByService), this.StartedByService },
                }));

                this.InitializeCachePaths(tracer, enlistment);
                PhysicalFileSystem fileSystem = new PhysicalFileSystem();
                using (ScalarContext context = new ScalarContext(tracer, fileSystem, enlistment))
                {
                    try
                    {
                        GitObjectsHttpRequestor objectRequestor = null;
                        CacheServerInfo         cacheServer;
                        GitObjects gitObjects;

                        switch (this.MaintenanceTask)
                        {
                        case ScalarConstants.VerbParameters.Maintenance.AllTasksName:
                            steps.Add(new ConfigStep(context));
                            this.InitializeServerConnection(tracer, enlistment, cacheServerUrl, out objectRequestor, out cacheServer);
                            gitObjects = new GitObjects(tracer, enlistment, objectRequestor, fileSystem);
                            steps.Add(new FetchStep(context, gitObjects, requireCacheLock: false, forceRun: !this.StartedByService));
                            steps.Add(new CommitGraphStep(context, requireObjectCacheLock: false));
                            steps.Add(new LooseObjectsStep(context, forceRun: !this.StartedByService));
                            steps.Add(new PackfileMaintenanceStep(
                                          context,
                                          forceRun: !this.StartedByService,
                                          batchSize: string.IsNullOrWhiteSpace(this.PackfileMaintenanceBatchSize) ?
                                          PackfileMaintenanceStep.DefaultBatchSizeBytes.ToString() :
                                          this.PackfileMaintenanceBatchSize));
                            break;

                        case ScalarConstants.VerbParameters.Maintenance.LooseObjectsTaskName:
                            this.FailIfBatchSizeSet(tracer);
                            steps.Add(new LooseObjectsStep(context, forceRun: !this.StartedByService));
                            break;

                        case ScalarConstants.VerbParameters.Maintenance.PackFilesTaskName:
                            steps.Add(new PackfileMaintenanceStep(
                                          context,
                                          forceRun: !this.StartedByService,
                                          batchSize: string.IsNullOrWhiteSpace(this.PackfileMaintenanceBatchSize) ?
                                          PackfileMaintenanceStep.DefaultBatchSizeBytes.ToString() :
                                          this.PackfileMaintenanceBatchSize));
                            break;

                        case ScalarConstants.VerbParameters.Maintenance.FetchTaskName:
                            this.FailIfBatchSizeSet(tracer);
                            this.InitializeServerConnection(tracer, enlistment, cacheServerUrl, out objectRequestor, out cacheServer);
                            gitObjects = new GitObjects(tracer, enlistment, objectRequestor, fileSystem);
                            steps.Add(new FetchStep(context, gitObjects, requireCacheLock: false, forceRun: !this.StartedByService));
                            break;

                        case ScalarConstants.VerbParameters.Maintenance.CommitGraphTaskName:
                            this.FailIfBatchSizeSet(tracer);
                            steps.Add(new CommitGraphStep(context, requireObjectCacheLock: false));
                            break;

                        case ScalarConstants.VerbParameters.Maintenance.ConfigTaskName:
                            this.FailIfBatchSizeSet(tracer);
                            steps.Add(new ConfigStep(context));
                            break;

                        default:
                            this.ReportErrorAndExit($"Unknown maintenance task requested: '{this.MaintenanceTask}'");
                            break;
                        }

                        foreach (GitMaintenanceStep step in steps)
                        {
                            this.ShowStatusWhileRunning(() => { step.Execute(); return(true); }, step.ProgressMessage);
                        }
                    }
                    catch (VerbAbortedException)
                    {
                        throw;
                    }
                    catch (AggregateException aggregateException)
                    {
                        string error = $"AggregateException thrown while running '{this.MaintenanceTask}' task: {aggregateException.Message}";
                        tracer.RelatedError(this.CreateEventMetadata(aggregateException), error);
                        foreach (Exception innerException in aggregateException.Flatten().InnerExceptions)
                        {
                            tracer.RelatedError(
                                this.CreateEventMetadata(innerException),
                                $"Unhandled {innerException.GetType().Name}: {innerException.Message}");
                        }

                        this.ReportErrorAndExit(tracer, ReturnCode.GenericError, error);
                    }
                    catch (Exception e)
                    {
                        string error = $"Exception thrown while running '{this.MaintenanceTask}' task: {e.Message}";
                        tracer.RelatedError(this.CreateEventMetadata(e), error);
                        this.ReportErrorAndExit(tracer, ReturnCode.GenericError, error);
                    }
                }
            }
        }
示例#18
0
        public override void Execute()
        {
            int exitCode = 0;

            // TODO(Mac): limit the length of the enlistment root based on the length constraints imposed by named pipes

            this.ValidatePathParameter(this.EnlistmentRootPathParameter);
            this.ValidatePathParameter(this.LocalCacheRoot);

            string fullEnlistmentRootPathParameter;
            string normalizedEnlistmentRootPath = this.GetCloneRoot(out fullEnlistmentRootPathParameter);

            if (!string.IsNullOrWhiteSpace(this.LocalCacheRoot))
            {
                string fullLocalCacheRootPath = Path.GetFullPath(this.LocalCacheRoot);

                string errorMessage;
                string normalizedLocalCacheRootPath;
                if (!GVFSPlatform.Instance.FileSystem.TryGetNormalizedPath(fullLocalCacheRootPath, out normalizedLocalCacheRootPath, out errorMessage))
                {
                    this.ReportErrorAndExit($"Failed to determine normalized path for '--local-cache-path' path {fullLocalCacheRootPath}: {errorMessage}");
                }

                if (normalizedLocalCacheRootPath.StartsWith(
                        Path.Combine(normalizedEnlistmentRootPath, GVFSConstants.WorkingDirectoryRootName),
                        StringComparison.OrdinalIgnoreCase))
                {
                    this.ReportErrorAndExit("'--local-cache-path' cannot be inside the src folder");
                }
            }

            this.CheckKernelDriverSupported(normalizedEnlistmentRootPath);
            this.CheckNotInsideExistingRepo(normalizedEnlistmentRootPath);
            this.BlockEmptyCacheServerUrl(this.CacheServerUrl);

            try
            {
                GVFSEnlistment enlistment;
                Result         cloneResult = new Result(false);

                CacheServerInfo cacheServer = null;
                GVFSConfig      gvfsConfig  = null;

                using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, "GVFSClone"))
                {
                    cloneResult = this.TryCreateEnlistment(fullEnlistmentRootPathParameter, normalizedEnlistmentRootPath, out enlistment);
                    if (cloneResult.Success)
                    {
                        tracer.AddLogFileEventListener(
                            GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Clone),
                            EventLevel.Informational,
                            Keywords.Any);
                        tracer.WriteStartEvent(
                            enlistment.EnlistmentRoot,
                            enlistment.RepoUrl,
                            this.CacheServerUrl,
                            new EventMetadata
                        {
                            { "Branch", this.Branch },
                            { "LocalCacheRoot", this.LocalCacheRoot },
                            { "SingleBranch", this.SingleBranch },
                            { "NoMount", this.NoMount },
                            { "NoPrefetch", this.NoPrefetch },
                            { "Unattended", this.Unattended },
                            { "IsElevated", GVFSPlatform.Instance.IsElevated() },
                            { "NamedPipeName", enlistment.NamedPipeName },
                            { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
                            { nameof(fullEnlistmentRootPathParameter), fullEnlistmentRootPathParameter },
                        });

                        CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);
                        cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheServerUrl);

                        string resolvedLocalCacheRoot;
                        if (string.IsNullOrWhiteSpace(this.LocalCacheRoot))
                        {
                            resolvedLocalCacheRoot = LocalCacheResolver.GetDefaultLocalCacheRoot(enlistment);
                        }
                        else
                        {
                            resolvedLocalCacheRoot = Path.GetFullPath(this.LocalCacheRoot);
                        }

                        this.Output.WriteLine("Clone parameters:");
                        this.Output.WriteLine("  Repo URL:     " + enlistment.RepoUrl);
                        this.Output.WriteLine("  Branch:       " + (string.IsNullOrWhiteSpace(this.Branch) ? "Default" : this.Branch));
                        this.Output.WriteLine("  Cache Server: " + cacheServer);
                        this.Output.WriteLine("  Local Cache:  " + resolvedLocalCacheRoot);
                        this.Output.WriteLine("  Destination:  " + enlistment.EnlistmentRoot);

                        string authErrorMessage = null;
                        if (!this.ShowStatusWhileRunning(
                                () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage),
                                "Authenticating",
                                normalizedEnlistmentRootPath))
                        {
                            this.ReportErrorAndExit(tracer, "Cannot clone because authentication failed");
                        }

                        RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes));
                        gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);

                        cacheServer = this.ResolveCacheServer(tracer, cacheServer, cacheServerResolver, gvfsConfig);

                        if (!GVFSPlatform.Instance.IsUnderConstruction)
                        {
                            this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: true);
                        }

                        this.ShowStatusWhileRunning(
                            () =>
                        {
                            cloneResult = this.TryClone(tracer, enlistment, cacheServer, retryConfig, gvfsConfig, resolvedLocalCacheRoot);
                            return(cloneResult.Success);
                        },
                            "Cloning",
                            normalizedEnlistmentRootPath);
                    }

                    if (!cloneResult.Success)
                    {
                        tracer.RelatedError(cloneResult.ErrorMessage);
                    }
                }

                if (cloneResult.Success)
                {
                    if (!this.NoPrefetch)
                    {
                        ReturnCode result = this.Execute <PrefetchVerb>(
                            fullEnlistmentRootPathParameter,
                            verb =>
                        {
                            verb.Commits             = true;
                            verb.SkipVersionCheck    = true;
                            verb.ResolvedCacheServer = cacheServer;
                            verb.GVFSConfig          = gvfsConfig;
                        });

                        if (result != ReturnCode.Success)
                        {
                            this.Output.WriteLine("\r\nError during prefetch @ {0}", fullEnlistmentRootPathParameter);
                            exitCode = (int)result;
                        }
                    }

                    if (this.NoMount)
                    {
                        this.Output.WriteLine("\r\nIn order to mount, first cd to within your enlistment, then call: ");
                        this.Output.WriteLine("gvfs mount");
                    }
                    else
                    {
                        this.Execute <MountVerb>(
                            fullEnlistmentRootPathParameter,
                            verb =>
                        {
                            verb.SkipMountedCheck     = true;
                            verb.SkipVersionCheck     = true;
                            verb.ResolvedCacheServer  = cacheServer;
                            verb.DownloadedGVFSConfig = gvfsConfig;
                        });
                    }
                }
                else
                {
                    this.Output.WriteLine("\r\nCannot clone @ {0}", fullEnlistmentRootPathParameter);
                    this.Output.WriteLine("Error: {0}", cloneResult.ErrorMessage);
                    exitCode = (int)ReturnCode.GenericError;
                }
            }
            catch (AggregateException e)
            {
                this.Output.WriteLine("Cannot clone @ {0}:", fullEnlistmentRootPathParameter);
                foreach (Exception ex in e.Flatten().InnerExceptions)
                {
                    this.Output.WriteLine("Exception: {0}", ex.ToString());
                }

                exitCode = (int)ReturnCode.GenericError;
            }
            catch (VerbAbortedException)
            {
                throw;
            }
            catch (Exception e)
            {
                this.ReportErrorAndExit("Cannot clone @ {0}: {1}", fullEnlistmentRootPathParameter, e.ToString());
            }

            Environment.Exit(exitCode);
        }
示例#19
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            using (JsonEtwTracer tracer = new JsonEtwTracer(GVFSConstants.GVFSEtwProviderName, "Prefetch"))
            {
                if (this.Verbose)
                {
                    tracer.AddDiagnosticConsoleEventListener(EventLevel.Informational, Keywords.Any);
                }

                string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment);

                tracer.AddLogFileEventListener(
                    GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Prefetch),
                    EventLevel.Informational,
                    Keywords.Any);
                tracer.WriteStartEvent(
                    enlistment.EnlistmentRoot,
                    enlistment.RepoUrl,
                    cacheServerUrl,
                    enlistment.GitObjectsRoot);

                RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes));

                CacheServerInfo cacheServer = this.ResolvedCacheServer;
                if (!this.SkipVersionCheck)
                {
                    string authErrorMessage;
                    if (!this.ShowStatusWhileRunning(
                            () => enlistment.Authentication.TryRefreshCredentials(tracer, out authErrorMessage),
                            "Authenticating"))
                    {
                        this.ReportErrorAndExit(tracer, "Unable to prefetch because authentication failed");
                    }

                    GVFSConfig gvfsConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);

                    CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);
                    cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerUrl, gvfsConfig);

                    this.ValidateClientVersions(tracer, enlistment, gvfsConfig, showWarnings: false);
                }

                try
                {
                    EventMetadata metadata = new EventMetadata();
                    metadata.Add("Commits", this.Commits);
                    metadata.Add("Files", this.Files);
                    metadata.Add("Folders", this.Folders);
                    metadata.Add("FoldersListFile", this.FoldersListFile);
                    tracer.RelatedEvent(EventLevel.Informational, "PerformPrefetch", metadata);

                    GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig);

                    if (this.Commits)
                    {
                        if (!string.IsNullOrWhiteSpace(this.Files) ||
                            !string.IsNullOrWhiteSpace(this.Folders) ||
                            !string.IsNullOrWhiteSpace(this.FoldersListFile))
                        {
                            this.ReportErrorAndExit(tracer, "You cannot prefetch commits and blobs at the same time.");
                        }

                        if (this.HydrateFiles)
                        {
                            this.ReportErrorAndExit(tracer, "You can only specify --hydrate with --files or --folders");
                        }

                        this.PrefetchCommits(tracer, enlistment, objectRequestor, cacheServer);
                    }
                    else
                    {
                        this.PrefetchBlobs(tracer, enlistment, objectRequestor, cacheServer);
                    }
                }
                catch (VerbAbortedException)
                {
                    throw;
                }
                catch (AggregateException aggregateException)
                {
                    this.Output.WriteLine(
                        "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(enlistment.EnlistmentRoot),
                        enlistment.EnlistmentRoot);
                    foreach (Exception innerException in aggregateException.Flatten().InnerExceptions)
                    {
                        tracer.RelatedError(
                            new EventMetadata
                        {
                            { "Verb", typeof(PrefetchVerb).Name },
                            { "Exception", innerException.ToString() }
                        },
                            $"Unhandled {innerException.GetType().Name}: {innerException.Message}");
                    }

                    Environment.ExitCode = (int)ReturnCode.GenericError;
                }
                catch (Exception e)
                {
                    this.Output.WriteLine(
                        "Cannot prefetch {0}. " + ConsoleHelper.GetGVFSLogMessage(enlistment.EnlistmentRoot),
                        enlistment.EnlistmentRoot);
                    tracer.RelatedError(
                        new EventMetadata
                    {
                        { "Verb", typeof(PrefetchVerb).Name },
                        { "Exception", e.ToString() }
                    },
                        $"Unhandled {e.GetType().Name}: {e.Message}");
                }
            }
        }
示例#20
0
        private Result DoClone(string fullEnlistmentRootPathParameter, string normalizedEnlistmentRootPath)
        {
            Result cloneResult = null;

            cloneResult = this.TryCreateEnlistment(fullEnlistmentRootPathParameter, normalizedEnlistmentRootPath, out this.enlistment);

            if (!cloneResult.Success)
            {
                this.tracer.RelatedError($"Error while creating enlistment: {cloneResult.ErrorMessage}");
                return(cloneResult);
            }

            this.tracer.AddLogFileEventListener(
                ScalarEnlistment.GetNewScalarLogFileName(this.enlistment.ScalarLogsRoot, ScalarConstants.LogFileTypes.Clone),
                EventLevel.Informational,
                Keywords.Any);
            this.tracer.WriteStartEvent(
                this.enlistment.EnlistmentRoot,
                this.enlistment.RepoUrl,
                this.CacheServerUrl,
                this.AddVerbDataToMetadata(new EventMetadata
            {
                { nameof(this.Branch), this.Branch },
                { nameof(this.LocalCacheRoot), this.LocalCacheRoot },
                { nameof(this.SingleBranch), this.SingleBranch },
                { nameof(this.FullClone), this.FullClone },
                { nameof(this.NoFetchCommitsAndTrees), this.NoFetchCommitsAndTrees },
                { nameof(this.Unattended), this.Unattended },
                { nameof(ScalarPlatform.Instance.IsElevated), ScalarPlatform.Instance.IsElevated() },
                { "ProcessID", Process.GetCurrentProcess().Id },
                { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
                { nameof(fullEnlistmentRootPathParameter), fullEnlistmentRootPathParameter },
            }));

            this.cacheServerResolver = new CacheServerResolver(this.tracer, this.enlistment);
            this.cacheServer         = this.cacheServerResolver.ParseUrlOrFriendlyName(this.CacheServerUrl);

            string resolvedLocalCacheRoot;

            if (string.IsNullOrWhiteSpace(this.LocalCacheRoot))
            {
                if (!LocalCacheResolver.TryGetDefaultLocalCacheRoot(this.enlistment, out resolvedLocalCacheRoot, out string localCacheRootError))
                {
                    this.ReportErrorAndExit(
                        this.tracer,
                        $"Failed to determine the default location for the local Scalar cache: `{localCacheRootError}`");
                }
            }
            else
            {
                resolvedLocalCacheRoot = Path.GetFullPath(this.LocalCacheRoot);
            }

            this.Output.WriteLine("Clone parameters:");
            this.Output.WriteLine("  Repo URL:     " + this.enlistment.RepoUrl);
            this.Output.WriteLine("  Branch:       " + (string.IsNullOrWhiteSpace(this.Branch) ? "Default" : this.Branch));
            this.Output.WriteLine("  Cache Server: " + this.cacheServer);
            this.Output.WriteLine("  Local Cache:  " + resolvedLocalCacheRoot);
            this.Output.WriteLine("  Destination:  " + this.enlistment.EnlistmentRoot);
            this.Output.WriteLine("  FullClone:     " + this.FullClone);

            string authErrorMessage = null;

            GitAuthentication.Result authResult = GitAuthentication.Result.UnableToDetermine;

            // Do not try authentication on SSH URLs.
            if (this.enlistment.RepoUrl.StartsWith("https://"))
            {
                authResult = this.TryAuthenticate(this.tracer, this.enlistment, out authErrorMessage);
            }

            if (authResult == GitAuthentication.Result.UnableToDetermine)
            {
                // We can't tell, because we don't have the right endpoint!
                return(this.GitClone());
            }

            if (authResult == GitAuthentication.Result.Failed)
            {
                this.ReportErrorAndExit(this.tracer, "Cannot clone because authentication failed: " + authErrorMessage);
            }

            this.retryConfig        = this.GetRetryConfig(this.tracer, this.enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes));
            this.serverScalarConfig = this.QueryScalarConfig(this.tracer, this.enlistment, this.retryConfig);

            this.cacheServer = this.ResolveCacheServer(this.tracer, this.cacheServer, this.cacheServerResolver, this.serverScalarConfig);

            this.ValidateClientVersions(this.tracer, this.enlistment, this.serverScalarConfig, showWarnings: true);

            using (this.objectRequestor = new GitObjectsHttpRequestor(this.tracer, this.enlistment, this.cacheServer, this.retryConfig))
            {
                cloneResult = this.CreateScalarDirctories(resolvedLocalCacheRoot);

                if (!cloneResult.Success)
                {
                    this.tracer.RelatedError(cloneResult.ErrorMessage);
                    return(cloneResult);
                }

                this.ShowStatusWhileRunning(
                    () =>
                {
                    cloneResult = this.CreateClone();
                    return(cloneResult.Success);
                },
                    "Cloning");

                if (!cloneResult.Success)
                {
                    this.tracer.RelatedError(cloneResult.ErrorMessage);
                    return(cloneResult);
                }

                if (!this.NoFetchCommitsAndTrees)
                {
                    ReturnCode result = this.Execute <RunVerb>(
                        this.enlistment,
                        verb =>
                    {
                        verb.MaintenanceTask     = ScalarConstants.VerbParameters.Maintenance.FetchTaskName;
                        verb.SkipVersionCheck    = true;
                        verb.ResolvedCacheServer = this.cacheServer;
                        verb.ServerScalarConfig  = this.serverScalarConfig;
                    });

                    if (result != ReturnCode.Success)
                    {
                        this.Output.WriteLine("\r\nError while fetching commits and trees @ {0}", fullEnlistmentRootPathParameter);
                        return(cloneResult);
                    }
                }

                this.ShowStatusWhileRunning(
                    () =>
                {
                    cloneResult = this.CheckoutRepo();
                    return(cloneResult.Success);
                },
                    "Populating working directory");
            }

            if (cloneResult.Success)
            {
                cloneResult = this.TryRegisterRepo();
            }

            return(cloneResult);
        }
示例#21
0
        protected override void Execute(GVFSEnlistment enlistment)
        {
            string diagnosticsRoot = Path.Combine(enlistment.DotGVFSRoot, "diagnostics");

            if (!Directory.Exists(diagnosticsRoot))
            {
                Directory.CreateDirectory(diagnosticsRoot);
            }

            string archiveFolderPath = Path.Combine(diagnosticsRoot, "gvfs_" + DateTime.Now.ToString("yyyyMMdd_HHmmss"));

            Directory.CreateDirectory(archiveFolderPath);

            using (FileStream diagnosticLogFile = new FileStream(Path.Combine(archiveFolderPath, "diagnostics.log"), FileMode.CreateNew))
                using (this.diagnosticLogFileWriter = new StreamWriter(diagnosticLogFile))
                {
                    this.WriteMessage("Collecting diagnostic info into temp folder " + archiveFolderPath);

                    this.WriteMessage(string.Empty);
                    this.WriteMessage("gvfs version " + ProcessHelper.GetCurrentProcessVersion());

                    GitVersion gitVersion = null;
                    string     error      = null;
                    if (!string.IsNullOrEmpty(enlistment.GitBinPath) && GitProcess.TryGetVersion(enlistment.GitBinPath, out gitVersion, out error))
                    {
                        this.WriteMessage("git version " + gitVersion.ToString());
                    }
                    else
                    {
                        this.WriteMessage("Could not determine git version. " + error);
                    }

                    this.WriteMessage(enlistment.GitBinPath);
                    this.WriteMessage(string.Empty);
                    this.WriteMessage("Enlistment root: " + enlistment.EnlistmentRoot);
                    this.WriteMessage("Cache Server: " + CacheServerResolver.GetCacheServerFromConfig(enlistment));

                    string localCacheRoot;
                    string gitObjectsRoot;
                    this.GetLocalCachePaths(enlistment, out localCacheRoot, out gitObjectsRoot);
                    string actualLocalCacheRoot = !string.IsNullOrWhiteSpace(localCacheRoot) ? localCacheRoot : gitObjectsRoot;
                    this.WriteMessage("Local Cache: " + actualLocalCacheRoot);
                    this.WriteMessage(string.Empty);

                    this.PrintDiskSpaceInfo(actualLocalCacheRoot, this.EnlistmentRootPathParameter);

                    this.RecordVersionInformation();

                    this.ShowStatusWhileRunning(
                        () =>
                        this.RunAndRecordGVFSVerb <StatusVerb>(archiveFolderPath, "gvfs_status.txt") != ReturnCode.Success ||
                        this.RunAndRecordGVFSVerb <UnmountVerb>(archiveFolderPath, "gvfs_unmount.txt", verb => verb.SkipLock = true) == ReturnCode.Success,
                        "Unmounting",
                        suppressGvfsLogMessage: true);

                    this.ShowStatusWhileRunning(
                        () =>
                    {
                        // .gvfs
                        this.CopyAllFiles(enlistment.EnlistmentRoot, archiveFolderPath, GVFSPlatform.Instance.Constants.DotGVFSRoot, copySubFolders: false);

                        // driver
                        if (this.FlushKernelDriverLogs())
                        {
                            string kernelLogsFolderPath = GVFSPlatform.Instance.KernelDriver.LogsFolderPath;

                            // This copy sometimes fails because the OS has an exclusive lock on the etl files. The error is not actionable
                            // for the user so we don't write the error message to stdout, just to our own log file.
                            this.CopyAllFiles(Path.GetDirectoryName(kernelLogsFolderPath), archiveFolderPath, Path.GetFileName(kernelLogsFolderPath), copySubFolders: false, hideErrorsFromStdout: true);
                        }

                        // .git
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Hooks.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Info.Root, copySubFolders: false);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Logs.Root, copySubFolders: true);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Refs.Root, copySubFolders: true);
                        this.CopyAllFiles(enlistment.WorkingDirectoryRoot, archiveFolderPath, GVFSConstants.DotGit.Objects.Info.Root, copySubFolders: false);
                        this.LogDirectoryEnumeration(enlistment.WorkingDirectoryRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGit.Objects.Root), GVFSConstants.DotGit.Objects.Pack.Root, "packs-local.txt");
                        this.LogLooseObjectCount(enlistment.WorkingDirectoryRoot, Path.Combine(archiveFolderPath, GVFSConstants.DotGit.Objects.Root), GVFSConstants.DotGit.Objects.Root, "objects-local.txt");

                        // databases
                        this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSPlatform.Instance.Constants.DotGVFSRoot), GVFSConstants.DotGVFS.Databases.Name, copySubFolders: false);

                        // local cache
                        this.CopyLocalCacheData(archiveFolderPath, localCacheRoot, gitObjectsRoot);

                        // corrupt objects
                        this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSPlatform.Instance.Constants.DotGVFSRoot), GVFSConstants.DotGVFS.CorruptObjectsName, copySubFolders: false);

                        // service
                        this.CopyAllFiles(
                            GVFSPlatform.Instance.GetDataRootForGVFS(),
                            archiveFolderPath,
                            this.ServiceName,
                            copySubFolders: true);

                        if (GVFSPlatform.Instance.UnderConstruction.SupportsGVFSUpgrade)
                        {
                            // upgrader
                            this.CopyAllFiles(
                                ProductUpgraderInfo.GetParentLogDirectoryPath(),
                                archiveFolderPath,
                                DeprecatedUpgradeLogsDirectory,
                                copySubFolders: true,
                                targetFolderName: Path.Combine(ProductUpgraderInfo.UpgradeDirectoryName, DeprecatedUpgradeLogsDirectory));

                            this.CopyAllFiles(
                                ProductUpgraderInfo.GetParentLogDirectoryPath(),
                                archiveFolderPath,
                                ProductUpgraderInfo.LogDirectory,
                                copySubFolders: true,
                                targetFolderName: Path.Combine(ProductUpgraderInfo.UpgradeDirectoryName, ProductUpgraderInfo.LogDirectory));

                            this.LogDirectoryEnumeration(
                                ProductUpgraderInfo.GetUpgradeProtectedDataDirectory(),
                                Path.Combine(archiveFolderPath, ProductUpgraderInfo.UpgradeDirectoryName),
                                ProductUpgraderInfo.DownloadDirectory,
                                "downloaded-assets.txt");
                        }

                        if (GVFSPlatform.Instance.UnderConstruction.SupportsGVFSConfig)
                        {
                            this.CopyFile(GVFSPlatform.Instance.GetDataRootForGVFS(), archiveFolderPath, LocalGVFSConfig.FileName);
                        }

                        return(true);
                    },
                        "Copying logs");

                    this.ShowStatusWhileRunning(
                        () => this.RunAndRecordGVFSVerb <MountVerb>(archiveFolderPath, "gvfs_mount.txt") == ReturnCode.Success,
                        "Mounting",
                        suppressGvfsLogMessage: true);

                    this.CopyAllFiles(enlistment.DotGVFSRoot, Path.Combine(archiveFolderPath, GVFSPlatform.Instance.Constants.DotGVFSRoot), "logs", copySubFolders: false);
                }

            string zipFilePath = archiveFolderPath + ".zip";

            this.ShowStatusWhileRunning(
                () =>
            {
                ZipFile.CreateFromDirectory(archiveFolderPath, zipFilePath);
                this.fileSystem.DeleteDirectory(archiveFolderPath);

                return(true);
            },
                "Creating zip file",
                suppressGvfsLogMessage: true);

            this.Output.WriteLine();
            this.Output.WriteLine("Diagnostics complete. All of the gathered info, as well as all of the output above, is captured in");
            this.Output.WriteLine(zipFilePath);
        }
示例#22
0
        private Result DoClone(string fullEnlistmentRootPathParameter, string normalizedEnlistmentRootPath)
        {
            Result cloneResult = null;

            cloneResult = this.TryCreateEnlistment(fullEnlistmentRootPathParameter, normalizedEnlistmentRootPath, out this.enlistment);

            if (!cloneResult.Success)
            {
                this.tracer.RelatedError($"Error while creating enlistment: {cloneResult.ErrorMessage}");
                return(cloneResult);
            }

            this.tracer.AddLogFileEventListener(
                ScalarEnlistment.GetNewScalarLogFileName(this.enlistment.ScalarLogsRoot, ScalarConstants.LogFileTypes.Clone),
                EventLevel.Informational,
                Keywords.Any);
            this.tracer.WriteStartEvent(
                this.enlistment.EnlistmentRoot,
                this.enlistment.RepoUrl,
                this.CacheServerUrl,
                this.AddVerbDataToMetadata(new EventMetadata
            {
                { nameof(this.Branch), this.Branch },
                { nameof(this.LocalCacheRoot), this.LocalCacheRoot },
                { nameof(this.SingleBranch), this.SingleBranch },
                { nameof(this.FullClone), this.FullClone },
                { nameof(this.NoFetchCommitsAndTrees), this.NoFetchCommitsAndTrees },
                { nameof(this.Unattended), this.Unattended },
                { nameof(ScalarPlatform.Instance.IsElevated), ScalarPlatform.Instance.IsElevated() },
                { "ProcessID", Process.GetCurrentProcess().Id },
                { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
                { nameof(fullEnlistmentRootPathParameter), fullEnlistmentRootPathParameter },
            }));

            this.cacheServerResolver = new CacheServerResolver(this.tracer, this.enlistment);
            this.cacheServer         = this.cacheServerResolver.ParseUrlOrFriendlyName(this.CacheServerUrl);

            string resolvedLocalCacheRoot;

            if (string.IsNullOrWhiteSpace(this.LocalCacheRoot))
            {
                if (!LocalCacheResolver.TryGetDefaultLocalCacheRoot(this.enlistment, out resolvedLocalCacheRoot, out string localCacheRootError))
                {
                    this.ReportErrorAndExit(
                        this.tracer,
                        $"Failed to determine the default location for the local Scalar cache: `{localCacheRootError}`");
                }
            }
            else
            {
                resolvedLocalCacheRoot = Path.GetFullPath(this.LocalCacheRoot);
            }

            // Determine what features of Git we have available to guide how we init/clone the repository
            var    gitFeatures = GitFeatureFlags.None;
            string gitBinPath  = ScalarPlatform.Instance.GitInstallation.GetInstalledGitBinPath();

            this.tracer.RelatedInfo("Attempting to determine Git version for installation '{0}'", gitBinPath);
            if (GitProcess.TryGetVersion(gitBinPath, out var gitVersion, out string gitVersionError))
            {
                this.tracer.RelatedInfo("Git installation '{0}' has version '{1}", gitBinPath, gitVersion);
                gitFeatures = gitVersion.GetFeatures();
            }