amp 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. data/.gitignore +1 -0
  2. data/.hgignore +26 -0
  3. data/AUTHORS +2 -0
  4. data/History.txt +6 -0
  5. data/LICENSE +37 -0
  6. data/MANIFESTO +7 -0
  7. data/Manifest.txt +294 -0
  8. data/README.md +129 -0
  9. data/Rakefile +102 -0
  10. data/SCHEDULE.markdown +12 -0
  11. data/STYLE +27 -0
  12. data/TODO.markdown +149 -0
  13. data/ampfile.rb +47 -0
  14. data/bin/amp +30 -0
  15. data/bin/amp1.9 +30 -0
  16. data/ext/amp/bz2/README.txt +39 -0
  17. data/ext/amp/bz2/bz2.c +1582 -0
  18. data/ext/amp/bz2/extconf.rb +77 -0
  19. data/ext/amp/bz2/mkmf.log +29 -0
  20. data/ext/amp/mercurial_patch/extconf.rb +5 -0
  21. data/ext/amp/mercurial_patch/mpatch.c +405 -0
  22. data/ext/amp/priority_queue/extconf.rb +5 -0
  23. data/ext/amp/priority_queue/priority_queue.c +947 -0
  24. data/ext/amp/support/extconf.rb +5 -0
  25. data/ext/amp/support/support.c +250 -0
  26. data/lib/amp.rb +200 -0
  27. data/lib/amp/commands/command.rb +507 -0
  28. data/lib/amp/commands/command_support.rb +137 -0
  29. data/lib/amp/commands/commands/config.rb +143 -0
  30. data/lib/amp/commands/commands/help.rb +29 -0
  31. data/lib/amp/commands/commands/init.rb +10 -0
  32. data/lib/amp/commands/commands/templates.rb +137 -0
  33. data/lib/amp/commands/commands/version.rb +7 -0
  34. data/lib/amp/commands/commands/workflow.rb +28 -0
  35. data/lib/amp/commands/commands/workflows/git/add.rb +65 -0
  36. data/lib/amp/commands/commands/workflows/git/copy.rb +27 -0
  37. data/lib/amp/commands/commands/workflows/git/mv.rb +23 -0
  38. data/lib/amp/commands/commands/workflows/git/rm.rb +60 -0
  39. data/lib/amp/commands/commands/workflows/hg/add.rb +53 -0
  40. data/lib/amp/commands/commands/workflows/hg/addremove.rb +86 -0
  41. data/lib/amp/commands/commands/workflows/hg/annotate.rb +46 -0
  42. data/lib/amp/commands/commands/workflows/hg/archive.rb +126 -0
  43. data/lib/amp/commands/commands/workflows/hg/branch.rb +28 -0
  44. data/lib/amp/commands/commands/workflows/hg/branches.rb +30 -0
  45. data/lib/amp/commands/commands/workflows/hg/bundle.rb +115 -0
  46. data/lib/amp/commands/commands/workflows/hg/clone.rb +95 -0
  47. data/lib/amp/commands/commands/workflows/hg/commit.rb +42 -0
  48. data/lib/amp/commands/commands/workflows/hg/copy.rb +31 -0
  49. data/lib/amp/commands/commands/workflows/hg/debug/dirstate.rb +32 -0
  50. data/lib/amp/commands/commands/workflows/hg/debug/index.rb +36 -0
  51. data/lib/amp/commands/commands/workflows/hg/default.rb +9 -0
  52. data/lib/amp/commands/commands/workflows/hg/diff.rb +30 -0
  53. data/lib/amp/commands/commands/workflows/hg/forget.rb +11 -0
  54. data/lib/amp/commands/commands/workflows/hg/heads.rb +25 -0
  55. data/lib/amp/commands/commands/workflows/hg/identify.rb +23 -0
  56. data/lib/amp/commands/commands/workflows/hg/import.rb +135 -0
  57. data/lib/amp/commands/commands/workflows/hg/incoming.rb +85 -0
  58. data/lib/amp/commands/commands/workflows/hg/info.rb +18 -0
  59. data/lib/amp/commands/commands/workflows/hg/log.rb +21 -0
  60. data/lib/amp/commands/commands/workflows/hg/manifest.rb +13 -0
  61. data/lib/amp/commands/commands/workflows/hg/merge.rb +53 -0
  62. data/lib/amp/commands/commands/workflows/hg/move.rb +28 -0
  63. data/lib/amp/commands/commands/workflows/hg/outgoing.rb +61 -0
  64. data/lib/amp/commands/commands/workflows/hg/pull.rb +74 -0
  65. data/lib/amp/commands/commands/workflows/hg/push.rb +20 -0
  66. data/lib/amp/commands/commands/workflows/hg/remove.rb +45 -0
  67. data/lib/amp/commands/commands/workflows/hg/resolve.rb +83 -0
  68. data/lib/amp/commands/commands/workflows/hg/revert.rb +53 -0
  69. data/lib/amp/commands/commands/workflows/hg/root.rb +13 -0
  70. data/lib/amp/commands/commands/workflows/hg/serve.rb +38 -0
  71. data/lib/amp/commands/commands/workflows/hg/status.rb +116 -0
  72. data/lib/amp/commands/commands/workflows/hg/tag.rb +69 -0
  73. data/lib/amp/commands/commands/workflows/hg/tags.rb +27 -0
  74. data/lib/amp/commands/commands/workflows/hg/tip.rb +13 -0
  75. data/lib/amp/commands/commands/workflows/hg/update.rb +27 -0
  76. data/lib/amp/commands/commands/workflows/hg/verify.rb +9 -0
  77. data/lib/amp/commands/commands/workflows/hg/view.rb +36 -0
  78. data/lib/amp/commands/dispatch.rb +181 -0
  79. data/lib/amp/commands/hooks.rb +81 -0
  80. data/lib/amp/dependencies/amp_support.rb +1 -0
  81. data/lib/amp/dependencies/amp_support/ruby_amp_support.rb +103 -0
  82. data/lib/amp/dependencies/minitar.rb +979 -0
  83. data/lib/amp/dependencies/priority_queue.rb +18 -0
  84. data/lib/amp/dependencies/priority_queue/c_priority_queue.rb +1 -0
  85. data/lib/amp/dependencies/priority_queue/poor_priority_queue.rb +46 -0
  86. data/lib/amp/dependencies/priority_queue/ruby_priority_queue.rb +525 -0
  87. data/lib/amp/dependencies/python_config.rb +211 -0
  88. data/lib/amp/dependencies/trollop.rb +713 -0
  89. data/lib/amp/dependencies/zip/ioextras.rb +155 -0
  90. data/lib/amp/dependencies/zip/stdrubyext.rb +111 -0
  91. data/lib/amp/dependencies/zip/tempfile_bugfixed.rb +186 -0
  92. data/lib/amp/dependencies/zip/zip.rb +1850 -0
  93. data/lib/amp/dependencies/zip/zipfilesystem.rb +609 -0
  94. data/lib/amp/dependencies/zip/ziprequire.rb +90 -0
  95. data/lib/amp/encoding/base85.rb +97 -0
  96. data/lib/amp/encoding/binary_diff.rb +82 -0
  97. data/lib/amp/encoding/difflib.rb +166 -0
  98. data/lib/amp/encoding/mercurial_diff.rb +378 -0
  99. data/lib/amp/encoding/mercurial_patch.rb +1 -0
  100. data/lib/amp/encoding/patch.rb +292 -0
  101. data/lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb +123 -0
  102. data/lib/amp/extensions/ditz.rb +41 -0
  103. data/lib/amp/extensions/lighthouse.rb +167 -0
  104. data/lib/amp/graphs/ancestor.rb +147 -0
  105. data/lib/amp/graphs/copies.rb +261 -0
  106. data/lib/amp/merges/merge_state.rb +164 -0
  107. data/lib/amp/merges/merge_ui.rb +322 -0
  108. data/lib/amp/merges/simple_merge.rb +450 -0
  109. data/lib/amp/profiling_hacks.rb +36 -0
  110. data/lib/amp/repository/branch_manager.rb +234 -0
  111. data/lib/amp/repository/dir_state.rb +950 -0
  112. data/lib/amp/repository/journal.rb +203 -0
  113. data/lib/amp/repository/lock.rb +207 -0
  114. data/lib/amp/repository/repositories/bundle_repository.rb +214 -0
  115. data/lib/amp/repository/repositories/http_repository.rb +377 -0
  116. data/lib/amp/repository/repositories/local_repository.rb +2661 -0
  117. data/lib/amp/repository/repository.rb +94 -0
  118. data/lib/amp/repository/store.rb +485 -0
  119. data/lib/amp/repository/tag_manager.rb +319 -0
  120. data/lib/amp/repository/updatable.rb +532 -0
  121. data/lib/amp/repository/verification.rb +431 -0
  122. data/lib/amp/repository/versioned_file.rb +475 -0
  123. data/lib/amp/revlogs/bundle_revlogs.rb +246 -0
  124. data/lib/amp/revlogs/changegroup.rb +217 -0
  125. data/lib/amp/revlogs/changelog.rb +338 -0
  126. data/lib/amp/revlogs/changeset.rb +521 -0
  127. data/lib/amp/revlogs/file_log.rb +165 -0
  128. data/lib/amp/revlogs/index.rb +493 -0
  129. data/lib/amp/revlogs/manifest.rb +195 -0
  130. data/lib/amp/revlogs/node.rb +18 -0
  131. data/lib/amp/revlogs/revlog.rb +1032 -0
  132. data/lib/amp/revlogs/revlog_support.rb +126 -0
  133. data/lib/amp/server/amp_user.rb +44 -0
  134. data/lib/amp/server/extension/amp_extension.rb +396 -0
  135. data/lib/amp/server/extension/authorization.rb +201 -0
  136. data/lib/amp/server/fancy_http_server.rb +252 -0
  137. data/lib/amp/server/fancy_views/_browser.haml +28 -0
  138. data/lib/amp/server/fancy_views/_diff_file.haml +13 -0
  139. data/lib/amp/server/fancy_views/_navbar.haml +17 -0
  140. data/lib/amp/server/fancy_views/changeset.haml +31 -0
  141. data/lib/amp/server/fancy_views/commits.haml +32 -0
  142. data/lib/amp/server/fancy_views/file.haml +35 -0
  143. data/lib/amp/server/fancy_views/file_diff.haml +23 -0
  144. data/lib/amp/server/fancy_views/harshcss/all_hallows_eve.css +72 -0
  145. data/lib/amp/server/fancy_views/harshcss/amy.css +147 -0
  146. data/lib/amp/server/fancy_views/harshcss/twilight.css +138 -0
  147. data/lib/amp/server/fancy_views/stylesheet.sass +175 -0
  148. data/lib/amp/server/http_server.rb +140 -0
  149. data/lib/amp/server/repo_user_management.rb +287 -0
  150. data/lib/amp/support/amp_config.rb +164 -0
  151. data/lib/amp/support/amp_ui.rb +287 -0
  152. data/lib/amp/support/docs.rb +54 -0
  153. data/lib/amp/support/generator.rb +78 -0
  154. data/lib/amp/support/ignore.rb +144 -0
  155. data/lib/amp/support/loaders.rb +93 -0
  156. data/lib/amp/support/logger.rb +103 -0
  157. data/lib/amp/support/match.rb +151 -0
  158. data/lib/amp/support/multi_io.rb +87 -0
  159. data/lib/amp/support/openers.rb +121 -0
  160. data/lib/amp/support/ruby_19_compatibility.rb +66 -0
  161. data/lib/amp/support/support.rb +1095 -0
  162. data/lib/amp/templates/blank.commit.erb +23 -0
  163. data/lib/amp/templates/blank.log.erb +18 -0
  164. data/lib/amp/templates/default.commit.erb +23 -0
  165. data/lib/amp/templates/default.log.erb +26 -0
  166. data/lib/amp/templates/template.rb +165 -0
  167. data/site/Rakefile +24 -0
  168. data/site/src/about/ampfile.haml +57 -0
  169. data/site/src/about/commands.haml +106 -0
  170. data/site/src/about/index.haml +33 -0
  171. data/site/src/about/performance.haml +31 -0
  172. data/site/src/about/workflows.haml +34 -0
  173. data/site/src/contribute/index.haml +65 -0
  174. data/site/src/contribute/style.haml +297 -0
  175. data/site/src/css/active4d.css +114 -0
  176. data/site/src/css/all_hallows_eve.css +72 -0
  177. data/site/src/css/all_themes.css +3299 -0
  178. data/site/src/css/amp.css +260 -0
  179. data/site/src/css/amy.css +147 -0
  180. data/site/src/css/blackboard.css +88 -0
  181. data/site/src/css/brilliance_black.css +605 -0
  182. data/site/src/css/brilliance_dull.css +599 -0
  183. data/site/src/css/cobalt.css +149 -0
  184. data/site/src/css/cur_amp.css +185 -0
  185. data/site/src/css/dawn.css +121 -0
  186. data/site/src/css/eiffel.css +121 -0
  187. data/site/src/css/espresso_libre.css +109 -0
  188. data/site/src/css/idle.css +62 -0
  189. data/site/src/css/iplastic.css +80 -0
  190. data/site/src/css/lazy.css +73 -0
  191. data/site/src/css/mac_classic.css +123 -0
  192. data/site/src/css/magicwb_amiga.css +104 -0
  193. data/site/src/css/pastels_on_dark.css +188 -0
  194. data/site/src/css/reset.css +55 -0
  195. data/site/src/css/slush_poppies.css +85 -0
  196. data/site/src/css/spacecadet.css +51 -0
  197. data/site/src/css/sunburst.css +180 -0
  198. data/site/src/css/twilight.css +137 -0
  199. data/site/src/css/zenburnesque.css +91 -0
  200. data/site/src/get/index.haml +32 -0
  201. data/site/src/helpers.rb +121 -0
  202. data/site/src/images/amp_logo.png +0 -0
  203. data/site/src/images/carbonica.png +0 -0
  204. data/site/src/images/revolution.png +0 -0
  205. data/site/src/images/tab-bg.png +0 -0
  206. data/site/src/images/tab-sliding-left.png +0 -0
  207. data/site/src/images/tab-sliding-right.png +0 -0
  208. data/site/src/include/_footer.haml +22 -0
  209. data/site/src/include/_header.haml +17 -0
  210. data/site/src/index.haml +104 -0
  211. data/site/src/learn/index.haml +46 -0
  212. data/site/src/scripts/jquery-1.3.2.min.js +19 -0
  213. data/site/src/scripts/jquery.cookie.js +96 -0
  214. data/tasks/stats.rake +155 -0
  215. data/tasks/yard.rake +171 -0
  216. data/test/dirstate_tests/dirstate +0 -0
  217. data/test/dirstate_tests/hgrc +5 -0
  218. data/test/dirstate_tests/test_dir_state.rb +192 -0
  219. data/test/functional_tests/resources/.hgignore +2 -0
  220. data/test/functional_tests/resources/STYLE.txt +25 -0
  221. data/test/functional_tests/resources/command.rb +372 -0
  222. data/test/functional_tests/resources/commands/annotate.rb +57 -0
  223. data/test/functional_tests/resources/commands/experimental/lolcats.rb +17 -0
  224. data/test/functional_tests/resources/commands/heads.rb +22 -0
  225. data/test/functional_tests/resources/commands/manifest.rb +12 -0
  226. data/test/functional_tests/resources/commands/status.rb +90 -0
  227. data/test/functional_tests/resources/version2/.hgignore +5 -0
  228. data/test/functional_tests/resources/version2/STYLE.txt +25 -0
  229. data/test/functional_tests/resources/version2/command.rb +372 -0
  230. data/test/functional_tests/resources/version2/commands/annotate.rb +45 -0
  231. data/test/functional_tests/resources/version2/commands/experimental/lolcats.rb +17 -0
  232. data/test/functional_tests/resources/version2/commands/heads.rb +22 -0
  233. data/test/functional_tests/resources/version2/commands/manifest.rb +12 -0
  234. data/test/functional_tests/resources/version2/commands/status.rb +90 -0
  235. data/test/functional_tests/resources/version3/.hgignore +5 -0
  236. data/test/functional_tests/resources/version3/STYLE.txt +31 -0
  237. data/test/functional_tests/resources/version3/command.rb +376 -0
  238. data/test/functional_tests/resources/version3/commands/annotate.rb +45 -0
  239. data/test/functional_tests/resources/version3/commands/experimental/lolcats.rb +17 -0
  240. data/test/functional_tests/resources/version3/commands/heads.rb +22 -0
  241. data/test/functional_tests/resources/version3/commands/manifest.rb +12 -0
  242. data/test/functional_tests/resources/version3/commands/status.rb +90 -0
  243. data/test/functional_tests/resources/version4/.hgignore +5 -0
  244. data/test/functional_tests/resources/version4/STYLE.txt +31 -0
  245. data/test/functional_tests/resources/version4/command.rb +376 -0
  246. data/test/functional_tests/resources/version4/commands/experimental/lolcats.rb +17 -0
  247. data/test/functional_tests/resources/version4/commands/heads.rb +22 -0
  248. data/test/functional_tests/resources/version4/commands/manifest.rb +12 -0
  249. data/test/functional_tests/resources/version4/commands/stats.rb +25 -0
  250. data/test/functional_tests/resources/version4/commands/status.rb +90 -0
  251. data/test/functional_tests/resources/version5_1/.hgignore +5 -0
  252. data/test/functional_tests/resources/version5_1/STYLE.txt +2 -0
  253. data/test/functional_tests/resources/version5_1/command.rb +374 -0
  254. data/test/functional_tests/resources/version5_1/commands/experimental/lolcats.rb +17 -0
  255. data/test/functional_tests/resources/version5_1/commands/heads.rb +22 -0
  256. data/test/functional_tests/resources/version5_1/commands/manifest.rb +12 -0
  257. data/test/functional_tests/resources/version5_1/commands/stats.rb +25 -0
  258. data/test/functional_tests/resources/version5_1/commands/status.rb +90 -0
  259. data/test/functional_tests/resources/version5_2/.hgignore +5 -0
  260. data/test/functional_tests/resources/version5_2/STYLE.txt +14 -0
  261. data/test/functional_tests/resources/version5_2/command.rb +376 -0
  262. data/test/functional_tests/resources/version5_2/commands/experimental/lolcats.rb +17 -0
  263. data/test/functional_tests/resources/version5_2/commands/manifest.rb +12 -0
  264. data/test/functional_tests/resources/version5_2/commands/newz.rb +12 -0
  265. data/test/functional_tests/resources/version5_2/commands/stats.rb +25 -0
  266. data/test/functional_tests/resources/version5_2/commands/status.rb +90 -0
  267. data/test/functional_tests/test_functional.rb +604 -0
  268. data/test/localrepo_tests/test_local_repo.rb +121 -0
  269. data/test/localrepo_tests/testrepo.tar.gz +0 -0
  270. data/test/manifest_tests/00manifest.i +0 -0
  271. data/test/manifest_tests/test_manifest.rb +72 -0
  272. data/test/merge_tests/base.txt +10 -0
  273. data/test/merge_tests/expected.local.txt +16 -0
  274. data/test/merge_tests/local.txt +11 -0
  275. data/test/merge_tests/remote.txt +11 -0
  276. data/test/merge_tests/test_merge.rb +26 -0
  277. data/test/revlog_tests/00changelog.i +0 -0
  278. data/test/revlog_tests/revision_added_changelog.i +0 -0
  279. data/test/revlog_tests/test_adding_index.i +0 -0
  280. data/test/revlog_tests/test_revlog.rb +333 -0
  281. data/test/revlog_tests/testindex.i +0 -0
  282. data/test/store_tests/store.tar.gz +0 -0
  283. data/test/store_tests/test_fncache_store.rb +122 -0
  284. data/test/test_amp.rb +9 -0
  285. data/test/test_base85.rb +14 -0
  286. data/test/test_bdiff.rb +42 -0
  287. data/test/test_commands.rb +122 -0
  288. data/test/test_difflib.rb +50 -0
  289. data/test/test_helper.rb +15 -0
  290. data/test/test_journal.rb +29 -0
  291. data/test/test_match.rb +134 -0
  292. data/test/test_mdiff.rb +74 -0
  293. data/test/test_mpatch.rb +14 -0
  294. data/test/test_support.rb +24 -0
  295. metadata +385 -0
