rapt 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|