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,203 +0,0 @@
1
- module Amp
2
- class StandardErrorReporter
3
- def self.report str
4
- STDERR.puts str
5
- end
6
- end
7
-
8
- ##
9
- # Provides a journal interface so when a large number of transactions
10
- # are occurring, and any one could fail, we can rollback the changes.
11
- class Journal
12
- DEFAULT_OPTS = {:reporter => StandardErrorReporter, :after_close => nil}
13
-
14
- attr_accessor :report, :journal, :after_close
15
-
16
- ##
17
- # @return [Amp::Journal]
18
- def self.start(file, opts=DEFAULT_OPTS)
19
- journal = Journal.new opts[:reporter], file, &opts[:after_close]
20
-
21
- if block_given?
22
- begin
23
- yield journal
24
- ensure
25
- journal.close
26
- end
27
- end
28
-
29
- journal
30
- end
31
-
32
- ##
33
- # Initializes the journal to get ready for some transactions.
34
- #
35
- # @param [#report] reporter an object that will keep track of any alerts
36
- # we have to send out. Must respond to #report.
37
- # @param [String] journal the path to the journal file to use
38
- # @param [Integer] createmode An octal number that sets the filemode
39
- # of the journal file we'll be using
40
- # @param [Proc] after_close A proc to call (with no args) after we
41
- # close (finish) the transaction.
42
- def initialize(reporter=StandardErrorReporter, journal="journal#{rand(10000)}", createmode=nil, &after_close)
43
- @count = 1
44
- @reporter = reporter
45
- @after_close = after_close
46
- @entries = []
47
- @map = {}
48
- @journal_file = journal
49
-
50
- @file = open(@journal_file, "w")
51
-
52
- FileUtils.chmod(createmode & 0666, @journal_file) unless createmode.nil?
53
- end
54
-
55
- ##
56
- # Kills the journal - used when shit goes down and we gotta give up
57
- # on the transactions.
58
- def delete
59
- if @journal_file
60
- abort if @entries.any?
61
- @file.close
62
- FileUtils.safe_unlink @journal_file
63
- end
64
- end
65
-
66
- ##
67
- # Adds an entry to the journal. Since all our files are just being appended
68
- # to all the time, all we really need is to keep track of how long the file
69
- # was when we last knew it to be safe. In other words, if the file started
70
- # off at 20 bytes, then an error happened, we just truncate it to 20 bytes.
71
- #
72
- # All params should be contained in the array
73
- #
74
- # @param file the name of the file we're modifying and need to track
75
- # @param offset the length of the file we're storing
76
- # @param data any extra data to hold onto
77
- def add_entry(array)
78
- file, offset, data = array[0], array[1], array[2]
79
- return if @map[file]
80
- @entries << {:file => file, :offset => offset, :data => data}
81
- @map[file] = @entries.size - 1
82
-
83
- # tell the journal how to truncate this revision
84
- @file.write("#{file}\0#{offset}\n")
85
- @file.flush
86
- end
87
-
88
- ##
89
- # Alias for {add_entry}
90
- alias :<< :add_entry
91
-
92
- ##
93
- # Finds the entry for a given file's path
94
- # @param [String] file the path to the file
95
- # @return [Hash] A hash with the values :file, :offset, and :data, as
96
- # they were when they were stored by {add_entry} or {update}
97
- def find_file(file)
98
- return @entries[@map[file]] if @map[file]
99
- nil
100
- end
101
-
102
- ##
103
- # Alias for {find_file}
104
- alias :find :find_file
105
-
106
- ##
107
- # Updates an entry's data, based on the filename. The file must already
108
- # have been journaled.
109
- #
110
- # @param [String] file the file to update
111
- # @param [Fixnum] offset the new offset to store
112
- # @param [String] data the new data to store
113
- def replace(file, offset, data=nil)
114
- raise IndexError.new("journal lookup failed #{file}") unless @map[file]
115
- index = @map[file]
116
- @entries[index] = {:file => file, :offset => offset, :data => data}
117
- @file.write("#{file}\0#{offset}\n")
118
- @file.flush
119
- end
120
-
121
- ##
122
- # Alias for {replace}
123
- alias :update :replace
124
-
125
- ##
126
- # No godly idea what this is for
127
- def nest
128
- @count += 1
129
- self
130
- end
131
-
132
- ##
133
- # Is the journal running right now?
134
- def running?
135
- @count > 0
136
- end
137
-
138
- ##
139
- # Closes up the journal. Will call the after_close proc passed
140
- # during instantiation.
141
- def close
142
- @count -= 1
143
- return if @count != 0
144
- @file.close
145
- @entries = []
146
- if @after_close
147
- @after_close.call
148
- else
149
- FileUtils.safe_unlink(@journal_file)
150
- end
151
- @journal_file = nil
152
- end
153
-
154
- ##
155
- # Abort, abort! abandon ship! This rolls back any changes we've made
156
- # during the current journalling session.
157
- def abort
158
- return unless @entries && @entries.any?
159
- @reporter.report "transaction abort!\n"
160
- @entries.each do |hash|
161
- file, offset = hash[:file], hash[:offset]
162
- begin
163
- fp = open(File.join(".hg","store",file), "a")
164
- fp.truncate offset
165
- fp.close
166
- rescue
167
- @reporter.report "Failed to truncate #{File.join(".hg","store",file)}\n"
168
- end
169
- end
170
- @entries = []
171
- @reporter.report "rollback completed\n"
172
- end
173
-
174
- ##
175
- # If we crashed during an abort, the journal file is gonna be sitting aorund
176
- # somewhere. So, we should rollback any changes it left lying around.
177
- #
178
- # @param [String] file the journal file to use during the rollback
179
- def self.rollback(file)
180
- files = {}
181
- fp = open(file)
182
- fp.each_line do |line|
183
- file, offset = line.split("\0")
184
- files[file] = offset.to_i
185
- end
186
- fp.close
187
- files.each do |file, offset|
188
- if o > 0
189
- fp = open(file, "a")
190
- fp.truncate o.to_i
191
- fp.close
192
- else
193
- fp = open(f)
194
- fn = fp.path
195
- fp.close
196
- FileUtils.safe_unlink fn
197
- end
198
- end
199
- FileUtils.safe_unlink file
200
- end
201
- end
202
- end
203
-
@@ -1,207 +0,0 @@
1
- module Amp
2
- module Repositories
3
- ##
4
- # = Lock
5
- # Manages a given lock file, indicating that the enclosing folder should not
6
- # be modified. Typically used during destructive operations on a repo (such as
7
- # a commit or push).
8
- #
9
- # We must be compatible with Mercurial's lock format, unfortunately. Doesn't life
10
- # suck?
11
- #####
12
- ##### From Mercurial code, explaining their format:
13
- #####
14
- #
15
- # lock is symlink on platforms that support it, file on others.
16
- #
17
- # symlink is used because create of directory entry and contents
18
- # are atomic even over nfs.
19
- #
20
- # old-style lock: symlink to pid
21
- # new-style lock: symlink to hostname:pid
22
- class Lock
23
- @@host = nil
24
-
25
- ##
26
- # Initializes the lock to a given file name, and creates the lock, effectively
27
- # locking the containing directory.
28
- #
29
- # @param [String] file the path to the the lock file to create
30
- # @param [Hash<Symbol => Object>] opts the options to use when creating the lock
31
- # @option [Integer] options :timeout (-1) the length of time to keep trying to create the lock.
32
- # defaults to -1 (indefinitely)
33
- # @option [Proc, #call] options :release_fxn (nil) A proc to run when the
34
- # lock is released
35
- # @option [String] options :desc (nil) A description of the lock
36
- def initialize(file, opts={:timeout => -1})
37
- @file = file
38
- @held = false
39
- @timeout = opts[:timeout]
40
- @release_fxn = opts[:release_fxn]
41
- @description = opts[:desc]
42
- apply_lock
43
- end
44
-
45
- ##
46
- # Applies the lock. Will sleep the thread for +timeout+ time trying to apply the lock before
47
- # giving up and raising an error.
48
- def apply_lock
49
- timeout = @timeout
50
- while true do
51
- begin
52
- # try_lock will raise of there is already a lock.
53
- try_lock
54
- return true
55
- rescue LockHeld => e
56
- # We'll put up with this exception for @timeout times, then give up.
57
- if timeout != 0
58
- sleep(1)
59
- timeout > 0 && timeout -= 1
60
- next
61
- end
62
- # Timeout's up? Raise an exception.
63
- raise LockHeld.new(Errno::ETIMEDOUT::Errno, e.filename, @desc, e.locker)
64
- end
65
- end
66
- end
67
-
68
- ##
69
- # Attempts to apply the lock. Raises if unsuccessful. Contains the logic for actually naming
70
- # the lock.
71
- def try_lock
72
- if @@host.nil?
73
- @@host = Socket.gethostname
74
- end
75
- lockname = "#{@@host}:#{Process.pid}"
76
- while !@held
77
- begin
78
- make_a_lock(@file, lockname)
79
- @held = true
80
- rescue Errno::EEXIST
81
- locker = test_lock
82
- unless locker.nil?
83
- raise LockHeld.new(Errno::EAGAIN::Errno, @file, @desc, locker)
84
- end
85
- rescue SystemCallError => e
86
- raise LockUnavailable.new(e.errno, e.to_s, @file, @desc)
87
- end
88
- end
89
- end
90
-
91
- ##
92
- # Creates a lock at the given location, with info about the locking process. Uses
93
- # a symlink if possible, because even over NFS, creating a symlink is atomic. Nice.
94
- # Otherwise, it will call make_a_lock_in_file on inferior OS's (cough windows cough)
95
- # and put the data in there.
96
- #
97
- # The symlink is actually a non-working symlink - it points the filename (such as "hglock")
98
- # to the data, even though the data is not an actual file. So hglock -> "medgar:25043" is
99
- # a sort-of possible lock this method would create.
100
- #
101
- # @param [String] file the filename of the lock
102
- # @param [String] info the info to store in the lock
103
- def make_a_lock(file, info)
104
- begin
105
- File.symlink(info, file)
106
- rescue Errno::EEXIST
107
- raise
108
- rescue
109
- make_a_lock_in_file(file, info)
110
- end
111
- end
112
-
113
- ##
114
- # Creates a lock at the given location, storing the info about the locking process in
115
- # an actual lock file. These locks are not preferred, because symlinks are atomic even
116
- # over NFS. Anyway, very simple. Create the file, write in the info, close 'er up.
117
- # That's 1 line in ruby, folks.
118
- #
119
- # @see make_a_lock
120
- # @param [String] file the filename of the lock
121
- # @param [String] info the info to store in the lock
122
- def make_a_lock_in_file(file, info)
123
- File.open(file, "w+") {|out| out.write info }
124
- end
125
-
126
- ##
127
- # Reads in the data associated with a lock file.
128
- #
129
- # @param [String] file the path to the lock file to read
130
- # @return [String] the data in the lock. In the format "#{locking_host}:#{locking_pid}"
131
- def read_lock(file)
132
- begin
133
- return File.readlink(file)
134
- rescue Errno::EINVAL, Errno::ENOSYS
135
- return File.read(file)
136
- end
137
- end
138
-
139
- ##
140
- # Checks to see if there is a process running with id +pid+.
141
- #
142
- # @param [Fixnum] pid the process ID to look up
143
- # @return [Boolean] is there a process with the given pid?
144
- def test_pid(pid)
145
- return true if Platform::OS == :vms
146
-
147
- begin
148
- # Doesn't actually kill it
149
- Process.kill(0, pid)
150
- true
151
- rescue Errno::ESRCH::Errno
152
- true
153
- rescue
154
- false
155
- end
156
- end
157
-
158
-
159
- ##
160
- # Text from mercurial code:
161
- #
162
- # return id of locker if lock is valid, else None.
163
- #
164
- # If old-style lock, we cannot tell what machine locker is on.
165
- # with new-style lock, if locker is on this machine, we can
166
- # see if locker is alive. If locker is on this machine but
167
- # not alive, we can safely break lock.
168
- #
169
- # The lock file is only deleted when None is returned.
170
- def test_lock
171
- locker = read_lock(@file)
172
- host, pid = locker.split(":", 1)
173
- return locker if pid.nil? || host != @@host
174
-
175
- pid = pid.to_i
176
- return locker if pid == 0
177
-
178
- return locker if test_pid pid
179
-
180
- # if locker dead, break lock. must do this with another lock
181
- # held, or can race and break valid lock.
182
- begin
183
- the_lock = Lock.new(@file + ".break")
184
- the_lock.try_lock
185
- File.unlink(@file)
186
- the_lock.release
187
- rescue LockError
188
- return locker
189
- end
190
- end
191
-
192
- ##
193
- # Releases the lock, signalling that it is now safe to modify the directory in which
194
- # the lock is found.
195
- def release
196
- if @held
197
- @held = false
198
- @release_fxn.call if @release_fxn
199
-
200
- File.unlink(@file) rescue ""
201
- end
202
- end
203
-
204
-
205
- end
206
- end
207
- end
@@ -1,214 +0,0 @@
1
- module Amp
2
- module Repositories
3
-
4
- ##
5
- # = BundleRepository
6
- # This class represents a read-only repository that combines both local
7
- # repository data with a bundle file. The bundle file contains un-merged-in
8
- # changesets - this is useful for, say, previewing the results of a pull
9
- # action.
10
- #
11
- # A bundle is stored in the following manner:
12
- # - Changelog entries
13
- # - Manifest entries
14
- # - Modified File entry #1
15
- # - Modified File entry #2
16
- # - ...
17
- # - Modified file entry #N
18
- class BundleRepository < LocalRepository
19
- def initialize(path="", config=nil, bundle_name="")
20
- @temp_parent = nil
21
- # Figure out what to do here - if there's no current local repository, that
22
- # takes some special work.
23
- begin
24
- super(path, false, config) # don't create, just look for a repository
25
- rescue
26
- # Ok, no local repository. Let's make one really quickly.
27
- @temp_parent = File.join(Dir.tmpdir, File.amp_make_tmpname("bundlerepo"))
28
- File.mkdir(@temp_parent)
29
- tmprepo = LocalRepository.new(@temp_parent, true, config) # true -> create
30
- super(@temp_parent, false, config) # and proceed as scheduled!
31
- end
32
-
33
- # Set up our URL variable, if anyone asks us what it is
34
- if path
35
- @url = "bundle:#{path}+#{bundle_name}"
36
- else
37
- @url = "bundle:#{bundle_name}"
38
- end
39
-
40
- @temp_file = nil
41
- @bundle_file = File.open(bundle_name, "r")
42
-
43
- @bundle_file.seek(0, IO::SEEK_END)
44
- Amp::UI.debug "Bundle File Size: #{@bundle_file.tell}"
45
- @bundle_file.seek(0, IO::SEEK_SET)
46
-
47
- # OK, now for the fun part - check the header to see if we're compressed.
48
- header = @bundle_file.read(6)
49
- # And switch based on that header
50
- if !header.start_with?("HG")
51
- # Not even an HG file. FML. Bail
52
- raise abort("#{bundle_name}: not a Mercurial bundle file")
53
- elsif not header.start_with?("HG10")
54
- # Not a version we understand, bail
55
- raise abort("#{bundle_name}: unknown bundle version")
56
- elsif header == "HG10BZ" || header == "HG10GZ"
57
- # Compressed! We'll have to save to a new file, because this could get messy.
58
- temp_file = Tempfile.new("hg-bundle-hg10un", @root)
59
- @temp_file_path = temp_file.path
60
- # Are we BZip, or GZip?
61
- case header
62
- when "HG10BZ"
63
- # fuck BZip. Seriously.
64
- headerio = StringIO.new "BZ", (ruby_19? ? "w+:ASCII-8BIT" : "w+")
65
- input = Amp::Support::MultiIO.new(headerio, @bundle_file)
66
- decomp = BZ2::Reader.new(input)
67
- when "HG10GZ"
68
- # Gzip is much nicer.
69
- decomp = Zlib::GzipReader.new(@bundle_file)
70
- end
71
-
72
- # We're writing this in an uncompressed fashion, of course.
73
- @temp_file.write("HG10UN")
74
- # While we can uncompressed....
75
- while !r.eof? do
76
- # Write the uncompressed data to our new file!
77
- @temp_file.write decomp.read(4096)
78
- end
79
- # and close 'er up
80
- @temp_file.close
81
-
82
- # Close the compressed bundle file
83
- @bundle_file.close
84
- # And re-open the uncompressed bundle file!
85
- @bundle_file = File.open(@temp_file_path, "r")
86
- # Skip the header.
87
- @bundle_file.seek(6)
88
- elsif header == "HG10UN"
89
- # uncompressed, do nothing
90
- else
91
- # We have no idae what's going on
92
- raise abort("#{bundle_name}: unknown bundle compression type")
93
- end
94
- # This hash stores pairs of {filename => position_in_bundle_file_of_this_file}
95
- @bundle_files_positions = {}
96
- end
97
-
98
- ##
99
- # Gets the changelog of the repository. This is different from {LocalRepository#changelog}
100
- # in that it uses a {BundleChangeLog}. Also, since the manifest is stored in the bundle
101
- # directly after the changelog, by checking our position in the bundle file, we can save
102
- # where the bundle_file is stored.
103
- #
104
- # @return [BundleChangeLog] the changelog for this repository.
105
- def changelog
106
- @changelog ||= Bundles::BundleChangeLog.new(@store.opener, @bundle_file)
107
- @manifest_start ||= @bundle_file.tell
108
- @changelog
109
- end
110
-
111
- ##
112
- # Gets the manifest of the repository. This is different from {LocalRepository#manifest}
113
- # in that it uses a {BundleManifest}. The file logs are stored in the bundle directly
114
- # after the manifest, so once we load the manifest, we save where the file logs start
115
- # when we are done loading the manifest.
116
- #
117
- # This has the side-effect of loading the changelog, if it hasn't been loaded already -#
118
- # this is necessary because the manifest changesets are stored after the changelog changesets,
119
- # and we must fully load the changelog changesets to know where to look for the manifest changesets.
120
- #
121
- # Don't look at me, I didn't design the file format.
122
- #
123
- # @return [BundleChangeLog] the changelog for this repository.
124
- def manifest
125
- return @manifest if @manifest
126
- @bundle_file.seek manifest_start
127
- @manifest ||= Bundles::BundleManifest.new @store.opener, @bundle_file, proc {|n| changelog.rev(n) }
128
- @file_start ||= @bundle_file.tell
129
- @manifest
130
- end
131
-
132
- ##
133
- # Returns the position in the bundle file where the manifest changesets are located.
134
- # This involves loading the changelog first - see {#manifest}
135
- #
136
- # @return [Integer] the position in the bundle file where we can find the manifest
137
- # changesets.
138
- def manifest_start
139
- changelog && @manifest_start
140
- end
141
-
142
- ##
143
- # Returns the position in the bundle file where the file log changesets are located.
144
- # This involves loading the changelog and the manifest first - see {#manifest}.
145
- #
146
- # @return [Integer] the position in the bundle file where we can find the file-log
147
- # changesets.
148
- def file_start
149
- manifest && @file_start
150
- end
151
-
152
- ##
153
- # Gets the file-log for the given path, so we can look at an individual
154
- # file's history, for example. However, we need to be cognizant of files that
155
- # traverse the local repository's history as well as the bundle file.
156
- #
157
- # @param [String] f the path to the file
158
- # @return [FileLog] a filelog (a type of revision log) for the given file
159
- def file(filename)
160
-
161
- # Load the file-log positions now - we didn't do this in the constructor for a reason
162
- # (if they don't ask for them, don't load them!)
163
- if @bundle_files_positions.empty?
164
- # Jump to the file position
165
- @bundle_file.seek file_start
166
- while true
167
- # get a changegroup chunk - it'll be the filename
168
- chunk = RevlogSupport::ChangeGroup.get_chunk @bundle_file
169
- # no filename? bail
170
- break if chunk.nil? || chunk.empty?
171
-
172
- # Now that we've read the filename, we're at the start of the changelogs for that
173
- # file. So let's save this position for later.
174
- @bundle_files_positions[chunk] = @bundle_file.tell
175
- # Then read chunks until we get to the next file!
176
- RevlogSupport::ChangeGroup.each_chunk(@bundle_file) {|c|}
177
- end
178
- end
179
-
180
- # Remove leading slash
181
- filename = filename.shift("/")
182
-
183
- # Does this file cross local history as well as the bundle?
184
- if @bundle_files_positions[filename]
185
- # If so, we'll need to make a BundleFileLog. Meh.
186
- @bundle_file.seek @bundle_files_positions[filename]
187
- Bundles::BundleFileLog.new @store.opener, filename, @bundle_file, proc {|n| changelog.rev(n) }
188
- else
189
- # Nope? Make a normal FileLog!
190
- FileLog.new(@store.opener, filename)
191
- end
192
- end
193
-
194
- ##
195
- # Gets the URL for this repository - unused, I believe.
196
- #
197
- # @return [String] the URL for the repository
198
- def url; @url; end
199
-
200
- ##
201
- # Closes the repository - in this case, it closes the bundle_file. Analogous to closing
202
- # an SSHRepository's socket.
203
- def close
204
- @bundle_file.close
205
- end
206
-
207
- # We can't copy files. Read-only.
208
- def can_copy?; false; end
209
- # Gets the current working directory. Not sure why we need this.
210
- def get_cwd; Dir.pwd; end
211
-
212
- end
213
- end
214
- end