erails 2.1.2

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 (193) hide show
  1. data/CHANGELOG +3 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +309 -0
  4. data/Rakefile +339 -0
  5. data/bin/about +4 -0
  6. data/bin/console +3 -0
  7. data/bin/dbconsole +3 -0
  8. data/bin/destroy +3 -0
  9. data/bin/erails +19 -0
  10. data/bin/generate +3 -0
  11. data/bin/performance/benchmarker +3 -0
  12. data/bin/performance/profiler +3 -0
  13. data/bin/performance/request +3 -0
  14. data/bin/plugin +3 -0
  15. data/bin/process/inspector +3 -0
  16. data/bin/process/reaper +3 -0
  17. data/bin/process/spawner +3 -0
  18. data/bin/runner +3 -0
  19. data/bin/server +3 -0
  20. data/builtin/rails_info/rails/info.rb +125 -0
  21. data/builtin/rails_info/rails/info_controller.rb +9 -0
  22. data/builtin/rails_info/rails/info_helper.rb +2 -0
  23. data/builtin/rails_info/rails_info_controller.rb +2 -0
  24. data/configs/apache.conf +40 -0
  25. data/configs/databases/frontbase.yml +28 -0
  26. data/configs/databases/mysql.yml +54 -0
  27. data/configs/databases/oracle.yml +39 -0
  28. data/configs/databases/postgresql.yml +48 -0
  29. data/configs/databases/sqlite2.yml +16 -0
  30. data/configs/databases/sqlite3.yml +19 -0
  31. data/configs/empty.log +0 -0
  32. data/configs/initializers/inflections.rb +10 -0
  33. data/configs/initializers/mime_types.rb +5 -0
  34. data/configs/initializers/new_rails_defaults.rb +17 -0
  35. data/configs/lighttpd.conf +54 -0
  36. data/configs/routes.rb +43 -0
  37. data/dispatches/dispatch.fcgi +24 -0
  38. data/dispatches/dispatch.rb +10 -0
  39. data/dispatches/gateway.cgi +97 -0
  40. data/doc/README_FOR_APP +2 -0
  41. data/environments/boot.rb +109 -0
  42. data/environments/development.rb +16 -0
  43. data/environments/environment.rb +71 -0
  44. data/environments/production.rb +22 -0
  45. data/environments/test.rb +22 -0
  46. data/fresh_rakefile +10 -0
  47. data/helpers/application.rb +15 -0
  48. data/helpers/application_helper.rb +3 -0
  49. data/helpers/test_helper.rb +38 -0
  50. data/html/404.html +30 -0
  51. data/html/422.html +30 -0
  52. data/html/500.html +30 -0
  53. data/html/favicon.ico +0 -0
  54. data/html/images/rails.png +0 -0
  55. data/html/index.html +274 -0
  56. data/html/javascripts/application.js +2 -0
  57. data/html/robots.txt +5 -0
  58. data/lib/code_statistics.rb +107 -0
  59. data/lib/commands/about.rb +3 -0
  60. data/lib/commands/console.rb +32 -0
  61. data/lib/commands/dbconsole.rb +67 -0
  62. data/lib/commands/destroy.rb +6 -0
  63. data/lib/commands/generate.rb +6 -0
  64. data/lib/commands/ncgi/listener +86 -0
  65. data/lib/commands/ncgi/tracker +69 -0
  66. data/lib/commands/performance/benchmarker.rb +24 -0
  67. data/lib/commands/performance/profiler.rb +50 -0
  68. data/lib/commands/performance/request.rb +6 -0
  69. data/lib/commands/plugin.rb +950 -0
  70. data/lib/commands/process/inspector.rb +68 -0
  71. data/lib/commands/process/reaper.rb +149 -0
  72. data/lib/commands/process/spawner.rb +219 -0
  73. data/lib/commands/process/spinner.rb +57 -0
  74. data/lib/commands/runner.rb +48 -0
  75. data/lib/commands/server.rb +39 -0
  76. data/lib/commands/servers/base.rb +31 -0
  77. data/lib/commands/servers/lighttpd.rb +94 -0
  78. data/lib/commands/servers/mongrel.rb +69 -0
  79. data/lib/commands/servers/new_mongrel.rb +16 -0
  80. data/lib/commands/servers/webrick.rb +66 -0
  81. data/lib/commands/update.rb +4 -0
  82. data/lib/commands.rb +17 -0
  83. data/lib/console_app.rb +30 -0
  84. data/lib/console_sandbox.rb +6 -0
  85. data/lib/console_with_helpers.rb +26 -0
  86. data/lib/dispatcher.rb +24 -0
  87. data/lib/fcgi_handler.rb +239 -0
  88. data/lib/initializer.rb +926 -0
  89. data/lib/rails/gem_builder.rb +21 -0
  90. data/lib/rails/gem_dependency.rb +129 -0
  91. data/lib/rails/mongrel_server/commands.rb +342 -0
  92. data/lib/rails/mongrel_server/handler.rb +55 -0
  93. data/lib/rails/plugin/loader.rb +152 -0
  94. data/lib/rails/plugin/locator.rb +100 -0
  95. data/lib/rails/plugin.rb +116 -0
  96. data/lib/rails/version.rb +9 -0
  97. data/lib/rails_generator/base.rb +263 -0
  98. data/lib/rails_generator/commands.rb +622 -0
  99. data/lib/rails_generator/generated_attribute.rb +42 -0
  100. data/lib/rails_generator/generators/applications/app/USAGE +9 -0
  101. data/lib/rails_generator/generators/applications/app/app_generator.rb +174 -0
  102. data/lib/rails_generator/generators/components/controller/USAGE +29 -0
  103. data/lib/rails_generator/generators/components/controller/controller_generator.rb +37 -0
  104. data/lib/rails_generator/generators/components/controller/templates/controller.rb +7 -0
  105. data/lib/rails_generator/generators/components/controller/templates/functional_test.rb +8 -0
  106. data/lib/rails_generator/generators/components/controller/templates/helper.rb +2 -0
  107. data/lib/rails_generator/generators/components/controller/templates/view.html.erb +2 -0
  108. data/lib/rails_generator/generators/components/integration_test/USAGE +8 -0
  109. data/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb +16 -0
  110. data/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb +10 -0
  111. data/lib/rails_generator/generators/components/mailer/USAGE +16 -0
  112. data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +30 -0
  113. data/lib/rails_generator/generators/components/mailer/templates/fixture.erb +3 -0
  114. data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +0 -0
  115. data/lib/rails_generator/generators/components/mailer/templates/mailer.rb +15 -0
  116. data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +21 -0
  117. data/lib/rails_generator/generators/components/mailer/templates/view.erb +3 -0
  118. data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +0 -0
  119. data/lib/rails_generator/generators/components/migration/USAGE +29 -0
  120. data/lib/rails_generator/generators/components/migration/migration_generator.rb +20 -0
  121. data/lib/rails_generator/generators/components/migration/templates/migration.rb +11 -0
  122. data/lib/rails_generator/generators/components/model/USAGE +27 -0
  123. data/lib/rails_generator/generators/components/model/model_generator.rb +45 -0
  124. data/lib/rails_generator/generators/components/model/templates/fixtures.yml +19 -0
  125. data/lib/rails_generator/generators/components/model/templates/migration.rb +16 -0
  126. data/lib/rails_generator/generators/components/model/templates/model.rb +2 -0
  127. data/lib/rails_generator/generators/components/model/templates/unit_test.rb +8 -0
  128. data/lib/rails_generator/generators/components/observer/USAGE +13 -0
  129. data/lib/rails_generator/generators/components/observer/observer_generator.rb +16 -0
  130. data/lib/rails_generator/generators/components/observer/templates/observer.rb +2 -0
  131. data/lib/rails_generator/generators/components/observer/templates/unit_test.rb +8 -0
  132. data/lib/rails_generator/generators/components/plugin/USAGE +25 -0
  133. data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +39 -0
  134. data/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE +20 -0
  135. data/lib/rails_generator/generators/components/plugin/templates/README +13 -0
  136. data/lib/rails_generator/generators/components/plugin/templates/Rakefile +22 -0
  137. data/lib/rails_generator/generators/components/plugin/templates/USAGE +8 -0
  138. data/lib/rails_generator/generators/components/plugin/templates/generator.rb +8 -0
  139. data/lib/rails_generator/generators/components/plugin/templates/init.rb +1 -0
  140. data/lib/rails_generator/generators/components/plugin/templates/install.rb +1 -0
  141. data/lib/rails_generator/generators/components/plugin/templates/plugin.rb +1 -0
  142. data/lib/rails_generator/generators/components/plugin/templates/tasks.rake +4 -0
  143. data/lib/rails_generator/generators/components/plugin/templates/uninstall.rb +1 -0
  144. data/lib/rails_generator/generators/components/plugin/templates/unit_test.rb +8 -0
  145. data/lib/rails_generator/generators/components/resource/USAGE +23 -0
  146. data/lib/rails_generator/generators/components/resource/resource_generator.rb +74 -0
  147. data/lib/rails_generator/generators/components/resource/templates/controller.rb +2 -0
  148. data/lib/rails_generator/generators/components/resource/templates/functional_test.rb +8 -0
  149. data/lib/rails_generator/generators/components/resource/templates/helper.rb +2 -0
  150. data/lib/rails_generator/generators/components/scaffold/USAGE +25 -0
  151. data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +93 -0
  152. data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +85 -0
  153. data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +45 -0
  154. data/lib/rails_generator/generators/components/scaffold/templates/helper.rb +2 -0
  155. data/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb +17 -0
  156. data/lib/rails_generator/generators/components/scaffold/templates/style.css +54 -0
  157. data/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb +18 -0
  158. data/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb +24 -0
  159. data/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb +17 -0
  160. data/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb +10 -0
  161. data/lib/rails_generator/generators/components/session_migration/USAGE +10 -0
  162. data/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb +18 -0
  163. data/lib/rails_generator/generators/components/session_migration/templates/migration.rb +16 -0
  164. data/lib/rails_generator/lookup.rb +249 -0
  165. data/lib/rails_generator/manifest.rb +53 -0
  166. data/lib/rails_generator/options.rb +150 -0
  167. data/lib/rails_generator/scripts/destroy.rb +30 -0
  168. data/lib/rails_generator/scripts/generate.rb +7 -0
  169. data/lib/rails_generator/scripts/update.rb +12 -0
  170. data/lib/rails_generator/scripts.rb +89 -0
  171. data/lib/rails_generator/secret_key_generator.rb +164 -0
  172. data/lib/rails_generator/simple_logger.rb +46 -0
  173. data/lib/rails_generator/spec.rb +44 -0
  174. data/lib/rails_generator.rb +43 -0
  175. data/lib/railties_path.rb +1 -0
  176. data/lib/ruby_version_check.rb +17 -0
  177. data/lib/rubyprof_ext.rb +35 -0
  178. data/lib/source_annotation_extractor.rb +102 -0
  179. data/lib/tasks/annotations.rake +23 -0
  180. data/lib/tasks/databases.rake +389 -0
  181. data/lib/tasks/documentation.rake +80 -0
  182. data/lib/tasks/framework.rake +105 -0
  183. data/lib/tasks/gems.rake +64 -0
  184. data/lib/tasks/log.rake +9 -0
  185. data/lib/tasks/misc.rake +57 -0
  186. data/lib/tasks/rails.rb +8 -0
  187. data/lib/tasks/routes.rake +17 -0
  188. data/lib/tasks/statistics.rake +18 -0
  189. data/lib/tasks/testing.rake +118 -0
  190. data/lib/tasks/tmp.rake +37 -0
  191. data/lib/test_help.rb +28 -0
  192. data/lib/webrick_server.rb +165 -0
  193. metadata +356 -0
