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.
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
@@ -0,0 +1,339 @@
1
+ module Amp
2
+ module Mercurial
3
+
4
+ ##
5
+ # This is used for faking data writing, until we're totally done
6
+ # accumulating data.
7
+ class FakeFileAppender
8
+
9
+ ##
10
+ # Initializes the fake file with the pointer to the real deal,
11
+ # and also the current data
12
+ def initialize(fp, buffer, size)
13
+ @data = buffer
14
+ @fp = fp
15
+ @offset = fp.tell
16
+ @size = size
17
+ end
18
+
19
+ ##
20
+ # Returns the endpoint of the data in the (fake) file
21
+ def endpt
22
+ @size + @data.join.size
23
+ end
24
+
25
+ ##
26
+ # Returns the current offset of the (fake) file
27
+ def tell
28
+ @offset
29
+ end
30
+
31
+ ##
32
+ # Nothing, since we don't flush, we just sit here
33
+ def flush; end
34
+
35
+ ##
36
+ # Closes the real file pointer for this fake file
37
+ def close
38
+ @fp.close
39
+ end
40
+
41
+ ##
42
+ # Seeks to the position requested. We're faking this, but it's a little
43
+ # tougher, because if we break the fake file down like this:
44
+ #
45
+ # [ actual file size = 10 | pending data size = 10 ]
46
+ #
47
+ # If the user seeks to 15, we need to make sure we don't try to seek to
48
+ # 15 in the file, as that would cause errors.
49
+ def seek(offset, whence)
50
+ if whence == IO::SEEK_SET
51
+ @offset = offset
52
+ elsif whence == IO::SEEK_CUR
53
+ @offset += offset
54
+ elsif whence == IO::SEEK_END
55
+ @offset = self.endpt + offset
56
+ end
57
+ if @offset < @size
58
+ @fp.seek @offset
59
+ end
60
+ end
61
+
62
+ ##
63
+ # Reads from the fake file, for _count_ bytes. This is a little sketchy
64
+ # because we might be reading some real data and some fake data, or all
65
+ # real, or all fake.
66
+ #
67
+ # @param [Integer] count how much to read. -1 will read it all.
68
+ # @return [String] the contents
69
+ def read(count=-1)
70
+ ret = ""
71
+
72
+ if @offset < @size
73
+ s = @fp.read(count)
74
+ ret = s
75
+ @offset += s.size
76
+ if count > 0
77
+ count -= s.size
78
+ end
79
+ end
80
+
81
+ unless count.zero?
82
+ doff = @offset - @size
83
+ @data.unshift @data.join
84
+ @data.delete_range(1..-1)
85
+ s = @data[0][doff..(doff+count-1)]
86
+ @offset += s.size
87
+ ret += s
88
+ end
89
+
90
+ ret
91
+ end
92
+
93
+ ##
94
+ # Writes to the fake file. Notice - this will only work because we only
95
+ # append to the file - we don't write in the middle anywhere, or this
96
+ # scheme would fail.
97
+ #
98
+ # @param [#to_s] s data to write
99
+ def write(s)
100
+ @data << s.to_s
101
+ @offset += s.size
102
+ end
103
+ end
104
+
105
+ class DelayedOpener
106
+ attr_accessor :default
107
+
108
+ ##
109
+ # Initializes the delayed opener, needing the real deal, and the owner
110
+ # of the delayed opener.
111
+ #
112
+ # @param [Opener] realopener the actual opener. Since the DelayedOpener
113
+ # doesn't know how to open files, we'll need this!
114
+ # @param [ChangeLog] owner the owner of the delayed opener. This reference
115
+ # is needed because we need to check on the state of the delayed_buffer
116
+ # and what not.
117
+ def initialize(realopener, owner)
118
+ @real_opener, @owner = realopener, owner
119
+ end
120
+
121
+ ##
122
+ # Specialized opener that will fake writing when asked to. We need to
123
+ # know who our owner is and we need a real opener so we can actually
124
+ # open files. The DelayedOpener doesn't know how to do real IO.
125
+ def open(name, mode="r")
126
+ fp = @real_opener.open(name, mode)
127
+ return fp if name != @owner.index_file
128
+
129
+ # Are we holding off on writing? if so, set up the file where we
130
+ # writing pending data.
131
+
132
+ if @owner.delay_count == 0
133
+ @owner.delay_name = File.amp_name(fp)
134
+ mode.gsub!(/a/, 'w') if @owner.empty?
135
+ return @real_opener.open(name+".a", mode) # See what I did there?
136
+ end
137
+
138
+ # FakeFileAppender = fake file so we don't do any real writing yet
139
+ size = File.stat(@real_opener.join(name)).size
140
+ ffa = FakeFileAppender.new(fp, @owner.delay_buffer, size)
141
+
142
+ return ffa
143
+ end
144
+ end
145
+
146
+ ##
147
+ # A ChangeLog is a special revision log that stores the actual commit data,
148
+ # including usernames, dates, messages, all kinds of stuff.
149
+ #
150
+ # This version of the revision log is special though, because sometimes
151
+ # we have to hold off on writing until all other updates are done, for
152
+ # example during merges that might fail. So we have to actually have
153
+ # a real Opener and a fake one, which will save the data in memory.
154
+ # When you call #finalize, the fake file will replace the real deal.
155
+ class ChangeLog < Revlog
156
+ attr_accessor :delay_count, :delay_name, :index_file, :delay_buffer, :node_map
157
+
158
+ ##
159
+ # Initializes the revision log. Just pass in an Opener. Amp::Opener.new(path)
160
+ # will do just fine.
161
+ #
162
+ # @param [Amp::Opener] opener an object that knows how to open
163
+ # and return files based on a root directory.
164
+ def initialize(opener)
165
+ super(opener, "00changelog.i")
166
+ @node_map = @index.node_map
167
+ end
168
+ alias_method :changelog_initialize, :initialize
169
+
170
+ ##
171
+ # Tells the changelog to stop writing updates directly to the file,
172
+ # and start saving any new info to memory/other files. Used when the
173
+ # changelog has to be the last file saved.
174
+ def delay_update
175
+ @_real_opener = @opener
176
+ @opener = DelayedOpener.new(@_real_opener, self) # Our fake Opener
177
+ @delay_count = self.size
178
+ @delay_buffer = []
179
+ @delay_name = nil
180
+ end
181
+
182
+ ##
183
+ # Finalizes the changelog by swapping out the fake file if it has to.
184
+ # If there's any other data left in the buffer, it will be written
185
+ # as well.
186
+ def finalize(journal)
187
+ if @delay_name
188
+ src = @_real_opener.join(@index_file+".a")
189
+ dest = @_real_opener.join(@index_file)
190
+ @opener = @_real_opener # switch back to normal mode....
191
+ return File.amp_force_rename(src, dest)
192
+ end
193
+
194
+ if @delay_buffer && @delay_buffer.any?
195
+ @fp = open(@index_file, "a")
196
+ @fp.write @delay_buffer.join
197
+ @fp.close
198
+ @delay_buffer = []
199
+ end
200
+ # check_inline_size journal
201
+ end
202
+
203
+ ##
204
+ # Reads while we're blocking this changelog's output.
205
+ # @param file the file to read in as a revision log
206
+ def read_pending(file)
207
+ r = Revlog.new(@opener, file)
208
+ @index = r.index
209
+ @node_map = r.index.node_map
210
+ @chunk_cache = r.chunk_cache
211
+ end
212
+
213
+ ##
214
+ # Writes our data, while being aware of the delay buffer when we're holding
215
+ # off on finalizing the changelog.
216
+ def write_pending
217
+ if @delay_buffer && @delay_buffer.size > 0
218
+ fp1 = @_real_opener.open(@index_file)
219
+ fp2 = @_real_opener.open(@index_file + ".a", "w+")
220
+ UI.debug "trying to open #{@index_file + ".a"}..."
221
+ fp2.write fp1.read
222
+ fp2.write @delay_buffer.join
223
+ fp2.close
224
+ fp1.close
225
+ @delay_buffer = []
226
+ @delay_name = @index_file
227
+ end
228
+ return true if @delay_name && @delay_name.any?
229
+ false
230
+ end
231
+
232
+ ##
233
+ # Does a check on our size, but knows enough to quit if we're still in
234
+ # delayed-writing mode.
235
+ # @param [Amp::Mercurial::Journal] journal the journal to use to keep track of our transaction
236
+ # @param [File] fp the file pointer to use to check our size
237
+ def check_inline_size(journal, fp=nil)
238
+ return if @opener.is_a? DelayedOpener
239
+ super(journal, fp)
240
+ end
241
+
242
+ ##
243
+ # Decodes the extra data stored with the commit, such as requirements
244
+ # or just about anything else we need to save
245
+ # @param [String] text the data in the revision, decompressed
246
+ # @return [Hash] key-value pairs, joining each file with its extra data
247
+ def decode_extra(text)
248
+ extra = {}
249
+ text.split("\0").select {|l| l.any? }.
250
+ map {|l| l.remove_slashes.split(":",2) }.
251
+ each {|k,v| extra[k]=v }
252
+ extra
253
+ end
254
+
255
+ ##
256
+ # Encodes the extra data in a format we can use for writing.
257
+ # @param [Hash] data the extra data to format
258
+ # @return [String] the encoded data
259
+ def encode_extra(data)
260
+ " " + data.sort.map {|k| "#{k}:#{data[k]}".add_slashes }.join("\0")
261
+ end
262
+
263
+ ##
264
+ # Reads the revision at the given node_id. It returns it in a format
265
+ # that tells us everything about the revision - the manifest_entry, the user
266
+ # who committed it, timestamps, the relevant filenames, the description
267
+ # message, and any extra data.
268
+ #
269
+ # @todo Text encodings, I hate you. but i must do them
270
+ # @param [Fixnum] node the node ID to lookup into the revision log
271
+ # @return [(String, String, [Float, Integer], [String], String, Hash)]
272
+ # The format is [ManifestEntry, Username, [Time, Timezone], [Filenames],
273
+ # Message, ExtraData].
274
+ def read(node)
275
+ text = decompress_revision node
276
+ if text.nil? || text.empty?
277
+ return [NULL_ID, "", [0,0], [], "", {"branch" => "default"}]
278
+ end
279
+ #p text
280
+ last = text.index("\n\n")
281
+ desc = text[last+2..-1] #TODO: encoding
282
+ l = text[0..last].split("\n")
283
+ manifest = l[0].unhexlify
284
+ user = l[1] #TODO: encoding
285
+ extra_data = l[2].split(' ', 3)
286
+ if extra_data.size != 3
287
+ time = extra_data.shift.to_f
288
+ timezone = extra_data.shift.to_i
289
+ extra = {}
290
+ else
291
+ time, timezone, extra = extra_data
292
+ time, timezone = time.to_f, timezone.to_i
293
+ extra = decode_extra text
294
+ end
295
+ extra["branch"] = "default" unless extra["branch"]
296
+
297
+ files = l[3..-1]
298
+
299
+ [manifest, user, [time, timezone], files, desc, extra]
300
+ end
301
+
302
+ ##
303
+ # Adds the given commit to the changelog.
304
+ #
305
+ # @todo Handle text encodings
306
+ # @todo figure out what the fuck is going on with these parameters
307
+ # @param [Amp::Mercurial::Manifest] manifest a hex-version of a node_id or something?
308
+ # @param [String] files the files relevant to the commit, to be included
309
+ # @param [String] desc the commit message from the user
310
+ # @param [Amp::Mercurial::Journal] journal the transaction journal to write to for rollbacks if
311
+ # something goes horribly wrong
312
+ # @param [String] p1 the first parent of this node
313
+ # @param [String] p2 the second parent of this node
314
+ # @param [Strng] user the username of the committer
315
+ # @param [Time] date the date of the commit
316
+ # @param [Hash] extra any extra data
317
+ def add(manifest, files, desc, journal, p1=nil, p2=nil, user=nil, date=nil, extra={})
318
+ user = user.strip
319
+ raise RevlogSupport::RevlogError.new("no \\n in username") if user=~ /\n/
320
+ user, desc = user, desc #TODO: encoding!
321
+
322
+ date = Time.now unless date
323
+ parsed_date = "#{date.to_i} #{-1 * date.utc_offset}"
324
+
325
+ if extra && ["default", "", nil].include?(extra["branch"])
326
+ extra.delete "branch"
327
+ end
328
+ if extra
329
+ extra = (extra.any?) ? encode_extra(extra) : ""
330
+ parsed_date = "#{parsed_date}#{extra}"
331
+ end
332
+
333
+ l = [manifest.hexlify, user, parsed_date] + files.sort + ["", desc]
334
+ text = l.join "\n"
335
+ add_revision text, journal, self.size, p1, p2
336
+ end
337
+ end
338
+ end
339
+ end
@@ -0,0 +1,152 @@
1
+ module Amp
2
+ module Mercurial
3
+ ##
4
+ # = FileLog
5
+ # A FileLog is the revision log that stores revision history for
6
+ # each individual file tracked by the system. It stores special meta-data
7
+ # for handling files that have been copied over their history.
8
+ #
9
+ class FileLog < Revlog
10
+ ##
11
+ # Initializes the revision log, being sure to encode directories
12
+ # to avoid naming conflicts
13
+ # @param [Opener] opener the opener to use for opening the file
14
+ # @param [String] path the path to the file, excluding "data".
15
+ #
16
+ def initialize(opener, path)
17
+ super(opener, ["data", encode_dir(path + ".i")].join("/"))
18
+ end
19
+
20
+ ##
21
+ # Encodes the directory to avoid naming conflicts
22
+ # @param [String] path the path to encode for naming conflict issues
23
+ # @return [String] the encoded directory path
24
+ #
25
+ def encode_dir(path)
26
+ path.gsub(".hg/",".hg.hg/").gsub(".i/",".i.hg/").gsub(".d/",".d.hg/")
27
+ end
28
+
29
+ ##
30
+ # Decodes the directory to avoid naming conflicts
31
+ # @param [String] path the path to decode for naming conflict issues
32
+ # @return [String] the decoded directory path
33
+ #
34
+ def decode_dir(path)
35
+ path.gsub(".d.hg/",".d/").gsub(".i.hg/",".i/").gsub(".hg.hg/",".hg/")
36
+ end
37
+
38
+ ##
39
+ # Reads the data of the revision, ignoring the meta data for copied files
40
+ # @param [String] node the node_id to read
41
+ # @return [String] the data of the revision
42
+ #
43
+ def read(node)
44
+ t = decompress_revision(node)
45
+ return t unless t.start_with?("\1\n")
46
+
47
+ start = t.index("\1\n", 2)
48
+ t[(start+2)..-1]
49
+ end
50
+
51
+ ##
52
+ # Reads the meta data in the node
53
+ # @param [String] node the node_id to read the meta of
54
+ # @return [Hash] the meta data in this revision. Could be empty hash.
55
+ #
56
+ def read_meta(node)
57
+ t = decompress_revision(node)
58
+ return {} unless t.start_with?("\1\n")
59
+
60
+ start = t.index("\1\n", 2)
61
+ mt = t[2..(start-1)]
62
+ m = {}
63
+ mt.split("\n").each do |l|
64
+ k, v = l.split(": ", 2)
65
+ m[k] = v
66
+ end
67
+ m
68
+ end
69
+
70
+ ##
71
+ # Adds a revision to the file's history. Overridden for special metadata
72
+ #
73
+ # @param [String] text the new text of the file
74
+ # @param [Hash] meta the meta data to use (if we copied)
75
+ # @param [Journal] journal for aborting transaction
76
+ # @param [Integer] link the revision number this is linked to
77
+ # @param [Integer] p1 (nil) the first parent of this new revision
78
+ # @param [Integer] p2 (nil) the second parent of this new revision
79
+ # @param [String] digest referring to the node this makes
80
+ def add(text, meta, journal, link, p1=nil, p2=nil)
81
+ if (meta && meta.any?) || text.start_with?("\1\n")
82
+ mt = ""
83
+ mt = meta.map {|k, v| "#{k}: #{v}\n"} if meta
84
+ text = "\1\n" + mt.join + "\1\n" + text
85
+ end
86
+ add_revision(text, journal, link, p1, p2)
87
+ end
88
+
89
+ ##
90
+ # Returns whether or not the file at _node_ has been renamed or
91
+ # copied in the immediate revision.
92
+ #
93
+ # @param [String] node the node_id of the revision
94
+ # @return [Array<String, String>] [new_path, flags]
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
+
107
+ ##
108
+ # Yields a block for every revision, while being sure to follow copies.
109
+ def each(&block)
110
+ if @index[0].parent_one_rev == NULL_REV
111
+ meta_info = renamed?(@index[0].node_id)
112
+ if meta_info
113
+ copied_log = FileLog.new(@opener, meta_info.first)
114
+ copied_log.each(&block)
115
+ end
116
+ end
117
+ super(&block)
118
+ end
119
+
120
+ ##
121
+ # Gets the size of the file. Overridden because of the metadata for
122
+ # copied files.
123
+ #
124
+ # @param [Integer] rev the number of the revision to lookup
125
+ # @return [String] the file's data
126
+ def size(rev)
127
+ node = self.node rev
128
+ if renamed? node
129
+ read(node).size
130
+ else
131
+ self[rev].compressed_len
132
+ end
133
+ end
134
+
135
+ ##
136
+ # Converts a given node in this revision with the text provided.
137
+ # overridden because it handles renamed files.
138
+ #
139
+ # @param [String] thenode the node ID to use
140
+ # @param [String] text the text to compare against
141
+ # @return [Boolean] true if they're different, false if not. silly, isn't
142
+ # it?
143
+ def cmp(thenode, text)
144
+ if renamed? thenode
145
+ t2 = read thenode
146
+ return t2 != text
147
+ end
148
+ super(thenode, text)
149
+ end
150
+ end # class FileLog
151
+ end # module Mercurial
152
+ end # module Amp