rails 1.0.0 → 1.1.0

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 (76) hide show
  1. data/CHANGELOG +152 -10
  2. data/README +30 -5
  3. data/Rakefile +18 -13
  4. data/bin/rails +1 -11
  5. data/{lib/rails_info.rb → builtin/rails_info/rails/info.rb} +25 -8
  6. data/builtin/{controllers/rails_info_controller.rb → rails_info/rails/info_controller.rb} +2 -2
  7. data/configs/databases/mysql.yml +47 -0
  8. data/configs/databases/oracle.yml +30 -0
  9. data/configs/databases/postgresql.yml +44 -0
  10. data/configs/databases/sqlite2.yml +16 -0
  11. data/configs/databases/sqlite3.yml +16 -0
  12. data/configs/lighttpd.conf +11 -5
  13. data/configs/routes.rb +5 -2
  14. data/environments/development.rb +3 -2
  15. data/environments/environment.rb +5 -8
  16. data/environments/production.rb +1 -2
  17. data/environments/test.rb +1 -1
  18. data/fresh_rakefile +2 -2
  19. data/html/500.html +1 -1
  20. data/html/index.html +3 -3
  21. data/html/javascripts/application.js +2 -0
  22. data/html/javascripts/controls.js +95 -30
  23. data/html/javascripts/dragdrop.js +161 -21
  24. data/html/javascripts/effects.js +310 -211
  25. data/html/javascripts/prototype.js +228 -28
  26. data/lib/code_statistics.rb +1 -1
  27. data/lib/commands/console.rb +3 -1
  28. data/lib/commands/plugin.rb +113 -70
  29. data/lib/commands/process/reaper.rb +1 -1
  30. data/lib/commands/process/spawner.rb +33 -4
  31. data/lib/commands/runner.rb +1 -1
  32. data/lib/commands/server.rb +3 -1
  33. data/lib/commands/servers/lighttpd.rb +41 -9
  34. data/lib/console_app.rb +27 -0
  35. data/lib/console_with_helpers.rb +23 -0
  36. data/lib/dispatcher.rb +8 -8
  37. data/lib/fcgi_handler.rb +22 -4
  38. data/lib/initializer.rb +107 -38
  39. data/lib/rails_generator/commands.rb +17 -7
  40. data/lib/rails_generator/generators/applications/app/app_generator.rb +30 -18
  41. data/lib/rails_generator/generators/components/integration_test/USAGE +14 -0
  42. data/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb +16 -0
  43. data/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb +10 -0
  44. data/lib/rails_generator/generators/components/mailer/USAGE +1 -1
  45. data/lib/rails_generator/generators/components/migration/USAGE +1 -1
  46. data/lib/rails_generator/generators/components/model/USAGE +3 -1
  47. data/lib/rails_generator/generators/components/model/model_generator.rb +16 -0
  48. data/lib/rails_generator/generators/components/model/templates/migration.rb +11 -0
  49. data/lib/rails_generator/generators/components/model/templates/unit_test.rb +1 -1
  50. data/lib/rails_generator/generators/components/plugin/USAGE +3 -1
  51. data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +1 -0
  52. data/lib/rails_generator/generators/components/plugin/templates/Rakefile +1 -1
  53. data/lib/rails_generator/generators/components/plugin/templates/install.rb +1 -0
  54. data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +1 -1
  55. data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +4 -0
  56. data/lib/rails_generator/generators/components/scaffold/templates/style.css +4 -4
  57. data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +1 -1
  58. data/lib/rails_generator/generators/components/session_migration/USAGE +1 -1
  59. data/lib/rails_generator/options.rb +2 -2
  60. data/lib/rails_version.rb +1 -1
  61. data/lib/ruby_version_check.rb +17 -0
  62. data/lib/tasks/databases.rake +141 -139
  63. data/lib/tasks/documentation.rake +73 -68
  64. data/lib/tasks/framework.rake +86 -58
  65. data/lib/tasks/log.rake +9 -0
  66. data/lib/tasks/misc.rake +2 -17
  67. data/lib/tasks/pre_namespace_aliases.rake +46 -0
  68. data/lib/tasks/statistics.rake +9 -8
  69. data/lib/tasks/testing.rake +81 -29
  70. data/lib/tasks/tmp.rake +30 -0
  71. data/lib/test_help.rb +1 -0
  72. data/lib/webrick_server.rb +6 -8
  73. metadata +284 -271
  74. data/bin/process/spinner +0 -3
  75. data/configs/database.yml +0 -85
  76. data/lib/tasks/javascripts.rake +0 -6
