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.
@@ -0,0 +1,148 @@
1
+ require 'open-uri'
2
+
3
+ class Plugin
4
+
5
+ attr_reader :name, :uri
6
+
7
+ def initialize(uri, name=nil)
8
+ @uri = uri
9
+ guess_name(uri)
10
+ end
11
+
12
+ def self.find(name)
13
+ name =~ /\// ? new(name) : Repositories.instance.find_plugin(name)
14
+ end
15
+
16
+ def to_s
17
+ "#{@name.ljust(30)}#{@uri}"
18
+ end
19
+
20
+ def svn_url?
21
+ @uri =~ /svn(?:\+ssh)?:\/\/*/
22
+ end
23
+
24
+ def installed?
25
+ File.directory?("#{rails_env.root}/vendor/plugins/#{name}") \
26
+ or rails_env.externals.detect{ |name, repo| self.uri == repo }
27
+ end
28
+
29
+ def install(method=nil, options = {})
30
+ method ||= rails_env.best_install_method?
31
+ method = :export if method == :http and svn_url?
32
+
33
+ uninstall if installed? and options[:force]
34
+
35
+ unless installed?
36
+ send("install_using_#{method}", options)
37
+ run_install_hook
38
+ else
39
+ puts "already installed: #{name} (#{uri}). pass --force to reinstall"
40
+ end
41
+ end
42
+
43
+ def uninstall
44
+ path = "#{rails_env.root}/vendor/plugins/#{name}"
45
+ if File.directory?(path)
46
+ puts "Removing 'vendor/plugins/#{name}'" if $verbose
47
+ run_uninstall_hook
48
+ rm_r path
49
+ else
50
+ puts "Plugin doesn't exist: #{path}"
51
+ end
52
+ # clean up svn:externals
53
+ externals = rails_env.externals
54
+ externals.reject!{|n,u| name == n or name == u}
55
+ rails_env.externals = externals
56
+ end
57
+
58
+ # Returns a hash representing this plugin's metadata
59
+ def about(force_refresh=false)
60
+ # Look in cache first
61
+ unless force_refresh
62
+ if Repositories.instance.source_cache['plugins'].has_key?(name)
63
+ return Repositories.instance.source_cache['plugins'][name]
64
+ end
65
+ end
66
+ # Get from original source
67
+ tmp = "#{rails_env.root}/_tmp_about.yml"
68
+ if svn_url?
69
+ cmd = %(svn export #{@uri}/about.yml "#{tmp}")
70
+ puts cmd if $verbose
71
+ system(cmd)
72
+ end
73
+ about_uri = svn_url? ? tmp : File.join(@uri, 'about.yml')
74
+ open(about_uri) do |stream|
75
+ about_hash = YAML.load(stream.read)
76
+ unless about_hash.is_a?(Hash) && !about_hash['plugin'].nil?
77
+ raise("#{name}'s about.yml wasn't valid YAML")
78
+ end
79
+ return about_hash
80
+ end
81
+ rescue
82
+ # Make yaml on the fly for this plugin.
83
+ # The 'plugin' field (uri to the resource) is the only required field.
84
+ {
85
+ 'plugin' => uri
86
+ }
87
+ ensure
88
+ FileUtils.rm_rf tmp if svn_url?
89
+ end
90
+
91
+ private
92
+
93
+ def run_install_hook
94
+ install_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/install.rb"
95
+ load install_hook_file if File.exists? install_hook_file
96
+ end
97
+
98
+ def run_uninstall_hook
99
+ uninstall_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/uninstall.rb"
100
+ load uninstall_hook_file if File.exists? uninstall_hook_file
101
+ end
102
+
103
+ def install_using_export(options = {})
104
+ svn_command :export, options
105
+ end
106
+
107
+ def install_using_checkout(options = {})
108
+ svn_command :checkout, options
109
+ end
110
+
111
+ def install_using_externals(options = {})
112
+ externals = rails_env.externals
113
+ externals.push([@name, uri])
114
+ rails_env.externals = externals
115
+ install_using_checkout(options)
116
+ end
117
+
118
+ def install_using_http(options = {})
119
+ root = rails_env.root
120
+ mkdir_p "#{root}/vendor/plugins"
121
+ Dir.chdir "#{root}/vendor/plugins"
122
+ puts "fetching from '#{uri}'" if $verbose
123
+ fetcher = RecursiveHTTPFetcher.new(uri)
124
+ fetcher.quiet = true if options[:quiet]
125
+ fetcher.fetch
126
+ end
127
+
128
+ def svn_command(cmd, options = {})
129
+ root = rails_env.root
130
+ mkdir_p "#{root}/vendor/plugins"
131
+ base_cmd = "svn #{cmd} #{uri} \"#{root}/vendor/plugins/#{name}\""
132
+ base_cmd += ' -q' if options[:quiet] and not $verbose
133
+ base_cmd += " -r #{options[:revision]}" if options[:revision]
134
+ puts base_cmd if $verbose
135
+ system(base_cmd)
136
+ end
137
+
138
+ def guess_name(url)
139
+ @name = File.basename(url)
140
+ if @name == 'trunk' || @name.empty?
141
+ @name = File.basename(File.dirname(url))
142
+ end
143
+ end
144
+
145
+ def rails_env
146
+ @rails_env || RailsEnvironment.default
147
+ end
148
+ end
@@ -0,0 +1,87 @@
1
+
2
+ class RailsEnvironment
3
+ attr_reader :root
4
+
5
+ def initialize(dir)
6
+ @root = dir
7
+ end
8
+
9
+ def self.find(dir=nil)
10
+ dir ||= pwd
11
+ while dir.length > 1
12
+ return new(dir) if File.exist?(File.join(dir, 'config', 'environment.rb'))
13
+ dir = File.dirname(dir)
14
+ end
15
+ end
16
+
17
+ def self.default
18
+ @default ||= find
19
+ end
20
+
21
+ def self.default=(rails_env)
22
+ @default = rails_env
23
+ end
24
+
25
+ def install(name_uri_or_plugin)
26
+ if name_uri_or_plugin.is_a? String
27
+ if name_uri_or_plugin =~ /:\/\//
28
+ plugin = Plugin.new(name_uri_or_plugin)
29
+ else
30
+ plugin = Plugins[name_uri_or_plugin]
31
+ end
32
+ else
33
+ plugin = name_uri_or_plugin
34
+ end
35
+ unless plugin.nil?
36
+ plugin.install
37
+ else
38
+ puts "plugin not found: #{name_uri_or_plugin}"
39
+ end
40
+ end
41
+
42
+ def use_svn?
43
+ require 'active_support/core_ext/kernel'
44
+ silence_stderr {`svn --version` rescue nil}
45
+ !$?.nil? && $?.success?
46
+ end
47
+
48
+ def use_externals?
49
+ use_svn? && File.directory?("#{root}/vendor/plugins/.svn")
50
+ end
51
+
52
+ def use_checkout?
53
+ # this is a bit of a guess. we assume that if the rails environment
54
+ # is under subversion then they probably want the plugin checked out
55
+ # instead of exported. This can be overridden on the command line
56
+ File.directory?("#{root}/.svn")
57
+ end
58
+
59
+ def best_install_method?
60
+ return :http unless use_svn?
61
+ case
62
+ when use_externals? then :externals
63
+ when use_checkout? then :checkout
64
+ else :export
65
+ end
66
+ end
67
+
68
+ def externals
69
+ return [] unless use_externals?
70
+ ext = `svn propget svn:externals "#{root}/vendor/plugins"`
71
+ ext.reject{ |line| line.strip == '' }.map do |line|
72
+ line.strip.split(/\s+/, 2)
73
+ end
74
+ end
75
+
76
+ def externals=(items)
77
+ unless items.is_a? String
78
+ items = items.map{|name,uri| "#{name.ljust(29)} #{uri.chomp('/')}"}.join("\n")
79
+ end
80
+ Tempfile.open("svn-set-prop") do |file|
81
+ file.write(items)
82
+ file.flush
83
+ system("svn propset -q svn:externals -F \"#{file.path}\" \"#{root}/vendor/plugins\"")
84
+ end
85
+ end
86
+
87
+ end
@@ -0,0 +1,65 @@
1
+ require 'open-uri'
2
+
3
+ class RecursiveHTTPFetcher
4
+ attr_accessor :quiet
5
+ def initialize(urls_to_fetch, cwd = ".")
6
+ @cwd = cwd
7
+ @urls_to_fetch = urls_to_fetch.to_a
8
+ @quiet = false
9
+ end
10
+
11
+ def ls
12
+ @urls_to_fetch.collect do |url|
13
+ if url =~ /^svn:\/\/.*/
14
+ `svn ls #{url}`.split("\n").map {|entry| "/#{entry}"} rescue nil
15
+ else
16
+ open(url) do |stream|
17
+ links("", stream.read)
18
+ end rescue nil
19
+ end
20
+ end.flatten
21
+ end
22
+
23
+ def push_d(dir)
24
+ @cwd = File.join(@cwd, dir)
25
+ FileUtils.mkdir_p(@cwd)
26
+ end
27
+
28
+ def pop_d
29
+ @cwd = File.dirname(@cwd)
30
+ end
31
+
32
+ def links(base_url, contents)
33
+ links = []
34
+ contents.scan(/href\s*=\s*\"*[^\">]*/i) do |link|
35
+ link = link.sub(/href="/i, "")
36
+ next if link =~ /^http/i || link =~ /^\./
37
+ links << File.join(base_url, link)
38
+ end
39
+ links
40
+ end
41
+
42
+ def download(link)
43
+ puts "+ #{File.join(@cwd, File.basename(link))}" unless @quiet
44
+ open(link) do |stream|
45
+ File.open(File.join(@cwd, File.basename(link)), "wb") do |file|
46
+ file.write(stream.read)
47
+ end
48
+ end
49
+ end
50
+
51
+ def fetch(links = @urls_to_fetch)
52
+ links.each do |l|
53
+ (l =~ /\/$/ || links == @urls_to_fetch) ? fetch_dir(l) : download(l)
54
+ end
55
+ end
56
+
57
+ def fetch_dir(url)
58
+ push_d(File.basename(url))
59
+ open(url) do |stream|
60
+ contents = stream.read
61
+ fetch(links(url, contents))
62
+ end
63
+ pop_d
64
+ end
65
+ end
@@ -0,0 +1,128 @@
1
+ require 'yaml'
2
+
3
+ class Repositories
4
+ include Enumerable
5
+
6
+ attr_accessor :source_cache
7
+
8
+ def initialize(cache_file = File.join(find_home, ".rails", "plugin_source_cache.yml"))
9
+ @cache_file = File.expand_path(cache_file)
10
+ load!
11
+ end
12
+
13
+ def each(&block)
14
+ @repositories.each(&block)
15
+ end
16
+
17
+ def add(uri)
18
+ unless find { |repo| repo.uri == uri }
19
+ repository = Repository.new(uri)
20
+ refresh_repository!(repository)
21
+ @repositories.push(repository).last
22
+ end
23
+ end
24
+
25
+ def remove(uri)
26
+ @repositories.reject!{|repo| repo.uri == uri}
27
+ end
28
+
29
+ def exist?(uri)
30
+ @repositories.detect{|repo| repo.uri == uri }
31
+ end
32
+
33
+ def all
34
+ @repositories
35
+ end
36
+
37
+ def find_plugin(name)
38
+ # Try to get plugin from cache first
39
+ if @source_cache['plugins'].has_key?(name) && @source_cache['plugins'][name].has_key?('plugin')
40
+ return Plugin.new(@source_cache['plugins'][name]['plugin'], name)
41
+ end
42
+
43
+ @repositories.each do |repo|
44
+ repo.each do |plugin|
45
+ return plugin if plugin.name == name
46
+ end
47
+ end
48
+ return nil
49
+ end
50
+
51
+ # List the known plugins from the sources cache.
52
+ def cached_plugins
53
+ @source_cache['plugins'].keys.sort.map do |plugin_name|
54
+ Plugin.new(@source_cache['plugins'][plugin_name]['plugin'], plugin_name)
55
+ end
56
+ end
57
+
58
+ # Returns the number of known plugins in the cache.
59
+ def plugin_count
60
+ source_cache['plugins'].keys.length
61
+ rescue
62
+ 0
63
+ end
64
+
65
+ # Gets the updated list of plugins available at each repository.
66
+ def refresh!
67
+ @repositories.each { |repo| refresh_repository!(repo) }
68
+ end
69
+
70
+ # Gets the list of plugins available at this repository.
71
+ def refresh_repository!(repository)
72
+ repository.plugins.each do |plugin|
73
+ if about_hash = plugin.about(true)
74
+ @source_cache['plugins'][plugin.name] = about_hash
75
+ end
76
+ end
77
+ end
78
+
79
+
80
+ def load!
81
+ @source_cache = File.exist?(@cache_file) ? YAML.load(File.read(@cache_file)) : defaults
82
+ @source_cache = defaults if @source_cache.keys.nil?
83
+ @repositories = @source_cache['repositories'].map { |source| Repository.new(source.strip) }
84
+ end
85
+
86
+ def save
87
+ mkdir_p(File.dirname(@cache_file)) unless File.exist?(File.dirname(@cache_file))
88
+ File.open(@cache_file, 'w') do |f|
89
+ @source_cache['repositories'] = @repositories.map {|r| r.uri }.uniq
90
+ f.write(@source_cache.to_yaml)
91
+ f.write("\n")
92
+ end
93
+ end
94
+
95
+ def defaults
96
+ {
97
+ 'repositories' => ['http://dev.rubyonrails.com/svn/rails/plugins/'],
98
+ 'plugins' => {}
99
+ }
100
+ end
101
+
102
+ def find_home
103
+ ['HOME', 'USERPROFILE'].each do |homekey|
104
+ return ENV[homekey] if ENV[homekey]
105
+ end
106
+ if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
107
+ return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
108
+ end
109
+ begin
110
+ File.expand_path("~")
111
+ rescue StandardError => ex
112
+ if File::ALT_SEPARATOR
113
+ "C:/"
114
+ else
115
+ "/"
116
+ end
117
+ end
118
+ end
119
+
120
+ def self.instance
121
+ # TODO Use test cache file if $testing
122
+ @instance ||= Repositories.new
123
+ end
124
+
125
+ def self.each(&block)
126
+ self.instance.each(&block)
127
+ end
128
+ end
@@ -0,0 +1,34 @@
1
+
2
+ class Repository
3
+ include Enumerable
4
+ attr_reader :uri, :plugins
5
+
6
+ def initialize(uri)
7
+ @uri = uri.chomp('/') << "/"
8
+ @plugins = nil
9
+ end
10
+
11
+ def plugins
12
+ unless @plugins
13
+ if $verbose
14
+ puts "Discovering plugins in #{@uri}"
15
+ puts index
16
+ end
17
+
18
+ @plugins = index.reject{ |line| line !~ /\/$/ }
19
+ @plugins.map! { |name| Plugin.new(File.join(@uri, name), name) }
20
+ end
21
+
22
+ @plugins
23
+ end
24
+
25
+ def each(&block)
26
+ plugins.each(&block)
27
+ end
28
+
29
+ private
30
+ def index
31
+ @index ||= RecursiveHTTPFetcher.new(@uri).ls
32
+ end
33
+ end
34
+