Exemple #1
0
        public override FixResult TryFixIssues(List <string> messages)
        {
            string indexBackupPath = null;

            if (File.Exists(this.indexPath))
            {
                if (!this.TryRenameToBackupFile(this.indexPath, out indexBackupPath, messages))
                {
                    return(FixResult.Failure);
                }
            }

            HashSet <string> sparseCheckoutFiles = null;

            if (File.Exists(this.sparseCheckoutPath))
            {
                GVFSContext context = new GVFSContext(
                    this.Tracer,
                    new PhysicalFileSystem(),
                    repository: null,
                    enlistment: this.Enlistment);

                SparseCheckout sparseCheckout = new SparseCheckout(context, this.sparseCheckoutPath);
                sparseCheckout.LoadOrCreate();
                sparseCheckoutFiles = new HashSet <string>(sparseCheckout.Entries.Select(line => line.TrimStart('/')));
            }

            GitIndexGenerator indexGen = new GitIndexGenerator(this.Tracer, this.Enlistment, shouldHashIndex: false);

            indexGen.CreateFromHeadTree(indexVersion: 4, sparseCheckoutEntries: sparseCheckoutFiles);

            if (indexGen.HasFailures || this.TryParseIndex(this.indexPath, messages) != IssueType.None)
            {
                if (indexBackupPath != null)
                {
                    this.RestoreFromBackupFile(indexBackupPath, this.indexPath, messages);
                }

                return(FixResult.Failure);
            }

            if (indexBackupPath != null)
            {
                if (!this.TryDeleteFile(indexBackupPath))
                {
                    messages.Add("Warning: Could not delete backed up .git\\index at: " + indexBackupPath);
                }
            }

            return(FixResult.Success);
        }