@@ -1,17 +1,13 @@
1
- /* Prototype JavaScript framework, version 1.4.0
1
+ /* Prototype JavaScript framework, version 1.5.0_pre1
2
2
  * (c) 2005 Sam Stephenson <sam@conio.net>
3
3
  *
4
- * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
5
- * against the source tree, available from the Prototype darcs repository.
6
- *
7
4
  * Prototype is freely distributable under the terms of an MIT-style license.
8
- *
9
5
  * For details, see the Prototype web site: http://prototype.conio.net/
10
6
  *
11
7
  /*--------------------------------------------------------------------------*/
12
8
 
13
9
  var Prototype = {
14
- Version: '1.4.0',
10
+ Version: '1.5.0_pre1',
15
11
  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
16
12
 
17
13
  emptyFunction: function() {},
@@ -120,26 +116,49 @@ PeriodicalExecuter.prototype = {
120
116
  }
121
117
  }
122
118
  }
119
+ Object.extend(String.prototype, {
120
+ gsub: function(pattern, replacement) {
121
+ var result = '', source = this, match;
122
+ replacement = arguments.callee.prepareReplacement(replacement);
123
+
124
+ while (source.length > 0) {
125
+ if (match = source.match(pattern)) {
126
+ result += source.slice(0, match.index);
127
+ result += (replacement(match) || '').toString();
128
+ source = source.slice(match.index + match[0].length);
129
+ } else {
130
+ result += source, source = '';
131
+ }
132
+ }
133
+ return result;
134
+ },
123
135
 
124
- /*--------------------------------------------------------------------------*/
136
+ sub: function(pattern, replacement, count) {
137
+ replacement = this.gsub.prepareReplacement(replacement);
138
+ count = count === undefined ? 1 : count;
125
139
 
126
- function $() {
127
- var elements = new Array();
140
+ return this.gsub(pattern, function(match) {
141
+ if (--count < 0) return match[0];
142
+ return replacement(match);
143
+ });
144
+ },
128
145
 
129
- for (var i = 0; i < arguments.length; i++) {
130
- var element = arguments[i];
131
- if (typeof element == 'string')
132
- element = document.getElementById(element);
146
+ scan: function(pattern, iterator) {
147
+ this.gsub(pattern, iterator);
148
+ return this;
149
+ },
133
150
 
134
- if (arguments.length == 1)
135
- return element;
151
+ truncate: function(length, truncation) {
152
+ length = length || 30;
153
+ truncation = truncation === undefined ? '...' : truncation;
154
+ return this.length > length ?
155
+ this.slice(0, length - truncation.length) + truncation : this;
156
+ },
136
157
 
137
- elements.push(element);
138
- }
158
+ strip: function() {
159
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
160
+ },
139
161
 
140
- return elements;
141
- }
142
- Object.extend(String.prototype, {
143
162
  stripTags: function() {
144
163
  return this.replace(/<\/?[^>]+>/gi, '');
145
164
  },
@@ -203,12 +222,35 @@ Object.extend(String.prototype, {
203
222
  },
204
223
 
205
224
  inspect: function() {
206
- return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
225
+ return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'";
207
226
  }
208
227
  });
209
228
 
229
+ String.prototype.gsub.prepareReplacement = function(replacement) {
230
+ if (typeof replacement == 'function') return replacement;
231
+ var template = new Template(replacement);
232
+ return function(match) { return template.evaluate(match) };
233
+ }
234
+
210
235
  String.prototype.parseQuery = String.prototype.toQueryParams;
211
236
 
237
+ var Template = Class.create();
238
+ Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
239
+ Template.prototype = {
240
+ initialize: function(template, pattern) {
241
+ this.template = template.toString();
242
+ this.pattern = pattern || Template.Pattern;
243
+ },
244
+
245
+ evaluate: function(object) {
246
+ return this.template.gsub(this.pattern, function(match) {
247
+ var before = match[1];
248
+ if (before == '\\') return match[2];
249
+ return before + (object[match[3]] || '').toString();
250
+ });
251
+ }
252
+ }
253
+
212
254
  var $break = new Object();
213
255
  var $continue = new Object();
214
256
 
@@ -375,8 +417,7 @@ var Enumerable = {
375
417
 
376
418
  var collections = [this].concat(args).map($A);
377
419
  return this.map(function(value, index) {
378
- iterator(value = collections.pluck(index));
379
- return value;
420
+ return iterator(collections.pluck(index));
380
421
  });
381
422
  },
382
423
 
@@ -662,7 +703,8 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
662
703
  setRequestHeaders: function() {
663
704
  var requestHeaders =
664
705
  ['X-Requested-With', 'XMLHttpRequest',
665
- 'X-Prototype-Version', Prototype.Version];
706
+ 'X-Prototype-Version', Prototype.Version,
707
+ 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
666
708
 
667
709
  if (this.options.method == 'post') {
668
710
  requestHeaders.push('Content-type',
@@ -831,22 +873,48 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
831
873
  this.updater = new Ajax.Updater(this.container, this.url, this.options);
832
874
  }
833
875
  });
876
+ function $() {
877
+ var results = [], element;
878
+ for (var i = 0; i < arguments.length; i++) {
879
+ element = arguments[i];
880
+ if (typeof element == 'string')
881
+ element = document.getElementById(element);
882
+ results.push(Element.extend(element));
883
+ }
884
+ return results.length < 2 ? results[0] : results;
885
+ }
886
+
834
887
  document.getElementsByClassName = function(className, parentElement) {
835
888
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
836
889
  return $A(children).inject([], function(elements, child) {
837
890
  if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
838
- elements.push(child);
891
+ elements.push(Element.extend(child));
839
892
  return elements;
840
893
  });
841
894
  }
842
895
 
843
896
  /*--------------------------------------------------------------------------*/
844
897
 
845
- if (!window.Element) {
898
+ if (!window.Element)
846
899
  var Element = new Object();
900
+
901
+ Element.extend = function(element) {
902
+ if (!element) return;
903
+
904
+ if (!element._extended && element.tagName && element != window) {
905
+ var methods = Element.Methods;
906
+ for (property in methods) {
907
+ var value = methods[property];
908
+ if (typeof value == 'function')
909
+ element[property] = value.bind(null, element);
910
+ }
911
+ }
912
+
913
+ element._extended = true;
914
+ return element;
847
915
  }
848
916
 
849
- Object.extend(Element, {
917
+ Element.Methods = {
850
918
  visible: function(element) {
851
919
  return $(element).style.display != 'none';
852
920
  },
@@ -882,6 +950,19 @@ Object.extend(Element, {
882
950
  setTimeout(function() {html.evalScripts()}, 10);
883
951
  },
884
952
 
953
+ replace: function(element, html) {
954
+ element = $(element);
955
+ if (element.outerHTML) {
956
+ element.outerHTML = html.stripScripts();
957
+ } else {
958
+ var range = element.ownerDocument.createRange();
959
+ range.selectNodeContents(element);
960
+ element.parentNode.replaceChild(
961
+ range.createContextualFragment(html.stripScripts()), element);
962
+ }
963
+ setTimeout(function() {html.evalScripts()}, 10);
964
+ },
965
+
885
966
  getHeight: function(element) {
886
967
  element = $(element);
887
968
  return element.offsetHeight;
@@ -920,6 +1001,13 @@ Object.extend(Element, {
920
1001
  return $(element).innerHTML.match(/^\s*$/);
921
1002
  },
922
1003
 
1004
+ childOf: function(element, ancestor) {
1005
+ element = $(element), ancestor = $(ancestor);
1006
+ while (element = element.parentNode)
1007
+ if (element == ancestor) return true;
1008
+ return false;
1009
+ },
1010
+
923
1011
  scrollTo: function(element) {
924
1012
  element = $(element);
925
1013
  var x = element.x ? element.x : element.offsetLeft,
@@ -1013,7 +1101,9 @@ Object.extend(Element, {
1013
1101
  element.style.overflow = element._overflow;
1014
1102
  element._overflow = undefined;
1015
1103
  }
1016
- });
1104
+ }
1105
+
1106
+ Object.extend(Element, Element.Methods);
1017
1107
 
1018
1108
  var Toggle = new Object();
1019
1109
  Toggle.display = Element.toggle;
@@ -1148,6 +1238,116 @@ Element.ClassNames.prototype = {
1148
1238
  }
1149
1239
 
1150
1240
  Object.extend(Element.ClassNames.prototype, Enumerable);
1241
+ var Selector = Class.create();
1242
+ Selector.prototype = {
1243
+ initialize: function(expression) {
1244
+ this.params = {classNames: []};
1245
+ this.expression = expression.toString().strip();
1246
+ this.parseExpression();
1247
+ this.compileMatcher();
1248
+ },
1249
+
1250
+ parseExpression: function() {
1251
+ function abort(message) { throw 'Parse error in selector: ' + message; }
1252
+
1253
+ if (this.expression == '') abort('empty expression');
1254
+
1255
+ var params = this.params, expr = this.expression, match, modifier, clause, rest;
1256
+ while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
1257
+ params.attributes = params.attributes || [];
1258
+ params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
1259
+ expr = match[1];
1260
+ }
1261
+
1262
+ if (expr == '*') return this.params.wildcard = true;
1263
+
1264
+ while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
1265
+ modifier = match[1], clause = match[2], rest = match[3];
1266
+ switch (modifier) {
1267
+ case '#': params.id = clause; break;
1268
+ case '.': params.classNames.push(clause); break;
1269
+ case '':
1270
+ case undefined: params.tagName = clause.toUpperCase(); break;
1271
+ default: abort(expr.inspect());
1272
+ }
1273
+ expr = rest;
1274
+ }
1275
+
1276
+ if (expr.length > 0) abort(expr.inspect());
1277
+ },
1278
+
1279
+ buildMatchExpression: function() {
1280
+ var params = this.params, conditions = [], clause;
1281
+
1282
+ if (params.wildcard)
1283
+ conditions.push('true');
1284
+ if (clause = params.id)
1285
+ conditions.push('element.id == ' + clause.inspect());
1286
+ if (clause = params.tagName)
1287
+ conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
1288
+ if ((clause = params.classNames).length > 0)
1289
+ for (var i = 0; i < clause.length; i++)
1290
+ conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
1291
+ if (clause = params.attributes) {
1292
+ clause.each(function(attribute) {
1293
+ var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
1294
+ var splitValueBy = function(delimiter) {
1295
+ return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
1296
+ }
1297
+
1298
+ switch (attribute.operator) {
1299
+ case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
1300
+ case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
1301
+ case '|=': conditions.push(
1302
+ splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
1303
+ ); break;
1304
+ case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
1305
+ case '':
1306
+ case undefined: conditions.push(value + ' != null'); break;
1307
+ default: throw 'Unknown operator ' + attribute.operator + ' in selector';
1308
+ }
1309
+ });
1310
+ }
1311
+
1312
+ return conditions.join(' && ');
1313
+ },
1314
+
1315
+ compileMatcher: function() {
1316
+ this.match = new Function('element', 'if (!element.tagName) return false; \
1317
+ return ' + this.buildMatchExpression());
1318
+ },
1319
+
1320
+ findElements: function(scope) {
1321
+ var element;
1322
+
1323
+ if (element = $(this.params.id))
1324
+ if (this.match(element))
1325
+ if (!scope || Element.childOf(element, scope))
1326
+ return [element];
1327
+
1328
+ scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
1329
+
1330
+ var results = [];
1331
+ for (var i = 0; i < scope.length; i++)
1332
+ if (this.match(element = scope[i]))
1333
+ results.push(Element.extend(element));
1334
+
1335
+ return results;
1336
+ },
1337
+
1338
+ toString: function() {
1339
+ return this.expression;
1340
+ }
1341
+ }
1342
+
1343
+ function $$() {
1344
+ return $A(arguments).map(function(expression) {
1345
+ return expression.strip().split(/\s+/).inject([null], function(results, expr) {
1346
+ var selector = new Selector(expr);
1347
+ return results.map(selector.findElements.bind(selector)).flatten();
1348
+ });
1349
+ }).flatten();
1350
+ }
1151
1351
  var Field = {
1152
1352
  clear: function() {
1153
1353
  for (var i = 0; i < arguments.length; i++)
@@ -1,6 +1,6 @@
1
1
  class CodeStatistics #:nodoc:
2
2
 
3
- TEST_TYPES = ['Units', 'Functionals', 'Unit tests', 'Functional tests']
3
+ TEST_TYPES = %w(Units Functionals Unit\ tests Functional\ tests Integration\ tests)
4
4
 
5
5
  def initialize(*pairs)
6
6
  @pairs = pairs
@@ -11,9 +11,11 @@ end
11
11
 
12
12
  libs = " -r irb/completion"
13
13
  libs << " -r #{RAILS_ROOT}/config/environment"
14
+ libs << " -r console_app"
14
15
  libs << " -r console_sandbox" if options[:sandbox]
16
+ libs << " -r console_with_helpers"
15
17
 
16
- ENV['RAILS_ENV'] = ARGV.first || 'development'
18
+ ENV['RAILS_ENV'] = ARGV.first || ENV['RAILS_ENV'] || 'development'
17
19
  if options[:sandbox]
18
20
  puts "Loading #{ENV['RAILS_ENV']} environment in sandbox."
19
21
  puts "Any modifications you make will be rolled back on exit."
@@ -31,10 +31,13 @@
31
31
  # look like subversion repositories with plugins:
32
32
  # http://wiki.rubyonrails.org/rails/pages/Plugins
33
33
  #
34
+ # * Unless you specify that you want to use svn, script/plugin uses plain ole
35
+ # HTTP for downloads. The following bullets are true if you specify
36
+ # that you want to use svn.
37
+ #
34
38
  # * If `vendor/plugins` is under subversion control, the script will
35
39
  # 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.
40
+ # use normal subversion commands to keep the plugins up to date.
38
41
  #
39
42
  # * Or, if `vendor/plugins` is not under subversion control, the
40
43
  # plugin is pulled via `svn checkout` or `svn export` but looks
@@ -58,7 +61,7 @@ class RailsEnvironment
58
61
  def initialize(dir)
59
62
  @root = dir
60
63
  end
61
-
64
+
62
65
  def self.find(dir=nil)
63
66
  dir ||= pwd
64
67
  while dir.length > 1
@@ -93,21 +96,22 @@ class RailsEnvironment
93
96
  end
94
97
 
95
98
  def use_svn?
96
- `svn --version` rescue nil
99
+ require 'active_support/core_ext/kernel'
100
+ silence_stderr {`svn --version` rescue nil}
97
101
  !$?.nil? && $?.success?
98
102
  end
99
103
 
100
104
  def use_externals?
101
- File.directory?("#{root}/vendor/plugins/.svn")
105
+ use_svn? && File.directory?("#{root}/vendor/plugins/.svn")
102
106
  end
103
-
107
+
104
108
  def use_checkout?
105
109
  # this is a bit of a guess. we assume that if the rails environment
106
110
  # is under subversion than they probably want the plugin checked out
107
111
  # instead of exported. This can be overridden on the command line
108
112
  File.directory?("#{root}/.svn")
109
113
  end
110
-
114
+
111
115
  def best_install_method
112
116
  return :http unless use_svn?
113
117
  case
@@ -119,12 +123,12 @@ class RailsEnvironment
119
123
 
120
124
  def externals
121
125
  return [] unless use_externals?
122
- ext = `svn propget svn:externals #{root}/vendor/plugins`
126
+ ext = `svn propget svn:externals "#{root}/vendor/plugins"`
123
127
  ext.reject{ |line| line.strip == '' }.map do |line|
124
128
  line.strip.split(/\s+/, 2)
125
129
  end
126
130
  end
127
-
131
+
128
132
  def externals=(items)
129
133
  unless items.is_a? String
130
134
  items = items.map{|name,uri| "#{name.ljust(29)} #{uri.chomp('/')}"}.join("\n")
@@ -132,7 +136,7 @@ class RailsEnvironment
132
136
  Tempfile.open("svn-set-prop") do |file|
133
137
  file.write(items)
134
138
  file.flush
135
- system("svn propset -q svn:externals -F #{file.path} #{root}/vendor/plugins")
139
+ system("svn propset -q svn:externals -F #{file.path} \"#{root}/vendor/plugins\"")
136
140
  end
137
141
  end
138
142
 
@@ -155,40 +159,73 @@ class Plugin
155
159
  or rails_env.externals.detect{ |name, repo| self.uri == repo }
156
160
  end
157
161
 
158
- def install(method=nil)
162
+ def install(method=nil, options = {})
159
163
  method ||= rails_env.best_install_method?
164
+
165
+ uninstall if installed? and options[:force]
166
+
160
167
  unless installed?
161
- send("install_using_#{method}")
168
+ send("install_using_#{method}", options)
169
+ run_install_hook
162
170
  else
163
- puts "already installed: #{name} (#{uri})"
171
+ puts "already installed: #{name} (#{uri}). pass --force to reinstall"
164
172
  end
165
173
  end
166
-
174
+
175
+ def uninstall
176
+ path = "#{rails_env.root}/vendor/plugins/#{name}"
177
+ if File.directory?(path)
178
+ puts "Removing 'vendor/plugins/#{name}'" if $verbose
179
+ rm_r path
180
+ else
181
+ puts "Plugin doesn't exist: #{path}"
182
+ end
183
+ # clean up svn:externals
184
+ externals = rails_env.externals
185
+ externals.reject!{|n,u| name == n or name == u}
186
+ rails_env.externals = externals
187
+ end
188
+
167
189
  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}")
190
+
191
+ def run_install_hook
192
+ install_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/install.rb"
193
+ load install_hook_file if File.exists? install_hook_file
194
+ end
195
+
196
+ def install_using_export(options = {})
197
+ svn_command :export, options
172
198
  end
173
199
 
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}")
200
+ def install_using_checkout(options = {})
201
+ svn_command :checkout, options
178
202
  end
179
203
 
180
- def install_using_externals
204
+ def install_using_externals(options = {})
181
205
  externals = rails_env.externals
182
206
  externals.push([@name, uri])
183
207
  rails_env.externals = externals
184
- install_using_checkout
208
+ install_using_checkout(options)
185
209
  end
186
210
 
187
- def install_using_http
211
+ def install_using_http(options = {})
188
212
  root = rails_env.root
189
213
  mkdir_p "#{root}/vendor/plugins"
190
214
  Dir.chdir "#{root}/vendor/plugins"
191
- RecursiveHTTPFetcher.new(uri).fetch
215
+ puts "fetching from '#{uri}'" if $verbose
216
+ fetcher = RecursiveHTTPFetcher.new(uri)
217
+ fetcher.quiet = true if options[:quiet]
218
+ fetcher.fetch
219
+ end
220
+
221
+ def svn_command(cmd, options = {})
222
+ root = rails_env.root
223
+ mkdir_p "#{root}/vendor/plugins"
224
+ base_cmd = "svn #{cmd} #{uri} \"#{root}/vendor/plugins/#{name}\""
225
+ base_cmd += ' -q' if options[:quiet] and not $verbose
226
+ base_cmd += " -r #{options[:revision]}" if options[:revision]
227
+ puts base_cmd if $verbose
228
+ system(base_cmd)
192
229
  end
193
230
 
194
231
  def guess_name(url)
@@ -239,7 +276,6 @@ class Repositories
239
276
  return plugin if plugin.name == name
240
277
  end
241
278
  end
242
-
243
279
  return nil
244
280
  end
245
281
 
@@ -298,8 +334,7 @@ class Repository
298
334
  attr_reader :uri, :plugins
299
335
 
300
336
  def initialize(uri)
301
- uri << "/" unless uri =~ /\/$/
302
- @uri = uri
337
+ @uri = uri.chomp('/') << "/"
303
338
  @plugins = nil
304
339
  end
305
340
 
@@ -310,7 +345,7 @@ class Repository
310
345
  puts index
311
346
  end
312
347
 
313
- @plugins = index.split(/\n/).reject{ |line| line !~ /\/$/ }
348
+ @plugins = index.reject{ |line| line !~ /\/$/ }
314
349
  @plugins.map! { |name| Plugin.new(File.join(@uri, name), name) }
315
350
  end
316
351
 
@@ -323,7 +358,7 @@ class Repository
323
358
 
324
359
  private
325
360
  def index
326
- @index ||= `svn ls #{@uri}`
361
+ @index ||= RecursiveHTTPFetcher.new(@uri).ls
327
362
  end
328
363
  end
329
364
 
@@ -411,7 +446,7 @@ module Commands
411
446
  command.parse!(sub)
412
447
  else
413
448
  puts "Unknown command: #{command}"
414
- puts "Try: #{$0} --help"
449
+ puts options
415
450
  exit 1
416
451
  end
417
452
  end
@@ -435,7 +470,6 @@ module Commands
435
470
  @sources = []
436
471
  @local = false
437
472
  @remote = true
438
- @details = false
439
473
  end
440
474
 
441
475
  def options
@@ -453,8 +487,6 @@ module Commands
453
487
  o.on( "--remote",
454
488
  "List remotely availabled plugins. This is the default behavior",
455
489
  "unless --local is provided.") {|@remote|}
456
- o.on( "-l", "--long",
457
- "Long listing / details about each plugin.") {|@details|}
458
490
  end
459
491
  end
460
492
 
@@ -469,14 +501,12 @@ module Commands
469
501
  @sources.map{|r| r.plugins}.flatten.each do |plugin|
470
502
  if @local or !plugin.installed?
471
503
  puts plugin.to_s
472
- system "svn info #{plugin.uri}" if @details
473
504
  end
474
505
  end
475
506
  else
476
507
  cd "#{@base_command.environment.root}/vendor/plugins"
477
508
  Dir["*"].select{|p| File.directory?(p)}.each do |name|
478
509
  puts name
479
- system "svn info #{name}" if @details
480
510
  end
481
511
  end
482
512
  end
@@ -644,7 +674,8 @@ module Commands
644
674
  class Install
645
675
  def initialize(base_command)
646
676
  @base_command = base_command
647
- @method = :export
677
+ @method = :http
678
+ @options = { :quiet => false, :revision => nil, :force => false }
648
679
  end
649
680
 
650
681
  def options
@@ -660,6 +691,14 @@ module Commands
660
691
  o.on( "-o", "--checkout",
661
692
  "Use svn checkout to grab the plugin.",
662
693
  "Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout }
694
+ o.on( "-q", "--quiet",
695
+ "Suppresses the output from installation.",
696
+ "Ignored if -v is passed (./script/plugin -v install ...)") { |v| @options[:quiet] = true }
697
+ o.on( "-r REVISION", "--revision REVISION",
698
+ "Checks out the given revision from subversion.",
699
+ "Ignored if subversion is not used.") { |v| @options[:revision] = v }
700
+ o.on( "-f", "--force",
701
+ "Reinstalls a plugin if it's already installed.") { |v| @options[:force] = true }
663
702
  o.separator ""
664
703
  o.separator "You can specify plugin names as given in 'plugin list' output or absolute URLs to "
665
704
  o.separator "a plugin repository."
@@ -672,8 +711,8 @@ module Commands
672
711
  case
673
712
  when (best == :http and @method != :http)
674
713
  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."
714
+ when (best == :export and (@method != :export and @method != :http))
715
+ msg = "Cannot install using #{@method} because this project is not under subversion."
677
716
  when (best != :externals and @method == :externals)
678
717
  msg = "Cannot install using externals because vendor/plugins is not under subversion."
679
718
  end
@@ -691,11 +730,11 @@ module Commands
691
730
  puts "Plugins will be installed using #{install_method}" if $verbose
692
731
  args.each do |name|
693
732
  if name =~ /\// then
694
- ::Plugin.new(name).install(install_method)
733
+ ::Plugin.new(name).install(install_method, @options)
695
734
  else
696
735
  plugin = Repositories.instance.find_plugin(name)
697
736
  unless plugin.nil?
698
- plugin.install(install_method)
737
+ plugin.install(install_method, @options)
699
738
  else
700
739
  puts "Plugin not found: #{name}"
701
740
  exit 1
@@ -705,39 +744,42 @@ module Commands
705
744
  end
706
745
  end
707
746
 
708
-
709
- class Remove
747
+ class Update
710
748
  def initialize(base_command)
711
749
  @base_command = base_command
712
750
  end
713
-
751
+
714
752
  def options
715
753
  OptionParser.new do |o|
716
754
  o.set_summary_indent(' ')
717
- o.banner = "Usage: #{@base_command.script_name} remove name [name]..."
718
- o.define_head "Remove plugins."
755
+ o.banner = "Usage: #{@base_command.script_name} update [name [name]...]"
756
+ o.on( "-r REVISION", "--revision REVISION",
757
+ "Checks out the given revision from subversion.",
758
+ "Ignored if subversion is not used.") { |v| @revision = v }
759
+ o.define_head "Update plugins."
719
760
  end
720
761
  end
721
-
762
+
722
763
  def parse!(args)
723
764
  options.parse!(args)
724
765
  root = @base_command.environment.root
766
+ cd root
767
+ args = Dir["vendor/plugins/*"].map do |f|
768
+ File.directory?("#{f}/.svn") ? File.basename(f) : nil
769
+ end.compact if args.empty?
770
+ cd "vendor/plugins"
725
771
  args.each do |name|
726
- path = "#{root}/vendor/plugins/#{name}"
727
- if File.directory?(path)
728
- rm_r path
772
+ if File.directory?(name)
773
+ puts "Updating plugin: #{name}"
774
+ system("svn #{$verbose ? '' : '-q'} up \"#{name}\" #{@revision ? "-r #{@revision}" : ''}")
729
775
  else
730
- puts "Plugin doesn't exist: #{path}"
776
+ puts "Plugin doesn't exist: #{name}"
731
777
  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
778
  end
737
779
  end
738
780
  end
739
781
 
740
- class Update
782
+ class Remove
741
783
  def initialize(base_command)
742
784
  @base_command = base_command
743
785
  end
@@ -745,25 +787,16 @@ module Commands
745
787
  def options
746
788
  OptionParser.new do |o|
747
789
  o.set_summary_indent(' ')
748
- o.banner = "Usage: #{@base_command.script_name} update [name [name]...]"
749
- o.define_head "Update plugins."
790
+ o.banner = "Usage: #{@base_command.script_name} remove name [name]..."
791
+ o.define_head "Remove plugins."
750
792
  end
751
793
  end
752
794
 
753
795
  def parse!(args)
754
796
  options.parse!(args)
755
797
  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
798
  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
799
+ ::Plugin.new(name).uninstall
767
800
  end
768
801
  end
769
802
  end
@@ -771,9 +804,19 @@ module Commands
771
804
  end
772
805
 
773
806
  class RecursiveHTTPFetcher
807
+ attr_accessor :quiet
774
808
  def initialize(urls_to_fetch, cwd = ".")
775
809
  @cwd = cwd
776
810
  @urls_to_fetch = urls_to_fetch.to_a
811
+ @quiet = false
812
+ end
813
+
814
+ def ls
815
+ @urls_to_fetch.collect do |url|
816
+ open(url) do |stream|
817
+ links("", stream.read)
818
+ end rescue nil
819
+ end.flatten
777
820
  end
778
821
 
779
822
  def push_d(dir)
@@ -796,7 +839,7 @@ class RecursiveHTTPFetcher
796
839
  end
797
840
 
798
841
  def download(link)
799
- puts "+ #{File.join(@cwd, File.basename(link))}"
842
+ puts "+ #{File.join(@cwd, File.basename(link))}" unless @quiet
800
843
  open(link) do |stream|
801
844
  File.open(File.join(@cwd, File.basename(link)), "wb") do |file|
802
845
  file.write(stream.read)