plugger 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/bin/plugger +545 -0
  2. data/lib/plugger.rb +24 -0
  3. metadata +47 -0
@@ -0,0 +1,545 @@
1
+ # Rails Plugin Manager.
2
+ #
3
+ # Installing plugins:
4
+ #
5
+ # $ rails plugin install continuous_builder asset_timestamping
6
+ #
7
+ # Specifying revisions:
8
+ #
9
+ # * Subversion revision is a single integer.
10
+ #
11
+ # * Git revision format:
12
+ # - full - 'refs/tags/1.8.0' or 'refs/heads/experimental'
13
+ # - short: 'experimental' (equivalent to 'refs/heads/experimental')
14
+ # 'tag 1.8.0' (equivalent to 'refs/tags/1.8.0')
15
+ #
16
+ #
17
+ # This is Free Software, copyright 2005 by Ryan Tomayko (rtomayko@gmail.com)
18
+ # and is licensed MIT: (http://www.opensource.org/licenses/mit-license.php)
19
+
20
+ $verbose = false
21
+
22
+ require 'rails'
23
+ require 'open-uri'
24
+ require 'fileutils'
25
+ require 'tempfile'
26
+
27
+ include FileUtils
28
+
29
+ class RailsEnvironment
30
+ attr_reader :root
31
+
32
+ def initialize(dir)
33
+ @root = dir
34
+ end
35
+
36
+ def self.find(dir=nil)
37
+ dir ||= pwd
38
+ while dir.length > 1
39
+ return new(dir) if File.exist?(File.join(dir, 'config', 'environment.rb'))
40
+ dir = File.dirname(dir)
41
+ end
42
+ end
43
+
44
+ def self.default
45
+ @default ||= find
46
+ end
47
+
48
+ def self.default=(rails_env)
49
+ @default = rails_env
50
+ end
51
+
52
+ def install(name_uri_or_plugin)
53
+ if name_uri_or_plugin.is_a? String
54
+ if name_uri_or_plugin =~ /:\/\//
55
+ plugin = Plugin.new(name_uri_or_plugin)
56
+ else
57
+ plugin = Plugins[name_uri_or_plugin]
58
+ end
59
+ else
60
+ plugin = name_uri_or_plugin
61
+ end
62
+ if plugin
63
+ plugin.install
64
+ else
65
+ puts "Plugin not found: #{name_uri_or_plugin}"
66
+ end
67
+ end
68
+
69
+ def use_svn?
70
+ require 'active_support/core_ext/kernel'
71
+ silence_stderr {`svn --version` rescue nil}
72
+ !$?.nil? && $?.success?
73
+ end
74
+
75
+ def use_externals?
76
+ use_svn? && File.directory?("#{root}/vendor/plugins/.svn")
77
+ end
78
+
79
+ def use_checkout?
80
+ # this is a bit of a guess. we assume that if the rails environment
81
+ # is under subversion then they probably want the plugin checked out
82
+ # instead of exported. This can be overridden on the command line
83
+ File.directory?("#{root}/.svn")
84
+ end
85
+
86
+ def best_install_method
87
+ return :http unless use_svn?
88
+ case
89
+ when use_externals? then :externals
90
+ when use_checkout? then :checkout
91
+ else :export
92
+ end
93
+ end
94
+
95
+ def externals
96
+ return [] unless use_externals?
97
+ ext = `svn propget svn:externals "#{root}/vendor/plugins"`
98
+ lines = ext.respond_to?(:lines) ? ext.lines : ext
99
+ lines.reject{ |line| line.strip == '' }.map do |line|
100
+ line.strip.split(/\s+/, 2)
101
+ end
102
+ end
103
+
104
+ def externals=(items)
105
+ unless items.is_a? String
106
+ items = items.map{|name,uri| "#{name.ljust(29)} #{uri.chomp('/')}"}.join("\n")
107
+ end
108
+ Tempfile.open("svn-set-prop") do |file|
109
+ file.write(items)
110
+ file.flush
111
+ system("svn propset -q svn:externals -F \"#{file.path}\" \"#{root}/vendor/plugins\"")
112
+ end
113
+ end
114
+ end
115
+
116
+ class Plugin
117
+ attr_reader :name, :uri
118
+
119
+ def initialize(uri, name = nil)
120
+ @uri = uri
121
+ guess_name(uri)
122
+ end
123
+
124
+ def self.find(name)
125
+ new(name)
126
+ end
127
+
128
+ def to_s
129
+ "#{@name.ljust(30)}#{@uri}"
130
+ end
131
+
132
+ def svn_url?
133
+ @uri =~ /svn(?:\+ssh)?:\/\/*/
134
+ end
135
+
136
+ def git_url?
137
+ @uri =~ /^git:\/\// || @uri =~ /\.git$/
138
+ end
139
+
140
+ def installed?
141
+ File.directory?("#{rails_env.root}/vendor/plugins/#{name}") \
142
+ or rails_env.externals.detect{ |name, repo| self.uri == repo }
143
+ end
144
+
145
+ def install(method=nil, options = {})
146
+ method ||= rails_env.best_install_method?
147
+ if :http == method
148
+ method = :export if svn_url?
149
+ method = :git if git_url?
150
+ end
151
+
152
+ uninstall if installed? and options[:force]
153
+
154
+ unless installed?
155
+ send("install_using_#{method}", options)
156
+ run_install_hook
157
+ else
158
+ puts "already installed: #{name} (#{uri}). pass --force to reinstall"
159
+ end
160
+ end
161
+
162
+ def uninstall
163
+ path = "#{rails_env.root}/vendor/plugins/#{name}"
164
+ if File.directory?(path)
165
+ puts "Removing 'vendor/plugins/#{name}'" if $verbose
166
+ run_uninstall_hook
167
+ rm_r path
168
+ else
169
+ puts "Plugin doesn't exist: #{path}"
170
+ end
171
+
172
+ if rails_env.use_externals?
173
+ # clean up svn:externals
174
+ externals = rails_env.externals
175
+ externals.reject!{|n, u| name == n or name == u}
176
+ rails_env.externals = externals
177
+ end
178
+ end
179
+
180
+ def info
181
+ tmp = "#{rails_env.root}/_tmp_about.yml"
182
+ if svn_url?
183
+ cmd = "svn export #{@uri} \"#{rails_env.root}/#{tmp}\""
184
+ puts cmd if $verbose
185
+ system(cmd)
186
+ end
187
+ open(svn_url? ? tmp : File.join(@uri, 'about.yml')) do |stream|
188
+ stream.read
189
+ end rescue "No about.yml found in #{uri}"
190
+ ensure
191
+ FileUtils.rm_rf tmp if svn_url?
192
+ end
193
+
194
+ private
195
+
196
+ def run_install_hook
197
+ install_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/install.rb"
198
+ load install_hook_file if File.exist? install_hook_file
199
+ end
200
+
201
+ def run_uninstall_hook
202
+ uninstall_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/uninstall.rb"
203
+ load uninstall_hook_file if File.exist? uninstall_hook_file
204
+ end
205
+
206
+ def install_using_export(options = {})
207
+ svn_command :export, options
208
+ end
209
+
210
+ def install_using_checkout(options = {})
211
+ svn_command :checkout, options
212
+ end
213
+
214
+ def install_using_externals(options = {})
215
+ externals = rails_env.externals
216
+ externals.push([@name, uri])
217
+ rails_env.externals = externals
218
+ install_using_checkout(options)
219
+ end
220
+
221
+ def install_using_http(options = {})
222
+ root = rails_env.root
223
+ mkdir_p "#{root}/vendor/plugins/#{@name}"
224
+ Dir.chdir "#{root}/vendor/plugins/#{@name}" do
225
+ puts "fetching from '#{uri}'" if $verbose
226
+ fetcher = RecursiveHTTPFetcher.new(uri, -1)
227
+ fetcher.quiet = true if options[:quiet]
228
+ fetcher.fetch
229
+ end
230
+ end
231
+
232
+ def install_using_git(options = {})
233
+ root = rails_env.root
234
+ mkdir_p(install_path = "#{root}/vendor/plugins/#{name}")
235
+ Dir.chdir install_path do
236
+ init_cmd = "git init"
237
+ init_cmd += " -q" if options[:quiet] and not $verbose
238
+ puts init_cmd if $verbose
239
+ system(init_cmd)
240
+ base_cmd = "git pull --depth 1 #{uri}"
241
+ base_cmd += " -q" if options[:quiet] and not $verbose
242
+ base_cmd += " #{options[:revision]}" if options[:revision]
243
+ puts base_cmd if $verbose
244
+ if system(base_cmd)
245
+ puts "removing: .git .gitignore" if $verbose
246
+ rm_rf %w(.git .gitignore)
247
+ else
248
+ rm_rf install_path
249
+ end
250
+ end
251
+ end
252
+
253
+ def svn_command(cmd, options = {})
254
+ root = rails_env.root
255
+ mkdir_p "#{root}/vendor/plugins"
256
+ base_cmd = "svn #{cmd} #{uri} \"#{root}/vendor/plugins/#{name}\""
257
+ base_cmd += ' -q' if options[:quiet] and not $verbose
258
+ base_cmd += " -r #{options[:revision]}" if options[:revision]
259
+ puts base_cmd if $verbose
260
+ system(base_cmd)
261
+ end
262
+
263
+ def guess_name(url)
264
+ @name = File.basename(url)
265
+ if @name == 'trunk' || @name.empty?
266
+ @name = File.basename(File.dirname(url))
267
+ end
268
+ @name.gsub!(/\.git$/, '') if @name =~ /\.git$/
269
+ end
270
+
271
+ def rails_env
272
+ @rails_env || RailsEnvironment.default
273
+ end
274
+ end
275
+
276
+ # load default environment and parse arguments
277
+ require 'optparse'
278
+ module Rails
279
+ module Commands
280
+ class Plugin
281
+ attr_reader :environment, :script_name
282
+ def initialize
283
+ @environment = RailsEnvironment.default
284
+ @rails_root = RailsEnvironment.default.root
285
+ @script_name = File.basename($0)
286
+ end
287
+
288
+ def environment=(value)
289
+ @environment = value
290
+ RailsEnvironment.default = value
291
+ end
292
+
293
+ def options
294
+ OptionParser.new do |o|
295
+ o.set_summary_indent(' ')
296
+ o.banner = "Usage: plugger [OPTIONS] command"
297
+ o.define_head "A Very Hacked Rails plugin manager."
298
+
299
+ o.separator ""
300
+ o.separator "GENERAL OPTIONS"
301
+
302
+ o.on("-r", "--root=DIR", String,
303
+ "Set an explicit rails app directory.",
304
+ "Default: #{@rails_root}") { |rails_root| @rails_root = rails_root; self.environment = RailsEnvironment.new(@rails_root) }
305
+
306
+ o.on("-v", "--verbose", "Turn on verbose output.") { |verbose| $verbose = verbose }
307
+ o.on("-h", "--help", "Show this help message.") { puts o; exit }
308
+
309
+ o.separator ""
310
+ o.separator "COMMANDS"
311
+
312
+ o.separator " install Install plugin(s) from known repositories or URLs."
313
+ o.separator " remove Uninstall plugins."
314
+
315
+ o.separator ""
316
+ o.separator "EXAMPLES"
317
+ o.separator " Install a plugin from a subversion URL:"
318
+ o.separator " plugger install http://example.com/my_svn_plugin\n"
319
+ o.separator " Install a plugin from a git URL:"
320
+ o.separator " plugger install git://github.com/SomeGuy/my_awesome_plugin.git\n"
321
+ o.separator " Install a plugin and add a svn:externals entry to vendor/plugins"
322
+ o.separator " plugger install -x my_svn_plugin\n"
323
+ end
324
+ end
325
+
326
+ def parse!(args=ARGV)
327
+ general, sub = split_args(args)
328
+ options.parse!(general)
329
+
330
+ command = general.shift
331
+ if command =~ /^(install|remove)$/
332
+ command = Commands.const_get(command.capitalize).new(self)
333
+ command.parse!(sub)
334
+ else
335
+ puts "Unknown command: #{command}" unless command.blank?
336
+ puts options
337
+ exit 1
338
+ end
339
+ end
340
+
341
+ def split_args(args)
342
+ left = []
343
+ left << args.shift while args[0] and args[0] =~ /^-/
344
+ left << args.shift if args[0]
345
+ [left, args]
346
+ end
347
+
348
+ def self.parse!(args=ARGV)
349
+ Plugin.new.parse!(args)
350
+ end
351
+ end
352
+
353
+ class Install
354
+ def initialize(base_command)
355
+ @base_command = base_command
356
+ @method = :http
357
+ @options = { :quiet => false, :revision => nil, :force => false }
358
+ end
359
+
360
+ def options
361
+ OptionParser.new do |o|
362
+ o.set_summary_indent(' ')
363
+ o.banner = "Usage: #{@base_command.script_name} install PLUGIN [PLUGIN [PLUGIN] ...]"
364
+ o.define_head "Install one or more plugins."
365
+ o.separator ""
366
+ o.separator "Options:"
367
+ o.on( "-x", "--externals",
368
+ "Use svn:externals to grab the plugin.",
369
+ "Enables plugin updates and plugin versioning.") { |v| @method = :externals }
370
+ o.on( "-o", "--checkout",
371
+ "Use svn checkout to grab the plugin.",
372
+ "Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout }
373
+ o.on( "-e", "--export",
374
+ "Use svn export to grab the plugin.",
375
+ "Exports the plugin, allowing you to check it into your local repository. Does not enable updates or add an svn:externals entry.") { |v| @method = :export }
376
+ o.on( "-q", "--quiet",
377
+ "Suppresses the output from installation.",
378
+ "Ignored if -v is passed (rails plugin -v install ...)") { |v| @options[:quiet] = true }
379
+ o.on( "-r REVISION", "--revision REVISION",
380
+ "Checks out the given revision from subversion or git.",
381
+ "Ignored if subversion/git is not used.") { |v| @options[:revision] = v }
382
+ o.on( "-f", "--force",
383
+ "Reinstalls a plugin if it's already installed.") { |v| @options[:force] = true }
384
+ o.separator ""
385
+ o.separator "You can specify plugin names as given in 'plugin list' output or absolute URLs to "
386
+ o.separator "a plugin repository."
387
+ end
388
+ end
389
+
390
+ def determine_install_method
391
+ best = @base_command.environment.best_install_method
392
+ @method = :http if best == :http and @method == :export
393
+ case
394
+ when (best == :http and @method != :http)
395
+ msg = "Cannot install using subversion because `svn' cannot be found in your PATH"
396
+ when (best == :export and (@method != :export and @method != :http))
397
+ msg = "Cannot install using #{@method} because this project is not under subversion."
398
+ when (best != :externals and @method == :externals)
399
+ msg = "Cannot install using externals because vendor/plugins is not under subversion."
400
+ end
401
+ if msg
402
+ puts msg
403
+ exit 1
404
+ end
405
+ @method
406
+ end
407
+
408
+ def parse!(args)
409
+ options.parse!(args)
410
+ if args.blank?
411
+ puts options
412
+ exit 1
413
+ end
414
+ environment = @base_command.environment
415
+ install_method = determine_install_method
416
+ puts "Plugins will be installed using #{install_method}" if $verbose
417
+ args.each do |name|
418
+ ::Plugin.find(name).install(install_method, @options)
419
+ end
420
+ rescue StandardError => e
421
+ puts "Plugin not found: #{args.inspect}"
422
+ puts e.inspect if $verbose
423
+ exit 1
424
+ end
425
+ end
426
+
427
+ class Remove
428
+ def initialize(base_command)
429
+ @base_command = base_command
430
+ end
431
+
432
+ def options
433
+ OptionParser.new do |o|
434
+ o.set_summary_indent(' ')
435
+ o.banner = "Usage: #{@base_command.script_name} remove name [name]..."
436
+ o.define_head "Remove plugins."
437
+ end
438
+ end
439
+
440
+ def parse!(args)
441
+ options.parse!(args)
442
+ if args.blank?
443
+ puts options
444
+ exit 1
445
+ end
446
+ root = @base_command.environment.root
447
+ args.each do |name|
448
+ ::Plugin.new(name).uninstall
449
+ end
450
+ end
451
+ end
452
+
453
+ class Info
454
+ def initialize(base_command)
455
+ @base_command = base_command
456
+ end
457
+
458
+ def options
459
+ OptionParser.new do |o|
460
+ o.set_summary_indent(' ')
461
+ o.banner = "Usage: #{@base_command.script_name} info name [name]..."
462
+ o.define_head "Shows plugin info at {url}/about.yml."
463
+ end
464
+ end
465
+
466
+ def parse!(args)
467
+ options.parse!(args)
468
+ args.each do |name|
469
+ puts ::Plugin.find(name).info
470
+ puts
471
+ end
472
+ end
473
+ end
474
+ end
475
+ end
476
+
477
+ class RecursiveHTTPFetcher
478
+ attr_accessor :quiet
479
+ def initialize(urls_to_fetch, level = 1, cwd = ".")
480
+ @level = level
481
+ @cwd = cwd
482
+ @urls_to_fetch = RUBY_VERSION >= '1.9' ? urls_to_fetch.lines : urls_to_fetch.to_a
483
+ @quiet = false
484
+ end
485
+
486
+ def ls
487
+ @urls_to_fetch.collect do |url|
488
+ if url =~ /^svn(\+ssh)?:\/\/.*/
489
+ `svn ls #{url}`.split("\n").map {|entry| "/#{entry}"} rescue nil
490
+ else
491
+ open(url) do |stream|
492
+ links("", stream.read)
493
+ end rescue nil
494
+ end
495
+ end.flatten
496
+ end
497
+
498
+ def push_d(dir)
499
+ @cwd = File.join(@cwd, dir)
500
+ FileUtils.mkdir_p(@cwd)
501
+ end
502
+
503
+ def pop_d
504
+ @cwd = File.dirname(@cwd)
505
+ end
506
+
507
+ def links(base_url, contents)
508
+ links = []
509
+ contents.scan(/href\s*=\s*\"*[^\">]*/i) do |link|
510
+ link = link.sub(/href="/i, "")
511
+ next if link =~ /svnindex.xsl$/
512
+ next if link =~ /^(\w*:|)\/\// || link =~ /^\./
513
+ links << File.join(base_url, link)
514
+ end
515
+ links
516
+ end
517
+
518
+ def download(link)
519
+ puts "+ #{File.join(@cwd, File.basename(link))}" unless @quiet
520
+ open(link) do |stream|
521
+ File.open(File.join(@cwd, File.basename(link)), "wb") do |file|
522
+ file.write(stream.read)
523
+ end
524
+ end
525
+ end
526
+
527
+ def fetch(links = @urls_to_fetch)
528
+ links.each do |l|
529
+ (l =~ /\/$/ || links == @urls_to_fetch) ? fetch_dir(l) : download(l)
530
+ end
531
+ end
532
+
533
+ def fetch_dir(url)
534
+ @level += 1
535
+ push_d(File.basename(url)) if @level > 0
536
+ open(url) do |stream|
537
+ contents = stream.read
538
+ fetch(links(url, contents))
539
+ end
540
+ pop_d if @level > 0
541
+ @level -= 1
542
+ end
543
+ end
544
+
545
+ Rails::Commands::Plugin.parse!
@@ -0,0 +1,24 @@
1
+ class Plugger
2
+
3
+ def self.hi
4
+ puts "Hi, I'm plugger. This is just a stub."
5
+ end
6
+
7
+ end
8
+
9
+ require 'rails/generators'
10
+ require 'active_support/dependencies'
11
+
12
+ puts "I'm loading plugins from #{Rails.root}"
13
+
14
+ Dir["#{Dir.pwd}/vendor/plugins/*/init.rb"].each do |f|
15
+ require_or_load f
16
+ end
17
+
18
+ Dir["#{Dir.pwd}/vendor/plugins/**/lib/generators/**/*.rb"].each do |f|
19
+ require_or_load f
20
+ end
21
+
22
+
23
+
24
+ require 'plugger/plugger_tasks'
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: plugger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kevin Lawver
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-18 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A simple thing that loads plugins
15
+ email: kevin@railsmachine.com
16
+ executables:
17
+ - plugger
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/plugger.rb
22
+ - bin/plugger
23
+ homepage: http://rubygems.org/gems/plugger
24
+ licenses: []
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 1.8.25
44
+ signing_key:
45
+ specification_version: 3
46
+ summary: Restores Rails plugins to Rails 4
47
+ test_files: []