Exemple #2
0
        public override FixResult TryFixIssues(List <string> messages)
        {
            string indexBackupPath = null;

            if (File.Exists(this.indexPath))
            {
                if (!this.TryRenameToBackupFile(this.indexPath, out indexBackupPath, messages))
                {
                    return(FixResult.Failure);
                }
            }

            GitIndexGenerator indexGen = new GitIndexGenerator(this.Tracer, this.Enlistment, shouldHashIndex: false);

            indexGen.CreateFromHeadTree(indexVersion: 4);

            if (indexGen.HasFailures || this.TryParseIndex(this.indexPath, messages) != IssueType.None)
            {
                if (indexBackupPath != null)
                {
                    this.RestoreFromBackupFile(indexBackupPath, this.indexPath, messages);
                }

                return(FixResult.Failure);
            }

            if (indexBackupPath != null)
            {
                if (!this.TryDeleteFile(indexBackupPath))
                {
                    messages.Add("Warning: Could not delete backed up .git\\index at: " + indexBackupPath);
                }
            }

            return(FixResult.Success);
        }
        /// <param name="branchOrCommit">A specific branch to filter for, or null for all branches returned from info/refs</param>
        public override void FastFetch(string branchOrCommit, bool isBranch)
        {
            if (string.IsNullOrWhiteSpace(branchOrCommit))
            {
                throw new FetchException("Must specify branch or commit to fetch");
            }

            GitRefs refs = null;
            string  commitToFetch;

            if (isBranch)
            {
                refs = this.ObjectRequestor.QueryInfoRefs(branchOrCommit);
                if (refs == null)
                {
                    throw new FetchException("Could not query info/refs from: {0}", this.Enlistment.RepoUrl);
                }
                else if (refs.Count == 0)
                {
                    throw new FetchException("Could not find branch {0} in info/refs from: {1}", branchOrCommit, this.Enlistment.RepoUrl);
                }

                commitToFetch = refs.GetTipCommitIds().Single();
            }
            else
            {
                commitToFetch = branchOrCommit;
            }

            this.DownloadMissingCommit(commitToFetch, this.GitObjects);

            // Configure pipeline
            // Checkout uses DiffHelper when running checkout.Start(), which we use instead of LsTreeHelper like in FetchHelper.cs
            // Checkout diff output => FindMissingBlobs => BatchDownload => IndexPack => Checkout available blobs
            CheckoutJob            checkout    = new CheckoutJob(this.checkoutThreadCount, this.PathWhitelist, commitToFetch, this.Tracer, this.Enlistment);
            FindMissingBlobsJob    blobFinder  = new FindMissingBlobsJob(this.SearchThreadCount, checkout.RequiredBlobs, checkout.AvailableBlobShas, this.Tracer, this.Enlistment);
            BatchObjectDownloadJob downloader  = new BatchObjectDownloadJob(this.DownloadThreadCount, this.ChunkSize, blobFinder.DownloadQueue, checkout.AvailableBlobShas, this.Tracer, this.Enlistment, this.ObjectRequestor, this.GitObjects);
            IndexPackJob           packIndexer = new IndexPackJob(this.IndexThreadCount, downloader.AvailablePacks, checkout.AvailableBlobShas, this.Tracer, this.GitObjects);

            // Start pipeline
            downloader.Start();
            blobFinder.Start();
            checkout.Start();

            blobFinder.WaitForCompletion();
            this.HasFailures |= blobFinder.HasFailures;

            // Delay indexing. It interferes with FindMissingBlobs, and doesn't help Bootstrapping.
            packIndexer.Start();

            downloader.WaitForCompletion();
            this.HasFailures |= downloader.HasFailures;

            packIndexer.WaitForCompletion();
            this.HasFailures |= packIndexer.HasFailures;

            // Since pack indexer is the last to finish before checkout finishes, it should propagate completion.
            // This prevents availableObjects from completing before packIndexer can push its objects through this link.
            checkout.AvailableBlobShas.CompleteAdding();
            checkout.WaitForCompletion();
            this.HasFailures |= checkout.HasFailures;

            if (!this.SkipConfigUpdate && !this.HasFailures)
            {
                this.UpdateRefs(branchOrCommit, isBranch, refs);

                if (isBranch)
                {
                    // Update the refspec before setting the upstream or git will complain the remote branch doesn't exist
                    this.HasFailures |= !RefSpecHelpers.UpdateRefSpec(this.Tracer, this.Enlistment, branchOrCommit, refs);

                    using (ITracer activity = this.Tracer.StartActivity("SetUpstream", EventLevel.Informational))
                    {
                        string            remoteBranch = refs.GetBranchRefPairs().Single().Key;
                        GitProcess        git          = new GitProcess(this.Enlistment);
                        GitProcess.Result result       = git.SetUpstream(branchOrCommit, remoteBranch);
                        if (result.HasErrors)
                        {
                            activity.RelatedError("Could not set upstream for {0} to {1}: {2}", branchOrCommit, remoteBranch, result.Errors);
                            this.HasFailures = true;
                        }
                    }
                }

                bool indexSigningIsOff = this.GetIsIndexSigningOff();

                // Update the index
                EventMetadata updateIndexMetadata = new EventMetadata();
                updateIndexMetadata.Add("IndexSigningIsOff", indexSigningIsOff);
                using (ITracer activity = this.Tracer.StartActivity("UpdateIndex", EventLevel.Informational, Keywords.Telemetry, updateIndexMetadata))
                {
                    // Create the index object now so it can track the current index
                    Index index = indexSigningIsOff ? new Index(this.Enlistment.EnlistmentRoot, activity) : null;

                    GitIndexGenerator indexGen = new GitIndexGenerator(this.Tracer, this.Enlistment, !indexSigningIsOff);
                    indexGen.CreateFromHeadTree();
                    this.HasFailures = indexGen.HasFailures;

                    if (!indexGen.HasFailures && index != null)
                    {
                        // Update from disk only if the caller says it is ok via command line
                        // or if we updated the whole tree and know that all files are up to date
                        bool allowIndexMetadataUpdateFromWorkingTree = this.allowIndexMetadataUpdateFromWorkingTree || checkout.UpdatedWholeTree;

                        index.UpdateFileSizesAndTimes(checkout.AddedOrEditedLocalFiles, allowIndexMetadataUpdateFromWorkingTree);
                    }
                }
            }
        }
