rapt 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +4 -0
- data/MIT-LICENSE +21 -0
- data/README +4 -0
- data/Rakefile +74 -0
- data/bin/rapt +6 -0
- data/lib/commands/plugin.rb +65 -0
- data/lib/commands/plugin/commands.rb +486 -0
- data/lib/commands/plugin/plugin.rb +148 -0
- data/lib/commands/plugin/rails_environment.rb +87 -0
- data/lib/commands/plugin/recursive_http_fetcher.rb +65 -0
- data/lib/commands/plugin/repositories.rb +128 -0
- data/lib/commands/plugin/repository.rb +34 -0
- data/test/commands/plugin/plugin_test.rb +58 -0
- data/test/commands/plugin/repository_test.rb +20 -0
- data/test/commands/plugin_test.rb +75 -0
- data/test/mocks/rails_environment.rb +5 -0
- data/test/sandbox/rails_app/config/boot.rb +44 -0
- data/test/sandbox/rails_app/config/environment.rb +0 -0
- data/test/sandbox/rails_app/script/plugin +3 -0
- metadata +75 -0
data/CHANGELOG
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2006 Geoffrey Grosenbach boss@topfunky.com
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/packagetask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'rake/contrib/rubyforgepublisher'
|
8
|
+
|
9
|
+
$:.unshift(File.dirname(__FILE__) + "/lib/commands")
|
10
|
+
require 'plugin'
|
11
|
+
|
12
|
+
PKG_NAME = 'rapt'
|
13
|
+
PKG_VERSION = '0.1.0'
|
14
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
15
|
+
|
16
|
+
RELEASE_NAME = "REL #{PKG_VERSION}"
|
17
|
+
|
18
|
+
RUBY_FORGE_PROJECT = PKG_NAME
|
19
|
+
RUBY_FORGE_USER = "topfunky"
|
20
|
+
|
21
|
+
desc "Default Task"
|
22
|
+
task :default => :test
|
23
|
+
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.pattern = 'test/**/*_test.rb'
|
27
|
+
t.verbose = true
|
28
|
+
end
|
29
|
+
|
30
|
+
# Genereate the RDoc documentation
|
31
|
+
Rake::RDocTask.new { |rdoc|
|
32
|
+
rdoc.rdoc_dir = 'doc'
|
33
|
+
rdoc.title = "Rapt -- Rails plugin manager"
|
34
|
+
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
35
|
+
rdoc.rdoc_files.include('README', 'CHANGELOG')
|
36
|
+
rdoc.rdoc_files.include('lib/plugin.rb')
|
37
|
+
rdoc.rdoc_files.include('lib/plugin/*.rb')
|
38
|
+
}
|
39
|
+
|
40
|
+
# Create compressed packages
|
41
|
+
spec = Gem::Specification.new do |s|
|
42
|
+
s.platform = Gem::Platform::RUBY
|
43
|
+
s.name = PKG_NAME
|
44
|
+
s.summary = "Rails plugin manager."
|
45
|
+
s.description = %q{Install, remove, and discover new plugins for your Ruby on Rails app.}
|
46
|
+
s.version = PKG_VERSION
|
47
|
+
|
48
|
+
s.authors = ["Ryan Tomayko", "Geoffrey Grosenbach"]
|
49
|
+
s.email = "boss@topfunky.com"
|
50
|
+
s.rubyforge_project = RUBY_FORGE_PROJECT
|
51
|
+
s.homepage = "http://nubyonrails.com/pages/rapt"
|
52
|
+
|
53
|
+
s.has_rdoc = false
|
54
|
+
s.requirements << 'none'
|
55
|
+
s.require_path = 'lib'
|
56
|
+
|
57
|
+
s.files = [ "Rakefile", "README", "CHANGELOG", "MIT-LICENSE" ]
|
58
|
+
%w(bin lib test).each do |dir|
|
59
|
+
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
60
|
+
end
|
61
|
+
s.executables = ["rapt"]
|
62
|
+
end
|
63
|
+
|
64
|
+
Rake::GemPackageTask.new(spec) do |p|
|
65
|
+
p.gem_spec = spec
|
66
|
+
p.need_tar = true
|
67
|
+
p.need_zip = true
|
68
|
+
end
|
69
|
+
|
70
|
+
# desc "Publish the API documentation"
|
71
|
+
# task :pgem => [:package] do
|
72
|
+
# Rake::SshFilePublisher.new("boss@topfunky.com", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
73
|
+
# end
|
74
|
+
|
data/bin/rapt
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Rails Plugin Manager.
|
2
|
+
#
|
3
|
+
# Listing available plugins:
|
4
|
+
#
|
5
|
+
# $ ./script/plugin list
|
6
|
+
# continuous_builder http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder
|
7
|
+
# asset_timestamping http://svn.aviditybytes.com/rails/plugins/asset_timestamping
|
8
|
+
# enumerations_mixin http://svn.protocool.com/rails/plugins/enumerations_mixin/trunk
|
9
|
+
# calculations http://techno-weenie.net/svn/projects/calculations/
|
10
|
+
# ...
|
11
|
+
#
|
12
|
+
# Installing plugins:
|
13
|
+
#
|
14
|
+
# $ ./script/plugin install continuous_builder asset_timestamping
|
15
|
+
#
|
16
|
+
# Finding Repositories:
|
17
|
+
#
|
18
|
+
# $ ./script/plugin discover
|
19
|
+
#
|
20
|
+
# Adding Repositories:
|
21
|
+
#
|
22
|
+
# $ ./script/plugin source http://svn.protocool.com/rails/plugins/
|
23
|
+
#
|
24
|
+
# How it works:
|
25
|
+
#
|
26
|
+
# * Maintains a list of subversion repositories that are assumed to have
|
27
|
+
# a plugin directory structure. Manage them with the (source, unsource,
|
28
|
+
# and sources commands)
|
29
|
+
#
|
30
|
+
# * The discover command scrapes the following page for things that
|
31
|
+
# look like subversion repositories with plugins:
|
32
|
+
# http://wiki.rubyonrails.org/rails/pages/Plugins
|
33
|
+
#
|
34
|
+
# * Unless you specify that you want to use svn, script/plugin uses plain old
|
35
|
+
# HTTP for downloads. The following bullets are true if you specify
|
36
|
+
# that you want to use svn.
|
37
|
+
#
|
38
|
+
# * If `vendor/plugins` is under subversion control, the script will
|
39
|
+
# modify the svn:externals property and perform an update. You can
|
40
|
+
# use normal subversion commands to keep the plugins up to date.
|
41
|
+
#
|
42
|
+
# * Or, if `vendor/plugins` is not under subversion control, the
|
43
|
+
# plugin is pulled via `svn checkout` or `svn export` but looks
|
44
|
+
# exactly the same.
|
45
|
+
#
|
46
|
+
# This is Free Software, copyright 2005 by Ryan Tomayko (rtomayko@gmail.com)
|
47
|
+
# and is licensed MIT: (http://www.opensource.org/licenses/mit-license.php)
|
48
|
+
|
49
|
+
$verbose = false
|
50
|
+
|
51
|
+
require 'open-uri'
|
52
|
+
require 'fileutils'
|
53
|
+
require 'tempfile'
|
54
|
+
|
55
|
+
include FileUtils
|
56
|
+
|
57
|
+
require File.dirname(__FILE__) + '/plugin/rails_environment'
|
58
|
+
require File.dirname(__FILE__) + '/plugin/plugin'
|
59
|
+
require File.dirname(__FILE__) + '/plugin/repositories'
|
60
|
+
require File.dirname(__FILE__) + '/plugin/repository'
|
61
|
+
require File.dirname(__FILE__) + '/plugin/commands'
|
62
|
+
require File.dirname(__FILE__) + '/plugin/recursive_http_fetcher'
|
63
|
+
|
64
|
+
|
65
|
+
|
@@ -0,0 +1,486 @@
|
|
1
|
+
|
2
|
+
# Load default environment and parse arguments
|
3
|
+
require 'optparse'
|
4
|
+
module Commands
|
5
|
+
|
6
|
+
class Plugin
|
7
|
+
attr_reader :environment, :script_name, :sources
|
8
|
+
def initialize
|
9
|
+
@environment = RailsEnvironment.default
|
10
|
+
@rails_root = RailsEnvironment.default.root
|
11
|
+
@script_name = File.basename($0)
|
12
|
+
@sources = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def environment=(value)
|
16
|
+
@environment = value
|
17
|
+
RailsEnvironment.default = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def options
|
21
|
+
OptionParser.new do |o|
|
22
|
+
o.set_summary_indent(' ')
|
23
|
+
o.banner = "Usage: #{@script_name} [OPTIONS] command"
|
24
|
+
o.define_head "Rails plugin manager."
|
25
|
+
|
26
|
+
o.separator ""
|
27
|
+
o.separator "GENERAL OPTIONS"
|
28
|
+
|
29
|
+
o.on("-r", "--root=DIR", String,
|
30
|
+
"Set an explicit rails app directory.",
|
31
|
+
"Default: #{@rails_root}") { |@rails_root| self.environment = RailsEnvironment.new(@rails_root) }
|
32
|
+
o.on("-s", "--source=URL1,URL2", Array,
|
33
|
+
"Use the specified plugin repositories instead of the defaults.") { |@sources|}
|
34
|
+
|
35
|
+
o.on("-v", "--verbose", "Turn on verbose output.") { |$verbose| }
|
36
|
+
o.on("-h", "--help", "Show this help message.") { puts o; exit }
|
37
|
+
|
38
|
+
o.separator ""
|
39
|
+
o.separator "COMMANDS"
|
40
|
+
|
41
|
+
o.separator " discover Discover plugin repositories."
|
42
|
+
o.separator " list List available plugins."
|
43
|
+
o.separator " about Show basic info about a plugin."
|
44
|
+
o.separator " install Install plugin(s) from known repositories or URLs."
|
45
|
+
o.separator " update Update installed plugins."
|
46
|
+
o.separator " remove Uninstall plugins."
|
47
|
+
o.separator " source Add a plugin source repository."
|
48
|
+
o.separator " unsource Remove a plugin repository."
|
49
|
+
o.separator " sources List currently configured plugin repositories."
|
50
|
+
|
51
|
+
o.separator ""
|
52
|
+
o.separator "EXAMPLES"
|
53
|
+
o.separator " Install a plugin:"
|
54
|
+
o.separator " #{@script_name} install continuous_builder\n"
|
55
|
+
o.separator " Install a plugin from a subversion URL:"
|
56
|
+
o.separator " #{@script_name} install http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder\n"
|
57
|
+
o.separator " Install a plugin and add a svn:externals entry to vendor/plugins"
|
58
|
+
o.separator " #{@script_name} install -x continuous_builder\n"
|
59
|
+
o.separator " Show information about the acts_as_chunky_bacon plugin:"
|
60
|
+
o.separator " #{@script_name} about acts_as_chunky_bacon\n"
|
61
|
+
o.separator " List all available plugins:"
|
62
|
+
o.separator " #{@script_name} list\n"
|
63
|
+
o.separator " List plugins in the specified repository:"
|
64
|
+
o.separator " #{@script_name} list --source=http://dev.rubyonrails.com/svn/rails/plugins/\n"
|
65
|
+
o.separator " Discover and prompt to add new repositories:"
|
66
|
+
o.separator " #{@script_name} discover\n"
|
67
|
+
o.separator " Discover new repositories but just list them, don't add anything:"
|
68
|
+
o.separator " #{@script_name} discover -l\n"
|
69
|
+
o.separator " Add a new repository to the source list:"
|
70
|
+
o.separator " #{@script_name} source http://dev.rubyonrails.com/svn/rails/plugins/\n"
|
71
|
+
o.separator " Remove a repository from the source list:"
|
72
|
+
o.separator " #{@script_name} unsource http://dev.rubyonrails.com/svn/rails/plugins/\n"
|
73
|
+
o.separator " Show currently configured repositories:"
|
74
|
+
o.separator " #{@script_name} sources\n"
|
75
|
+
o.separator " Show the options for the list command:"
|
76
|
+
o.separator " #{@script_name} list -h\n"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse!(args=ARGV)
|
81
|
+
general, sub = split_args(args)
|
82
|
+
options.parse!(general)
|
83
|
+
|
84
|
+
command = general.shift
|
85
|
+
if command =~ /^(list|discover|install|source|unsource|sources|remove|update|about)$/
|
86
|
+
command = Commands.const_get(command.capitalize).new(self)
|
87
|
+
command.parse!(sub)
|
88
|
+
else
|
89
|
+
puts "Unknown command: #{command}"
|
90
|
+
puts options
|
91
|
+
exit 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def split_args(args)
|
96
|
+
left = []
|
97
|
+
left << args.shift while args[0] and args[0] =~ /^-/
|
98
|
+
left << args.shift if args[0]
|
99
|
+
return [left, args]
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.parse!(args=ARGV)
|
103
|
+
Plugin.new.parse!(args)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
class List
|
109
|
+
def initialize(base_command)
|
110
|
+
@base_command = base_command
|
111
|
+
@sources = []
|
112
|
+
@local = false
|
113
|
+
@remote = false
|
114
|
+
@cached = true
|
115
|
+
end
|
116
|
+
|
117
|
+
def options
|
118
|
+
OptionParser.new do |o|
|
119
|
+
o.set_summary_indent(' ')
|
120
|
+
o.banner = "Usage: #{@base_command.script_name} list [OPTIONS] [PATTERN]"
|
121
|
+
o.define_head "List available plugins."
|
122
|
+
o.separator ""
|
123
|
+
o.separator "Options:"
|
124
|
+
o.separator ""
|
125
|
+
o.on( "-s", "--source=URL1,URL2", Array,
|
126
|
+
"Use the specified plugin repositories.") {|@sources| @remote = true; @cached = false }
|
127
|
+
o.on( "--local",
|
128
|
+
"List locally installed plugins.") {|@local| @cached = false }
|
129
|
+
o.on( "--cached",
|
130
|
+
"List the known plugins in the local sources cache. This is the default behavior.") {|@cached|}
|
131
|
+
o.on( "--remote",
|
132
|
+
"List remotely available plugins.",
|
133
|
+
"unless --local is provided.") {|@remote| @cached = false }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def parse!(args)
|
138
|
+
options.order!(args)
|
139
|
+
unless @sources.empty?
|
140
|
+
@sources.map!{ |uri| Repository.new(uri) }
|
141
|
+
else
|
142
|
+
@sources = Repositories.instance.all
|
143
|
+
end
|
144
|
+
if @remote
|
145
|
+
@sources.map{|r| r.plugins}.flatten.each do |plugin|
|
146
|
+
if @local or !plugin.installed?
|
147
|
+
puts plugin.to_s
|
148
|
+
end
|
149
|
+
end
|
150
|
+
elsif @cached
|
151
|
+
Repositories.instance.cached_plugins.each { |plugin| puts plugin.to_s }
|
152
|
+
puts "\nThere are #{Repositories.instance.plugin_count} plugins in the source cache.\n\n"
|
153
|
+
else
|
154
|
+
cd "#{@base_command.environment.root}/vendor/plugins"
|
155
|
+
Dir["*"].select{|p| File.directory?(p)}.each do |name|
|
156
|
+
puts name
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
class Sources
|
164
|
+
def initialize(base_command)
|
165
|
+
@base_command = base_command
|
166
|
+
end
|
167
|
+
|
168
|
+
def options
|
169
|
+
OptionParser.new do |o|
|
170
|
+
o.set_summary_indent(' ')
|
171
|
+
o.banner = "Usage: #{@base_command.script_name} sources [OPTIONS] [PATTERN]"
|
172
|
+
o.define_head "List configured plugin repositories."
|
173
|
+
o.separator ""
|
174
|
+
o.separator "Options:"
|
175
|
+
o.separator ""
|
176
|
+
o.on( "-c", "--check",
|
177
|
+
"Report status of repository.") { |@sources| } # TODO Implement
|
178
|
+
o.on( "-r", "--refresh",
|
179
|
+
"Refresh the source cache with the list of plugins available in each repository.") { refresh }
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def parse!(args)
|
184
|
+
options.parse!(args)
|
185
|
+
Repositories.each do |repo|
|
186
|
+
puts repo.uri
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def refresh
|
191
|
+
puts "Refreshing source cache (may take a few minutes)..."
|
192
|
+
repositories = Repositories.instance
|
193
|
+
repositories.refresh!
|
194
|
+
repositories.save
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
class Source
|
200
|
+
def initialize(base_command)
|
201
|
+
@base_command = base_command
|
202
|
+
end
|
203
|
+
|
204
|
+
def options
|
205
|
+
OptionParser.new do |o|
|
206
|
+
o.set_summary_indent(' ')
|
207
|
+
o.banner = "Usage: #{@base_command.script_name} source REPOSITORY"
|
208
|
+
o.define_head "Add a new repository."
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def parse!(args)
|
213
|
+
options.parse!(args)
|
214
|
+
count = 0
|
215
|
+
args.each do |uri|
|
216
|
+
if Repositories.instance.add(uri)
|
217
|
+
puts "added: #{uri.ljust(50)}" if $verbose
|
218
|
+
count += 1
|
219
|
+
else
|
220
|
+
puts "failed: #{uri.ljust(50)}"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
Repositories.instance.save
|
224
|
+
puts "Added #{count} repositories."
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
class Unsource
|
230
|
+
def initialize(base_command)
|
231
|
+
@base_command = base_command
|
232
|
+
end
|
233
|
+
|
234
|
+
def options
|
235
|
+
OptionParser.new do |o|
|
236
|
+
o.set_summary_indent(' ')
|
237
|
+
o.banner = "Usage: #{@base_command.script_name} source URI [URI [URI]...]"
|
238
|
+
o.define_head "Remove repositories from the default search list."
|
239
|
+
o.separator ""
|
240
|
+
o.on_tail("-h", "--help", "Show this help message.") { puts o; exit }
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def parse!(args)
|
245
|
+
options.parse!(args)
|
246
|
+
count = 0
|
247
|
+
args.each do |uri|
|
248
|
+
if Repositories.instance.remove(uri)
|
249
|
+
count += 1
|
250
|
+
puts "removed: #{uri.ljust(50)}"
|
251
|
+
else
|
252
|
+
puts "failed: #{uri.ljust(50)}"
|
253
|
+
end
|
254
|
+
end
|
255
|
+
Repositories.instance.save
|
256
|
+
puts "Removed #{count} repositories."
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
class Discover
|
262
|
+
def initialize(base_command)
|
263
|
+
@base_command = base_command
|
264
|
+
@list = false
|
265
|
+
@prompt = true
|
266
|
+
end
|
267
|
+
|
268
|
+
def options
|
269
|
+
OptionParser.new do |o|
|
270
|
+
o.set_summary_indent(' ')
|
271
|
+
o.banner = "Usage: #{@base_command.script_name} discover URI [URI [URI]...]"
|
272
|
+
o.define_head "Discover repositories referenced on a page."
|
273
|
+
o.separator ""
|
274
|
+
o.separator "Options:"
|
275
|
+
o.separator ""
|
276
|
+
o.on( "-l", "--list",
|
277
|
+
"List but don't prompt or add discovered repositories.") { |@list| @prompt = !@list }
|
278
|
+
o.on( "-n", "--no-prompt",
|
279
|
+
"Add all new repositories without prompting.") { |v| @prompt = false }
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def parse!(args)
|
284
|
+
options.parse!(args)
|
285
|
+
args = ['http://wiki.rubyonrails.org/rails/pages/Plugins', 'http://agilewebdevelopment.com/plugins/scrape'] if args.empty?
|
286
|
+
args.each do |uri|
|
287
|
+
scrape(uri) do |repo_uri|
|
288
|
+
catch(:next_uri) do
|
289
|
+
if @prompt
|
290
|
+
begin
|
291
|
+
$stdout.print "Add #{repo_uri}? [Y/n] "
|
292
|
+
throw :next_uri if $stdin.gets !~ /^y?$/i
|
293
|
+
rescue Interrupt
|
294
|
+
$stdout.puts
|
295
|
+
exit 1
|
296
|
+
end
|
297
|
+
elsif @list
|
298
|
+
puts repo_uri
|
299
|
+
throw :next_uri
|
300
|
+
end
|
301
|
+
Repositories.instance.add(repo_uri)
|
302
|
+
puts "discovered: #{repo_uri}" if $verbose or !@prompt
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
Repositories.instance.save
|
307
|
+
end
|
308
|
+
|
309
|
+
def scrape(uri)
|
310
|
+
require 'open-uri'
|
311
|
+
puts "Scraping #{uri}" if $verbose
|
312
|
+
dupes = []
|
313
|
+
content = open(uri).each do |line|
|
314
|
+
begin
|
315
|
+
if line =~ /<a[^>]*href=['"]([^'"]*)['"]/ || line =~ /(svn:\/\/[^<|\n]*)/
|
316
|
+
uri = $1
|
317
|
+
if uri =~ /^\w+:\/\// && uri =~ /\/plugins\// && uri !~ /\/browser\// && uri !~ /^http:\/\/wiki\.rubyonrails/ && uri !~ /http:\/\/instiki/
|
318
|
+
uri = extract_repository_uri(uri)
|
319
|
+
yield uri unless dupes.include?(uri) || Repositories.instance.exist?(uri)
|
320
|
+
dupes << uri
|
321
|
+
end
|
322
|
+
end
|
323
|
+
rescue
|
324
|
+
puts "Problems scraping '#{uri}': #{$!.to_s}"
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
def extract_repository_uri(uri)
|
330
|
+
uri.match(/(svn|https?):.*\/plugins\//i)[0]
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
class Install
|
335
|
+
def initialize(base_command)
|
336
|
+
@base_command = base_command
|
337
|
+
@method = :http
|
338
|
+
@options = { :quiet => false, :revision => nil, :force => false }
|
339
|
+
end
|
340
|
+
|
341
|
+
def options
|
342
|
+
OptionParser.new do |o|
|
343
|
+
o.set_summary_indent(' ')
|
344
|
+
o.banner = "Usage: #{@base_command.script_name} install PLUGIN [PLUGIN [PLUGIN] ...]"
|
345
|
+
o.define_head "Install one or more plugins."
|
346
|
+
o.separator ""
|
347
|
+
o.separator "Options:"
|
348
|
+
o.on( "-x", "--externals",
|
349
|
+
"Use svn:externals to grab the plugin.",
|
350
|
+
"Enables plugin updates and plugin versioning.") { |v| @method = :externals }
|
351
|
+
o.on( "-o", "--checkout",
|
352
|
+
"Use svn checkout to grab the plugin.",
|
353
|
+
"Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout }
|
354
|
+
o.on( "-q", "--quiet",
|
355
|
+
"Suppresses the output from installation.",
|
356
|
+
"Ignored if -v is passed (./script/plugin -v install ...)") { |v| @options[:quiet] = true }
|
357
|
+
o.on( "-r REVISION", "--revision REVISION",
|
358
|
+
"Checks out the given revision from subversion.",
|
359
|
+
"Ignored if subversion is not used.") { |v| @options[:revision] = v }
|
360
|
+
o.on( "-f", "--force",
|
361
|
+
"Reinstalls a plugin if it's already installed.") { |v| @options[:force] = true }
|
362
|
+
o.separator ""
|
363
|
+
o.separator "You can specify plugin names as given in 'plugin list' output or absolute URLs to "
|
364
|
+
o.separator "a plugin repository."
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
def determine_install_method
|
369
|
+
best = @base_command.environment.best_install_method?
|
370
|
+
@method = :http if best == :http and @method == :export
|
371
|
+
case
|
372
|
+
when (best == :http and @method != :http)
|
373
|
+
msg = "Cannot install using subversion because `svn' cannot be found in your PATH"
|
374
|
+
when (best == :export and (@method != :export and @method != :http))
|
375
|
+
msg = "Cannot install using #{@method} because this project is not under subversion."
|
376
|
+
when (best != :externals and @method == :externals)
|
377
|
+
msg = "Cannot install using externals because vendor/plugins is not under subversion."
|
378
|
+
end
|
379
|
+
if msg
|
380
|
+
puts msg
|
381
|
+
exit 1
|
382
|
+
end
|
383
|
+
@method
|
384
|
+
end
|
385
|
+
|
386
|
+
def parse!(args)
|
387
|
+
options.parse!(args)
|
388
|
+
environment = @base_command.environment
|
389
|
+
install_method = determine_install_method
|
390
|
+
puts "Plugins will be installed using #{install_method}" if $verbose
|
391
|
+
args.each do |name|
|
392
|
+
::Plugin.find(name).install(install_method, @options)
|
393
|
+
end
|
394
|
+
rescue
|
395
|
+
puts "Plugin not found: #{args.inspect}"
|
396
|
+
exit 1
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
class Update
|
401
|
+
def initialize(base_command)
|
402
|
+
@base_command = base_command
|
403
|
+
end
|
404
|
+
|
405
|
+
def options
|
406
|
+
OptionParser.new do |o|
|
407
|
+
o.set_summary_indent(' ')
|
408
|
+
o.banner = "Usage: #{@base_command.script_name} update [name [name]...]"
|
409
|
+
o.on( "-r REVISION", "--revision REVISION",
|
410
|
+
"Checks out the given revision from subversion.",
|
411
|
+
"Ignored if subversion is not used.") { |v| @revision = v }
|
412
|
+
o.define_head "Update plugins."
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
def parse!(args)
|
417
|
+
options.parse!(args)
|
418
|
+
root = @base_command.environment.root
|
419
|
+
cd root
|
420
|
+
args = Dir["vendor/plugins/*"].map do |f|
|
421
|
+
File.directory?("#{f}/.svn") ? File.basename(f) : nil
|
422
|
+
end.compact if args.empty?
|
423
|
+
cd "vendor/plugins"
|
424
|
+
args.each do |name|
|
425
|
+
if File.directory?(name)
|
426
|
+
puts "Updating plugin: #{name}"
|
427
|
+
system("svn #{$verbose ? '' : '-q'} up \"#{name}\" #{@revision ? "-r #{@revision}" : ''}")
|
428
|
+
else
|
429
|
+
puts "Plugin doesn't exist: #{name}"
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
class Remove
|
436
|
+
def initialize(base_command)
|
437
|
+
@base_command = base_command
|
438
|
+
end
|
439
|
+
|
440
|
+
def options
|
441
|
+
OptionParser.new do |o|
|
442
|
+
o.set_summary_indent(' ')
|
443
|
+
o.banner = "Usage: #{@base_command.script_name} remove name [name]..."
|
444
|
+
o.define_head "Remove plugins."
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
def parse!(args)
|
449
|
+
options.parse!(args)
|
450
|
+
root = @base_command.environment.root
|
451
|
+
args.each do |name|
|
452
|
+
::Plugin.new(name).uninstall
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
class About
|
458
|
+
def initialize(base_command)
|
459
|
+
@base_command = base_command
|
460
|
+
end
|
461
|
+
|
462
|
+
def options
|
463
|
+
OptionParser.new do |o|
|
464
|
+
o.set_summary_indent(' ')
|
465
|
+
o.banner = "Usage: #{@base_command.script_name} about name [name]..."
|
466
|
+
o.define_head "Shows plugin info at {url}/about.yml."
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
def parse!(args)
|
471
|
+
options.parse!(args)
|
472
|
+
args.each do |name|
|
473
|
+
if plugin = ::Plugin.find(name)
|
474
|
+
if about_hash = plugin.about
|
475
|
+
puts about_hash.to_yaml + "\n"
|
476
|
+
next
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
puts "Plugin #{name} could not be found in the known repositories."
|
481
|
+
puts
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|