rails 0.14.2 → 0.14.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rails might be problematic. Click here for more details.

Files changed (53) hide show
  1. data/CHANGELOG +83 -0
  2. data/README +16 -53
  3. data/Rakefile +10 -11
  4. data/bin/about +3 -0
  5. data/bin/plugin +3 -0
  6. data/configs/database.yml +65 -3
  7. data/configs/lighttpd.conf +40 -0
  8. data/environments/boot.rb +2 -2
  9. data/environments/environment.rb +3 -3
  10. data/environments/test.rb +1 -7
  11. data/helpers/test_helper.rb +19 -4
  12. data/html/javascripts/controls.js +18 -5
  13. data/html/javascripts/dragdrop.js +6 -3
  14. data/html/javascripts/effects.js +181 -290
  15. data/html/javascripts/prototype.js +13 -11
  16. data/lib/commands/about.rb +2 -0
  17. data/lib/commands/plugin.rb +823 -0
  18. data/lib/commands/process/reaper.rb +3 -3
  19. data/lib/commands/server.rb +23 -54
  20. data/lib/commands/servers/lighttpd.rb +56 -0
  21. data/lib/commands/servers/webrick.rb +59 -0
  22. data/lib/dispatcher.rb +30 -8
  23. data/lib/fcgi_handler.rb +6 -1
  24. data/lib/initializer.rb +107 -42
  25. data/lib/rails_generator/generators/applications/app/app_generator.rb +14 -12
  26. data/lib/rails_generator/generators/components/migration/migration_generator.rb +52 -5
  27. data/lib/rails_generator/generators/components/model/templates/fixtures.yml +2 -2
  28. data/lib/rails_generator/generators/components/model/templates/unit_test.rb +1 -5
  29. data/lib/rails_generator/generators/components/plugin/USAGE +33 -0
  30. data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +33 -0
  31. data/lib/rails_generator/generators/components/plugin/templates/README +4 -0
  32. data/lib/rails_generator/generators/components/plugin/templates/Rakefile +22 -0
  33. data/lib/rails_generator/generators/components/plugin/templates/USAGE +8 -0
  34. data/lib/rails_generator/generators/components/plugin/templates/generator.rb +8 -0
  35. data/lib/rails_generator/generators/components/plugin/templates/init.rb +1 -0
  36. data/lib/rails_generator/generators/components/plugin/templates/plugin.rb +1 -0
  37. data/lib/rails_generator/generators/components/plugin/templates/tasks.rake +4 -0
  38. data/lib/rails_generator/generators/components/plugin/templates/unit_test.rb +8 -0
  39. data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +6 -1
  40. data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +1 -1
  41. data/lib/rails_generator/generators/components/scaffold/templates/style.css +1 -1
  42. data/lib/rails_generator/lookup.rb +1 -0
  43. data/lib/rails_info.rb +94 -0
  44. data/lib/rails_version.rb +1 -1
  45. data/lib/tasks/databases.rake +8 -5
  46. data/lib/tasks/documentation.rake +34 -1
  47. data/lib/tasks/framework.rake +50 -12
  48. data/lib/tasks/misc.rake +5 -1
  49. data/lib/tasks/rails.rb +2 -2
  50. data/lib/tasks/testing.rake +14 -1
  51. metadata +28 -9
  52. data/html/javascripts/scriptaculous.js +0 -47
  53. data/html/javascripts/slider.js +0 -258
@@ -1,4 +1,4 @@
1
- /* Prototype JavaScript framework, version 1.4.0_rc0
1
+ /* Prototype JavaScript framework, version 1.4.0_rc2
2
2
  * (c) 2005 Sam Stephenson <sam@conio.net>
3
3
  *
4
4
  * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
@@ -11,7 +11,7 @@
11
11
  /*--------------------------------------------------------------------------*/
12
12
 
