rapt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+