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.
- data/CHANGELOG +83 -0
- data/README +16 -53
- data/Rakefile +10 -11
- data/bin/about +3 -0
- data/bin/plugin +3 -0
- data/configs/database.yml +65 -3
- data/configs/lighttpd.conf +40 -0
- data/environments/boot.rb +2 -2
- data/environments/environment.rb +3 -3
- data/environments/test.rb +1 -7
- data/helpers/test_helper.rb +19 -4
- data/html/javascripts/controls.js +18 -5
- data/html/javascripts/dragdrop.js +6 -3
- data/html/javascripts/effects.js +181 -290
- data/html/javascripts/prototype.js +13 -11
- data/lib/commands/about.rb +2 -0
- data/lib/commands/plugin.rb +823 -0
- data/lib/commands/process/reaper.rb +3 -3
- data/lib/commands/server.rb +23 -54
- data/lib/commands/servers/lighttpd.rb +56 -0
- data/lib/commands/servers/webrick.rb +59 -0
- data/lib/dispatcher.rb +30 -8
- data/lib/fcgi_handler.rb +6 -1
- data/lib/initializer.rb +107 -42
- data/lib/rails_generator/generators/applications/app/app_generator.rb +14 -12
- data/lib/rails_generator/generators/components/migration/migration_generator.rb +52 -5
- data/lib/rails_generator/generators/components/model/templates/fixtures.yml +2 -2
- data/lib/rails_generator/generators/components/model/templates/unit_test.rb +1 -5
- data/lib/rails_generator/generators/components/plugin/USAGE +33 -0
- data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +33 -0
- data/lib/rails_generator/generators/components/plugin/templates/README +4 -0
- data/lib/rails_generator/generators/components/plugin/templates/Rakefile +22 -0
- data/lib/rails_generator/generators/components/plugin/templates/USAGE +8 -0
- data/lib/rails_generator/generators/components/plugin/templates/generator.rb +8 -0
- data/lib/rails_generator/generators/components/plugin/templates/init.rb +1 -0
- data/lib/rails_generator/generators/components/plugin/templates/plugin.rb +1 -0
- data/lib/rails_generator/generators/components/plugin/templates/tasks.rake +4 -0
- data/lib/rails_generator/generators/components/plugin/templates/unit_test.rb +8 -0
- data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +6 -1
- data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +1 -1
- data/lib/rails_generator/generators/components/scaffold/templates/style.css +1 -1
- data/lib/rails_generator/lookup.rb +1 -0
- data/lib/rails_info.rb +94 -0
- data/lib/rails_version.rb +1 -1
- data/lib/tasks/databases.rake +8 -5
- data/lib/tasks/documentation.rake +34 -1
- data/lib/tasks/framework.rake +50 -12
- data/lib/tasks/misc.rake +5 -1
- data/lib/tasks/rails.rb +2 -2
- data/lib/tasks/testing.rake +14 -1
- metadata +28 -9
- data/html/javascripts/scriptaculous.js +0 -47
- data/html/javascripts/slider.js +0 -258
@@ -1,4 +1,4 @@
|
|
1
|
-
/* Prototype JavaScript framework, version 1.4.
|
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.
|
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 = (
|
788
|
+
var children = ($(parentElement) || document.body).getElementsByTagName('*');
|
787
789
|
return $A(children).inject([], function(elements, child) {
|
788
|
-
if (
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1210
|
+
element = $(element);
|
1209
1211
|
var method = element.tagName.toLowerCase();
|
1210
1212
|
var parameter = Form.Element.Serializers[method](element);
|
1211
1213
|
|
@@ -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!
|