13
13
  var Prototype = {
14
- Version: '1.4.0_rc0',
14
+ Version: '1.4.0_rc2',
15
15
 
16
16
  emptyFunction: function() {},
17
17
  K: function(x) {return x}
@@ -607,8 +607,8 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
607
607
 
608
608
  try {
609
609
  this.url = url;
610
- if (this.options.method == 'get')
611
- this.url += '?' + parameters;
610
+ if (this.options.method == 'get' && parameters.length > 0)
611
+ this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
612
612
 
613
613
  Ajax.Responders.dispatch('onCreate', this, this.transport);
614
614
 
@@ -626,6 +626,8 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
626
626
  this.transport.send(this.options.method == 'post' ? body : null);
627
627
 
628
628
  } catch (e) {
629
+ (this.options.onException || Prototype.emptyFunction)(this, e);
630
+ Ajax.Responders.dispatch('onException', this, e);
629
631
  }
630
632
  },
631
633
 
@@ -783,9 +785,9 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
783
785
  }
784
786
  });
785
787
  document.getElementsByClassName = function(className, parentElement) {
786
- var children = (document.body || $(parentElement)).getElementsByTagName('*');
788
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
787
789
  return $A(children).inject([], function(elements, child) {
788
- if (Element.hasClassName(child, className))
790
+ if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
789
791
  elements.push(child);
790
792
  return elements;
791
793
  });
@@ -1129,7 +1131,7 @@ var Form = {
1129
1131
  },
1130
1132
 
1131
1133
  getElements: function(form) {
1132
- var form = $(form);
1134
+ form = $(form);
1133
1135
  var elements = new Array();
1134
1136
 
1135
1137
  for (tagName in Form.Element.Serializers) {
@@ -1141,7 +1143,7 @@ var Form = {
1141
1143
  },
1142
1144
 
1143
1145
  getInputs: function(form, typeName, name) {
1144
- var form = $(form);
1146
+ form = $(form);
1145
1147
  var inputs = form.getElementsByTagName('input');
1146
1148
 
1147
1149
  if (!typeName && !name)
@@ -1177,7 +1179,7 @@ var Form = {
1177
1179
  },
1178
1180
 
1179
1181
  focusFirstElement: function(form) {
1180
- var form = $(form);
1182
+ form = $(form);
1181
1183
  var elements = Form.getElements(form);
1182
1184
  for (var i = 0; i < elements.length; i++) {
1183
1185
  var element = elements[i];
@@ -1195,7 +1197,7 @@ var Form = {
1195
1197
 
1196
1198
  Form.Element = {
1197
1199
  serialize: function(element) {
1198
- var element = $(element);
1200
+ element = $(element);
1199
1201
  var method = element.tagName.toLowerCase();
1200
1202
  var parameter = Form.Element.Serializers[method](element);
1201
1203
 
@@ -1205,7 +1207,7 @@ Form.Element = {
1205
1207
  },
1206
1208
 
1207
1209
  getValue: function(element) {
1208
- var element = $(element);
1210
+ element = $(element);
1209
1211
  var method = element.tagName.toLowerCase();
1210
1212
  var parameter = Form.Element.Serializers[method](element);
1211
1213
 
@@ -0,0 +1,2 @@
1
+ require 'environment'
2
+ puts Rails::Info
@@ -0,0 +1,823 @@
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
+ # * If `vendor/plugins` is under subversion control, the script will
35
+ # modify the svn:externals property and perform an update. You can
36
+ # use normal subversion commands to keep the plugins up to date or
37
+ # you can use the built in update command.
38
+ #
39
+ # * Or, if `vendor/plugins` is not under subversion control, the
40
+ # plugin is pulled via `svn checkout` or `svn export` but looks
41
+ # exactly the same.
42
+ #
43
+ # This is Free Software, copyright 2005 by Ryan Tomayko (rtomayko@gmail.com)
44
+ # and is licensed MIT: (http://www.opensource.org/licenses/mit-license.php)
45
+
46
+ $verbose = false
47
+
48
+
49
+ require 'open-uri'
50
+ require 'fileutils'
51
+ require 'tempfile'
52
+
53
+ include FileUtils
54
+
55
+ class RailsEnvironment
56
+ attr_reader :root
57
+
58
+ def initialize(dir)
59
+ @root = dir
60
+ end
61
+
62
+ def self.find(dir=nil)
63
+ dir ||= pwd
64
+ while dir.length > 1
65
+ return new(dir) if File.exist?(File.join(dir, 'config', 'environment.rb'))
66
+ dir = File.dirname(dir)
67
+ end
68
+ end
69
+
70
+ def self.default
71
+ @default ||= find
72
+ end
73
+
74
+ def self.default=(rails_env)
75
+ @default = rails_env
76
+ end
77
+
78
+ def install(name_uri_or_plugin)
79
+ if name_uri_or_plugin.is_a? String
80
+ if name_uri_or_plugin =~ /:\/\//
81
+ plugin = Plugin.new(name_uri_or_plugin)
82
+ else
83
+ plugin = Plugins[name_uri_or_plugin]
84
+ end
85
+ else
86
+ plugin = name_uri_or_plugin
87
+ end
88
+ unless plugin.nil?
89
+ plugin.install
90
+ else
91
+ puts "plugin not found: #{name_uri_or_plugin}"
92
+ end
93
+ end
94
+
95
+ def use_svn?
96
+ `svn --version` rescue nil
97
+ !$?.nil? && $?.success?
98
+ end
99
+
100
+ def use_externals?
101
+ File.directory?("#{root}/vendor/plugins/.svn")
102
+ end
103
+
104
+ def use_checkout?
105
+ # this is a bit of a guess. we assume that if the rails environment
106
+ # is under subversion than they probably want the plugin checked out
107
+ # instead of exported. This can be overridden on the command line
108
+ File.directory?("#{root}/.svn")
109
+ end
110
+
111
+ def best_install_method
112
+ return :http unless use_svn?
113
+ case
114
+ when use_externals? then :externals
115
+ when use_checkout? then :checkout
116
+ else :export
117
+ end
118
+ end
119
+
120
+ def externals
121
+ return [] unless use_externals?
122
+ ext = silence_stderr { `svn propget svn:externals #{root}/vendor/plugins` }
123
+ ext.reject{ |line| line.strip == '' }.map do |line|
124
+ line.strip.split(/\s+/, 2)
125
+ end
126
+ end
127
+
128
+ def externals=(items)
129
+ unless items.is_a? String
130
+ items = items.map{|name,uri| "#{name.ljust(29)} #{uri.chomp('/')}"}.join("\n")
131
+ end
132
+ Tempfile.open("svn-set-prop") do |file|
133
+ file.write(items)
134
+ file.flush
135
+ system("svn propset -q svn:externals -F #{file.path} #{root}/vendor/plugins")
136
+ end
137
+ end
138
+
139
+ end
140
+
141
+ class Plugin
142
+ attr_reader :name, :uri
143
+
144
+ def initialize(uri, name=nil)
145
+ @uri = uri
146
+ guess_name(uri)
147
+ end
148
+
149
+ def to_s
150
+ "#{@name.ljust(30)}#{@uri}"
151
+ end
152
+
153
+ def installed?
154
+ File.directory?("#{rails_env.root}/vendor/plugins/#{name}") \
155
+ or rails_env.externals.detect{ |name, repo| self.uri == repo }
156
+ end
157
+
158
+ def install(method=nil)
159
+ method ||= rails_env.best_install_method?
160
+ unless installed?
161
+ send("install_using_#{method}")
162
+ else
163
+ puts "already installed: #{name} (#{uri})"
164
+ end
165
+ end
166
+
167
+ private
168
+ def install_using_export
169
+ root = rails_env.root
170
+ mkdir_p "#{root}/vendor/plugins"
171
+ system("svn export #{uri} #{root}/vendor/plugins/#{name}")
172
+ end
173
+
174
+ def install_using_checkout
175
+ root = rails_env.root
176
+ mkdir_p "#{root}/vendor/plugins"
177
+ system("svn checkout #{uri} #{root}/vendor/plugins/#{name}")
178
+ end
179
+
180
+ def install_using_externals
181
+ externals = rails_env.externals
182
+ externals.push([@name, uri])
183
+ rails_env.externals = externals
184
+ install_using_checkout
185
+ end
186
+
187
+ def install_using_http
188
+ root = rails_env.root
189
+ mkdir_p "#{root}/vendor/plugins"
190
+ Dir.chdir "#{root}/vendor/plugins"
191
+ RecursiveHTTPFetcher.new(uri).fetch
192
+ end
193
+
194
+ def guess_name(url)
195
+ @name = File.basename(url)
196
+ if @name == 'trunk' || @name.empty?
197
+ @name = File.basename(File.dirname(url))
198
+ end
199
+ end
200
+
201
+ def rails_env
202
+ @rails_env || RailsEnvironment.default
203
+ end
204
+ end
205
+
206
+ class Repositories
207
+ include Enumerable
208
+
209
+ def initialize(cache_file = File.join(find_home, ".rails-plugin-sources"))
210
+ @cache_file = File.expand_path(cache_file)
211
+ load!
212
+ end
213
+
214
+ def each(&block)
215
+ @repositories.each(&block)
216
+ end
217
+
218
+ def add(uri)
219
+ unless find{|repo| repo.uri == uri }
220
+ @repositories.push(Repository.new(uri)).last
221
+ end
222
+ end
223
+
224
+ def remove(uri)
225
+ @repositories.reject!{|repo| repo.uri == uri}
226
+ end
227
+
228
+ def exist?(uri)
229
+ @repositories.detect{|repo| repo.uri == uri }
230
+ end
231
+
232
+ def all
233
+ @repositories
234
+ end
235
+
236
+ def find_plugin(name)
237
+ @repositories.each do |repo|
238
+ repo.each do |plugin|
239
+ return plugin if plugin.name == name
240
+ end
241
+ end
242
+
243
+ return nil
244
+ end
245
+
246
+ def load!
247
+ contents = File.exist?(@cache_file) ? File.read(@cache_file) : defaults
248
+ contents = defaults if contents.empty?
249
+ @repositories = contents.split(/\n/).reject do |line|
250
+ line =~ /^\s*#/ or line =~ /^\s*$/
251
+ end.map { |source| Repository.new(source.strip) }
252
+ end
253
+
254
+ def save
255
+ File.open(@cache_file, 'w') do |f|
256
+ each do |repo|
257
+ f.write(repo.uri)
258
+ f.write("\n")
259
+ end
260
+ end
261
+ end
262
+
263
+ def defaults
264
+ <<-DEFAULTS
265
+ http://dev.rubyonrails.com/svn/rails/plugins/
266
+ DEFAULTS
267
+ end
268
+
269
+ def find_home
270
+ ['HOME', 'USERPROFILE'].each do |homekey|
271
+ return ENV[homekey] if ENV[homekey]
272
+ end
273
+ if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
274
+ return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
275
+ end
276
+ begin
277
+ File.expand_path("~")
278
+ rescue StandardError => ex
279
+ if File::ALT_SEPARATOR
280
+ "C:/"
281
+ else
282
+ "/"
283
+ end
284
+ end
285
+ end
286
+
287
+ def self.instance
288
+ @instance ||= Repositories.new
289
+ end
290
+
291
+ def self.each(&block)
292
+ self.instance.each(&block)
293
+ end
294
+ end
295
+
296
+ class Repository
297
+ include Enumerable
298
+ attr_reader :uri, :plugins
299
+
300
+ def initialize(uri)
301
+ uri << "/" unless uri =~ /\/$/
302
+ @uri = uri
303
+ @plugins = nil
304
+ end
305
+
306
+ def plugins
307
+ unless @plugins
308
+ if $verbose
309
+ puts "Discovering plugins in #{@uri}"
310
+ puts index
311
+ end
312
+
313
+ @plugins = index.split(/\n/).reject{ |line| line !~ /\/$/ }
314
+ @plugins.map! { |name| Plugin.new(File.join(@uri, name), name) }
315
+ end
316
+
317
+ @plugins
318
+ end
319
+
320
+ def each(&block)
321
+ plugins.each(&block)
322
+ end
323
+
324
+ private
325
+ def index
326
+ @index ||= `svn ls #{@uri}`
327
+ end
328
+ end
329
+
330
+
331
+ # load default environment and parse arguments
332
+ require 'optparse'
333
+ module Commands
334
+
335
+ class Plugin
336
+ attr_reader :environment, :script_name, :sources
337
+ def initialize
338
+ @environment = RailsEnvironment.default
339
+ @rails_root = RailsEnvironment.default.root
340
+ @script_name = File.basename($0)
341
+ @sources = []
342
+ end
343
+
344
+ def environment=(value)
345
+ @environment = value
346
+ RailsEnvironment.default = value
347
+ end
348
+
349
+ def options
350
+ OptionParser.new do |o|
351
+ o.set_summary_indent(' ')
352
+ o.banner = "Usage: #{@script_name} [OPTIONS] command"
353
+ o.define_head "Rails plugin manager."
354
+
355
+ o.separator ""
356
+ o.separator "GENERAL OPTIONS"
357
+
358
+ o.on("-r", "--root=DIR", String,
359
+ "Set an explicit rails app directory.",
360
+ "Default: #{@rails_root}") { |@rails_root| self.environment = RailsEnvironment.new(@rails_root) }
361
+ o.on("-s", "--source=URL1,URL2", Array,
362
+ "Use the specified plugin repositories instead of the defaults.") { |@sources|}
363
+
364
+ o.on("-v", "--verbose", "Turn on verbose output.") { |$verbose| }
365
+ o.on("-h", "--help", "Show this help message.") { puts o; exit }
366
+
367
+ o.separator ""
368
+ o.separator "COMMANDS"
369
+
370
+ o.separator " discover Discover plugin repositories."
371
+ o.separator " list List available plugins."
372
+ o.separator " install Install plugin(s) from known repositories or URLs."
373
+ o.separator " update Update installed plugins."
374
+ o.separator " remove Uninstall plugins."
375
+ o.separator " source Add a plugin source repository."
376
+ o.separator " unsource Remove a plugin repository."
377
+ o.separator " sources List currently configured plugin repositories."
378
+
379
+ o.separator ""
380
+ o.separator "EXAMPLES"
381
+ o.separator " Install a plugin:"
382
+ o.separator " #{@script_name} install continuous_builder\n"
383
+ o.separator " Install a plugin from a subversion URL:"
384
+ o.separator " #{@script_name} install http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder\n"
385
+ o.separator " Install a plugin and add a svn:externals entry to vendor/plugins"
386
+ o.separator " #{@script_name} install -x continuous_builder\n"
387
+ o.separator " List all available plugins:"
388
+ o.separator " #{@script_name} list\n"
389
+ o.separator " List plugins in the specified repository:"
390
+ o.separator " #{@script_name} list --source=http://dev.rubyonrails.com/svn/rails/plugins/\n"
391
+ o.separator " Discover and prompt to add new repositories:"
392
+ o.separator " #{@script_name} discover\n"
393
+ o.separator " Discover new repositories but just list them, don't add anything:"
394
+ o.separator " #{@script_name} discover -l\n"
395
+ o.separator " Add a new repository to the source list:"
396
+ o.separator " #{@script_name} source http://dev.rubyonrails.com/svn/rails/plugins/\n"
397
+ o.separator " Remove a repository from the source list:"
398
+ o.separator " #{@script_name} unsource http://dev.rubyonrails.com/svn/rails/plugins/\n"
399
+ o.separator " Show currently configured repositories:"
400
+ o.separator " #{@script_name} sources\n"
401
+ end
402
+ end
403
+
404
+ def parse!(args=ARGV)
405
+ general, sub = split_args(args)
406
+ options.parse!(general)
407
+
408
+ command = general.shift
409
+ if command =~ /^(list|discover|install|source|unsource|sources|remove|update)$/
410
+ command = Commands.const_get(command.capitalize).new(self)
411
+ command.parse!(sub)
412
+ else
413
+ puts "Unknown command: #{command}"
414
+ puts "Try: #{$0} --help"
415
+ exit 1
416
+ end
417
+ end
418
+
419
+ def split_args(args)
420
+ left = []
421
+ left << args.shift while args[0] and args[0] =~ /^-/
422
+ left << args.shift if args[0]
423
+ return [left, args]
424
+ end
425
+
426
+ def self.parse!(args=ARGV)
427
+ Plugin.new.parse!(args)
428
+ end
429
+ end
430
+
431
+
432
+ class List
433
+ def initialize(base_command)
434
+ @base_command = base_command
435
+ @sources = []
436
+ @local = false
437
+ @remote = true
438
+ @details = false
439
+ end
440
+
441
+ def options
442
+ OptionParser.new do |o|
443
+ o.set_summary_indent(' ')
444
+ o.banner = "Usage: #{@base_command.script_name} list [OPTIONS] [PATTERN]"
445
+ o.define_head "List available plugins."
446
+ o.separator ""
447
+ o.separator "Options:"
448
+ o.separator ""
449
+ o.on( "-s", "--source=URL1,URL2", Array,
450
+ "Use the specified plugin repositories.") {|@sources|}
451
+ o.on( "--local",
452
+ "List locally installed plugins.") {|@local| @remote = false}
453
+ o.on( "--remote",
454
+ "List remotely availabled plugins. This is the default behavior",
455
+ "unless --local is provided.") {|@remote|}
456
+ o.on( "-l", "--long",
457
+ "Long listing / details about each plugin.") {|@details|}
458
+ end
459
+ end
460
+
461
+ def parse!(args)
462
+ options.order!(args)
463
+ unless @sources.empty?
464
+ @sources.map!{ |uri| Repository.new(uri) }
465
+ else
466
+ @sources = Repositories.instance.all
467
+ end
468
+ if @remote
469
+ @sources.map{|r| r.plugins}.flatten.each do |plugin|
470
+ if @local or !plugin.installed?
471
+ puts plugin.to_s
472
+ system "svn info #{plugin.uri}" if @details
473
+ end
474
+ end
475
+ else
476
+ cd "#{@base_command.environment.root}/vendor/plugins"
477
+ Dir["*"].select{|p| File.directory?(p)}.each do |name|
478
+ puts name
479
+ system "svn info #{name}" if @details
480
+ end
481
+ end
482
+ end
483
+ end
484
+
485
+
486
+ class Sources
487
+ def initialize(base_command)
488
+ @base_command = base_command
489
+ end
490
+
491
+ def options
492
+ OptionParser.new do |o|
493
+ o.set_summary_indent(' ')
494
+ o.banner = "Usage: #{@base_command.script_name} sources [OPTIONS] [PATTERN]"
495
+ o.define_head "List configured plugin repositories."
496
+ o.separator ""
497
+ o.separator "Options:"
498
+ o.separator ""
499
+ o.on( "-c", "--check",
500
+ "Report status of repository.") { |@sources|}
501
+ end
502
+ end
503
+
504
+ def parse!(args)
505
+ options.parse!(args)
506
+ Repositories.each do |repo|
507
+ puts repo.uri
508
+ end
509
+ end
510
+ end
511
+
512
+
513
+ class Source
514
+ def initialize(base_command)
515
+ @base_command = base_command
516
+ end
517
+
518
+ def options
519
+ OptionParser.new do |o|
520
+ o.set_summary_indent(' ')
521
+ o.banner = "Usage: #{@base_command.script_name} source REPOSITORY"
522
+ o.define_head "Add a new repository."
523
+ end
524
+ end
525
+
526
+ def parse!(args)
527
+ options.parse!(args)
528
+ count = 0
529
+ args.each do |uri|
530
+ if Repositories.instance.add(uri)
531
+ puts "added: #{uri.ljust(50)}" if $verbose
532
+ count += 1
533
+ else
534
+ puts "failed: #{uri.ljust(50)}"
535
+ end
536
+ end
537
+ Repositories.instance.save
538
+ puts "Added #{count} repositories."
539
+ end
540
+ end
541
+
542
+
543
+ class Unsource
544
+ def initialize(base_command)
545
+ @base_command = base_command
546
+ end
547
+
548
+ def options
549
+ OptionParser.new do |o|
550
+ o.set_summary_indent(' ')
551
+ o.banner = "Usage: #{@base_command.script_name} source URI [URI [URI]...]"
552
+ o.define_head "Remove repositories from the default search list."
553
+ o.separator ""
554
+ o.on_tail("-h", "--help", "Show this help message.") { puts o; exit }
555
+ end
556
+ end
557
+
558
+ def parse!(args)
559
+ options.parse!(args)
560
+ count = 0
561
+ args.each do |uri|
562
+ if Repositories.instance.remove(uri)
563
+ count += 1
564
+ puts "removed: #{uri.ljust(50)}"
565
+ else
566
+ puts "failed: #{uri.ljust(50)}"
567
+ end
568
+ end
569
+ Repositories.instance.save
570
+ puts "Removed #{count} repositories."
571
+ end
572
+ end
573
+
574
+
575
+ class Discover
576
+ def initialize(base_command)
577
+ @base_command = base_command
578
+ @list = false
579
+ @prompt = true
580
+ end
581
+
582
+ def options
583
+ OptionParser.new do |o|
584
+ o.set_summary_indent(' ')
585
+ o.banner = "Usage: #{@base_command.script_name} discover URI [URI [URI]...]"
586
+ o.define_head "Discover repositories referenced on a page."
587
+ o.separator ""
588
+ o.separator "Options:"
589
+ o.separator ""
590
+ o.on( "-l", "--list",
591
+ "List but don't prompt or add discovered repositories.") { |@list| @prompt = !@list }
592
+ o.on( "-n", "--no-prompt",
593
+ "Add all new repositories without prompting.") { |v| @prompt = !v }
594
+ end
595
+ end
596
+
597
+ def parse!(args)
598
+ options.parse!(args)
599
+ args = ['http://wiki.rubyonrails.org/rails/pages/Plugins'] if args.empty?
600
+ args.each do |uri|
601
+ scrape(uri) do |repo_uri|
602
+ catch(:next_uri) do
603
+ if @prompt
604
+ begin
605
+ $stdout.print "Add #{repo_uri}? [Y/n] "
606
+ throw :next_uri if $stdin.gets !~ /^y?$/i
607
+ rescue Interrupt
608
+ $stdout.puts
609
+ exit 1
610
+ end
611
+ elsif @list
612
+ puts repo_uri
613
+ throw :next_uri
614
+ end
615
+ Repositories.instance.add(repo_uri)
616
+ puts "discovered: #{repo_uri}" if $verbose or !@prompt
617
+ end
618
+ end
619
+ end
620
+ Repositories.instance.save
621
+ end
622
+
623
+ def scrape(uri)
624
+ require 'open-uri'
625
+ puts "Scraping #{uri}" if $verbose
626
+ dupes = []
627
+ content = open(uri).each do |line|
628
+ if line =~ /<a[^>]*href=['"]([^'"]*)['"]/
629
+ uri = $1
630
+ if uri =~ /\/plugins\// and uri !~ /\/browser\//
631
+ uri = extract_repository_uri(uri)
632
+ yield uri unless dupes.include?(uri) or Repositories.instance.exist?(uri)
633
+ dupes << uri
634
+ end
635
+ end
636
+ end
637
+ end
638
+
639
+ def extract_repository_uri(uri)
640
+ uri.match(/(svn|https?):.*\/plugins\//i)[0]
641
+ end
642
+ end
643
+
644
+ class Install
645
+ def initialize(base_command)
646
+ @base_command = base_command
647
+ @method = :export
648
+ end
649
+
650
+ def options
651
+ OptionParser.new do |o|
652
+ o.set_summary_indent(' ')
653
+ o.banner = "Usage: #{@base_command.script_name} install PLUGIN [PLUGIN [PLUGIN] ...]"
654
+ o.define_head "Install one or more plugins."
655
+ o.separator ""
656
+ o.separator "Options:"
657
+ o.on( "-x", "--externals",
658
+ "Use svn:externals to grab the plugin.",
659
+ "Enables plugin updates and plugin versioning.") { |v| @method = :externals }
660
+ o.on( "-o", "--checkout",
661
+ "Use svn checkout to grab the plugin.",
662
+ "Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout }
663
+ o.separator ""
664
+ o.separator "You can specify plugin names as given in 'plugin list' output or absolute URLs to "
665
+ o.separator "a plugin repository."
666
+ end
667
+ end
668
+
669
+ def determine_install_method
670
+ best = @base_command.environment.best_install_method
671
+ @method = :http if best == :http and @method == :export
672
+ case
673
+ when (best == :http and @method != :http)
674
+ msg = "Cannot install using subversion because `svn' cannot be found in your PATH"
675
+ when (best == :export and (@method != :export and method != :http))
676
+ msg = "Cannot install using #{requested} because this project is not under subversion."
677
+ when (best != :externals and @method == :externals)
678
+ msg = "Cannot install using externals because vendor/plugins is not under subversion."
679
+ end
680
+ if msg
681
+ puts msg
682
+ exit 1
683
+ end
684
+ @method
685
+ end
686
+
687
+ def parse!(args)
688
+ options.parse!(args)
689
+ environment = @base_command.environment
690
+ install_method = determine_install_method
691
+ puts "Plugins will be installed using #{install_method}" if $verbose
692
+ args.each do |name|
693
+ if name =~ /\// then
694
+ ::Plugin.new(name).install(install_method)
695
+ else
696
+ plugin = Repositories.instance.find_plugin(name)
697
+ unless plugin.nil?
698
+ plugin.install(install_method)
699
+ else
700
+ puts "Plugin not found: #{name}"
701
+ exit 1
702
+ end
703
+ end
704
+ end
705
+ end
706
+ end
707
+
708
+
709
+ class Remove
710
+ def initialize(base_command)
711
+ @base_command = base_command
712
+ end
713
+
714
+ def options
715
+ OptionParser.new do |o|
716
+ o.set_summary_indent(' ')
717
+ o.banner = "Usage: #{@base_command.script_name} remove name [name]..."
718
+ o.define_head "Remove plugins."
719
+ end
720
+ end
721
+
722
+ def parse!(args)
723
+ options.parse!(args)
724
+ root = @base_command.environment.root
725
+ args.each do |name|
726
+ path = "#{root}/vendor/plugins/#{name}"
727
+ if File.directory?(path)
728
+ rm_r path
729
+ else
730
+ puts "Plugin doesn't exist: #{path}"
731
+ end
732
+ # clean up svn:externals
733
+ externals = @base_command.environment.externals
734
+ externals.reject!{|n,u| name == n or name == u}
735
+ @base_command.environment.externals = externals
736
+ end
737
+ end
738
+ end
739
+
740
+ class Update
741
+ def initialize(base_command)
742
+ @base_command = base_command
743
+ end
744
+
745
+ def options
746
+ OptionParser.new do |o|
747
+ o.set_summary_indent(' ')
748
+ o.banner = "Usage: #{@base_command.script_name} update [name [name]...]"
749
+ o.define_head "Update plugins."
750
+ end
751
+ end
752
+
753
+ def parse!(args)
754
+ options.parse!(args)
755
+ root = @base_command.environment.root
756
+ args = Dir["#{root}/vendor/plugins/*"].map do |f|
757
+ File.directory?("#{f}/.svn") ? File.basename(f) : nil
758
+ end.compact if args.empty?
759
+ cd "#{root}/vendor/plugins"
760
+ args.each do |name|
761
+ if File.directory?(name)
762
+ puts "Updating plugin: #{name}"
763
+ system("svn #{$verbose ? '' : '-q'} up #{name}")
764
+ else
765
+ puts "Plugin doesn't exist: #{name}"
766
+ end
767
+ end
768
+ end
769
+ end
770
+
771
+ end
772
+
773
+ class RecursiveHTTPFetcher
774
+ def initialize(urls_to_fetch, cwd = ".")
775
+ @cwd = cwd
776
+ @urls_to_fetch = urls_to_fetch.to_a
777
+ end
778
+
779
+ def push_d(dir)
780
+ @cwd = File.join(@cwd, dir)
781
+ FileUtils.mkdir_p(@cwd)
782
+ end
783
+
784
+ def pop_d
785
+ @cwd = File.dirname(@cwd)
786
+ end
787
+
788
+ def links(base_url, contents)
789
+ links = []
790
+ contents.scan(/href\s*=\s*\"*[^\">]*/i) do |link|
791
+ link = link.sub(/href="/i, "")
792
+ next if link =~ /^http/i || link =~ /^\./
793
+ links << File.join(base_url, link)
794
+ end
795
+ links
796
+ end
797
+
798
+ def download(link)
799
+ puts "+ #{File.join(@cwd, File.basename(link))}"
800
+ open(link) do |stream|
801
+ File.open(File.join(@cwd, File.basename(link)), "wb") do |file|
802
+ file.write(stream.read)
803
+ end
804
+ end
805
+ end
806
+
807
+ def fetch(links = @urls_to_fetch)
808
+ links.each do |l|
809
+ (l =~ /\/$/ || links == @urls_to_fetch) ? fetch_dir(l) : download(l)
810
+ end
811
+ end
812
+
813
+ def fetch_dir(url)
814
+ push_d(File.basename(url))
815
+ open(url) do |stream|
816
+ contents = stream.read
817
+ fetch(links(url, contents))
818
+ end
819
+ pop_d
820
+ end
821
+ end
822
+
823
+ Commands::Plugin.parse!