@@ -0,0 +1,507 @@
1
+ require 'amp/commands/command_support.rb'
2
+
3
+ module Amp
4
+
5
+ ##
6
+ # Represents a command within the Amp system. Simply instantiating a new
7
+ # command will make it available to the Amp executable. You configure the
8
+ # command by filling out a block in the command's initializer.
9
+ # @example
10
+ # Command.new "add" do |c|
11
+ # c.workflow :hg
12
+ # c.opt :include, "Paths to include",
13
+ # :options => {:short => "-I", :multi => true}
14
+ # c.opt :print_names, :desc => "Print the filenames",
15
+ # :options => {:short => "-p" ,
16
+ # :default => false,
17
+ # :type => :boolean}
18
+ # c.on_run do |options, arguments|
19
+ # if options[:print_names]
20
+ # arguments.each do |filename|
21
+ # puts filename
22
+ # end
23
+ # end
24
+ # end
25
+ # c.help "This is the help text when the user runs `amp help add`"
26
+ # end
27
+ #
28
+ class Command
29
+ include CommandSupport
30
+
31
+ # The current namespace to append to any new commands
32
+ # Not thread-safe at all
33
+ @current_namespaces = []
34
+
35
+ # All the commands registered in the system
36
+ @all_commands = {}
37
+
38
+ # Synonyms for commands. Used as a backup.
39
+ @all_synonyms = {}
40
+
41
+ # Workflows for splitting up commands into groups.
42
+ # The hash will automatically fill slots with empty hashes
43
+ # upon reads if they are empty.
44
+ #
45
+ # Workflows are doubly linked, in that the cvar +self.class.workflows+ keeps track of
46
+ # what commands belong to it, and the commands themselves keep track of which
47
+ # workflows they belong to.
48
+ @workflows = Hash.new {|h, k| h[k] = {} }
49
+
50
+ # These are options that all commands support. Allows the user to put
51
+ # them after the subcommand.
52
+ GLOBAL_OPTIONS = []
53
+ # {:name => :verbose, :desc => "Verbose output", :options => {:short => "-v"}}
54
+
55
+ class << self
56
+
57
+ attr_reader :current_namespaces
58
+
59
+ ##
60
+ # Returns all of the commands registered in the system.
61
+ #
62
+ # @return [Hash<Symbol => Amp::Command>] the commands, keyed by command name as a string
63
+ attr_reader :all_commands
64
+
65
+ ##
66
+ # Returns all the synonyms registered in the system.
67
+ #
68
+ # @return [Hash<Symbol => Amp::Command>] the synonyms, keyed by the synonym as a string
69
+ attr_reader :all_synonyms
70
+ attr_reader :workflows
71
+
72
+ ##
73
+ # Appends the given namespace to the active namespace for new commands.
74
+ #
75
+ # @param [String, #to_s] namespace the new namespace to add
76
+ def use_namespace(namespace)
77
+ current_namespaces.push namespace
78
+ end
79
+
80
+ ##
81
+ # Removes one namespace from the active namespaces for new commands
82
+ def pop_namespace
83
+ current_namespaces.pop
84
+ end
85
+
86
+ ##
87
+ # Returns all commands and synonyms registered in the system.
88
+ # The commands are merged into the synonyms so that any synonym with
89
+ # the same name as a command will be overwritten in the hash.
90
+ #
91
+ # @return [Hash<Symbol => Amp::Command>] the commands and synonyms,
92
+ # keyed by command name as a string
93
+ def all
94
+ all_synonyms.merge all_commands
95
+ end
96
+
97
+ ##
98
+ # Returns all commands and synonyms registered in the system for a
99
+ # given workflow. The ":all" workflow is automatically merged in, as well.
100
+ #
101
+ # @param [Symbol] workflow the workflow whose commands we need
102
+ # @return [Hash<Symbol => Amp::Command>] the commands and synonyms for the
103
+ # workflow (and all global commands), keyed by command name as a string
104
+ def all_for_workflow(flow, synonyms=true)
105
+ flow = flow.to_sym
106
+
107
+ cmds = workflows[flow].merge workflows[:all]
108
+
109
+ if synonyms
110
+ # because there is no way to view all synonyms with workflow +flow+,
111
+ # we have to work bottom up (hence the doubly linked aspect for commands,
112
+ # which is reduced to singly linked)
113
+ syns = all_synonyms.select {|k, v| v.workflows.include? flow }
114
+ syns = syns.to_hash
115
+ else
116
+ syns = {}
117
+ end
118
+
119
+ syns.merge cmds
120
+ end
121
+
122
+ ##
123
+ # Gets a specific command, for a given workflow. This is necessary because it
124
+ # will be expected that 2 different workflows have a command with the same name
125
+ # (such as "move").
126
+ #
127
+ # @param [String, Symbol] cmd the command to look up
128
+ # @param [Symbol] the workflow to use for the lookup
129
+ # @return [Amp::Command] the command for the given name and workflow
130
+ def command_for_workflow(cmd, flow)
131
+ all_for_workflow(flow)[cmd.to_sym]
132
+ end
133
+
134
+ ##
135
+ # Returns all of the commands registered in the system.
136
+ #
137
+ # @return [Hash<Symbol => Amp::Command>, NilClass] the commands, keyed by
138
+ # command name as a symbol. returns nil if nothing is found
139
+ def [](arg)
140
+ all[arg.to_sym]
141
+ end
142
+ end
143
+
144
+ # Command-specific command-line options
145
+ attr_accessor :options
146
+ # The name of the command (eg 'add', 'init')
147
+ attr_accessor :name
148
+ # Short, 1-line description of the command
149
+ attr_accessor :description
150
+ # The Trollop parser
151
+ attr_accessor :parser
152
+
153
+ ##
154
+ # Creates a command in the Amp system. Simply instantiating a new
155
+ # command will make it available to the Amp executable. You configure the
156
+ # command by filling out a block in the command's initializer.
157
+ #
158
+ # @example
159
+ # Command.new("add") do |c|
160
+ # c.opt :include, "Paths to include",
161
+ # :options => {:short => "-I", :multi => true}
162
+ # c.opt :print_names, :desc => "Print the filenames",
163
+ # :options => {:short => "-p", :default => false,
164
+ # :type => :boolean}
165
+ # c.on_run do |options, arguments|
166
+ # puts "silly!"
167
+ # end
168
+ # end
169
+ # @param name the name of the command that the user will use to call
170
+ # the command
171
+ # @param &block a block of code where you can configure the command
172
+ # @yield This block configures the command. Set up options, add an on_run
173
+ # handler, and so on.
174
+ # @yieldparam The command itself - it is yielded so you can modify it.
175
+ def initialize(name, require_new = false)
176
+ # so that you can do additions to commands, just like ammending rake tasks
177
+ full_name = (self.class.current_namespaces + [name]).join(":")
178
+ name = full_name.to_sym
179
+ if self.class.all_commands[name]
180
+ yield self.class.all_commands[name] if block_given?
181
+ return self.class.all_commands[name]
182
+ end
183
+
184
+ @name = name
185
+ @help = ""
186
+ @options = []
187
+ self.class.all_commands[name] = self
188
+ @before = []
189
+ @after = []
190
+
191
+ @workflows = []
192
+ @synonyms = []
193
+ yield(self) if block_given?
194
+ workflow :all if @workflows.empty?
195
+ @options += GLOBAL_OPTIONS
196
+ end
197
+
198
+ ##
199
+ # Adds an command-line option to the command.
200
+ #
201
+ # @param name the name of the command the user will type to run it
202
+ # @param desc the short, one-line description of the command
203
+ # @param options the options that configure the command-line option
204
+ # (too meta? sorry!)
205
+ # @option [String] options :short (nil) the short version of the option
206
+ # (e.g. "-I")
207
+ # @option [String] options :default (nil) the default value of the option.
208
+ # @option [Symbol] options :type (:string) the type of the option. Allows
209
+ # you to force Integer or URL matches.
210
+ # @option [Boolean] options :multi (false) can this option take multiple
211
+ # values?
212
+ def opt(name, desc='', options={})
213
+ @options << {:name => name, :desc => desc, :options => options}
214
+ end
215
+ alias_method :add_opt, :opt
216
+
217
+ ##
218
+ # Override a default value for a command option. Useful for user-provided
219
+ # ampfiles.
220
+ #
221
+ # @example This example will make `amp status` default to mercurial-style
222
+ # output, instead of amp's colorful, easy-to-read output.
223
+ # command :status do |c|
224
+ # default :hg, true
225
+ # default :"no-color", true
226
+ # end
227
+ # @param [Symbol, #to_sym] opt the option to modify. Can be symbol or string.
228
+ # @param value the new default value for the option
229
+ def default(opt, value)
230
+ opt = opt.to_sym
231
+ the_opt = @options.select {|o| o[:name] == opt}.first
232
+ if the_opt
233
+ the_opt[:options][:default] = value
234
+ end
235
+ end
236
+
237
+ ##
238
+ # This method is how you set what the command does when it is run.
239
+ #
240
+ # @param &block the code to run when the command runs
241
+ # @yield The code to run when the command is executed, after options
242
+ # are prepared.
243
+ # @yieldparam options The options that the dispatcher has prepared for
244
+ # the command. Includes global and local.
245
+ # @yieldparam arguments All arguments passed to the command, after
246
+ # the options.
247
+ # @example
248
+ # Command.new("email_news") do |c|
249
+ # c.on_run do |options, arguments|
250
+ # arguments.each do |email_address|
251
+ # send_some_email(options[:email_subject],email_address)
252
+ # end
253
+ # end
254
+ # end
255
+ def on_run(&block)
256
+ @code = proc(&block) # this way we have the ability to do `return`
257
+ end
258
+
259
+ ##
260
+ # This method lets you set a synonym (or synonyms) for this command.
261
+ # For example, the "remove" command has the synonym "rm". Example:
262
+ # command :remove do |c|
263
+ # c.synonym :rm, :destroy, :nuke
264
+ # end
265
+ # then you can do
266
+ # amp nuke badfile.rb
267
+ def synonym(*args)
268
+ args.each do |arg|
269
+ @synonyms << arg
270
+ self.class.all_synonyms[arg.to_sym] = self
271
+ end
272
+ end
273
+ alias_method :synonyms, :synonym
274
+
275
+ ##
276
+ # Specifies a workflow that may access this command. Workflows are
277
+ # groups of commands, pure and simple. If the user has no specified
278
+ # workflow, the mercurial workflow is used by default.
279
+ def workflow(*args)
280
+ if args.any? # unless args.empty?
281
+ args.each do |arg|
282
+ self.class.workflows[arg][self.name.to_sym] = self # register globally
283
+ @workflows << arg # register locally
284
+ end
285
+ else
286
+ @workflows
287
+ end
288
+ end
289
+ alias_method :workflows, :workflow
290
+
291
+ ##
292
+ # This returns the list of actions to run before the command, in order (first
293
+ # ones are run first). You can modify this array in any way you choose, and
294
+ # it is run _before_ the command is run.
295
+ #
296
+ # @yield Extra code to run before the command is executed, after options
297
+ # are prepared.
298
+ # @yieldparam options The options that the dispatcher has prepared
299
+ # for the command. Includes global and local.
300
+ # @yieldparam arguments All arguments passed to the command, after the options.
301
+ # @return [Hash] an array of strings and blocks. Strings are assumed to
302
+ # be command names and blocks are pieces of code to be run.
303
+ def before(*args, &block)
304
+ args.each do |arg|
305
+ @before << proc {|opts, args| Amp::Command[arg.to_sym].run(opts, args) }
306
+ end
307
+
308
+ @before << block if block
309
+ @before
310
+ end
311
+ ##
312
+ # This returns the list of actions to run after the command, in order (first
313
+ # ones are run first). You can modify this array in any way you choose, and
314
+ # it is run _after_ the command is run.
315
+ #
316
+ # @yield Extra code to run after the command is executed, after options are prepared.
317
+ # @yieldparam options The options that the dispatcher has prepared for the command.
318
+ # Includes global and local.
319
+ # @yieldparam arguments All arguments passed to the command, after the options.
320
+ # @return [Hash] an array of strings and blocks. Strings are assumed to be command
321
+ # names and blocks are pieces of code to be run.
322
+ def after(*args, &block)
323
+ args.each do |arg|
324
+ @after << proc {|opts, args| Amp::Command[arg.to_sym].run(opts, args) }
325
+ end
326
+
327
+ @after << block if block
328
+ @after
329
+ end
330
+
331
+ ##
332
+ # The one-line description of the command. This is the first line
333
+ # of the help text. If no argument is passed, then the desription
334
+ # is returned. If an argument is passed, it will be set to be the
335
+ # first line of the help text.
336
+ #
337
+ # @example cmd.desc # => "This command is useless."
338
+ # @param [String, nil] str the help text to set
339
+ def desc(str=nil)
340
+ str ? @help = "#{str}\n\n#{@help}" : @help.split("\n").first
341
+ end
342
+
343
+ ##
344
+ # Trollop's help info for the command
345
+ def educate
346
+ @parser ? @parser.educate : ''
347
+ end
348
+ alias_method :education, :educate
349
+
350
+ ##
351
+ # Sets the command to not laod a repository when run. Useful for purely
352
+ # informational commands (such as version) or initializing a new
353
+ # repository.
354
+ def no_repo
355
+ NO_REPO_ALLOWED[@name] = true
356
+ end
357
+
358
+ # @see no_repo
359
+ def no_repo=(value)
360
+ NO_REPO_ALLOWED[@name] = value
361
+ end
362
+
363
+ ##
364
+ # Sets the command to not require a repository to run, but try to load one.
365
+ # Used, for example, for the templates command, which sometimes stores
366
+ # information in the local repository.
367
+ def maybe_repo
368
+ MAYBE_REPO_ALLOWED[@name] = true
369
+ end
370
+
371
+ # @see no_repo
372
+ def maybe_repo=(value)
373
+ MAYBE_REPO_ALLOWED[@name] = value
374
+ end
375
+
376
+ ##
377
+ # Sets the help text for the command. This can be a very long string,
378
+ # as it is what the user sees when they type `amp help +name+`
379
+ #
380
+ # @param str the help text to set
381
+ # @example cmd.help %Q{
382
+ # Big help text!
383
+ # }
384
+ def help(str=nil)
385
+ str ? @help << str : @help
386
+ end
387
+
388
+ ##
389
+ # Sets the help text for the command. This can be a very long string,
390
+ # as it is what the user sees when they type `amp help +name+`
391
+ #
392
+ # @param str the help text to set
393
+ alias :help= :help
394
+
395
+ ##
396
+ # Parses the commands from the command line using Trollop. You probably
397
+ # shouldn't override this method, but if you have good reason, go for it.
398
+ #
399
+ # @return [Hash<Symbol => Object>] The parsed command-line options
400
+ def collect_options
401
+ options = @options # hack to get around the fact that
402
+ help = @help # Trollop uses instance eval
403
+
404
+ ret = Trollop::options do
405
+ banner help
406
+
407
+ # we can't use @options here because Trollop::options uses instance_eval
408
+ # therefore we have to use a local to cheat death^H^H^H^H^Hinstance_eval
409
+ options.each do |option|
410
+ opt option[:name], option[:desc], option[:options]
411
+ end
412
+ end
413
+
414
+ @parser = ret.pop
415
+ ret.first
416
+ end
417
+
418
+ def inspect
419
+ "#<Amp::Command #{name}>"
420
+ end
421
+
422
+ ##
423
+ # Adds a namespace to the name of the command. This extra method is
424
+ # needed because many class variables expect this command based on its name -
425
+ # if we don't update these, then our entire program will expect a
426
+ # command with the old name. Not cool.
427
+ #
428
+ # @param [String] ns the namespace to put in front of the command's name
429
+ def add_namespace(ns)
430
+ to = "#{ns}:#{name}".to_sym
431
+ if self.class.all_commands[name] == self
432
+ self.class.all_commands[to] = self.class.all_commands.delete name
433
+ end
434
+ @workflows.each do |flow|
435
+ if self.class.workflows[flow][name] == self
436
+ self.class.workflows[flow][to] = self.class.workflows[flow].delete name
437
+ end
438
+ end
439
+ @synonyms.each do |syn|
440
+ if self.class.all_synonyms[syn] == self
441
+ self.class.all_synonyms["#{ns}:#{syn}"] = self.class.all_synonyms.delete syn
442
+ end
443
+ end
444
+ @name = to
445
+ end
446
+
447
+ ##
448
+ # Called by the dispatcher to execute the command. You really don't need to
449
+ # override this. The `$break` global can be set by anything, which
450
+ # will halt the chain.
451
+ #
452
+ # @param [Hash<Symbol => Object>] options The global options, merged with the command-specific
453
+ # options, as decided by the dispatcher.
454
+ # @param [Array<String>] arguments The list of arguments, passed after the options. Could
455
+ # be a filename, for example.
456
+ # @return [Amp::Command] the command being run
457
+ def run(options={}, args=[])
458
+ # run the before commands
459
+ @before.each {|cmd| result = cmd.run options, args; return if !result || $break }
460
+
461
+ @code[options, args] # and of course the actual command...
462
+
463
+ # top it off with the after commands
464
+ @after.each {|cmd| result = cmd.run options, args; return if !result || $break }
465
+
466
+ self
467
+ end
468
+
469
+ NO_REPO_ALLOWED = {}
470
+ %w(clone init help version debugcomplete debugdata debugindex
471
+ debugindexdot debugdate debuginstall debugfsinfo).each do |k|
472
+ NO_REPO_ALLOWED[k.to_sym] = true
473
+ end
474
+
475
+ MAYBE_REPO_ALLOWED = {}
476
+ %w().each do |k|
477
+ MAYBE_REPO_ALLOWED[k.to_sym] = true
478
+ end
479
+
480
+ end
481
+ end
482
+
483
+ module Amp
484
+ module KernelMethods
485
+ # shortcut
486
+ def command(name, &block)
487
+ Amp::Command.new name, &block
488
+ end
489
+
490
+ ##
491
+ # Stops the command from running any further - uses the global options.
492
+ def cut!; $break = true; end
493
+
494
+ # Rake style namespacing
495
+ # After new commands are made, alter their names
496
+ # so that they're "#{namespace}:#{command}"
497
+ # NOTE: THIS IS NOT RAKE-FRIENDLY
498
+ # If you load this into a script with Rake, they will
499
+ # fight to the death and only one will have a proper namespace method!
500
+ def namespace(name)
501
+ # current commands
502
+ Amp::Command.use_namespace name.to_s
503
+ yield
504
+ Amp::Command.pop_namespace
505
+ end
506
+ end
507
+ end