plugger 0.0.1

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.
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: []