amp 0.5.2 → 0.5.3

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