Exemple #4
0
        /// <param name="branchOrCommit">A specific branch to filter for, or null for all branches returned from info/refs</param>
        public override void Prefetch(string branchOrCommit, bool isBranch)
        {
            if (string.IsNullOrWhiteSpace(branchOrCommit))
            {
                throw new FetchException("Must specify branch or commit to fetch");
            }

            GitRefs refs = null;
            string  commitToFetch;

            if (isBranch)
            {
                refs = this.ObjectRequestor.QueryInfoRefs(branchOrCommit);
                if (refs == null)
                {
                    throw new FetchException("Could not query info/refs from: {0}", this.Enlistment.RepoUrl);
                }
                else if (refs.Count == 0)
                {
                    throw new FetchException("Could not find branch {0} in info/refs from: {1}", branchOrCommit, this.Enlistment.RepoUrl);
                }

                commitToFetch = refs.GetTipCommitId(branchOrCommit);
            }
            else
            {
                commitToFetch = branchOrCommit;
            }

            using (new IndexLock(this.Enlistment.EnlistmentRoot, this.Tracer))
            {
                this.DownloadMissingCommit(commitToFetch, this.GitObjects);

                // Configure pipeline
                // Checkout uses DiffHelper when running checkout.Start(), which we use instead of LsTreeHelper
                // Checkout diff output => FindBlobs => BatchDownload => IndexPack => Checkout available blobs
                CheckoutStage            checkout    = new CheckoutStage(this.checkoutThreadCount, this.FolderList, commitToFetch, this.Tracer, this.Enlistment, this.forceCheckout);
                FindBlobsStage           blobFinder  = new FindBlobsStage(this.SearchThreadCount, checkout.RequiredBlobs, checkout.AvailableBlobShas, this.Tracer, this.Enlistment);
                BatchObjectDownloadStage downloader  = new BatchObjectDownloadStage(this.DownloadThreadCount, this.ChunkSize, blobFinder.MissingBlobs, checkout.AvailableBlobShas, this.Tracer, this.Enlistment, this.ObjectRequestor, this.GitObjects);
                IndexPackStage           packIndexer = new IndexPackStage(this.IndexThreadCount, downloader.AvailablePacks, checkout.AvailableBlobShas, this.Tracer, this.GitObjects);

                // Start pipeline
                downloader.Start();
                blobFinder.Start();
                checkout.Start();

                blobFinder.WaitForCompletion();
                this.HasFailures |= blobFinder.HasFailures;

                // Delay indexing. It interferes with FindMissingBlobs, and doesn't help Bootstrapping.
                packIndexer.Start();

                downloader.WaitForCompletion();
                this.HasFailures |= downloader.HasFailures;

                packIndexer.WaitForCompletion();
                this.HasFailures |= packIndexer.HasFailures;

                // Since pack indexer is the last to finish before checkout finishes, it should propagate completion.
                // This prevents availableObjects from completing before packIndexer can push its objects through this link.
                checkout.AvailableBlobShas.CompleteAdding();
                checkout.WaitForCompletion();
                this.HasFailures |= checkout.HasFailures;

                if (!this.SkipConfigUpdate && !this.HasFailures)
                {
                    bool shouldSignIndex = !this.GetIsIndexSigningOff();

                    // Update the index - note that this will take some time
                    EventMetadata updateIndexMetadata = new EventMetadata();
                    updateIndexMetadata.Add("IndexSigningIsOff", shouldSignIndex);
                    using (ITracer activity = this.Tracer.StartActivity("UpdateIndex", EventLevel.Informational, Keywords.Telemetry, updateIndexMetadata))
                    {
                        Index             sourceIndex = this.GetSourceIndex();
                        GitIndexGenerator indexGen    = new GitIndexGenerator(this.Tracer, this.Enlistment, shouldSignIndex);
                        indexGen.CreateFromRef(commitToFetch, indexVersion: 2, isFinal: false);
                        this.HasFailures |= indexGen.HasFailures;

                        if (!indexGen.HasFailures)
                        {
                            Index newIndex = new Index(
                                this.Enlistment.EnlistmentRoot,
                                this.Tracer,
                                indexGen.TemporaryIndexFilePath,
                                readOnly: false);

                            // Update from disk only if the caller says it is ok via command line
                            // or if we updated the whole tree and know that all files are up to date
                            bool allowIndexMetadataUpdateFromWorkingTree = this.allowIndexMetadataUpdateFromWorkingTree || checkout.UpdatedWholeTree;
                            newIndex.UpdateFileSizesAndTimes(checkout.AddedOrEditedLocalFiles, allowIndexMetadataUpdateFromWorkingTree, shouldSignIndex, sourceIndex);

                            // All the slow stuff is over, so we will now move the final index into .git\index, shortly followed by
                            // updating the ref files and releasing index.lock.
                            string indexPath = Path.Combine(this.Enlistment.DotGitRoot, GVFSConstants.DotGit.IndexName);
                            this.Tracer.RelatedEvent(EventLevel.Informational, "MoveUpdatedIndexToFinalLocation", new EventMetadata()
                            {
                                { "UpdatedIndex", indexGen.TemporaryIndexFilePath }, { "Index", indexPath }
                            });
                            File.Delete(indexPath);
                            File.Move(indexGen.TemporaryIndexFilePath, indexPath);
                            newIndex.WriteFastFetchIndexVersionMarker();
                        }
                    }

                    if (!this.HasFailures)
                    {
                        this.UpdateRefs(branchOrCommit, isBranch, refs);

                        if (isBranch)
                        {
                            // Update the refspec before setting the upstream or git will complain the remote branch doesn't exist
                            this.HasFailures |= !this.UpdateRefSpec(this.Tracer, this.Enlistment, branchOrCommit, refs);

                            using (ITracer activity = this.Tracer.StartActivity("SetUpstream", EventLevel.Informational))
                            {
                                string            remoteBranch = refs.GetBranchRefPairs().Single().Key;
                                GitProcess        git          = new GitProcess(this.Enlistment);
                                GitProcess.Result result       = git.SetUpstream(branchOrCommit, remoteBranch);
                                if (result.ExitCodeIsFailure)
                                {
                                    activity.RelatedError("Could not set upstream for {0} to {1}: {2}", branchOrCommit, remoteBranch, result.Errors);
                                    this.HasFailures = true;
                                }
                            }
                        }
                    }
                }
            }
        }