public void WriteBundle(HgBundle hgBundle, Stream stream, HgBundleFormat format, HgBundleCompression compression)
        {
            //
            // First things first -- we need to write out bundle header
            var header = 
                format == HgBundleFormat.BundlePre10 ?
                    null :
                    GetCompressionHeader(compression);
            
            if(header != null)
            {
                var headerBuffer = Encoding.ASCII.GetBytes(header);
                stream.Write(headerBuffer, 0, headerBuffer.Length);
            } // if

            using(var compressedStream = GetCompressedStream(stream, compression))
            using(var binaryWriter = new BigEndianBinaryWriter(new BufferedStream(compressedStream, 1024 * 128)))
            {
                log.Debug("writing changesets");
                WriteBundleGroup(hgBundle.Changelog, binaryWriter);
                binaryWriter.Flush();

                log.Debug("writing manifests");
                WriteBundleGroup(hgBundle.Manifest, binaryWriter);
                binaryWriter.Flush();
                //
                // Sometimes HgBundleFile.File has no chunks and Mercurial chokes on that.
                log.Debug("writing files");
                foreach(var file in hgBundle.Files)
                {
                    string filePath = null;
                    foreach(var chunk in file.File)
                    {
                        if(filePath == null)
                        {
                            filePath = file.Path.FullPath.TrimStart('/');
                            binaryWriter.Write((uint)filePath.Length + 4);
                            binaryWriter.Write(hgEncoder.EncodeAsLocal(filePath));

                            log.Debug("writing file '{0}'", filePath);
                        } // if

                        WriteChunk(binaryWriter, chunk);
                    } // foreach

                    if(filePath != null)
                        WriteZeroChunk(binaryWriter);

                    binaryWriter.Flush();
                } // foreach

                binaryWriter.Write((uint)0);
                
                binaryWriter.Flush();
                compressedStream.Flush();
                stream.Flush();
            } // using
        }
        public HgBundle BuildBundle(HgRepository hgRepository, HgRevset hgRevset)
        {
            log.Debug("bundling changelog");
            var paths = new HashSet<string>();
            var changelog = BuildChangesetBundleGroup(hgRepository, hgRevset, hc => paths.AddRange(hc.Files));

            log.Debug("bundling manifests");
            var manifest = BuildManifestBundleGroup(hgRepository, hgRevset);

            //
            // List of all files that ever were tracked
            log.Debug("bundling filelogs");
            var files = BuildBundleFiles(hgRepository, hgRevset, paths);

            var hgBundle = new HgBundle(changelog, manifest, files);
            return hgBundle;
        }
        public HgCommitStats Commit(HgBundle hgBundle)
        {
            log.Info("committing bundle");

            using(AcquireLock())
            {
                var hgJournal = new HgJournal(Store);
                var hgTransaction = new HgTransaction(Store, hgJournal);

                var tip = Changelog.Tip;

                try
                {
                    //
                    // Adding changesets
                    log.Info("committing changesets");
                    hgTransaction.Enlist(Changelog);
                    
                    int changesets;
                    var revisions = CommitChangelog(tip, hgBundle.Changelog, Changelog.Revlog, out changesets);

                    //
                    // Adding manifests
                    log.Info("committing manifests");
                    hgTransaction.Enlist(Manifest);

                    var manifests = 0;
                    Commit(revisions, hgBundle.Manifest, Manifest.Revlog, ref manifests);

                    //
                    // Adding file changes
                    log.Info("committing files");
                    var changedFiles = 0;
                    var changes = 0;

                    foreach(var file in hgBundle.Files)
                    {
                        changedFiles++;

                        log.Debug("committing '{0}'", file.Path.FullPath);

                        var filelog = Store.GetFilelog(file.Path) ?? Store.CreateFilelog(file.Path);
                        hgTransaction.Enlist(filelog);

                        var hgBundleGroup = file.File;

                        Commit(revisions, hgBundleGroup, filelog.Revlog, ref changes);
                    } // foreach

                    if(BundleCommitting != null)
                    {
                        var args = new HgBundleCommittedEventArgs(revisions.Keys.Select(k => Changelog[k]));
                        BundleCommitting(args);
                    } // if
                    
                    hgTransaction.Commit();

                    //
                    // We need to force changelog re-read since after CommitChangelog() the changelog is
                    // being read off a temp file.
                    changelog = null;

                    branchManager.RefreshBranchmap(tip == null ? 0 : tip.Metadata.Revision, Changelog.Tip.Metadata);

                    if(BundleCommitted != null)
                    {
                        var args = new HgBundleCommittedEventArgs(revisions.Keys.Select(k => Changelog[k]));
                        BundleCommitted(args);
                    } // if

                    return new HgCommitStats(changesets, manifests, changes, changedFiles);
                } // try
                catch(Exception e)
                {
                    log.ErrorException("could not commit bundle", e);

                    hgTransaction.Rollback();

                    //
                    // Reset changelog and manifest so that they'll be reread
                    changelog = null;
                    manifest = null;

                    throw;
                } // catch
            } // using
        }