amp 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.hgignore +26 -0
- data/AUTHORS +2 -0
- data/History.txt +6 -0
- data/LICENSE +37 -0
- data/MANIFESTO +7 -0
- data/Manifest.txt +294 -0
- data/README.md +129 -0
- data/Rakefile +102 -0
- data/SCHEDULE.markdown +12 -0
- data/STYLE +27 -0
- data/TODO.markdown +149 -0
- data/ampfile.rb +47 -0
- data/bin/amp +30 -0
- data/bin/amp1.9 +30 -0
- data/ext/amp/bz2/README.txt +39 -0
- data/ext/amp/bz2/bz2.c +1582 -0
- data/ext/amp/bz2/extconf.rb +77 -0
- data/ext/amp/bz2/mkmf.log +29 -0
- data/ext/amp/mercurial_patch/extconf.rb +5 -0
- data/ext/amp/mercurial_patch/mpatch.c +405 -0
- data/ext/amp/priority_queue/extconf.rb +5 -0
- data/ext/amp/priority_queue/priority_queue.c +947 -0
- data/ext/amp/support/extconf.rb +5 -0
- data/ext/amp/support/support.c +250 -0
- data/lib/amp.rb +200 -0
- data/lib/amp/commands/command.rb +507 -0
- data/lib/amp/commands/command_support.rb +137 -0
- data/lib/amp/commands/commands/config.rb +143 -0
- data/lib/amp/commands/commands/help.rb +29 -0
- data/lib/amp/commands/commands/init.rb +10 -0
- data/lib/amp/commands/commands/templates.rb +137 -0
- data/lib/amp/commands/commands/version.rb +7 -0
- data/lib/amp/commands/commands/workflow.rb +28 -0
- data/lib/amp/commands/commands/workflows/git/add.rb +65 -0
- data/lib/amp/commands/commands/workflows/git/copy.rb +27 -0
- data/lib/amp/commands/commands/workflows/git/mv.rb +23 -0
- data/lib/amp/commands/commands/workflows/git/rm.rb +60 -0
- data/lib/amp/commands/commands/workflows/hg/add.rb +53 -0
- data/lib/amp/commands/commands/workflows/hg/addremove.rb +86 -0
- data/lib/amp/commands/commands/workflows/hg/annotate.rb +46 -0
- data/lib/amp/commands/commands/workflows/hg/archive.rb +126 -0
- data/lib/amp/commands/commands/workflows/hg/branch.rb +28 -0
- data/lib/amp/commands/commands/workflows/hg/branches.rb +30 -0
- data/lib/amp/commands/commands/workflows/hg/bundle.rb +115 -0
- data/lib/amp/commands/commands/workflows/hg/clone.rb +95 -0
- data/lib/amp/commands/commands/workflows/hg/commit.rb +42 -0
- data/lib/amp/commands/commands/workflows/hg/copy.rb +31 -0
- data/lib/amp/commands/commands/workflows/hg/debug/dirstate.rb +32 -0
- data/lib/amp/commands/commands/workflows/hg/debug/index.rb +36 -0
- data/lib/amp/commands/commands/workflows/hg/default.rb +9 -0
- data/lib/amp/commands/commands/workflows/hg/diff.rb +30 -0
- data/lib/amp/commands/commands/workflows/hg/forget.rb +11 -0
- data/lib/amp/commands/commands/workflows/hg/heads.rb +25 -0
- data/lib/amp/commands/commands/workflows/hg/identify.rb +23 -0
- data/lib/amp/commands/commands/workflows/hg/import.rb +135 -0
- data/lib/amp/commands/commands/workflows/hg/incoming.rb +85 -0
- data/lib/amp/commands/commands/workflows/hg/info.rb +18 -0
- data/lib/amp/commands/commands/workflows/hg/log.rb +21 -0
- data/lib/amp/commands/commands/workflows/hg/manifest.rb +13 -0
- data/lib/amp/commands/commands/workflows/hg/merge.rb +53 -0
- data/lib/amp/commands/commands/workflows/hg/move.rb +28 -0
- data/lib/amp/commands/commands/workflows/hg/outgoing.rb +61 -0
- data/lib/amp/commands/commands/workflows/hg/pull.rb +74 -0
- data/lib/amp/commands/commands/workflows/hg/push.rb +20 -0
- data/lib/amp/commands/commands/workflows/hg/remove.rb +45 -0
- data/lib/amp/commands/commands/workflows/hg/resolve.rb +83 -0
- data/lib/amp/commands/commands/workflows/hg/revert.rb +53 -0
- data/lib/amp/commands/commands/workflows/hg/root.rb +13 -0
- data/lib/amp/commands/commands/workflows/hg/serve.rb +38 -0
- data/lib/amp/commands/commands/workflows/hg/status.rb +116 -0
- data/lib/amp/commands/commands/workflows/hg/tag.rb +69 -0
- data/lib/amp/commands/commands/workflows/hg/tags.rb +27 -0
- data/lib/amp/commands/commands/workflows/hg/tip.rb +13 -0
- data/lib/amp/commands/commands/workflows/hg/update.rb +27 -0
- data/lib/amp/commands/commands/workflows/hg/verify.rb +9 -0
- data/lib/amp/commands/commands/workflows/hg/view.rb +36 -0
- data/lib/amp/commands/dispatch.rb +181 -0
- data/lib/amp/commands/hooks.rb +81 -0
- data/lib/amp/dependencies/amp_support.rb +1 -0
- data/lib/amp/dependencies/amp_support/ruby_amp_support.rb +103 -0
- data/lib/amp/dependencies/minitar.rb +979 -0
- data/lib/amp/dependencies/priority_queue.rb +18 -0
- data/lib/amp/dependencies/priority_queue/c_priority_queue.rb +1 -0
- data/lib/amp/dependencies/priority_queue/poor_priority_queue.rb +46 -0
- data/lib/amp/dependencies/priority_queue/ruby_priority_queue.rb +525 -0
- data/lib/amp/dependencies/python_config.rb +211 -0
- data/lib/amp/dependencies/trollop.rb +713 -0
- data/lib/amp/dependencies/zip/ioextras.rb +155 -0
- data/lib/amp/dependencies/zip/stdrubyext.rb +111 -0
- data/lib/amp/dependencies/zip/tempfile_bugfixed.rb +186 -0
- data/lib/amp/dependencies/zip/zip.rb +1850 -0
- data/lib/amp/dependencies/zip/zipfilesystem.rb +609 -0
- data/lib/amp/dependencies/zip/ziprequire.rb +90 -0
- data/lib/amp/encoding/base85.rb +97 -0
- data/lib/amp/encoding/binary_diff.rb +82 -0
- data/lib/amp/encoding/difflib.rb +166 -0
- data/lib/amp/encoding/mercurial_diff.rb +378 -0
- data/lib/amp/encoding/mercurial_patch.rb +1 -0
- data/lib/amp/encoding/patch.rb +292 -0
- data/lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb +123 -0
- data/lib/amp/extensions/ditz.rb +41 -0
- data/lib/amp/extensions/lighthouse.rb +167 -0
- data/lib/amp/graphs/ancestor.rb +147 -0
- data/lib/amp/graphs/copies.rb +261 -0
- data/lib/amp/merges/merge_state.rb +164 -0
- data/lib/amp/merges/merge_ui.rb +322 -0
- data/lib/amp/merges/simple_merge.rb +450 -0
- data/lib/amp/profiling_hacks.rb +36 -0
- data/lib/amp/repository/branch_manager.rb +234 -0
- data/lib/amp/repository/dir_state.rb +950 -0
- data/lib/amp/repository/journal.rb +203 -0
- data/lib/amp/repository/lock.rb +207 -0
- data/lib/amp/repository/repositories/bundle_repository.rb +214 -0
- data/lib/amp/repository/repositories/http_repository.rb +377 -0
- data/lib/amp/repository/repositories/local_repository.rb +2661 -0
- data/lib/amp/repository/repository.rb +94 -0
- data/lib/amp/repository/store.rb +485 -0
- data/lib/amp/repository/tag_manager.rb +319 -0
- data/lib/amp/repository/updatable.rb +532 -0
- data/lib/amp/repository/verification.rb +431 -0
- data/lib/amp/repository/versioned_file.rb +475 -0
- data/lib/amp/revlogs/bundle_revlogs.rb +246 -0
- data/lib/amp/revlogs/changegroup.rb +217 -0
- data/lib/amp/revlogs/changelog.rb +338 -0
- data/lib/amp/revlogs/changeset.rb +521 -0
- data/lib/amp/revlogs/file_log.rb +165 -0
- data/lib/amp/revlogs/index.rb +493 -0
- data/lib/amp/revlogs/manifest.rb +195 -0
- data/lib/amp/revlogs/node.rb +18 -0
- data/lib/amp/revlogs/revlog.rb +1032 -0
- data/lib/amp/revlogs/revlog_support.rb +126 -0
- data/lib/amp/server/amp_user.rb +44 -0
- data/lib/amp/server/extension/amp_extension.rb +396 -0
- data/lib/amp/server/extension/authorization.rb +201 -0
- data/lib/amp/server/fancy_http_server.rb +252 -0
- data/lib/amp/server/fancy_views/_browser.haml +28 -0
- data/lib/amp/server/fancy_views/_diff_file.haml +13 -0
- data/lib/amp/server/fancy_views/_navbar.haml +17 -0
- data/lib/amp/server/fancy_views/changeset.haml +31 -0
- data/lib/amp/server/fancy_views/commits.haml +32 -0
- data/lib/amp/server/fancy_views/file.haml +35 -0
- data/lib/amp/server/fancy_views/file_diff.haml +23 -0
- data/lib/amp/server/fancy_views/harshcss/all_hallows_eve.css +72 -0
- data/lib/amp/server/fancy_views/harshcss/amy.css +147 -0
- data/lib/amp/server/fancy_views/harshcss/twilight.css +138 -0
- data/lib/amp/server/fancy_views/stylesheet.sass +175 -0
- data/lib/amp/server/http_server.rb +140 -0
- data/lib/amp/server/repo_user_management.rb +287 -0
- data/lib/amp/support/amp_config.rb +164 -0
- data/lib/amp/support/amp_ui.rb +287 -0
- data/lib/amp/support/docs.rb +54 -0
- data/lib/amp/support/generator.rb +78 -0
- data/lib/amp/support/ignore.rb +144 -0
- data/lib/amp/support/loaders.rb +93 -0
- data/lib/amp/support/logger.rb +103 -0
- data/lib/amp/support/match.rb +151 -0
- data/lib/amp/support/multi_io.rb +87 -0
- data/lib/amp/support/openers.rb +121 -0
- data/lib/amp/support/ruby_19_compatibility.rb +66 -0
- data/lib/amp/support/support.rb +1095 -0
- data/lib/amp/templates/blank.commit.erb +23 -0
- data/lib/amp/templates/blank.log.erb +18 -0
- data/lib/amp/templates/default.commit.erb +23 -0
- data/lib/amp/templates/default.log.erb +26 -0
- data/lib/amp/templates/template.rb +165 -0
- data/site/Rakefile +24 -0
- data/site/src/about/ampfile.haml +57 -0
- data/site/src/about/commands.haml +106 -0
- data/site/src/about/index.haml +33 -0
- data/site/src/about/performance.haml +31 -0
- data/site/src/about/workflows.haml +34 -0
- data/site/src/contribute/index.haml +65 -0
- data/site/src/contribute/style.haml +297 -0
- data/site/src/css/active4d.css +114 -0
- data/site/src/css/all_hallows_eve.css +72 -0
- data/site/src/css/all_themes.css +3299 -0
- data/site/src/css/amp.css +260 -0
- data/site/src/css/amy.css +147 -0
- data/site/src/css/blackboard.css +88 -0
- data/site/src/css/brilliance_black.css +605 -0
- data/site/src/css/brilliance_dull.css +599 -0
- data/site/src/css/cobalt.css +149 -0
- data/site/src/css/cur_amp.css +185 -0
- data/site/src/css/dawn.css +121 -0
- data/site/src/css/eiffel.css +121 -0
- data/site/src/css/espresso_libre.css +109 -0
- data/site/src/css/idle.css +62 -0
- data/site/src/css/iplastic.css +80 -0
- data/site/src/css/lazy.css +73 -0
- data/site/src/css/mac_classic.css +123 -0
- data/site/src/css/magicwb_amiga.css +104 -0
- data/site/src/css/pastels_on_dark.css +188 -0
- data/site/src/css/reset.css +55 -0
- data/site/src/css/slush_poppies.css +85 -0
- data/site/src/css/spacecadet.css +51 -0
- data/site/src/css/sunburst.css +180 -0
- data/site/src/css/twilight.css +137 -0
- data/site/src/css/zenburnesque.css +91 -0
- data/site/src/get/index.haml +32 -0
- data/site/src/helpers.rb +121 -0
- data/site/src/images/amp_logo.png +0 -0
- data/site/src/images/carbonica.png +0 -0
- data/site/src/images/revolution.png +0 -0
- data/site/src/images/tab-bg.png +0 -0
- data/site/src/images/tab-sliding-left.png +0 -0
- data/site/src/images/tab-sliding-right.png +0 -0
- data/site/src/include/_footer.haml +22 -0
- data/site/src/include/_header.haml +17 -0
- data/site/src/index.haml +104 -0
- data/site/src/learn/index.haml +46 -0
- data/site/src/scripts/jquery-1.3.2.min.js +19 -0
- data/site/src/scripts/jquery.cookie.js +96 -0
- data/tasks/stats.rake +155 -0
- data/tasks/yard.rake +171 -0
- data/test/dirstate_tests/dirstate +0 -0
- data/test/dirstate_tests/hgrc +5 -0
- data/test/dirstate_tests/test_dir_state.rb +192 -0
- data/test/functional_tests/resources/.hgignore +2 -0
- data/test/functional_tests/resources/STYLE.txt +25 -0
- data/test/functional_tests/resources/command.rb +372 -0
- data/test/functional_tests/resources/commands/annotate.rb +57 -0
- data/test/functional_tests/resources/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/commands/heads.rb +22 -0
- data/test/functional_tests/resources/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/commands/status.rb +90 -0
- data/test/functional_tests/resources/version2/.hgignore +5 -0
- data/test/functional_tests/resources/version2/STYLE.txt +25 -0
- data/test/functional_tests/resources/version2/command.rb +372 -0
- data/test/functional_tests/resources/version2/commands/annotate.rb +45 -0
- data/test/functional_tests/resources/version2/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/version2/commands/heads.rb +22 -0
- data/test/functional_tests/resources/version2/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/version2/commands/status.rb +90 -0
- data/test/functional_tests/resources/version3/.hgignore +5 -0
- data/test/functional_tests/resources/version3/STYLE.txt +31 -0
- data/test/functional_tests/resources/version3/command.rb +376 -0
- data/test/functional_tests/resources/version3/commands/annotate.rb +45 -0
- data/test/functional_tests/resources/version3/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/version3/commands/heads.rb +22 -0
- data/test/functional_tests/resources/version3/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/version3/commands/status.rb +90 -0
- data/test/functional_tests/resources/version4/.hgignore +5 -0
- data/test/functional_tests/resources/version4/STYLE.txt +31 -0
- data/test/functional_tests/resources/version4/command.rb +376 -0
- data/test/functional_tests/resources/version4/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/version4/commands/heads.rb +22 -0
- data/test/functional_tests/resources/version4/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/version4/commands/stats.rb +25 -0
- data/test/functional_tests/resources/version4/commands/status.rb +90 -0
- data/test/functional_tests/resources/version5_1/.hgignore +5 -0
- data/test/functional_tests/resources/version5_1/STYLE.txt +2 -0
- data/test/functional_tests/resources/version5_1/command.rb +374 -0
- data/test/functional_tests/resources/version5_1/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/version5_1/commands/heads.rb +22 -0
- data/test/functional_tests/resources/version5_1/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/version5_1/commands/stats.rb +25 -0
- data/test/functional_tests/resources/version5_1/commands/status.rb +90 -0
- data/test/functional_tests/resources/version5_2/.hgignore +5 -0
- data/test/functional_tests/resources/version5_2/STYLE.txt +14 -0
- data/test/functional_tests/resources/version5_2/command.rb +376 -0
- data/test/functional_tests/resources/version5_2/commands/experimental/lolcats.rb +17 -0
- data/test/functional_tests/resources/version5_2/commands/manifest.rb +12 -0
- data/test/functional_tests/resources/version5_2/commands/newz.rb +12 -0
- data/test/functional_tests/resources/version5_2/commands/stats.rb +25 -0
- data/test/functional_tests/resources/version5_2/commands/status.rb +90 -0
- data/test/functional_tests/test_functional.rb +604 -0
- data/test/localrepo_tests/test_local_repo.rb +121 -0
- data/test/localrepo_tests/testrepo.tar.gz +0 -0
- data/test/manifest_tests/00manifest.i +0 -0
- data/test/manifest_tests/test_manifest.rb +72 -0
- data/test/merge_tests/base.txt +10 -0
- data/test/merge_tests/expected.local.txt +16 -0
- data/test/merge_tests/local.txt +11 -0
- data/test/merge_tests/remote.txt +11 -0
- data/test/merge_tests/test_merge.rb +26 -0
- data/test/revlog_tests/00changelog.i +0 -0
- data/test/revlog_tests/revision_added_changelog.i +0 -0
- data/test/revlog_tests/test_adding_index.i +0 -0
- data/test/revlog_tests/test_revlog.rb +333 -0
- data/test/revlog_tests/testindex.i +0 -0
- data/test/store_tests/store.tar.gz +0 -0
- data/test/store_tests/test_fncache_store.rb +122 -0
- data/test/test_amp.rb +9 -0
- data/test/test_base85.rb +14 -0
- data/test/test_bdiff.rb +42 -0
- data/test/test_commands.rb +122 -0
- data/test/test_difflib.rb +50 -0
- data/test/test_helper.rb +15 -0
- data/test/test_journal.rb +29 -0
- data/test/test_match.rb +134 -0
- data/test/test_mdiff.rb +74 -0
- data/test/test_mpatch.rb +14 -0
- data/test/test_support.rb +24 -0
- metadata +385 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
module Amp
|
|
2
|
+
module Bundles
|
|
3
|
+
##
|
|
4
|
+
# This module handles revlogs passed to our client (or server)
|
|
5
|
+
# through the bundle file format. Thing is, this revision log
|
|
6
|
+
# spans both a physical filelog, and a bundle (the new revisions),
|
|
7
|
+
# and we might need to get stuff from both. It's kind of like the
|
|
8
|
+
# DelayedOpener/FakeAppender for changelogs.
|
|
9
|
+
module BundleRevlog
|
|
10
|
+
include RevlogSupport::Node
|
|
11
|
+
BUNDLED_INDEX_ENTRY_SIZE = 80
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# Initializes a bundle revlog. Takes, in addition to the normal
|
|
15
|
+
# revlog arguments, a bundle_file. This is any IO we can read
|
|
16
|
+
# from that will give us additional revisions, aside from the
|
|
17
|
+
# revisions stored in the real Revlog. It also takes a link_mapper
|
|
18
|
+
# that will connect things to the changelog revisions (including
|
|
19
|
+
# changelog revisions in the bundle).
|
|
20
|
+
#
|
|
21
|
+
# @param [Opener] opener the opener to use for openinf up the index_file
|
|
22
|
+
# @param [String] index_file the name of the file containing the revlog's
|
|
23
|
+
# index
|
|
24
|
+
# @param [IO] bundle_file an IO that we can #read from
|
|
25
|
+
# @param [Proc, #call] link_mapper a function that will give us the link-index
|
|
26
|
+
# to connect revisions to changelog revisions based on node_ids
|
|
27
|
+
def bundle_initialize(opener, index_file, bundle_file, link_mapper = nil)
|
|
28
|
+
@bundle_file = bundle_file
|
|
29
|
+
@base_map = {}
|
|
30
|
+
|
|
31
|
+
num_revs = self.index_size
|
|
32
|
+
previous = nil
|
|
33
|
+
all_chunk_positions do |chunk, start|
|
|
34
|
+
chunk_size = chunk.size
|
|
35
|
+
|
|
36
|
+
# each chunk starts with 4 node IDs: the new node's ID, its 2 parent node IDs,
|
|
37
|
+
# and the node ID of the corresponding revision in the changelog. In that order.
|
|
38
|
+
# If we have less than 80 bytes (BUNDLED_INDEX_ENTRY_SIZE), then we're fucked.
|
|
39
|
+
if chunk_size < BUNDLED_INDEX_ENTRY_SIZE
|
|
40
|
+
raise abort("invalid changegroup")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
start += BUNDLED_INDEX_ENTRY_SIZE
|
|
44
|
+
chunk_size -= BUNDLED_INDEX_ENTRY_SIZE
|
|
45
|
+
|
|
46
|
+
# Get the aforementioned node IDs
|
|
47
|
+
node, parent_1, parent_2, changeset = chunk[0..79].unpack("a20a20a20a20")
|
|
48
|
+
|
|
49
|
+
# Do we already have this node? Skip it.
|
|
50
|
+
if @index.has_node? node
|
|
51
|
+
previous = node
|
|
52
|
+
next
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# make sure we have the new node's parents, or all of our operations will fail!
|
|
56
|
+
# at least, the interesting ones.
|
|
57
|
+
[parent_1, parent_2].each do |parent|
|
|
58
|
+
unless @index.has_node? parent
|
|
59
|
+
raise abort("Unknown parent: #{parent}@#{index_file}")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
link_rev = (link_mapper && link_mapper[changeset]) || num_revs
|
|
64
|
+
previous ||= parent_1
|
|
65
|
+
|
|
66
|
+
@index << [RevlogSupport::Support.offset_version(start, 0), chunk_size, -1, -1, link_rev,
|
|
67
|
+
revision_index_for_node(parent_1), revision_index_for_node(parent_2),
|
|
68
|
+
node]
|
|
69
|
+
|
|
70
|
+
@index.node_map[node] = num_revs
|
|
71
|
+
@base_map[num_revs] = previous
|
|
72
|
+
|
|
73
|
+
previous = node
|
|
74
|
+
num_revs += 1
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
alias_method :bundle_revlog_initialize, :initialize
|
|
78
|
+
##
|
|
79
|
+
# Returns whether the revision index is in the bundle part of this revlog,
|
|
80
|
+
# or if it's in the actual, stored revlog file.
|
|
81
|
+
#
|
|
82
|
+
# @param [Fixnum] revision the revision index to lookup
|
|
83
|
+
# @return [Boolean] is the revision in the bundle section?
|
|
84
|
+
def bundled_revision?(revision)
|
|
85
|
+
return false if revision < 0
|
|
86
|
+
!!@base_map[revision]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
# Returns the base revision for the revision at the given index, while being
|
|
91
|
+
# cognizant of the bundle-ness of this revlog.
|
|
92
|
+
#
|
|
93
|
+
# @param [Fixnum] revision the revision index to lookup the base-revision of
|
|
94
|
+
# @return [String] the revision node ID of the base for the requested revision
|
|
95
|
+
def bundled_base_revision_for_index(revision)
|
|
96
|
+
@base_map[revision] || base_revision_for_index(revision)
|
|
97
|
+
end
|
|
98
|
+
alias_method :bundled_base, :bundled_base_revision_for_index
|
|
99
|
+
|
|
100
|
+
##
|
|
101
|
+
# Gets a chunk of data from the datafile (or, if inline, from the index
|
|
102
|
+
# file). Just give it a revision index and which data file to use. Only difference
|
|
103
|
+
# is that this will check the bundlefile if necessary.
|
|
104
|
+
#
|
|
105
|
+
# @param [Fixnum] rev the revision index to extract
|
|
106
|
+
# @param [IO] data_file The IO file descriptor for loading data
|
|
107
|
+
# @return [String] the raw data from the index (posssibly compressed)
|
|
108
|
+
def get_chunk(revision, datafile=nil, cache_len = 4096)
|
|
109
|
+
# Warning: in case of bundle, the diff is against bundlebase, not against
|
|
110
|
+
# rev - 1
|
|
111
|
+
# TODO: could use some caching
|
|
112
|
+
unless bundled_revision?(revision)
|
|
113
|
+
return super(revision, datafile)
|
|
114
|
+
end
|
|
115
|
+
@bundle_file.seek data_start_for_index(revision)
|
|
116
|
+
@bundle_file.read self[revision].compressed_len
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
##
|
|
120
|
+
# Diffs 2 revisions, based on their indices. They are returned in
|
|
121
|
+
# BinaryDiff format.
|
|
122
|
+
#
|
|
123
|
+
# @param [Fixnum] rev1 the index of the source revision
|
|
124
|
+
# @param [Fixnum] rev2 the index of the destination revision
|
|
125
|
+
# @return [String] The diff of the 2 revisions.
|
|
126
|
+
def revision_diff(rev1, rev2)
|
|
127
|
+
both_bundled = bundled_revision?(rev1) && bundled_revision?(rev2)
|
|
128
|
+
if both_bundled
|
|
129
|
+
# super-quick path if both are bundled and rev2 == rev1 + 1 diff
|
|
130
|
+
revision_base = self.revision_index_for_node bundled_base_revision_for_index(rev2)
|
|
131
|
+
if revision_base == rev1
|
|
132
|
+
# if rev2 = rev1 + a diff, just get the diff!
|
|
133
|
+
return get_chunk(revision2)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
# normal style
|
|
137
|
+
return super(rev1, rev2)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
##
|
|
141
|
+
# Given a node ID, extracts that revision and decompresses it. What you get
|
|
142
|
+
# back will the pristine revision data! Checks for bundle-ness when we access
|
|
143
|
+
# a node.
|
|
144
|
+
#
|
|
145
|
+
# @param [String] node the Node ID of the revision to extract.
|
|
146
|
+
# @return [String] the pristine revision data.
|
|
147
|
+
def decompress_revision(node)
|
|
148
|
+
return "" if node == NULL_ID
|
|
149
|
+
|
|
150
|
+
text = nil
|
|
151
|
+
chain = []
|
|
152
|
+
iter_node = node
|
|
153
|
+
rev = revision_index_for_node(node)
|
|
154
|
+
# walk backwards down the chain. Every single node is going
|
|
155
|
+
# to be a diff, because it's from a bundle.
|
|
156
|
+
while bundled_revision? rev
|
|
157
|
+
if @index.cache && @index.cache[0] == iter_node
|
|
158
|
+
text = @index.cache[2]
|
|
159
|
+
break
|
|
160
|
+
end
|
|
161
|
+
chain << rev
|
|
162
|
+
iter_node = bundled_base_revision_for_index rev
|
|
163
|
+
rev = revision_index_for_node iter_node
|
|
164
|
+
end
|
|
165
|
+
# done walking back, see if we have a stored cache!
|
|
166
|
+
text = super(iter_node) if text.nil? || text.empty?
|
|
167
|
+
|
|
168
|
+
while chain.any?
|
|
169
|
+
delta = get_chunk(chain.pop)
|
|
170
|
+
text = Diffs::MercurialPatch.apply_patches(text, [delta])
|
|
171
|
+
end
|
|
172
|
+
p1, p2 = parents_for_node node
|
|
173
|
+
|
|
174
|
+
if node != RevlogSupport::Support.history_hash(text, p1, p2)
|
|
175
|
+
raise RevlogSupport::RevlogError.new("integrity check failed on %s:%d, data:%s" %
|
|
176
|
+
[(@index.inline? ? @index_file : @data_file), rev(node), text.inspect])
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
@index.cache = [node, revision_index_for_node(node), text]
|
|
180
|
+
text
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
##
|
|
184
|
+
# Give an error to enforce read-only behavior
|
|
185
|
+
def add_revision(text, transaction, link, p1, p2, d=nil, index_file_handle = nil)
|
|
186
|
+
raise NotImplementedError.new
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
##
|
|
190
|
+
# Give an error to enforce read-only behavior
|
|
191
|
+
def add_group(revisions, link_mapper, journal)
|
|
192
|
+
raise NotImplementedError.new
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
private
|
|
197
|
+
|
|
198
|
+
def all_chunk_positions
|
|
199
|
+
results = []
|
|
200
|
+
RevlogSupport::ChangeGroup.each_chunk(@bundle_file) do |chunk|
|
|
201
|
+
if block_given?
|
|
202
|
+
yield(chunk, @bundle_file.tell - chunk.size)
|
|
203
|
+
else
|
|
204
|
+
results << [chunk, @bundle_file.tell - chunk.size]
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
results unless block_given?
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
class BundleChangeLog < ChangeLog
|
|
212
|
+
include BundleRevlog
|
|
213
|
+
def initialize(opener, bundle_file)
|
|
214
|
+
# This is the changelog initializer
|
|
215
|
+
super(opener)
|
|
216
|
+
# This is the bundle initializer
|
|
217
|
+
bundle_initialize(opener, @index_file, bundle_file)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
class BundleManifest < Manifest
|
|
222
|
+
include BundleRevlog
|
|
223
|
+
|
|
224
|
+
def initialize(opener, bundle_file, link_mapper)
|
|
225
|
+
# This is the manifest initializer
|
|
226
|
+
super(opener)
|
|
227
|
+
# This is the bundle initializer
|
|
228
|
+
bundle_initialize(opener, @index_file, bundle_file, link_mapper)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
class BundleFileLog < FileLog
|
|
234
|
+
include BundleRevlog
|
|
235
|
+
|
|
236
|
+
def initialize(opener, path, bundle_file, link_mapper)
|
|
237
|
+
# This is the manifest initializer
|
|
238
|
+
super(opener, path)
|
|
239
|
+
# This is the bundle initializer
|
|
240
|
+
bundle_initialize(opener, @index_file, bundle_file, link_mapper)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
end
|
|
246
|
+
end
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
require 'tempfile'
|
|
2
|
+
module Amp
|
|
3
|
+
module RevlogSupport
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class handles changegroups - most specifically, packaging up a bunch
|
|
7
|
+
# of revisions into a single bundled file.
|
|
8
|
+
#
|
|
9
|
+
module ChangeGroup
|
|
10
|
+
BUNDLE_HEADERS = {
|
|
11
|
+
"" => "",
|
|
12
|
+
"HG10UN" => "HG10UN",
|
|
13
|
+
"HG10BZ" => "HG10",
|
|
14
|
+
"HG10GZ" => "HG10GZ"
|
|
15
|
+
}
|
|
16
|
+
FORMAT_PRIORITIES = BUNDLE_TYPES = ["HG10GZ", "HG10BZ", "HG10UN"]
|
|
17
|
+
class ChangeGroupError < StandardError; end
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Loads a single chunk of data from a changegroup. Each chunk is stored in the
|
|
21
|
+
# changegroup as:
|
|
22
|
+
# (uint32_t) length <-- less than 4 if we should terminate
|
|
23
|
+
# (length * char) body
|
|
24
|
+
# Example:
|
|
25
|
+
# 00 00 00 05 h e l l o
|
|
26
|
+
#
|
|
27
|
+
# @param [IO, #read] source the source stream with all the data that we'll be
|
|
28
|
+
# working on.
|
|
29
|
+
# @return [String] the data read in. Will be either nil or the empty string if
|
|
30
|
+
# no data was read.
|
|
31
|
+
def self.get_chunk(source)
|
|
32
|
+
data = source.read 4
|
|
33
|
+
return "" if data.nil? || data.empty?
|
|
34
|
+
l = data.unpack("N")[0]
|
|
35
|
+
return "" if l <= 4
|
|
36
|
+
data = source.read(l - 4)
|
|
37
|
+
if data.size < l - 4
|
|
38
|
+
raise ChangeGroupError.new("premature EOF when reading changegroup:" +
|
|
39
|
+
"(got #{data.size} bytes, expected #{l-4})")
|
|
40
|
+
end
|
|
41
|
+
return data
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
# Loads each chunk, in a row, until we run out of chunks in the changegroup.
|
|
46
|
+
# Yields the data to the caller. This will run until we hit a terminating chunk.
|
|
47
|
+
#
|
|
48
|
+
# @param [IO, #read] source The stream from which we will read the data in sequence
|
|
49
|
+
# @yield Each chunk of data will be yielded to be processed
|
|
50
|
+
# @yieldparam [String] chunk the chunk that is yielded
|
|
51
|
+
def self.each_chunk(source)
|
|
52
|
+
begin
|
|
53
|
+
c = self.get_chunk(source) # get a chunk
|
|
54
|
+
yield c unless c.empty? # yield if not empty
|
|
55
|
+
end until c.empty? # keep going if we have more!
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
##
|
|
59
|
+
# If we have data of size +size+, then return the encoded header for the chunk
|
|
60
|
+
#
|
|
61
|
+
# @param [Integer] size the size of the chunk we wish to encode
|
|
62
|
+
# @return [String] the encoded header for the chunk
|
|
63
|
+
def self.chunk_header(size)
|
|
64
|
+
[size + 4].pack("N")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
##
|
|
68
|
+
# The terminating chunk that indicates the end of a chunk sequence
|
|
69
|
+
#
|
|
70
|
+
# @return [String] the encoded terminating chunk
|
|
71
|
+
def self.closing_chunk
|
|
72
|
+
"\000\000\000\000" # [0].pack("N")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
##
|
|
76
|
+
# Returns a compressing stream based on the header for a changegroup bundle.
|
|
77
|
+
# The bundle header will specify that the contents should be either uncompressed,
|
|
78
|
+
# BZip compressed, or GZip compressed. This will return a stream that responds
|
|
79
|
+
# to #<< and #flush, where #flush will return the unread, decompressed data,
|
|
80
|
+
# and #<< will input uncompressed data.
|
|
81
|
+
#
|
|
82
|
+
# @param [String] header the header for the changegroup bundle. Can be either
|
|
83
|
+
# HG10UN, HG10GZ, or HG10BZ, or HG10.
|
|
84
|
+
# @return [IO, #<<, #flush] an IO stream that accepts uncompressed data via #<< or
|
|
85
|
+
# #write, and returns compressed data by #flush.
|
|
86
|
+
def self.compressor_by_type(header)
|
|
87
|
+
case header
|
|
88
|
+
when "HG10UN", ""
|
|
89
|
+
# new StringIO
|
|
90
|
+
result = StringIO.new "",(ruby_19? ? "w+:ASCII-8BIT" : "w+")
|
|
91
|
+
# have to fix the fact that StringIO doesn't conform to the other streams,
|
|
92
|
+
# and give it a #flush method. Kind of hackish.
|
|
93
|
+
class << result
|
|
94
|
+
def flush
|
|
95
|
+
ret = self.string.dup # get the current read-in string
|
|
96
|
+
self.string.replace "" # erase our contents
|
|
97
|
+
self.rewind # rewind the IO
|
|
98
|
+
self.tell
|
|
99
|
+
ret # return the string
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
#return the altered StringIO
|
|
103
|
+
result
|
|
104
|
+
when "HG10GZ"
|
|
105
|
+
# lazy-load Zlib
|
|
106
|
+
require 'zlib'
|
|
107
|
+
# Return a deflating stream (compressor)
|
|
108
|
+
Zlib::Deflate.new
|
|
109
|
+
when "HG10BZ", "HG10"
|
|
110
|
+
# lazy load BZip
|
|
111
|
+
need { '../../../ext/amp/bz2/bz2' }
|
|
112
|
+
# Return a compressing BZip stream
|
|
113
|
+
BZ2::Writer.new
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
##
|
|
118
|
+
# Returns a stream that will decompress the IO pointed to by file_handle,
|
|
119
|
+
# when #read is called upon it. Note: file_handle doesn't have to be a file!
|
|
120
|
+
#
|
|
121
|
+
# @param [String] header the header of the stream. Specifies which compression
|
|
122
|
+
# to handle
|
|
123
|
+
# @param [IO, #read] file_handle the input stream that will provide the compressed
|
|
124
|
+
# data.
|
|
125
|
+
# @return [IO, #read] an IO object that we can #read to get uncompressed data
|
|
126
|
+
def self.unbundle(header, file_handle)
|
|
127
|
+
# uncompressed? just return the input IO!
|
|
128
|
+
return file_handle if header == "HG10UN"
|
|
129
|
+
# if we have no header, we're uncompressed
|
|
130
|
+
if !header.start_with?("HG")
|
|
131
|
+
# append the header to it. meh
|
|
132
|
+
headerio = StringIO.new(header, (ruby_19? ? "w+:ASCII-8BIT" : "w+"))
|
|
133
|
+
Amp::Support::MultiIO.new(headerio, file_handle)
|
|
134
|
+
# WOW we have legacy support already
|
|
135
|
+
elsif header == "HG10GZ"
|
|
136
|
+
# Get a gzip reader
|
|
137
|
+
Zlib::GzipReader.new(file_handle)
|
|
138
|
+
elsif header == "HG10BZ"
|
|
139
|
+
# get a BZip reader, but it has to decompress "BZ" first. Meh.
|
|
140
|
+
headerio = StringIO.new("BZ", (ruby_19? ? "w+:ASCII-8BIT" : "w+"))
|
|
141
|
+
input = Amp::Support::MultiIO.new(headerio, file_handle)
|
|
142
|
+
BZ2::Reader.new(input)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
##
|
|
147
|
+
# Writes a set of changegroups to a bundle. If no IO is specified, a new StringIO
|
|
148
|
+
# is created, and the bundle is written to that (i.e., memory). the IO used is returned.
|
|
149
|
+
#
|
|
150
|
+
# @param [IO, #read, #seek] changegroup A stream that will feed in an uncompressed
|
|
151
|
+
# changegroup
|
|
152
|
+
# @param [String] bundletype A specified compression type - either "HG10UN", "HG10GZ",
|
|
153
|
+
# or "HG10BZ". The empty string defaults to "HG10UN".
|
|
154
|
+
# @param [IO, #write] fh (StringIO.new) An output stream to write to, such as a File
|
|
155
|
+
# or a socket. If not specified, a StringIO is created and returned.
|
|
156
|
+
# @return [IO, #write] the output IO stream is returned, even if a new one is not
|
|
157
|
+
# created on the fly.
|
|
158
|
+
def self.write_bundle(changegroup, bundletype, fh = StringIO.new("", (ruby_19? ? "w+:ASCII-8BIT" : "w+")))
|
|
159
|
+
# rewind the changegroup to start at the beginning
|
|
160
|
+
changegroup.rewind
|
|
161
|
+
# pick out our header
|
|
162
|
+
header = BUNDLE_HEADERS[bundletype]
|
|
163
|
+
# get a compressing stream
|
|
164
|
+
compressor = compressor_by_type header
|
|
165
|
+
# output the header (uncompressed)
|
|
166
|
+
fh.write header
|
|
167
|
+
|
|
168
|
+
# These 2 variables are for checking to see if #changegroup has been fully
|
|
169
|
+
# read in or not.
|
|
170
|
+
empty = false
|
|
171
|
+
count = 0
|
|
172
|
+
|
|
173
|
+
# Do at least 2 changegroups (changelog + manifest), then go until we're empty
|
|
174
|
+
while !empty || count <= 2
|
|
175
|
+
# Set empty to true for this particular file (each iteration of this loop
|
|
176
|
+
# represents compressing 1 file's changesets into changegroups in the bundle)
|
|
177
|
+
empty = true
|
|
178
|
+
# Add 1 to the number of files we've comrpessed
|
|
179
|
+
count += 1
|
|
180
|
+
# For each chunk in the changegroup (i.e. each changeset)
|
|
181
|
+
inner_count = 0
|
|
182
|
+
self.each_chunk(changegroup) do |chunk|
|
|
183
|
+
|
|
184
|
+
#puts "\t\twrite_bundle inner loop count #{inner_count}"
|
|
185
|
+
inner_count += 1
|
|
186
|
+
empty = false
|
|
187
|
+
# Compress the chunk header
|
|
188
|
+
compressor << chunk_header(chunk.size)
|
|
189
|
+
# Write the chunk header
|
|
190
|
+
fh.write(compressor.flush)
|
|
191
|
+
|
|
192
|
+
# compress the actual chunk 1 megabyte at a time
|
|
193
|
+
step_amt = 1048576
|
|
194
|
+
(0..chunk.size).step(step_amt) do |pos|
|
|
195
|
+
compressor << chunk[pos..(pos+step_amt-1)]
|
|
196
|
+
fh.write(compressor.flush)
|
|
197
|
+
fh.flush
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
# Compress the terminating chunk - this indicates that there are no more changesets
|
|
201
|
+
# for the current file
|
|
202
|
+
compressor << closing_chunk
|
|
203
|
+
# Write the terminating chunk out!
|
|
204
|
+
fh.write compressor.flush
|
|
205
|
+
fh.flush
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Write anything left over in that there compressor
|
|
209
|
+
fh.write compressor.flush
|
|
210
|
+
# Kill the compressor
|
|
211
|
+
compressor.close
|
|
212
|
+
# Return the IO we wrote to (in case we instantiated it)
|
|
213
|
+
return fh
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|