@@ -0,0 +1,950 @@
1
+ # Rails Plugin Manager.
2
+ #
3
+ # Listing available plugins:
4
+ #
5
+ # $ ./script/plugin list
6
+ # continuous_builder http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder
7
+ # asset_timestamping http://svn.aviditybytes.com/rails/plugins/asset_timestamping
8
+ # enumerations_mixin http://svn.protocool.com/rails/plugins/enumerations_mixin/trunk
9
+ # calculations http://techno-weenie.net/svn/projects/calculations/
10
+ # ...
11
+ #
12
+ # Installing plugins:
13
+ #
14
+ # $ ./script/plugin install continuous_builder asset_timestamping
15
+ #
16
+ # Finding Repositories:
17
+ #
18
+ # $ ./script/plugin discover
19
+ #
20
+ # Adding Repositories:
21
+ #
22
+ # $ ./script/plugin source http://svn.protocool.com/rails/plugins/
23
+ #
24
+ # How it works:
25
+ #
26
+ # * Maintains a list of subversion repositories that are assumed to have
27
+ # a plugin directory structure. Manage them with the (source, unsource,
28
+ # and sources commands)
29
+ #
30
+ # * The discover command scrapes the following page for things that
31
+ # look like subversion repositories with plugins:
32
+ # http://wiki.rubyonrails.org/rails/pages/Plugins
33
+ #
34
+ # * Unless you specify that you want to use svn, script/plugin uses plain old
35
+ # HTTP for downloads. The following bullets are true if you specify
36
+ # that you want to use svn.
37
+ #
38
+ # * If `vendor/plugins` is under subversion control, the script will
39
+ # modify the svn:externals property and perform an update. You can
40
+ # use normal subversion commands to keep the plugins up to date.
41
+ #
42
+ # * Or, if `vendor/plugins` is not under subversion control, the
43
+ # plugin is pulled via `svn checkout` or `svn export` but looks
44
+ # exactly the same.
45
+ #
46
+ # This is Free Software, copyright 2005 by Ryan Tomayko (rtomayko@gmail.com)
47
+ # and is licensed MIT: (http://www.opensource.org/licenses/mit-license.php)
48
+
49
+ $verbose = false
50
+
51
+
52
+ require 'open-uri'
53
+ require 'fileutils'
54
+ require 'tempfile'
55
+
56
+ include FileUtils
57
+
58
+ class RailsEnvironment
59
+ attr_reader :root
60
+
61
+ def initialize(dir)
62
+ @root = dir
63
+ end
64
+
65
+ def self.find(dir=nil)
66
+ dir ||= pwd
67
+ while dir.length > 1
68
+ return new(dir) if File.exist?(File.join(dir, 'config', 'environment.rb'))
69
+ dir = File.dirname(dir)
70
+ end
71
+ end
72
+
73
+ def self.default
74
+ @default ||= find
75
+ end
76
+
77
+ def self.default=(rails_env)
78
+ @default = rails_env
79
+ end
80
+
81
+ def install(name_uri_or_plugin)
82
+ if name_uri_or_plugin.is_a? String
83
+ if name_uri_or_plugin =~ /:\/\//
84
+ plugin = Plugin.new(name_uri_or_plugin)
85
+ else
86
+ plugin = Plugins[name_uri_or_plugin]
87
+ end
88
+ else
89
+ plugin = name_uri_or_plugin
90
+ end
91
+ unless plugin.nil?
92
+ plugin.install
93
+ else
94
+ puts "Plugin not found: #{name_uri_or_plugin}"
95
+ end
96
+ end
97
+
98
+ def use_svn?
99
+ require 'active_support/core_ext/kernel'
100
+ silence_stderr {`svn --version` rescue nil}
101
+ !$?.nil? && $?.success?
102
+ end
103
+
104
+ def use_externals?
105
+ use_svn? && File.directory?("#{root}/vendor/plugins/.svn")
106
+ end
107
+
108
+ def use_checkout?
109
+ # this is a bit of a guess. we assume that if the rails environment
110
+ # is under subversion then they probably want the plugin checked out
111
+ # instead of exported. This can be overridden on the command line
112
+ File.directory?("#{root}/.svn")
113
+ end
114
+
115
+ def best_install_method
116
+ return :http unless use_svn?
117
+ case
118
+ when use_externals? then :externals
119
+ when use_checkout? then :checkout
120
+ else :export
121
+ end
122
+ end
123
+
124
+ def externals
125
+ return [] unless use_externals?
126
+ ext = `svn propget svn:externals "#{root}/vendor/plugins"`
127
+ ext.reject{ |line| line.strip == '' }.map do |line|
128
+ line.strip.split(/\s+/, 2)
129
+ end
130
+ end
131
+
132
+ def externals=(items)
133
+ unless items.is_a? String
134
+ items = items.map{|name,uri| "#{name.ljust(29)} #{uri.chomp('/')}"}.join("\n")
135
+ end
136
+ Tempfile.open("svn-set-prop") do |file|
137
+ file.write(items)
138
+ file.flush
139
+ system("svn propset -q svn:externals -F \"#{file.path}\" \"#{root}/vendor/plugins\"")
140
+ end
141
+ end
142
+
143
+ end
144
+
145
+ class Plugin
146
+ attr_reader :name, :uri
147
+
148
+ def initialize(uri, name=nil)
149
+ @uri = uri
150
+ guess_name(uri)
151
+ end
152
+
153
+ def self.find(name)
154
+ name =~ /\// ? new(name) : Repositories.instance.find_plugin(name)
155
+ end
156
+
157
+ def to_s
158
+ "#{@name.ljust(30)}#{@uri}"
159
+ end
160
+
161
+ def svn_url?
162
+ @uri =~ /svn(?:\+ssh)?:\/\/*/
163
+ end
164
+
165
+ def git_url?
166
+ @uri =~ /^git:\/\// || @uri =~ /\.git$/
167
+ end
168
+
169
+ def installed?
170
+ File.directory?("#{rails_env.root}/vendor/plugins/#{name}") \
171
+ or rails_env.externals.detect{ |name, repo| self.uri == repo }
172
+ end
173
+
174
+ def install(method=nil, options = {})
175
+ method ||= rails_env.best_install_method?
176
+ if :http == method
177
+ method = :export if svn_url?
178
+ method = :clone if git_url?
179
+ end
180
+
181
+ uninstall if installed? and options[:force]
182
+
183
+ unless installed?
184
+ send("install_using_#{method}", options)
185
+ run_install_hook
186
+ else
187
+ puts "already installed: #{name} (#{uri}). pass --force to reinstall"
188
+ end
189
+ end
190
+
191
+ def uninstall
192
+ path = "#{rails_env.root}/vendor/plugins/#{name}"
193
+ if File.directory?(path)
194
+ puts "Removing 'vendor/plugins/#{name}'" if $verbose
195
+ run_uninstall_hook
196
+ rm_r path
197
+ else
198
+ puts "Plugin doesn't exist: #{path}"
199
+ end
200
+ # clean up svn:externals
201
+ externals = rails_env.externals
202
+ externals.reject!{|n,u| name == n or name == u}
203
+ rails_env.externals = externals
204
+ end
205
+
206
+ def info
207
+ tmp = "#{rails_env.root}/_tmp_about.yml"
208
+ if svn_url?
209
+ cmd = "svn export #{@uri} \"#{rails_env.root}/#{tmp}\""
210
+ puts cmd if $verbose
211
+ system(cmd)
212
+ end
213
+ open(svn_url? ? tmp : File.join(@uri, 'about.yml')) do |stream|
214
+ stream.read
215
+ end rescue "No about.yml found in #{uri}"
216
+ ensure
217
+ FileUtils.rm_rf tmp if svn_url?
218
+ end
219
+
220
+ private
221
+
222
+ def run_install_hook
223
+ install_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/install.rb"
224
+ load install_hook_file if File.exist? install_hook_file
225
+ end
226
+
227
+ def run_uninstall_hook
228
+ uninstall_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/uninstall.rb"
229
+ load uninstall_hook_file if File.exist? uninstall_hook_file
230
+ end
231
+
232
+ def install_using_export(options = {})
233
+ svn_command :export, options
234
+ end
235
+
236
+ def install_using_checkout(options = {})
237
+ svn_command :checkout, options
238
+ end
239
+
240
+ def install_using_externals(options = {})
241
+ externals = rails_env.externals
242
+ externals.push([@name, uri])
243
+ rails_env.externals = externals
244
+ install_using_checkout(options)
245
+ end
246
+
247
+ def install_using_http(options = {})
248
+ root = rails_env.root
249
+ mkdir_p "#{root}/vendor/plugins/#{@name}"
250
+ Dir.chdir "#{root}/vendor/plugins/#{@name}" do
251
+ puts "fetching from '#{uri}'" if $verbose
252
+ fetcher = RecursiveHTTPFetcher.new(uri, -1)
253
+ fetcher.quiet = true if options[:quiet]
254
+ fetcher.fetch
255
+ end
256
+ end
257
+
258
+ def install_using_clone(options = {})
259
+ git_command :clone, options
260
+ end
261
+
262
+ def svn_command(cmd, options = {})
263
+ root = rails_env.root
264
+ mkdir_p "#{root}/vendor/plugins"
265
+ base_cmd = "svn #{cmd} #{uri} \"#{root}/vendor/plugins/#{name}\""
266
+ base_cmd += ' -q' if options[:quiet] and not $verbose
267
+ base_cmd += " -r #{options[:revision]}" if options[:revision]
268
+ puts base_cmd if $verbose
269
+ system(base_cmd)
270
+ end
271
+
272
+ def git_command(cmd, options = {})
273
+ root = rails_env.root
274
+ mkdir_p "#{root}/vendor/plugins"
275
+ base_cmd = "git #{cmd} --depth 1 #{uri} \"#{root}/vendor/plugins/#{name}\""
276
+ puts base_cmd if $verbose
277
+ puts "removing: #{root}/vendor/plugins/#{name}/.git"
278
+ system(base_cmd)
279
+ rm_rf "#{root}/vendor/plugins/#{name}/.git"
280
+ end
281
+
282
+ def guess_name(url)
283
+ @name = File.basename(url)
284
+ if @name == 'trunk' || @name.empty?
285
+ @name = File.basename(File.dirname(url))
286
+ end
287
+ @name.gsub!(/\.git$/, '') if @name =~ /\.git$/
288
+ end
289
+
290
+ def rails_env
291
+ @rails_env || RailsEnvironment.default
292
+ end
293
+ end
294
+
295
+ class Repositories
296
+ include Enumerable
297
+
298
+ def initialize(cache_file = File.join(find_home, ".rails-plugin-sources"))
299
+ @cache_file = File.expand_path(cache_file)
300
+ load!
301
+ end
302
+
303
+ def each(&block)
304
+ @repositories.each(&block)
305
+ end
306
+
307
+ def add(uri)
308
+ unless find{|repo| repo.uri == uri }
309
+ @repositories.push(Repository.new(uri)).last
310
+ end
311
+ end
312
+
313
+ def remove(uri)
314
+ @repositories.reject!{|repo| repo.uri == uri}
315
+ end
316
+
317
+ def exist?(uri)
318
+ @repositories.detect{|repo| repo.uri == uri }
319
+ end
320
+
321
+ def all
322
+ @repositories
323
+ end
324
+
325
+ def find_plugin(name)
326
+ @repositories.each do |repo|
327
+ repo.each do |plugin|
328
+ return plugin if plugin.name == name
329
+ end
330
+ end
331
+ return nil
332
+ end
333
+
334
+ def load!
335
+ contents = File.exist?(@cache_file) ? File.read(@cache_file) : defaults
336
+ contents = defaults if contents.empty?
337
+ @repositories = contents.split(/\n/).reject do |line|
338
+ line =~ /^\s*#/ or line =~ /^\s*$/
339
+ end.map { |source| Repository.new(source.strip) }
340
+ end
341
+
342
+ def save
343
+ File.open(@cache_file, 'w') do |f|
344
+ each do |repo|
345
+ f.write(repo.uri)
346
+ f.write("\n")
347
+ end
348
+ end
349
+ end
350
+
351
+ def defaults
352
+ <<-DEFAULTS
353
+ http://dev.rubyonrails.com/svn/rails/plugins/
354
+ DEFAULTS
355
+ end
356
+
357
+ def find_home
358
+ ['HOME', 'USERPROFILE'].each do |homekey|
359
+ return ENV[homekey] if ENV[homekey]
360
+ end
361
+ if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
362
+ return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
363
+ end
364
+ begin
365
+ File.expand_path("~")
366
+ rescue StandardError => ex
367
+ if File::ALT_SEPARATOR
368
+ "C:/"
369
+ else
370
+ "/"
371
+ end
372
+ end
373
+ end
374
+
375
+ def self.instance
376
+ @instance ||= Repositories.new
377
+ end
378
+
379
+ def self.each(&block)
380
+ self.instance.each(&block)
381
+ end
382
+ end
383
+
384
+ class Repository
385
+ include Enumerable
386
+ attr_reader :uri, :plugins
387
+
388
+ def initialize(uri)
389
+ @uri = uri.chomp('/') << "/"
390
+ @plugins = nil
391
+ end
392
+
393
+ def plugins
394
+ unless @plugins
395
+ if $verbose
396
+ puts "Discovering plugins in #{@uri}"
397
+ puts index
398
+ end
399
+
400
+ @plugins = index.reject{ |line| line !~ /\/$/ }
401
+ @plugins.map! { |name| Plugin.new(File.join(@uri, name), name) }
402
+ end
403
+
404
+ @plugins
405
+ end
406
+
407
+ def each(&block)
408
+ plugins.each(&block)
409
+ end
410
+
411
+ private
412
+ def index
413
+ @index ||= RecursiveHTTPFetcher.new(@uri).ls
414
+ end
415
+ end
416
+
417
+
418
+ # load default environment and parse arguments
419
+ require 'optparse'
420
+ module Commands
421
+
422
+ class Plugin
423
+ attr_reader :environment, :script_name, :sources
424
+ def initialize
425
+ @environment = RailsEnvironment.default
426
+ @rails_root = RailsEnvironment.default.root
427
+ @script_name = File.basename($0)
428
+ @sources = []
429
+ end
430
+
431
+ def environment=(value)
432
+ @environment = value
433
+ RailsEnvironment.default = value
434
+ end
435
+
436
+ def options
437
+ OptionParser.new do |o|
438
+ o.set_summary_indent(' ')
439
+ o.banner = "Usage: #{@script_name} [OPTIONS] command"
440
+ o.define_head "Rails plugin manager."
441
+
442
+ o.separator ""
443
+ o.separator "GENERAL OPTIONS"
444
+
445
+ o.on("-r", "--root=DIR", String,
446
+ "Set an explicit rails app directory.",
447
+ "Default: #{@rails_root}") { |@rails_root| self.environment = RailsEnvironment.new(@rails_root) }
448
+ o.on("-s", "--source=URL1,URL2", Array,
449
+ "Use the specified plugin repositories instead of the defaults.") { |@sources|}
450
+
451
+ o.on("-v", "--verbose", "Turn on verbose output.") { |$verbose| }
452
+ o.on("-h", "--help", "Show this help message.") { puts o; exit }
453
+
454
+ o.separator ""
455
+ o.separator "COMMANDS"
456
+
457
+ o.separator " discover Discover plugin repositories."
458
+ o.separator " list List available plugins."
459
+ o.separator " install Install plugin(s) from known repositories or URLs."
460
+ o.separator " update Update installed plugins."
461
+ o.separator " remove Uninstall plugins."
462
+ o.separator " source Add a plugin source repository."
463
+ o.separator " unsource Remove a plugin repository."
464
+ o.separator " sources List currently configured plugin repositories."
465
+
466
+ o.separator ""
467
+ o.separator "EXAMPLES"
468
+ o.separator " Install a plugin:"
469
+ o.separator " #{@script_name} install continuous_builder\n"
470
+ o.separator " Install a plugin from a subversion URL:"
471
+ o.separator " #{@script_name} install http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder\n"
472
+ o.separator " Install a plugin from a git URL:"
473
+ o.separator " #{@script_name} install git://github.com/SomeGuy/my_awesome_plugin.git\n"
474
+ o.separator " Install a plugin and add a svn:externals entry to vendor/plugins"
475
+ o.separator " #{@script_name} install -x continuous_builder\n"
476
+ o.separator " List all available plugins:"
477
+ o.separator " #{@script_name} list\n"
478
+ o.separator " List plugins in the specified repository:"
479
+ o.separator " #{@script_name} list --source=http://dev.rubyonrails.com/svn/rails/plugins/\n"
480
+ o.separator " Discover and prompt to add new repositories:"
481
+ o.separator " #{@script_name} discover\n"
482
+ o.separator " Discover new repositories but just list them, don't add anything:"
483
+ o.separator " #{@script_name} discover -l\n"
484
+ o.separator " Add a new repository to the source list:"
485
+ o.separator " #{@script_name} source http://dev.rubyonrails.com/svn/rails/plugins/\n"
486
+ o.separator " Remove a repository from the source list:"
487
+ o.separator " #{@script_name} unsource http://dev.rubyonrails.com/svn/rails/plugins/\n"
488
+ o.separator " Show currently configured repositories:"
489
+ o.separator " #{@script_name} sources\n"
490
+ end
491
+ end
492
+
493
+ def parse!(args=ARGV)
494
+ general, sub = split_args(args)
495
+ options.parse!(general)
496
+
497
+ command = general.shift
498
+ if command =~ /^(list|discover|install|source|unsource|sources|remove|update|info)$/
499
+ command = Commands.const_get(command.capitalize).new(self)
500
+ command.parse!(sub)
501
+ else
502
+ puts "Unknown command: #{command}"
503
+ puts options
504
+ exit 1
505
+ end
506
+ end
507
+
508
+ def split_args(args)
509
+ left = []
510
+ left << args.shift while args[0] and args[0] =~ /^-/
511
+ left << args.shift if args[0]
512
+ return [left, args]
513
+ end
514
+
515
+ def self.parse!(args=ARGV)
516
+ Plugin.new.parse!(args)
517
+ end
518
+ end
519
+
520
+
521
+ class List
522
+ def initialize(base_command)
523
+ @base_command = base_command
524
+ @sources = []
525
+ @local = false
526
+ @remote = true
527
+ end
528
+
529
+ def options
530
+ OptionParser.new do |o|
531
+ o.set_summary_indent(' ')
532
+ o.banner = "Usage: #{@base_command.script_name} list [OPTIONS] [PATTERN]"
533
+ o.define_head "List available plugins."
534
+ o.separator ""
535
+ o.separator "Options:"
536
+ o.separator ""
537
+ o.on( "-s", "--source=URL1,URL2", Array,
538
+ "Use the specified plugin repositories.") {|@sources|}
539
+ o.on( "--local",
540
+ "List locally installed plugins.") {|@local| @remote = false}
541
+ o.on( "--remote",
542
+ "List remotely available plugins. This is the default behavior",
543
+ "unless --local is provided.") {|@remote|}
544
+ end
545
+ end
546
+
547
+ def parse!(args)
548
+ options.order!(args)
549
+ unless @sources.empty?
550
+ @sources.map!{ |uri| Repository.new(uri) }
551
+ else
552
+ @sources = Repositories.instance.all
553
+ end
554
+ if @remote
555
+ @sources.map{|r| r.plugins}.flatten.each do |plugin|
556
+ if @local or !plugin.installed?
557
+ puts plugin.to_s
558
+ end
559
+ end
560
+ else
561
+ cd "#{@base_command.environment.root}/vendor/plugins"
562
+ Dir["*"].select{|p| File.directory?(p)}.each do |name|
563
+ puts name
564
+ end
565
+ end
566
+ end
567
+ end
568
+
569
+
570
+ class Sources
571
+ def initialize(base_command)
572
+ @base_command = base_command
573
+ end
574
+
575
+ def options
576
+ OptionParser.new do |o|
577
+ o.set_summary_indent(' ')
578
+ o.banner = "Usage: #{@base_command.script_name} sources [OPTIONS] [PATTERN]"
579
+ o.define_head "List configured plugin repositories."
580
+ o.separator ""
581
+ o.separator "Options:"
582
+ o.separator ""
583
+ o.on( "-c", "--check",
584
+ "Report status of repository.") { |@sources|}
585
+ end
586
+ end
587
+
588
+ def parse!(args)
589
+ options.parse!(args)
590
+ Repositories.each do |repo|
591
+ puts repo.uri
592
+ end
593
+ end
594
+ end
595
+
596
+
597
+ class Source
598
+ def initialize(base_command)
599
+ @base_command = base_command
600
+ end
601
+
602
+ def options
603
+ OptionParser.new do |o|
604
+ o.set_summary_indent(' ')
605
+ o.banner = "Usage: #{@base_command.script_name} source REPOSITORY [REPOSITORY [REPOSITORY]...]"
606
+ o.define_head "Add new repositories to the default search list."
607
+ end
608
+ end
609
+
610
+ def parse!(args)
611
+ options.parse!(args)
612
+ count = 0
613
+ args.each do |uri|
614
+ if Repositories.instance.add(uri)
615
+ puts "added: #{uri.ljust(50)}" if $verbose
616
+ count += 1
617
+ else
618
+ puts "failed: #{uri.ljust(50)}"
619
+ end
620
+ end
621
+ Repositories.instance.save
622
+ puts "Added #{count} repositories."
623
+ end
624
+ end
625
+
626
+
627
+ class Unsource
628
+ def initialize(base_command)
629
+ @base_command = base_command
630
+ end
631
+
632
+ def options
633
+ OptionParser.new do |o|
634
+ o.set_summary_indent(' ')
635
+ o.banner = "Usage: #{@base_command.script_name} unsource URI [URI [URI]...]"
636
+ o.define_head "Remove repositories from the default search list."
637
+ o.separator ""
638
+ o.on_tail("-h", "--help", "Show this help message.") { puts o; exit }
639
+ end
640
+ end
641
+
642
+ def parse!(args)
643
+ options.parse!(args)
644
+ count = 0
645
+ args.each do |uri|
646
+ if Repositories.instance.remove(uri)
647
+ count += 1
648
+ puts "removed: #{uri.ljust(50)}"
649
+ else
650
+ puts "failed: #{uri.ljust(50)}"
651
+ end
652
+ end
653
+ Repositories.instance.save
654
+ puts "Removed #{count} repositories."
655
+ end
656
+ end
657
+
658
+
659
+ class Discover
660
+ def initialize(base_command)
661
+ @base_command = base_command
662
+ @list = false
663
+ @prompt = true
664
+ end
665
+
666
+ def options
667
+ OptionParser.new do |o|
668
+ o.set_summary_indent(' ')
669
+ o.banner = "Usage: #{@base_command.script_name} discover URI [URI [URI]...]"
670
+ o.define_head "Discover repositories referenced on a page."
671
+ o.separator ""
672
+ o.separator "Options:"
673
+ o.separator ""
674
+ o.on( "-l", "--list",
675
+ "List but don't prompt or add discovered repositories.") { |@list| @prompt = !@list }
676
+ o.on( "-n", "--no-prompt",
677
+ "Add all new repositories without prompting.") { |v| @prompt = !v }
678
+ end
679
+ end
680
+
681
+ def parse!(args)
682
+ options.parse!(args)
683
+ args = ['http://wiki.rubyonrails.org/rails/pages/Plugins'] if args.empty?
684
+ args.each do |uri|
685
+ scrape(uri) do |repo_uri|
686
+ catch(:next_uri) do
687
+ if @prompt
688
+ begin
689
+ $stdout.print "Add #{repo_uri}? [Y/n] "
690
+ throw :next_uri if $stdin.gets !~ /^y?$/i
691
+ rescue Interrupt
692
+ $stdout.puts
693
+ exit 1
694
+ end
695
+ elsif @list
696
+ puts repo_uri
697
+ throw :next_uri
698
+ end
699
+ Repositories.instance.add(repo_uri)
700
+ puts "discovered: #{repo_uri}" if $verbose or !@prompt
701
+ end
702
+ end
703
+ end
704
+ Repositories.instance.save
705
+ end
706
+
707
+ def scrape(uri)
708
+ require 'open-uri'
709
+ puts "Scraping #{uri}" if $verbose
710
+ dupes = []
711
+ content = open(uri).each do |line|
712
+ begin
713
+ if line =~ /<a[^>]*href=['"]([^'"]*)['"]/ || line =~ /(svn:\/\/[^<|\n]*)/
714
+ uri = $1
715
+ if uri =~ /^\w+:\/\// && uri =~ /\/plugins\// && uri !~ /\/browser\// && uri !~ /^http:\/\/wiki\.rubyonrails/ && uri !~ /http:\/\/instiki/
716
+ uri = extract_repository_uri(uri)
717
+ yield uri unless dupes.include?(uri) || Repositories.instance.exist?(uri)
718
+ dupes << uri
719
+ end
720
+ end
721
+ rescue
722
+ puts "Problems scraping '#{uri}': #{$!.to_s}"
723
+ end
724
+ end
725
+ end
726
+
727
+ def extract_repository_uri(uri)
728
+ uri.match(/(svn|https?):.*\/plugins\//i)[0]
729
+ end
730
+ end
731
+
732
+ class Install
733
+ def initialize(base_command)
734
+ @base_command = base_command
735
+ @method = :http
736
+ @options = { :quiet => false, :revision => nil, :force => false }
737
+ end
738
+
739
+ def options
740
+ OptionParser.new do |o|
741
+ o.set_summary_indent(' ')
742
+ o.banner = "Usage: #{@base_command.script_name} install PLUGIN [PLUGIN [PLUGIN] ...]"
743
+ o.define_head "Install one or more plugins."
744
+ o.separator ""
745
+ o.separator "Options:"
746
+ o.on( "-x", "--externals",
747
+ "Use svn:externals to grab the plugin.",
748
+ "Enables plugin updates and plugin versioning.") { |v| @method = :externals }
749
+ o.on( "-o", "--checkout",
750
+ "Use svn checkout to grab the plugin.",
751
+ "Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout }
752
+ o.on( "-e", "--export",
753
+ "Use svn export to grab the plugin.",
754
+ "Exports the plugin, allowing you to check it into your local repository. Does not enable updates, or add an svn:externals entry.") { |v| @method = :export }
755
+ o.on( "-q", "--quiet",
756
+ "Suppresses the output from installation.",
757
+ "Ignored if -v is passed (./script/plugin -v install ...)") { |v| @options[:quiet] = true }
758
+ o.on( "-r REVISION", "--revision REVISION",
759
+ "Checks out the given revision from subversion.",
760
+ "Ignored if subversion is not used.") { |v| @options[:revision] = v }
761
+ o.on( "-f", "--force",
762
+ "Reinstalls a plugin if it's already installed.") { |v| @options[:force] = true }
763
+ o.separator ""
764
+ o.separator "You can specify plugin names as given in 'plugin list' output or absolute URLs to "
765
+ o.separator "a plugin repository."
766
+ end
767
+ end
768
+
769
+ def determine_install_method
770
+ best = @base_command.environment.best_install_method
771
+ @method = :http if best == :http and @method == :export
772
+ case
773
+ when (best == :http and @method != :http)
774
+ msg = "Cannot install using subversion because `svn' cannot be found in your PATH"
775
+ when (best == :export and (@method != :export and @method != :http))
776
+ msg = "Cannot install using #{@method} because this project is not under subversion."
777
+ when (best != :externals and @method == :externals)
778
+ msg = "Cannot install using externals because vendor/plugins is not under subversion."
779
+ end
780
+ if msg
781
+ puts msg
782
+ exit 1
783
+ end
784
+ @method
785
+ end
786
+
787
+ def parse!(args)
788
+ options.parse!(args)
789
+ environment = @base_command.environment
790
+ install_method = determine_install_method
791
+ puts "Plugins will be installed using #{install_method}" if $verbose
792
+ args.each do |name|
793
+ ::Plugin.find(name).install(install_method, @options)
794
+ end
795
+ rescue StandardError => e
796
+ puts "Plugin not found: #{args.inspect}"
797
+ puts e.inspect if $verbose
798
+ exit 1
799
+ end
800
+ end
801
+
802
+ class Update
803
+ def initialize(base_command)
804
+ @base_command = base_command
805
+ end
806
+
807
+ def options
808
+ OptionParser.new do |o|
809
+ o.set_summary_indent(' ')
810
+ o.banner = "Usage: #{@base_command.script_name} update [name [name]...]"
811
+ o.on( "-r REVISION", "--revision REVISION",
812
+ "Checks out the given revision from subversion.",
813
+ "Ignored if subversion is not used.") { |v| @revision = v }
814
+ o.define_head "Update plugins."
815
+ end
816
+ end
817
+
818
+ def parse!(args)
819
+ options.parse!(args)
820
+ root = @base_command.environment.root
821
+ cd root
822
+ args = Dir["vendor/plugins/*"].map do |f|
823
+ File.directory?("#{f}/.svn") ? File.basename(f) : nil
824
+ end.compact if args.empty?
825
+ cd "vendor/plugins"
826
+ args.each do |name|
827
+ if File.directory?(name)
828
+ puts "Updating plugin: #{name}"
829
+ system("svn #{$verbose ? '' : '-q'} up \"#{name}\" #{@revision ? "-r #{@revision}" : ''}")
830
+ else
831
+ puts "Plugin doesn't exist: #{name}"
832
+ end
833
+ end
834
+ end
835
+ end
836
+
837
+ class Remove
838
+ def initialize(base_command)
839
+ @base_command = base_command
840
+ end
841
+
842
+ def options
843
+ OptionParser.new do |o|
844
+ o.set_summary_indent(' ')
845
+ o.banner = "Usage: #{@base_command.script_name} remove name [name]..."
846
+ o.define_head "Remove plugins."
847
+ end
848
+ end
849
+
850
+ def parse!(args)
851
+ options.parse!(args)
852
+ root = @base_command.environment.root
853
+ args.each do |name|
854
+ ::Plugin.new(name).uninstall
855
+ end
856
+ end
857
+ end
858
+
859
+ class Info
860
+ def initialize(base_command)
861
+ @base_command = base_command
862
+ end
863
+
864
+ def options
865
+ OptionParser.new do |o|
866
+ o.set_summary_indent(' ')
867
+ o.banner = "Usage: #{@base_command.script_name} info name [name]..."
868
+ o.define_head "Shows plugin info at {url}/about.yml."
869
+ end
870
+ end
871
+
872
+ def parse!(args)
873
+ options.parse!(args)
874
+ args.each do |name|
875
+ puts ::Plugin.find(name).info
876
+ puts
877
+ end
878
+ end
879
+ end
880
+ end
881
+
882
+ class RecursiveHTTPFetcher
883
+ attr_accessor :quiet
884
+ def initialize(urls_to_fetch, level = 1, cwd = ".")
885
+ @level = level
886
+ @cwd = cwd
887
+ @urls_to_fetch = urls_to_fetch.to_a
888
+ @quiet = false
889
+ end
890
+
891
+ def ls
892
+ @urls_to_fetch.collect do |url|
893
+ if url =~ /^svn(\+ssh)?:\/\/.*/
894
+ `svn ls #{url}`.split("\n").map {|entry| "/#{entry}"} rescue nil
895
+ else
896
+ open(url) do |stream|
897
+ links("", stream.read)
898
+ end rescue nil
899
+ end
900
+ end.flatten
901
+ end
902
+
903
+ def push_d(dir)
904
+ @cwd = File.join(@cwd, dir)
905
+ FileUtils.mkdir_p(@cwd)
906
+ end
907
+
908
+ def pop_d
909
+ @cwd = File.dirname(@cwd)
910
+ end
911
+
912
+ def links(base_url, contents)
913
+ links = []
914
+ contents.scan(/href\s*=\s*\"*[^\">]*/i) do |link|
915
+ link = link.sub(/href="/i, "")
916
+ next if link =~ /svnindex.xsl$/
917
+ next if link =~ /^(\w*:|)\/\// || link =~ /^\./
918
+ links << File.join(base_url, link)
919
+ end
920
+ links
921
+ end
922
+
923
+ def download(link)
924
+ puts "+ #{File.join(@cwd, File.basename(link))}" unless @quiet
925
+ open(link) do |stream|
926
+ File.open(File.join(@cwd, File.basename(link)), "wb") do |file|
927
+ file.write(stream.read)
928
+ end
929
+ end
930
+ end
931
+
932
+ def fetch(links = @urls_to_fetch)
933
+ links.each do |l|
934
+ (l =~ /\/$/ || links == @urls_to_fetch) ? fetch_dir(l) : download(l)
935
+ end
936
+ end
937
+
938
+ def fetch_dir(url)
939
+ @level += 1
940
+ push_d(File.basename(url)) if @level > 0
941
+ open(url) do |stream|
942
+ contents = stream.read
943
+ fetch(links(url, contents))
944
+ end
945
+ pop_d if @level > 0
946
+ @level -= 1
947
+ end
948
+ end
949
+
950
+ Commands::Plugin.parse!