private HgManifestNode(HgManifestTreeNodeType type, string name, HgPath path, HgNodeID? nodeID)
 {
     Type = type;
     Name = name;
     Path = path;
     NodeID = nodeID;
 }
 public HgChunk(HgNodeID nodeID, HgNodeID firstParentNodeID, HgNodeID secondParentNodeID, HgNodeID changesetNodeID, byte[] data)
 {
     NodeID = nodeID;
     FirstParentNodeID = firstParentNodeID;
     SecondParentNodeID = secondParentNodeID;
     ChangesetNodeID = changesetNodeID;
     Data = data;
 }
        protected virtual HgRevlogEntryData GetRevlogEntryData(HgNodeID hgNodeID)
        {
            if(hgNodeID == HgNodeID.Null) return null;

            var key = string.Format("revlog:{0}@{1}", Revlog.IndexPath, hgNodeID.Long);
            var hgRevlogEntryData = revlogEntryCache.GetOrAdd(key, () => revlogReader.ReadRevlogEntry(hgNodeID));

            return hgRevlogEntryData;
        }
        public void UpdateBookmark(string name, HgNodeID changesetNodeID)
        {
            var bookmarks = ReadBookmarks();

            bookmarks.Remove(bookmarks.SingleOrDefault(b => b.Name == name));
            bookmarks.Add(new HgBookmark(name, repository.Changelog[changesetNodeID]));

            WriteBookmarks(bookmarks);
        }
 public HgCommit(HgNodeID firstParentNodeID, HgNodeID secondParentNodeID, HgAuthor committedBy, DateTimeOffset committedAt, HgBranch branch, string comment, 
     params HgCommitFileEntry[] files) : 
     base(firstParentNodeID, secondParentNodeID)
 {
     CommittedBy = committedBy;
     CommittedAt = committedAt;
     Branch = branch;
     Comment = comment;
     Files = new ReadOnlyCollection<HgCommitFileEntry>(new List<HgCommitFileEntry>(files));
 }
 public HgRevlogEntryMetadata(HgNodeID nodeID, uint revision, uint linkRevision, HgNodeID firstParentRevisionNodeID, HgNodeID secondParentRevisionNodeID, 
     uint firstParentRevision, uint secondParentRevision)
 {
     SecondParentRevision = secondParentRevision;
     FirstParentRevision = firstParentRevision;
     NodeID = nodeID;
     Revision = revision;
     LinkRevision = linkRevision;
     FirstParentRevisionNodeID = firstParentRevisionNodeID;
     SecondParentRevisionNodeID = secondParentRevisionNodeID;
 }
        public override HgManifestEntry this[HgNodeID hgNodeID]
        {
            get
            {
                var largefilesEnabledManifestEntry = underlyingManifest[hgNodeID];
                var manifestEntry = new HgManifestEntry(
                    largefilesEnabledManifestEntry.Metadata, 
                    largefilesEnabledManifestEntry.Files.Select(f => new HgManifestFileEntry(new HgPath(f.Path.FullPath.SubstringAfter(".hglf/")), f.FilelogNodeID)).ToList());

                return manifestEntry;
            }
        }
        private static HgNodeID Max(HgNodeID l, HgNodeID r)
        {
            var ln = l.NodeID;
            var rn = r.NodeID;
            for(var i = 0; i < Math.Min(ln.Length, rn.Length); ++i)
            {
                if(ln[i] > rn[i]) return l;
                if(ln[i] < rn[i]) return r;
            } // for

            return l;
        }
 public HgChangeset(HgRevlogEntryMetadata metadata, HgNodeID manifestNodeID, HgAuthor committedBy, DateTimeOffset committedAt, HgBranch branch, 
     HgNodeID sourceNodeID, IEnumerable<string> files, string comment)
 {
     Metadata = metadata;
     ManifestNodeID = manifestNodeID;
     CommittedBy = committedBy;
     CommittedAt = committedAt;
     Branch = branch;
     SourceNodeID = sourceNodeID;
     Files = new ReadOnlyCollection<string>(new List<string>(files));
     Comment = comment;
 }
        public virtual HgRevlogEntry GetEntry(HgNodeID nodeID)
        {
            uint revision = 0;
            if(nodeCache.TryGetValue(nodeID, out revision))
                return GetEntry(revision);

            if (nodeID.NodeID.Length == 20) return null;

            //
            // Nope, no match. Might be a shortened SHA, so we'll have to look through the whole revlog
            var node = entries.FirstOrDefault(e => e.NodeID.Equals(nodeID));
            return node;
        }
 public virtual HgManifestEntry this[HgNodeID hgNodeID]
 {
     get
     {
         var key = string.Format("manifest:{0}@{1}", Revlog.IndexPath, hgNodeID.Long);
         return ObjectCache.GetOrAdd(key,
             () => {
                 var hgRevlogEntryData = GetRevlogEntryData(hgNodeID);
                 return 
                     hgRevlogEntryData == null ?
                         null :
                         hgManifestReader.ReadManifestEntry(hgRevlogEntryData);
             });
     }
 }
 public HgRevlogEntry(UInt32 revision, HgNodeID nodeID, ulong offset, ushort flags, uint compressedLength, uint uncompressedLength, 
     uint baseRevision, uint linkRevision, uint firstParentRevision, HgNodeID firstParentRevisionNodeID, uint secondParentRevision, HgNodeID secondParentRevisionNodeID)
 {
     Revision = revision;
     Offset = offset;
     Flags = flags;
     CompressedLength = compressedLength;
     UncompressedLength = uncompressedLength;
     BaseRevision = baseRevision;
     LinkRevision = linkRevision;
     FirstParentRevision = firstParentRevision;
     SecondParentRevision = secondParentRevision;
     NodeID = nodeID;
     FirstParentRevisionNodeID = firstParentRevisionNodeID;
     SecondParentRevisionNodeID = secondParentRevisionNodeID;
 }
        public HgChangeset this[HgNodeID hgNodeID]
        {
            get
            {
                if(hgNodeID == HgNodeID.Null)
                    return HgChangeset.Null;

                var key = string.Format("changelog:{0}@{1}", Revlog.IndexPath, hgNodeID.Long);
                return ObjectCache.GetOrAdd(key,
                    () => {
                        var hgRevlogEntryData = GetRevlogEntryData(hgNodeID);
                        return
                            hgRevlogEntryData == null
                                ? null
                                : hgChangelogReader.ReadChangeset(hgRevlogEntryData);
                    });
            }
        }
        private HgChangeset ReadChangesetInternal(HgRevlogEntryData revlogEntryData)
        {
            var filesStart = revlogEntryData.Data.IndexOfNth((byte)'\n', 3);
            var filesEnd = revlogEntryData.Data.IndexOf((byte)'\n', (byte)'\n');

            var headerString = hgEncoder.DecodeAsUtf8(revlogEntryData.Data, 0, filesStart);
            
            var filesString = 
                filesStart == filesEnd ? 
                    "" :
                    hgEncoder.DecodeAsLocal(
                        revlogEntryData.Data, 
                        filesStart + 1, // The \n 
                        filesEnd - filesStart - 1);
            
            var commentString = hgEncoder.DecodeAsUtf8(
                revlogEntryData.Data, 
                filesEnd + 2, // These \n\n bytes 
                revlogEntryData.Data.Length - filesEnd - 2);

            var header = headerString.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

            var manifestNodeID = new HgNodeID(header[0]);
            var committedBy = HgAuthor.Parse(header[1]);

            var timeParts = header[2].Split(' ');
            var time = int.Parse(timeParts[0]);
            var timeZone = int.Parse(timeParts[1]);

            var branchData = header[2].SubstringAfterNth(" ", 1).Or("branch:default");

            var b = branchData.Split('\0').Select(s => new { key = s.Split(':')[0], value = s.Split(':')[1] }).ToDictionary(s => s.key, s => s.value).DefaultableWith(v => "");
            var branchName = new HgBranch(b["branch"].Or("default"), b["close"] == "1");
            var sourceNodeID = new HgNodeID(b["source"].Or(HgNodeID.Null.Long));
            
            var dateTime = DateTime.SpecifyKind(new DateTime(1970, 1, 1).AddSeconds(time).AddSeconds(-1 * timeZone), DateTimeKind.Local);
            var committedAt = new DateTimeOffset(dateTime);

            var files = filesString.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            
            var metadata = GetRevlogEntryMetadata(revlogEntryData.Entry);

            return new HgChangeset(metadata, manifestNodeID, committedBy, committedAt, branchName, sourceNodeID, files, commentString);
        }
        private IList<HgBookmark> ReadBookmarks()
        {
            var bookmarks = new List<HgBookmark>();

            if(!Alphaleonis.Win32.Filesystem.File.Exists(bookmarksPath)) 
                return bookmarks;

            using(var booknmarksStream = fileSystem.OpenRead(bookmarksPath))
            using(var streamReader = new StreamReader(booknmarksStream))
            {
                var line = "";
                while((line = streamReader.ReadLine()) != null)
                {
                    var changesetNodeID = new HgNodeID(line.SubstringBefore(" "));
                    var name = line.SubstringAfter(" ").Trim();

                    bookmarks.Add(new HgBookmark(name, repository.Changelog[changesetNodeID]));
                } // while
            } // using

            return bookmarks;
        }
        protected HgNodeID GetRevlogEntryDataNodeID(HgNodeID firstParentNodeID, HgNodeID secondParentNodeID, byte[] data)
        {
            var parents = new[] {
                Min(firstParentNodeID, secondParentNodeID),
                Max(firstParentNodeID, secondParentNodeID)
            };

            using(var hash = new SHA1Managed())
            {
                hash.Initialize();
                var buffer = new byte[hash.HashSize / 8];
                hash.TransformBlock(parents[0].NodeID, 0, 20, buffer, 0);
                hash.TransformBlock(parents[1].NodeID, 0, 20, buffer, 0);
                hash.TransformFinalBlock(data, 0, data.Length);

                buffer = hash.Hash;

                var node = new HgNodeID(buffer);

                return node;
            } // using
            
        }
        public HgChangesetDetails GetChangesetDetails(HgNodeID hgNodeID, int context = 3)
        {
            var c = Changelog[hgNodeID];
            if(c == null) return null;

            var m = Manifest[c.ManifestNodeID];
            if(m == null) return new HgChangesetDetails(c, new List<HgChangesetFileDetails>());

            IList<HgChangesetFileDetails> files;

            var diffGenerator = new HgDiffGenerator();
            
            //
            // For a very first changeset we treat all files as Added
            if(c.Metadata.FirstParentRevisionNodeID == HgNodeID.Null)
            {
                files =
                    m.Files.
                        Select(f => new {
                            f = f.Path,
                            file = GetFile(m[f.Path.FullPath]),
                        }).
                        Select(f => new HgChangesetFileDetails(f.f, HgChangesetFileOperation.Added, 
                            f.file.IsBinary ? 
                                null :
                                GetHgRollupFileDiffInfo(f.f, f.file.IsBinary, diffGenerator.UnifiedDiff("", Encoder.DecodeAsUtf8(f.file.Data), context, false, true, true)))).
                        ToList();
            } //  if
            else
            {
                Func<HgManifestFileEntry, string> fileName = mfe => mfe.Path.FullPath.TrimStart('/');

                HgManifestEntry mp1 = null;
                ISet<string> cf = null, f_ = null, fp1 = null;

                cf = new HashSet<string>(c.Files.Select(f => f.TrimStart('/')).ToList());
                f_ = new HashSet<string>(m.Files.Select(fileName));

                var p1 = Changelog[c.Metadata.FirstParentRevisionNodeID];
                mp1 = Manifest[p1.ManifestNodeID];
                fp1 = new HashSet<string>(mp1.Files.Select(fileName));

                var addedFiles = f_.Except(fp1).Intersect(cf).ToList();
                var removedFiles = fp1.Except(f_).Intersect(cf).ToList();
                var modifiedFiles = f_.Intersect(fp1).Intersect(cf).Where(f => m[f].FilelogNodeID != mp1[f].FilelogNodeID || 
                    !GetFile(m[f]).Data.SequenceEqual(GetFile(mp1[f]).Data)).ToList();

                Func<HgFile, HgFile, HgUnifiedDiff> diff = (f /* from */, t /* to */) => {
                    if(f != null && f.IsBinary || t != null && t.IsBinary) return null;

                    var a = f == null ? "" : Encoder.DecodeAsUtf8(f.Data);
                    var b = t == null ? "" : Encoder.DecodeAsUtf8(t.Data);

                    return diffGenerator.UnifiedDiff(a, b, context, false, true, true);
                };

                var removed = 
                    removedFiles.
                        Select(f => new {
                            f,
                            file = GetFile(mp1[f]),
                        }).
                        Where(f => f.file != null).
                        Select(f => Removed(f.f, 
                            GetHgRollupFileDiffInfo(
                                new HgPath(f.f),
                                f.file.IsBinary,
                                diff(f.file, null)))).
                        Where(f => f.Diff != null && (f.Diff.Additions > 0 || f.Diff.Removals > 0));

                var added = 
                    addedFiles.
                        Select(f => new {
                            f,
                            file = GetFile(m[f]),
                        }).
                        Where(f => f.file != null).
                        Select(f => Added(f.f, 
                            GetHgRollupFileDiffInfo(
                                new HgPath(f.f),
                                f.file.IsBinary,
                                diff(null, f.file)))).
                        Where(f => f.Diff != null && (f.Diff.Additions > 0 || f.Diff.Removals > 0));

                var modified = 
                    modifiedFiles.
                        Select(f => new {
                            f,
                            file = GetFile(m[f]),
                        }).
                        Where(f => f.file != null).
                        Select(f => Modified(f.f, 
                            GetHgRollupFileDiffInfo(
                                new HgPath(f.f),
                                f.file.IsBinary,
                                diff(GetFile(mp1[f.f]), f.file)))).
                        Where(f => f.Diff == null || f.Diff.Additions > 0 || f.Diff.Removals > 0);

                //
                // Prepare enough room to avoid reallocations later on
                files = new List<HgChangesetFileDetails>(f_.Count * 2);

                files.AddRange(added);
                files.AddRange(modified);
                files.AddRange(removed);
            } // else

            var changesetDetails = new HgChangesetDetails(c, files);
            return changesetDetails;
        }
 public HgRevlogEntryData ReadRevlogEntry(HgNodeID nodeID)
 {
     var revlogEntryData = standinRevlogReader.ReadRevlogEntry(nodeID);
     return GetRevlogEntryData(revlogEntryData);
 }
 public HgSubrepository(HgPath path, string repositoryPath, HgNodeID nodeID)
 {
     Path = path;
     RepositoryPath = repositoryPath;
     NodeID = nodeID;
 }
 public HgFileCopyInfo(HgPath path, HgNodeID nodeID)
 {
     Path = path;
     NodeID = nodeID;
 }
 public HgCommitFileEntry(HgNodeID firstParentNodeID, HgNodeID secondParentNodeID, HgPath path, byte[] content) : base(firstParentNodeID, secondParentNodeID)
 {
     Path = path;
     Content = content;
 }
        public HgCompareInfo PerformComparison(HgNodeID baseNodeID, HgNodeID headNodeID, bool includeFileDiffs = false)
        {
            var hgRevsetManager = new HgRevsetManager();
            var @base = Changelog[baseNodeID];
            var head = Changelog[headNodeID];

            var baseAncestors = hgRevsetManager.GetAncestors(this, new HgRevset(@base.Metadata));
            var headAncestors = hgRevsetManager.GetAncestors(this, new HgRevset(head.Metadata));

            var changesets = GetChangesets(headAncestors - baseAncestors);

            if(changesets.Count == 0)
                return new HgCompareInfo(@base, head, new List<HgChangeset>(), new List<HgRollupFileDiffInfo>());

            var files = changesets.SelectMany(c => c.Files).Distinct().OrderBy(f => f).ToList();

            var startManifest = Manifest[@base.ManifestNodeID];
            var endManifest = Manifest[head.ManifestNodeID];

            //
            // Only pick files that were indeed changed between two bounding changesets
            
            var diffs = new List<HgRollupFileDiffInfo>();
            if(includeFileDiffs)
            {
                var changedFiles = files.Where(f => startManifest[f] == null && endManifest[f] != null || startManifest[f] != null && endManifest[f] == null || (startManifest[f] != null && endManifest[f] != null && startManifest[f].FilelogNodeID != endManifest[f].FilelogNodeID)).ToList();
                var diffGenerator = new HgDiffGenerator();
                diffs = changedFiles.
                    Select(f => new {
                        file = f,
                        start = startManifest[f],
                        end = endManifest[f]
                    }).
                    Select(f => new {
                        f.file,
                        start = f.start == null ? null : GetFile(f.start),
                        end = f.end == null ? null : GetFile(f.end)
                    }).
                    Select(f => new {
                        f.file,
                        isBinary = f.start != null && f.start.IsBinary || f.end != null && f.end.IsBinary,
                        f.start,
                        f.end
                    }).
                    Select(f => new {
                        f.file,
                        f.isBinary,
                        start = f.start == null || f.isBinary ? "" : Encoder.DecodeAsUtf8(f.start.Data),
                        end = f.end == null || f.isBinary ? "" : Encoder.DecodeAsUtf8(f.end.Data)
                    }).
                    Select(f => new { 
                        f.file,
                        f.isBinary,
                        diff = f.isBinary ? null : diffGenerator.UnifiedDiff(f.start, f.end, 3)
                    }).
                    //
                    // Do not include files that were not in fact changed between revision
                    Where(f => f.diff == null || f.diff.Hunks.Sum(h => h.Lines.Count(l => l.Added || l.Removed )) > 0).
                    Select(f => GetHgRollupFileDiffInfo(new HgPath(f.file), f.isBinary, f.diff)).
                    ToList();
            }

            return new HgCompareInfo(@base, head, changesets, diffs);
        }
 public void UpdateBookmark(string bookmarkName, HgNodeID changesetNodeID)
 {
     bookmarkManager.UpdateBookmark(bookmarkName, changesetNodeID);
 }
        private IEnumerable<uint> GetFileHistory(HgFilelog filelog, HgNodeID startNodeID)
        {
            var entries = 
                filelog.Revlog.Entries.
                    OrderByDescending(e => e.Revision).
                    SkipWhile(e => e.NodeID != startNodeID).
                    ToList();

            foreach(var entry in entries)
            {
                
                yield return entry.LinkRevision;

                var file = GetFile(new HgManifestFileEntry(filelog.Path, entry.NodeID));
                if(file.CopyInfo != null)
                {
                    var sourceFilelog = GetFilelog(file.CopyInfo.Path);
                    if(sourceFilelog == null) yield break;

                    foreach(var changeset in GetFileHistory(sourceFilelog, file.CopyInfo.NodeID))
                        yield return changeset;

                    yield break;
                }   
            
                if(entry.FirstParentRevisionNodeID == HgNodeID.Null)
                    yield break;

            } // foreach
        }
        public HgDivergenceInfo GetDivergence(HgNodeID baseNodeID, HgNodeID headNodeID)
        {
            var hgRevsetManager = new HgRevsetManager();
            var @base = (baseNodeID == HgNodeID.Null ? null : Changelog[baseNodeID]);
            var head = (headNodeID == HgNodeID.Null ? null : Changelog[headNodeID]);

            var baseAncestors = @base == null ?
                new HgRevset() : 
                hgRevsetManager.GetAncestors(this, new HgRevset(@base.Metadata));
            var headAncestors = head == null ?
                new HgRevset() :
                hgRevsetManager.GetAncestors(this, new HgRevset(head.Metadata));

            var ahead = headAncestors - baseAncestors;
            var behind = baseAncestors - headAncestors;

            //
            // If ahead has only one commit and that one is closing branch without affecting any files, ignore it altogether
            if(ahead.Count == 1)
            {
                var aheadChangeset = Changelog[ahead.Single().NodeID];
                if(aheadChangeset.Branch.Closed && aheadChangeset.Files.Count == 0)
                    ahead = new HgRevset();
            } // if

            return new HgDivergenceInfo(ahead, head, behind, @base);
        }
        public IList<HgChangeset> GetFileHistory(HgPath path, HgNodeID? startFilelogNodeID = null)
        {
            var filelog = GetFilelog(path);
            if(filelog == null) return null;

            var changesetNodeIDs = GetFileHistory(filelog, startFilelogNodeID ?? filelog.Revlog.Entries.Last().NodeID);
            
            var revsetManager = new HgRevsetManager();
            var revset = revsetManager.GetRevset(this, changesetNodeIDs);
            
            return GetChangesets(revset).OrderByDescending(c => c.Metadata.Revision).ToList();
        }
        private HgNodeID Commit(HgNodeID firstParentNodeID, HgNodeID secondParentNodeID, byte[] content, HgRevlog hgRevlog)
        {
            var data = new byte[]{};

            if(firstParentNodeID != HgNodeID.Null)
            {
                var hgRevlogReader = new HgRevlogReader(hgRevlog, fileSystem);
                data = hgRevlogReader.ReadRevlogEntry(firstParentNodeID).Data;
            } // if
                        
            var linkRevision = Changelog == null ? 0 : Changelog.Revlog.Entries.Count;

            var hgNodeID = new HgRevlogWriter(hgRevlog, fileSystem).WriteRevlogEntryData((uint)linkRevision, firstParentNodeID, secondParentNodeID, content);
            return hgNodeID;
        }
        private HgFile GetFileImpl(HgManifestFileEntry manifestFileEntry, HgNodeID filelogNodeID)
        {
            var filelog = GetFilelog(manifestFileEntry.Path);
            if(filelog == null) return null;

            var hgRevlogReader = Store.CreateRevlogReader(filelog.Revlog);
            var hgRevlogData = hgRevlogReader.ReadRevlogEntry(filelogNodeID);
            if(hgRevlogData == null) return null;

            //
            // Handle copyinfo and possibly other inband metadata. This part of Mercurial I don't like
            var data = hgRevlogData.Data;
            var copyInfo = HgFileCopyInfo.ExtractFileCopyInfo(ref data);

            log.Debug("retrieved file {0}@{1}", manifestFileEntry.Path.FullPath, filelogNodeID.Short);

            return new HgFile(manifestFileEntry.Path, hgRevlogData.Entry, data, copyInfo);
        }
 internal HgRevlogEntry(HgNodeID nodeID)
 {
     NodeID = nodeID;
 }
 public HgRevision(uint revision, HgNodeID nodeID)
   : this()
 {
   Revision = revision;
   NodeID = nodeID;
 }