amp 0.5.2 → 0.5.3
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 +12 -0
- data/.hgignore +3 -0
- data/AUTHORS +1 -1
- data/Manifest.txt +99 -38
- data/README.md +3 -3
- data/Rakefile +53 -18
- data/SCHEDULE.markdown +5 -1
- data/TODO.markdown +120 -149
- data/ampfile.rb +3 -1
- data/bin/amp +4 -1
- data/ext/amp/bz2/extconf.rb +1 -1
- data/ext/amp/mercurial_patch/extconf.rb +1 -1
- data/ext/amp/mercurial_patch/mpatch.c +4 -3
- data/ext/amp/priority_queue/extconf.rb +1 -1
- data/ext/amp/support/extconf.rb +1 -1
- data/ext/amp/support/support.c +1 -1
- data/lib/amp.rb +125 -67
- data/lib/amp/commands/command.rb +12 -10
- data/lib/amp/commands/command_support.rb +8 -1
- data/lib/amp/commands/commands/help.rb +2 -20
- data/lib/amp/commands/commands/init.rb +14 -2
- data/lib/amp/commands/commands/templates.rb +6 -4
- data/lib/amp/commands/commands/version.rb +15 -1
- data/lib/amp/commands/commands/workflow.rb +3 -3
- data/lib/amp/commands/commands/workflows/git/add.rb +3 -3
- data/lib/amp/commands/commands/workflows/git/copy.rb +1 -1
- data/lib/amp/commands/commands/workflows/git/rm.rb +4 -2
- data/lib/amp/commands/commands/workflows/hg/add.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/addremove.rb +2 -2
- data/lib/amp/commands/commands/workflows/hg/annotate.rb +8 -2
- data/lib/amp/commands/commands/workflows/hg/bisect.rb +253 -0
- data/lib/amp/commands/commands/workflows/hg/branch.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/branches.rb +3 -3
- data/lib/amp/commands/commands/workflows/hg/bundle.rb +3 -3
- data/lib/amp/commands/commands/workflows/hg/clone.rb +4 -5
- data/lib/amp/commands/commands/workflows/hg/commit.rb +37 -1
- data/lib/amp/commands/commands/workflows/hg/copy.rb +2 -1
- data/lib/amp/commands/commands/workflows/hg/debug/index.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/diff.rb +3 -8
- data/lib/amp/commands/commands/workflows/hg/forget.rb +5 -4
- data/lib/amp/commands/commands/workflows/hg/identify.rb +6 -6
- data/lib/amp/commands/commands/workflows/hg/import.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/incoming.rb +2 -2
- data/lib/amp/commands/commands/workflows/hg/log.rb +5 -4
- data/lib/amp/commands/commands/workflows/hg/merge.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/move.rb +5 -3
- data/lib/amp/commands/commands/workflows/hg/outgoing.rb +1 -1
- data/lib/amp/commands/commands/workflows/hg/push.rb +6 -7
- data/lib/amp/commands/commands/workflows/hg/remove.rb +2 -2
- data/lib/amp/commands/commands/workflows/hg/resolve.rb +6 -23
- data/lib/amp/commands/commands/workflows/hg/root.rb +1 -2
- data/lib/amp/commands/commands/workflows/hg/status.rb +21 -12
- data/lib/amp/commands/commands/workflows/hg/tag.rb +2 -2
- data/lib/amp/commands/commands/workflows/hg/untrack.rb +12 -0
- data/lib/amp/commands/commands/workflows/hg/verify.rb +13 -3
- data/lib/amp/commands/commands/workflows/hg/what_changed.rb +18 -0
- data/lib/amp/commands/dispatch.rb +12 -13
- data/lib/amp/dependencies/amp_support.rb +1 -1
- data/lib/amp/dependencies/amp_support/ruby_amp_support.rb +1 -0
- data/lib/amp/dependencies/maruku.rb +136 -0
- data/lib/amp/dependencies/maruku/attributes.rb +227 -0
- data/lib/amp/dependencies/maruku/defaults.rb +71 -0
- data/lib/amp/dependencies/maruku/errors_management.rb +92 -0
- data/lib/amp/dependencies/maruku/helpers.rb +260 -0
- data/lib/amp/dependencies/maruku/input/charsource.rb +326 -0
- data/lib/amp/dependencies/maruku/input/extensions.rb +69 -0
- data/lib/amp/dependencies/maruku/input/html_helper.rb +189 -0
- data/lib/amp/dependencies/maruku/input/linesource.rb +111 -0
- data/lib/amp/dependencies/maruku/input/parse_block.rb +615 -0
- data/lib/amp/dependencies/maruku/input/parse_doc.rb +234 -0
- data/lib/amp/dependencies/maruku/input/parse_span_better.rb +746 -0
- data/lib/amp/dependencies/maruku/input/rubypants.rb +225 -0
- data/lib/amp/dependencies/maruku/input/type_detection.rb +147 -0
- data/lib/amp/dependencies/maruku/input_textile2/t2_parser.rb +163 -0
- data/lib/amp/dependencies/maruku/maruku.rb +33 -0
- data/lib/amp/dependencies/maruku/output/to_ansi.rb +223 -0
- data/lib/amp/dependencies/maruku/output/to_html.rb +991 -0
- data/lib/amp/dependencies/maruku/output/to_markdown.rb +164 -0
- data/lib/amp/dependencies/maruku/output/to_s.rb +56 -0
- data/lib/amp/dependencies/maruku/string_utils.rb +191 -0
- data/lib/amp/dependencies/maruku/structures.rb +167 -0
- data/lib/amp/dependencies/maruku/structures_inspect.rb +87 -0
- data/lib/amp/dependencies/maruku/structures_iterators.rb +61 -0
- data/lib/amp/dependencies/maruku/textile2.rb +1 -0
- data/lib/amp/dependencies/maruku/toc.rb +199 -0
- data/lib/amp/dependencies/maruku/usage/example1.rb +33 -0
- data/lib/amp/dependencies/maruku/version.rb +40 -0
- data/lib/amp/dependencies/priority_queue.rb +2 -1
- data/lib/amp/dependencies/python_config.rb +2 -1
- data/lib/amp/graphs/ancestor.rb +2 -1
- data/lib/amp/graphs/copies.rb +236 -233
- data/lib/amp/help/entries/__default__.erb +31 -0
- data/lib/amp/help/entries/commands.erb +6 -0
- data/lib/amp/help/entries/mdtest.md +35 -0
- data/lib/amp/help/entries/silly +3 -0
- data/lib/amp/help/help.rb +288 -0
- data/lib/amp/profiling_hacks.rb +5 -3
- data/lib/amp/repository/abstract/abstract_changeset.rb +97 -0
- data/lib/amp/repository/abstract/abstract_local_repo.rb +181 -0
- data/lib/amp/repository/abstract/abstract_staging_area.rb +180 -0
- data/lib/amp/repository/abstract/abstract_versioned_file.rb +100 -0
- data/lib/amp/repository/abstract/common_methods/changeset.rb +75 -0
- data/lib/amp/repository/abstract/common_methods/local_repo.rb +277 -0
- data/lib/amp/repository/abstract/common_methods/staging_area.rb +233 -0
- data/lib/amp/repository/abstract/common_methods/versioned_file.rb +71 -0
- data/lib/amp/repository/generic_repo_picker.rb +78 -0
- data/lib/amp/repository/git/repo_format/changeset.rb +336 -0
- data/lib/amp/repository/git/repo_format/staging_area.rb +192 -0
- data/lib/amp/repository/git/repo_format/versioned_file.rb +119 -0
- data/lib/amp/repository/git/repositories/local_repository.rb +164 -0
- data/lib/amp/repository/git/repository.rb +41 -0
- data/lib/amp/repository/mercurial/encoding/mercurial_diff.rb +382 -0
- data/lib/amp/repository/mercurial/encoding/mercurial_patch.rb +1 -0
- data/lib/amp/repository/mercurial/encoding/patch.rb +294 -0
- data/lib/amp/repository/mercurial/encoding/pure_ruby/ruby_mercurial_patch.rb +124 -0
- data/lib/amp/repository/mercurial/merging/merge_ui.rb +327 -0
- data/lib/amp/repository/mercurial/merging/simple_merge.rb +452 -0
- data/lib/amp/repository/mercurial/repo_format/branch_manager.rb +266 -0
- data/lib/amp/repository/mercurial/repo_format/changeset.rb +768 -0
- data/lib/amp/repository/mercurial/repo_format/dir_state.rb +716 -0
- data/lib/amp/repository/mercurial/repo_format/journal.rb +218 -0
- data/lib/amp/repository/mercurial/repo_format/lock.rb +210 -0
- data/lib/amp/repository/mercurial/repo_format/merge_state.rb +228 -0
- data/lib/amp/repository/mercurial/repo_format/staging_area.rb +367 -0
- data/lib/amp/repository/mercurial/repo_format/store.rb +487 -0
- data/lib/amp/repository/mercurial/repo_format/tag_manager.rb +322 -0
- data/lib/amp/repository/mercurial/repo_format/updatable.rb +543 -0
- data/lib/amp/repository/mercurial/repo_format/updater.rb +848 -0
- data/lib/amp/repository/mercurial/repo_format/verification.rb +433 -0
- data/lib/amp/repository/mercurial/repositories/bundle_repository.rb +216 -0
- data/lib/amp/repository/mercurial/repositories/http_repository.rb +386 -0
- data/lib/amp/repository/mercurial/repositories/local_repository.rb +2034 -0
- data/lib/amp/repository/mercurial/repository.rb +119 -0
- data/lib/amp/repository/mercurial/revlogs/bundle_revlogs.rb +249 -0
- data/lib/amp/repository/mercurial/revlogs/changegroup.rb +217 -0
- data/lib/amp/repository/mercurial/revlogs/changelog.rb +339 -0
- data/lib/amp/repository/mercurial/revlogs/file_log.rb +152 -0
- data/lib/amp/repository/mercurial/revlogs/index.rb +500 -0
- data/lib/amp/repository/mercurial/revlogs/manifest.rb +201 -0
- data/lib/amp/repository/mercurial/revlogs/node.rb +20 -0
- data/lib/amp/repository/mercurial/revlogs/revlog.rb +1026 -0
- data/lib/amp/repository/mercurial/revlogs/revlog_support.rb +129 -0
- data/lib/amp/repository/mercurial/revlogs/versioned_file.rb +597 -0
- data/lib/amp/repository/repository.rb +11 -88
- data/lib/amp/server/extension/amp_extension.rb +3 -3
- data/lib/amp/server/fancy_http_server.rb +1 -1
- data/lib/amp/server/fancy_views/_browser.haml +1 -1
- data/lib/amp/server/fancy_views/_diff_file.haml +1 -8
- data/lib/amp/server/fancy_views/changeset.haml +2 -2
- data/lib/amp/server/fancy_views/file.haml +1 -1
- data/lib/amp/server/fancy_views/file_diff.haml +1 -1
- data/lib/amp/support/amp_ui.rb +13 -29
- data/lib/amp/support/generator.rb +1 -1
- data/lib/amp/support/loaders.rb +1 -2
- data/lib/amp/support/logger.rb +10 -16
- data/lib/amp/support/match.rb +18 -4
- data/lib/amp/support/mercurial/ignore.rb +151 -0
- data/lib/amp/support/openers.rb +8 -3
- data/lib/amp/support/support.rb +91 -46
- data/lib/amp/templates/{blank.commit.erb → mercurial/blank.commit.erb} +0 -0
- data/lib/amp/templates/{blank.log.erb → mercurial/blank.log.erb} +0 -0
- data/lib/amp/templates/{default.commit.erb → mercurial/default.commit.erb} +0 -0
- data/lib/amp/templates/{default.log.erb → mercurial/default.log.erb} +0 -0
- data/lib/amp/templates/template.rb +18 -18
- data/man/amp.1 +51 -0
- data/site/src/about/commands.haml +1 -1
- data/site/src/css/amp.css +1 -1
- data/site/src/index.haml +3 -3
- data/tasks/man.rake +39 -0
- data/tasks/stats.rake +1 -10
- data/tasks/yard.rake +1 -50
- data/test/dirstate_tests/test_dir_state.rb +10 -8
- data/test/functional_tests/annotate.out +31 -0
- data/test/functional_tests/test_functional.rb +155 -63
- data/test/localrepo_tests/ampfile.rb +12 -0
- data/test/localrepo_tests/test_local_repo.rb +56 -57
- data/test/manifest_tests/test_manifest.rb +3 -5
- data/test/merge_tests/test_merge.rb +3 -3
- data/test/revlog_tests/test_revlog.rb +14 -6
- data/test/store_tests/test_fncache_store.rb +19 -19
- data/test/test_19_compatibility.rb +46 -0
- data/test/test_base85.rb +2 -2
- data/test/test_bdiff.rb +2 -2
- data/test/test_changegroup.rb +59 -0
- data/test/test_commands.rb +2 -2
- data/test/test_difflib.rb +2 -2
- data/test/test_generator.rb +34 -0
- data/test/test_ignore.rb +203 -0
- data/test/test_journal.rb +18 -13
- data/test/test_match.rb +2 -2
- data/test/test_mdiff.rb +3 -3
- data/test/test_mpatch.rb +3 -3
- data/test/test_multi_io.rb +40 -0
- data/test/test_support.rb +18 -2
- data/test/test_templates.rb +38 -0
- data/test/test_ui.rb +79 -0
- data/test/testutilities.rb +56 -0
- metadata +168 -49
- data/ext/amp/bz2/mkmf.log +0 -38
- data/lib/amp/encoding/mercurial_diff.rb +0 -378
- data/lib/amp/encoding/mercurial_patch.rb +0 -1
- data/lib/amp/encoding/patch.rb +0 -292
- data/lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb +0 -123
- data/lib/amp/merges/merge_state.rb +0 -164
- data/lib/amp/merges/merge_ui.rb +0 -322
- data/lib/amp/merges/simple_merge.rb +0 -450
- data/lib/amp/repository/branch_manager.rb +0 -234
- data/lib/amp/repository/dir_state.rb +0 -950
- data/lib/amp/repository/journal.rb +0 -203
- data/lib/amp/repository/lock.rb +0 -207
- data/lib/amp/repository/repositories/bundle_repository.rb +0 -214
- data/lib/amp/repository/repositories/http_repository.rb +0 -377
- data/lib/amp/repository/repositories/local_repository.rb +0 -2661
- data/lib/amp/repository/store.rb +0 -485
- data/lib/amp/repository/tag_manager.rb +0 -319
- data/lib/amp/repository/updatable.rb +0 -532
- data/lib/amp/repository/verification.rb +0 -431
- data/lib/amp/repository/versioned_file.rb +0 -475
- data/lib/amp/revlogs/bundle_revlogs.rb +0 -246
- data/lib/amp/revlogs/changegroup.rb +0 -217
- data/lib/amp/revlogs/changelog.rb +0 -338
- data/lib/amp/revlogs/changeset.rb +0 -521
- data/lib/amp/revlogs/file_log.rb +0 -165
- data/lib/amp/revlogs/index.rb +0 -493
- data/lib/amp/revlogs/manifest.rb +0 -195
- data/lib/amp/revlogs/node.rb +0 -18
- data/lib/amp/revlogs/revlog.rb +0 -1045
- data/lib/amp/revlogs/revlog_support.rb +0 -126
- data/lib/amp/support/ignore.rb +0 -144
- data/site/Rakefile +0 -38
- data/test/test_amp.rb +0 -9
- data/test/test_helper.rb +0 -15
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
module Amp
|
|
2
|
+
module Mercurial
|
|
3
|
+
module RevlogSupport
|
|
4
|
+
include Node
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# This class represents one revision entry in the index.
|
|
8
|
+
#
|
|
9
|
+
# Format on disk (in BitStruct notation):
|
|
10
|
+
#
|
|
11
|
+
# default_options :endian => :network
|
|
12
|
+
#
|
|
13
|
+
# signed :offset_flags, 64
|
|
14
|
+
# signed :compressed_len, 32
|
|
15
|
+
# signed :uncompressed_len, 32
|
|
16
|
+
# signed :base_rev, 32
|
|
17
|
+
# signed :link_rev, 32
|
|
18
|
+
# signed :parent_one_rev, 32
|
|
19
|
+
# signed :parent_two_rev, 32
|
|
20
|
+
# char :node_id, 160
|
|
21
|
+
# pad :padding, 96
|
|
22
|
+
#
|
|
23
|
+
# [offset_flags] - this is a double-word (8 bytes) - that combines the offset into the data file
|
|
24
|
+
# and any flags about the entry
|
|
25
|
+
# [compressed_len] - this is the length of the data when compressed
|
|
26
|
+
# [uncompresed_len] - length of the data uncompresed
|
|
27
|
+
# [base_rev] - the revision of the filelog
|
|
28
|
+
# [link_rev] - the revision of the whole repo where this was attached
|
|
29
|
+
# [parent_one_rev] - the parent revision the revision. Even if it's not a merge,
|
|
30
|
+
# it will have at least this parent entry
|
|
31
|
+
# [parent_two_rev] - if the revision is a merge, then it will have a second parent.
|
|
32
|
+
class IndexEntry < Struct.new(:offset_flags, :compressed_len, :uncompressed_len, :base_rev,
|
|
33
|
+
:link_rev, :parent_one_rev, :parent_two_rev, :node_id)
|
|
34
|
+
include Comparable
|
|
35
|
+
|
|
36
|
+
INDEX_FORMAT_NG = "Q NNNNNN a20 x12"
|
|
37
|
+
BLOCK_SIZE = 64
|
|
38
|
+
|
|
39
|
+
def initialize(*args)
|
|
40
|
+
if args.size == 1 && args[0].respond_to?(:read)
|
|
41
|
+
super(*(args[0].read(BLOCK_SIZE).unpack(INDEX_FORMAT_NG)))
|
|
42
|
+
else
|
|
43
|
+
super(*args)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def to_s
|
|
48
|
+
fix_signs
|
|
49
|
+
ret = self.to_a.pack(INDEX_FORMAT_NG)
|
|
50
|
+
fix_signs
|
|
51
|
+
ret
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Fixes the values to force them to be signed (possible to be negative)
|
|
55
|
+
def fix_signs
|
|
56
|
+
self.offset_flags = self.offset_flags.byte_swap_64
|
|
57
|
+
self.parent_one_rev = self.parent_one_rev.to_signed_32
|
|
58
|
+
self.parent_two_rev = self.parent_two_rev.to_signed_32
|
|
59
|
+
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Compares this entry to another
|
|
64
|
+
def <=> other_entry
|
|
65
|
+
this.base_rev <=> other_entry.base_rev
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Gives a hash value so we can stick these entries into a hash
|
|
69
|
+
def hash
|
|
70
|
+
node_id.hash
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
##
|
|
75
|
+
# = Index
|
|
76
|
+
# The Index is a file that keeps track of the revision data. All revisions
|
|
77
|
+
# go through an index. This class, {Index}, is the most basic class. It
|
|
78
|
+
# provides an Index.parse method so that you can read a file in, and
|
|
79
|
+
# the class will figure out which version it is, and all that jazz.
|
|
80
|
+
#
|
|
81
|
+
class Index
|
|
82
|
+
include Mercurial::RevlogSupport::Support
|
|
83
|
+
include Enumerable
|
|
84
|
+
|
|
85
|
+
# This is the packed format of the version number of the index.
|
|
86
|
+
VERSION_FORMAT = "N"
|
|
87
|
+
# The version (either {REVLOG_VERSION_0} or {REVLOG_VERSION_NG})
|
|
88
|
+
attr_reader :version
|
|
89
|
+
# The actual lookup array. Each revision has an index in this list, and
|
|
90
|
+
# that list also happens to be relatively chronological.
|
|
91
|
+
attr_reader :index
|
|
92
|
+
# This node_map lets you look up node_id's (NOT INDEX-NUMBERS),
|
|
93
|
+
# which are strings, and get the index into @index of the
|
|
94
|
+
# node you're looking up.
|
|
95
|
+
attr_reader :node_map
|
|
96
|
+
# This allows a couple neat caching tricks to speed up acces and cut
|
|
97
|
+
# down on IO.
|
|
98
|
+
attr_reader :chunk_cache
|
|
99
|
+
# This is the path to the index file. Can be a URL. I don't care and
|
|
100
|
+
# neither should you.
|
|
101
|
+
attr_reader :indexfile
|
|
102
|
+
# This is the raw cache data. Another helpful bit.
|
|
103
|
+
attr_accessor :cache
|
|
104
|
+
|
|
105
|
+
##
|
|
106
|
+
# This method will parse the file at the provided path and return
|
|
107
|
+
# an appropriate Index object. The object will be of the class that
|
|
108
|
+
# fits the file provided, based on version and whether
|
|
109
|
+
# it is inline.
|
|
110
|
+
#
|
|
111
|
+
# @param [String] inputfile the filepath to load and parse
|
|
112
|
+
# @return [Index] Some subclassed version of Index that's parsed the file
|
|
113
|
+
def self.parse(opener, inputfile)
|
|
114
|
+
versioninfo = REVLOG_DEFAULT_VERSION
|
|
115
|
+
i = ""
|
|
116
|
+
begin
|
|
117
|
+
opener.open(inputfile) do |f|
|
|
118
|
+
i = f.read(4)
|
|
119
|
+
end
|
|
120
|
+
versioninfo = i.unpack(VERSION_FORMAT).first if i.size > 0
|
|
121
|
+
# Check if the data is with the index info.
|
|
122
|
+
inline = (versioninfo & REVLOG_NG_INLINE_DATA > 0)
|
|
123
|
+
# Get the version number of the index file.
|
|
124
|
+
version = Support.get_version versioninfo
|
|
125
|
+
rescue
|
|
126
|
+
inline = true
|
|
127
|
+
version = REVLOG_VERSION_NG
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Pick a subclass for the version and in-line-icity we found.
|
|
131
|
+
case [version, inline]
|
|
132
|
+
when [REVLOG_VERSION_0, false]
|
|
133
|
+
IndexVersion0.new opener, inputfile
|
|
134
|
+
when [REVLOG_VERSION_NG, false]
|
|
135
|
+
IndexVersionNG.new opener, inputfile
|
|
136
|
+
when [REVLOG_VERSION_NG, true]
|
|
137
|
+
IndexInlineNG.new opener, inputfile
|
|
138
|
+
else
|
|
139
|
+
raise RevlogError.new("Invalid format: #{version} flags: #{get_flags(versioninfo)}")
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
##
|
|
144
|
+
# Returns whether a given node ID exists, without throwing a lookup error.
|
|
145
|
+
#
|
|
146
|
+
# @param [String] node the node_id to lookup. 20 bytes, binary.
|
|
147
|
+
# @return [Boolean] is the node in the index?
|
|
148
|
+
def has_node?(node)
|
|
149
|
+
@node_map[node]
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
##
|
|
153
|
+
# This provides quick lookup into the index, based on revision
|
|
154
|
+
# number. NOT ID's, index numbers.
|
|
155
|
+
#
|
|
156
|
+
# @param [Fixnum] index the index to look up
|
|
157
|
+
# @return [IndexEntry] the revision requested
|
|
158
|
+
def [](index)
|
|
159
|
+
@index[index]
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
##
|
|
163
|
+
# This method writes the index to file. Pretty 1337h4><.
|
|
164
|
+
#
|
|
165
|
+
# @param [String] index_file the path to the index file.
|
|
166
|
+
def write_entry(index_file, journal)
|
|
167
|
+
raise abort("Use a concrete class. Yeah, I called it a concrete class. I hate" +
|
|
168
|
+
" Java too, but you tried to use an abstract class.")
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
##
|
|
172
|
+
# Adds an item to the index safely. DO NOT USE some_index.index <<. It's
|
|
173
|
+
# some_index << entry.
|
|
174
|
+
#
|
|
175
|
+
# @param [[Integer, Integer, Integer, Integer, Integer, Integer,
|
|
176
|
+
# Integer, Integer]] item the data to enter as an entry. See the spec fo
|
|
177
|
+
# {IndexEntry}.
|
|
178
|
+
def <<(item)
|
|
179
|
+
@index.insert(-2, IndexEntry.new(*item)) if item.is_a? Array
|
|
180
|
+
@index.insert(-2, item) if item.is_a? IndexEntry
|
|
181
|
+
# leave the terminating entry intact
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Returns the number of entries in the index, including the null revision
|
|
185
|
+
def size
|
|
186
|
+
@index.size
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Iterates over each entry in the index, including the null revision
|
|
190
|
+
def each(&b)
|
|
191
|
+
@index.each(&b)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
##
|
|
196
|
+
# = IndexVersion0
|
|
197
|
+
# This handles old versions of the index file format.
|
|
198
|
+
# These are apparently so old they were version 0.
|
|
199
|
+
class IndexVersion0 < Index
|
|
200
|
+
# Binary data format for each revision entry
|
|
201
|
+
INDEX_FORMAT_V0 = "N4 a20 a20 a20"
|
|
202
|
+
# The size of each revision entry
|
|
203
|
+
BLOCK_SIZE = (4 * 4) + (3 * 20)
|
|
204
|
+
# The offset into the entry where the SHA1 is stored for validation
|
|
205
|
+
SHA1_OFFSET = 56
|
|
206
|
+
|
|
207
|
+
# Return the size of 1 entry
|
|
208
|
+
def entry_size; BLOCK_SIZE; end
|
|
209
|
+
# Return what version this index is
|
|
210
|
+
def version; REVLOG_VERSION_0; end
|
|
211
|
+
# Does the index store the data with the revision index entries?
|
|
212
|
+
def inline?; false; end
|
|
213
|
+
|
|
214
|
+
# Initializes the index by reading from the provided filename. Users probably
|
|
215
|
+
# don't need this because {Index}#{parse} will do this for you.
|
|
216
|
+
#
|
|
217
|
+
# @param [String] inputfile the path to the index file
|
|
218
|
+
def initialize(opener, inputfile)
|
|
219
|
+
@opener = opener
|
|
220
|
+
@indexfile = inputfile
|
|
221
|
+
@node_map = {Node::NULL_ID => Node::NULL_REV}
|
|
222
|
+
@index = []
|
|
223
|
+
n = offset = 0
|
|
224
|
+
if File.exists?(opener.join(inputfile))
|
|
225
|
+
opener.open(inputfile) do |f|
|
|
226
|
+
|
|
227
|
+
while !f.eof?
|
|
228
|
+
current = f.read(BLOCK_SIZE)
|
|
229
|
+
entry = current.unpack(INDEX_FORMAT_V0)
|
|
230
|
+
new_entry = IndexEntry.new(offset_version(entry[0],0), entry[1], -1, entry[2], entry[3],
|
|
231
|
+
(@node_map[entry[4]] || nullrev), (@node_map[entry[5]] || nullrev),
|
|
232
|
+
entry[6])
|
|
233
|
+
@index << new_entry.fix_signs
|
|
234
|
+
@node_map[entry[6]] = n
|
|
235
|
+
n += 1
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
@cache = nil
|
|
240
|
+
self
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
##
|
|
244
|
+
# This method writes the index to file. Pretty 1337h4><.
|
|
245
|
+
#
|
|
246
|
+
# @param [String] index_file the path to the index file.
|
|
247
|
+
def write_entry(index_file, entry, journal, data)
|
|
248
|
+
curr = self.size - 1
|
|
249
|
+
|
|
250
|
+
node_map[entry.last] = curr
|
|
251
|
+
|
|
252
|
+
link = entry[4]
|
|
253
|
+
data_file = index_file[0..-3] + ".d"
|
|
254
|
+
|
|
255
|
+
entry = pack_entry entry, link
|
|
256
|
+
|
|
257
|
+
data_file_handle = open(data_file, "a")
|
|
258
|
+
index_file_handle = open(index_file, "a+")
|
|
259
|
+
|
|
260
|
+
journal << {:file => data_file, :offset => offset}
|
|
261
|
+
journal << {:file => index_file, :offset => curr * entry.size}
|
|
262
|
+
|
|
263
|
+
data_file_handle.write data[:compression] if data[:compression].any?
|
|
264
|
+
data_file_handle.write data[:text]
|
|
265
|
+
|
|
266
|
+
data_file_handle.flush
|
|
267
|
+
index_file_handle.write entry
|
|
268
|
+
end
|
|
269
|
+
##
|
|
270
|
+
# This takes an entry and packs it into binary data for writing to
|
|
271
|
+
# the file.
|
|
272
|
+
#
|
|
273
|
+
# @param [IndexEntry] entry the revision entry to pack up for writing
|
|
274
|
+
# @param rev unused by version 0. Kept to make the interface uniform
|
|
275
|
+
# @return [String] the Binary data packed up for writing.
|
|
276
|
+
def pack_entry(entry, rev)
|
|
277
|
+
entry = IndexEntry.new(*entry) if entry.kind_of? Array
|
|
278
|
+
entry.fix_signs
|
|
279
|
+
e2 = [RevlogSupport::Support.offset_type(entry.offset_flags),
|
|
280
|
+
entry.compressed_len, entry.base_rev, entry.link_rev,
|
|
281
|
+
@index[entry.parent_one_rev].node_id,
|
|
282
|
+
@index[entry.parent_two_rev].node_id, entry.node_id]
|
|
283
|
+
e2.pack(INDEX_FORMAT_V0)
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
##
|
|
288
|
+
# = IndexVersionNG
|
|
289
|
+
# This is the current version of the index. I'm not sure why they call
|
|
290
|
+
# it Version 'NG' but they do. An index of this type is *not* inline.
|
|
291
|
+
class IndexVersionNG < Index
|
|
292
|
+
VERSION_FORMAT = "N"
|
|
293
|
+
# The binary format used for pack/unpack
|
|
294
|
+
INDEX_FORMAT_NG = "Q NNNNNN a20 x12"
|
|
295
|
+
# The distance into the entry to go to find the SHA1 hash
|
|
296
|
+
SHA1_OFFSET = 32
|
|
297
|
+
# The size of a single block in the index
|
|
298
|
+
BLOCK_SIZE = 8 + (6 * 4) + 20 + 12
|
|
299
|
+
|
|
300
|
+
##
|
|
301
|
+
# Initializes the index by parsing the given file.
|
|
302
|
+
#
|
|
303
|
+
# @param [String] inputfile the path to the index file.
|
|
304
|
+
def initialize(opener, inputfile)
|
|
305
|
+
@opener = opener
|
|
306
|
+
@indexfile = inputfile
|
|
307
|
+
@cache = nil
|
|
308
|
+
@index = []
|
|
309
|
+
@node_map = {Node::NULL_ID => Node::NULL_REV}
|
|
310
|
+
|
|
311
|
+
opened = parse_file
|
|
312
|
+
|
|
313
|
+
if opened
|
|
314
|
+
first_entry = @index[0]
|
|
315
|
+
type = get_version(first_entry.offset_flags)
|
|
316
|
+
first_entry.offset_flags = offset_version(0, type) #turn off inline
|
|
317
|
+
@index[0] = first_entry
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
@index << IndexEntry.new(0,0,0,-1,-1,-1,-1,Node::NULL_ID)
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
##
|
|
324
|
+
# returns the size of 1 block in this type of index
|
|
325
|
+
def entry_size; BLOCK_SIZE; end
|
|
326
|
+
|
|
327
|
+
# returns the version number of the index
|
|
328
|
+
def version; REVLOG_VERSION_NG; end
|
|
329
|
+
# returns whether or not the index stores data with revision info
|
|
330
|
+
def inline?; false; end
|
|
331
|
+
|
|
332
|
+
##
|
|
333
|
+
# Parses each index entry. Internal use only.
|
|
334
|
+
#
|
|
335
|
+
# @return [Boolean] whether the file was opened
|
|
336
|
+
def parse_file
|
|
337
|
+
n = 0
|
|
338
|
+
begin
|
|
339
|
+
@opener.open(@indexfile,"r") do |f|
|
|
340
|
+
until f.eof?
|
|
341
|
+
# read the entry
|
|
342
|
+
entry = IndexEntry.new(f).fix_signs
|
|
343
|
+
# store it in the map
|
|
344
|
+
@node_map[entry.node_id] = n
|
|
345
|
+
# add it to the index
|
|
346
|
+
@index << entry
|
|
347
|
+
n += 1
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
return true
|
|
351
|
+
rescue Errno::ENOENT
|
|
352
|
+
return false
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
##
|
|
357
|
+
# Packs up the revision entry for writing to the binary file.
|
|
358
|
+
#
|
|
359
|
+
# @param [IndexEntry] entry this is the entry that has to be formatted
|
|
360
|
+
# into binary.
|
|
361
|
+
# @param [Fixnum] rev this is the index number of the entry - if it's
|
|
362
|
+
# the first revision (rev == 0) then we treat it slightly differently.
|
|
363
|
+
# @return [String] the entry converted into binary suitable for writing.
|
|
364
|
+
def pack_entry(entry, rev)
|
|
365
|
+
entry = IndexEntry.new(*entry) if entry.kind_of? Array
|
|
366
|
+
p = entry.to_s
|
|
367
|
+
if rev == 0 || rev == 1
|
|
368
|
+
p = [version].pack(VERSION_FORMAT) + p[4..-1] # initial entry
|
|
369
|
+
end
|
|
370
|
+
p
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
##
|
|
374
|
+
# This method writes the index to file. Pretty 1337h4><.
|
|
375
|
+
#
|
|
376
|
+
# @param [String] index_file the path to the index file.
|
|
377
|
+
def write_entry(index_file, entry, journal, data, index_file_handle = nil)
|
|
378
|
+
curr = self.size - 1
|
|
379
|
+
|
|
380
|
+
link = (entry.is_a? Array) ? entry[4] : entry.link_rev
|
|
381
|
+
data_file = index_file[0..-3] + ".d"
|
|
382
|
+
|
|
383
|
+
entry = pack_entry entry, link
|
|
384
|
+
|
|
385
|
+
@opener.open(data_file, "a+") do |data_file_handle|
|
|
386
|
+
data_offset = data_file_handle.tell
|
|
387
|
+
|
|
388
|
+
data_file_handle.write data[:compression] if data[:compression].any?
|
|
389
|
+
data_file_handle.write data[:text]
|
|
390
|
+
data_file_handle.flush
|
|
391
|
+
|
|
392
|
+
journal << {:file => data_file, :offset => data_offset, :data => curr}
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
index_file_handle ||= (opened = true && @opener.open(index_file, "a+"))
|
|
396
|
+
|
|
397
|
+
offset = index_file_handle.tell
|
|
398
|
+
index_file_handle.write entry
|
|
399
|
+
index_file_handle.close if opened
|
|
400
|
+
|
|
401
|
+
journal << {:file => index_file, :offset => offset, :data => curr}
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
##
|
|
407
|
+
# = LazyIndex
|
|
408
|
+
# When this gets filled in, this class will let us access an index without loading
|
|
409
|
+
# every entry first. This is handy because index files can get pretty fuckin big.
|
|
410
|
+
class LazyIndex < Index
|
|
411
|
+
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
##
|
|
415
|
+
# = IndexInlineNG
|
|
416
|
+
# This is a variant of the current version of the index format, in which the data
|
|
417
|
+
# is stored in the actual index file itself, right after the little revision
|
|
418
|
+
# entry block (see {IndexEntry}). This means less IO, which is good.
|
|
419
|
+
#
|
|
420
|
+
class IndexInlineNG < IndexVersionNG
|
|
421
|
+
VERSION_FORMAT = "N"
|
|
422
|
+
# We're inline!
|
|
423
|
+
INDEX_FORMAT_NG = "Q NNNNNN a20 x12"
|
|
424
|
+
# The distance into the entry to go to find the SHA1 hash
|
|
425
|
+
SHA1_OFFSET = 32
|
|
426
|
+
# The size of a single block in the index
|
|
427
|
+
BLOCK_SIZE = 8 + (6 * 4) + 20 + 12
|
|
428
|
+
|
|
429
|
+
def inline?; true; end
|
|
430
|
+
def version; REVLOG_VERSION_NG | REVLOG_NG_INLINE_DATA; end
|
|
431
|
+
def pack_entry(entry, rev)
|
|
432
|
+
entry = IndexEntry.new(*entry) if entry.kind_of? Array
|
|
433
|
+
p = entry.to_s
|
|
434
|
+
if rev == 0 || rev == 1
|
|
435
|
+
p = [version].pack(VERSION_FORMAT) + p[4..-1] # initial entry
|
|
436
|
+
end
|
|
437
|
+
p
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
##
|
|
442
|
+
# @todo "not sure what the 0 is for yet or i'd make this a hash" (see code)
|
|
443
|
+
# This method overrides the parent class' method that reads entries sequentially
|
|
444
|
+
# from the index file. Each entry is followed by the data for that revision
|
|
445
|
+
# so we have to skip over that data for our purposes.
|
|
446
|
+
def parse_file
|
|
447
|
+
n = offset = 0
|
|
448
|
+
begin
|
|
449
|
+
@opener.open(@indexfile,"r") do |f|
|
|
450
|
+
return false if f.eof?
|
|
451
|
+
while !f.eof?
|
|
452
|
+
# read 1 entry
|
|
453
|
+
entry = IndexEntry.new(f).fix_signs
|
|
454
|
+
# store it in the map
|
|
455
|
+
@node_map[entry.node_id] = n
|
|
456
|
+
# add it to the index
|
|
457
|
+
@index << entry
|
|
458
|
+
n += 1
|
|
459
|
+
break if entry.compressed_len < 0
|
|
460
|
+
|
|
461
|
+
# skip past the data, too!
|
|
462
|
+
f.seek(entry.compressed_len, IO::SEEK_CUR)
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
return true
|
|
466
|
+
rescue Errno::ENOENT
|
|
467
|
+
return false
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
##
|
|
472
|
+
# This method writes the index entry to file. Pretty 1337h4><.
|
|
473
|
+
#
|
|
474
|
+
# @param [String] index_file the path to the index file.
|
|
475
|
+
def write_entry(index_file, entry, journal, data, index_file_handle = nil)
|
|
476
|
+
curr = self.size - 1
|
|
477
|
+
prev = curr - 1
|
|
478
|
+
|
|
479
|
+
link = (entry.is_a? Array) ? entry[4] : entry.link_rev
|
|
480
|
+
|
|
481
|
+
entry = pack_entry entry, curr
|
|
482
|
+
|
|
483
|
+
index_file_handle ||= (opened = true && @opener.open(index_file, "a+"))
|
|
484
|
+
|
|
485
|
+
offset = index_file_handle.tell
|
|
486
|
+
|
|
487
|
+
index_file_handle.write entry
|
|
488
|
+
index_file_handle.write data[:compression] if data[:compression].any?
|
|
489
|
+
index_file_handle.write data[:text]
|
|
490
|
+
|
|
491
|
+
index_file_handle.close if opened
|
|
492
|
+
|
|
493
|
+
journal << {:file => index_file, :offset => offset, :data => curr}
|
|
494
|
+
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
end
|