radiant-ray-extension 3.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README.markdown +30 -0
- data/Rakefile +26 -0
- data/bin/ray +5 -0
- data/doc/Extension.html +1189 -0
- data/doc/Ray.html +175 -0
- data/doc/Ray/CLI.html +585 -0
- data/doc/Ray/Cache.html +709 -0
- data/doc/Ray/Gem.html +760 -0
- data/doc/Ray/Git.html +278 -0
- data/doc/Ray/GitHub.html +553 -0
- data/doc/Ray/RubyGems.html +501 -0
- data/doc/Ray/Zip.html +300 -0
- data/doc/Search.html +433 -0
- data/doc/String.html +242 -0
- data/doc/_index.html +84 -0
- data/doc/class_list.html +47 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +55 -0
- data/doc/css/style.css +322 -0
- data/doc/file.LICENSE.html +85 -0
- data/doc/file.README.html +97 -0
- data/doc/file_list.html +46 -0
- data/doc/frames.html +13 -0
- data/doc/index.html +84 -0
- data/doc/js/app.js +205 -0
- data/doc/js/full_list.js +167 -0
- data/doc/js/jquery.js +16 -0
- data/doc/method_list.html +46 -0
- data/doc/top-level-namespace.html +105 -0
- data/lib/ray.rb +8 -0
- data/lib/ray/cli.rb +271 -0
- data/lib/ray/constants.rb +17 -0
- data/lib/ray/extension.rb +116 -0
- data/lib/ray/extension/gem.rb +96 -0
- data/lib/ray/extension/git.rb +30 -0
- data/lib/ray/extension/zip.rb +44 -0
- data/lib/ray/search.rb +62 -0
- data/lib/ray/search/cache.rb +61 -0
- data/lib/ray/search/github.rb +40 -0
- data/lib/ray/search/rubygems.rb +36 -0
- data/lib/ray/string.rb +18 -0
- data/ray.gemspec +31 -0
- data/spec/fixtures/Gemfile +4 -0
- data/spec/fixtures/cache_single.yml +8 -0
- data/spec/fixtures/cassettes/github_v2_api_no_matches.yml +38 -0
- data/spec/fixtures/cassettes/github_v2_api_search_no_matches.yml +38 -0
- data/spec/fixtures/cassettes/github_v2_api_search_reorder_children.yml +75 -0
- data/spec/fixtures/cassettes/github_v2_api_search_single.yml +74 -0
- data/spec/fixtures/cassettes/github_v3_api_owner_name.yml +75 -0
- data/spec/fixtures/cassettes/rubygems_v1_api_gem_info.yml +36 -0
- data/spec/fixtures/cassettes/rubygems_v1_api_no_matches.yml +34 -0
- data/spec/fixtures/cassettes/rubygems_v1_api_search_no_matches.yml +34 -0
- data/spec/fixtures/cassettes/rubygems_v1_api_search_reorder.yml +36 -0
- data/spec/fixtures/cassettes/rubygems_v1_api_search_reorder_children.yml +36 -0
- data/spec/fixtures/cassettes/rubygems_v1_api_search_single.yml +41 -0
- data/spec/fixtures/cassettes/zip_file.yml +101 -0
- data/spec/fixtures/dummy.zip +0 -0
- data/spec/fixtures/dummy/README +1 -0
- data/spec/fixtures/dummy/Rakefile +109 -0
- data/spec/fixtures/dummy/config/initializers/radiant_config.rb +3 -0
- data/spec/fixtures/dummy/config/locales/en.yml +3 -0
- data/spec/fixtures/dummy/config/routes.rb +5 -0
- data/spec/fixtures/dummy/dummy_extension.rb +21 -0
- data/spec/fixtures/dummy/lib/radiant-dummy-extension.rb +8 -0
- data/spec/fixtures/dummy/lib/tasks/dummy_extension_tasks.rake +47 -0
- data/spec/fixtures/dummy/public/stylesheets/extensions/dummy/dummy.css +0 -0
- data/spec/fixtures/dummy/radiant-dummy-extension.gemspec +29 -0
- data/spec/ray/cli_spec.rb +56 -0
- data/spec/ray/extension/gem_spec.rb +214 -0
- data/spec/ray/extension/git_spec.rb +216 -0
- data/spec/ray/extension/zip_spec.rb +239 -0
- data/spec/ray/search/cache_spec.rb +74 -0
- data/spec/ray/search/github_spec.rb +137 -0
- data/spec/ray/search/rubygems_spec.rb +127 -0
- data/spec/ray/string_spec.rb +30 -0
- data/spec/spec_helper.rb +27 -0
- metadata +205 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
# Friendly extension management for Radiant CMS
|
2
|
+
module Ray
|
3
|
+
|
4
|
+
VERSION = "3.0.0.alpha"
|
5
|
+
|
6
|
+
RAY = File.expand_path "~/.ray"
|
7
|
+
CACHE = "#{RAY}/cache.yml"
|
8
|
+
|
9
|
+
ROOT = File.expand_path Dir.pwd
|
10
|
+
GEMFILE = "#{ROOT}/Gemfile"
|
11
|
+
EXT_DIR = "#{ROOT}/vendor/extensions"
|
12
|
+
TMP_DIR = "#{ROOT}/tmp/ray"
|
13
|
+
RG_V1_API = "http://rubygems.org/api/v1"
|
14
|
+
GH_V2_API = "http://github.com/api/v2/json"
|
15
|
+
GH_V3_API = "https://api.github.com"
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "open-uri"
|
3
|
+
require "rake"
|
4
|
+
require "ray/string"
|
5
|
+
|
6
|
+
module Extension
|
7
|
+
|
8
|
+
attr_accessor :author,
|
9
|
+
:description,
|
10
|
+
:homepage,
|
11
|
+
:name,
|
12
|
+
:uri,
|
13
|
+
:version
|
14
|
+
|
15
|
+
def initialize options = {}
|
16
|
+
@author = options[:author]
|
17
|
+
@description = options[:description]
|
18
|
+
@homepage = options[:homepage]
|
19
|
+
@name = options[:name].to_s.to_extension_name
|
20
|
+
@uri = options[:uri]
|
21
|
+
@version = options[:version]
|
22
|
+
end
|
23
|
+
|
24
|
+
def disable
|
25
|
+
unless File.exist? "#{Ray::EXT_DIR}/#{@name}"
|
26
|
+
raise "The #{@name} extension is not installed"
|
27
|
+
end
|
28
|
+
|
29
|
+
FileUtils.mkdir_p "#{Ray::EXT_DIR}/.disabled"
|
30
|
+
FileUtils.mv "#{Ray::EXT_DIR}/#{@name}", "#{Ray::EXT_DIR}/.disabled/#{@name}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def enable
|
34
|
+
unless File.exist? "#{Ray::EXT_DIR}/.disabled/#{@name}"
|
35
|
+
raise "The #{@name} extension is not disabled"
|
36
|
+
end
|
37
|
+
|
38
|
+
FileUtils.mv "#{Ray::EXT_DIR}/.disabled/#{@name}", "#{Ray::EXT_DIR}/#{@name}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def uninstall
|
42
|
+
unless File.exist? "#{Ray::EXT_DIR}/#{@name}"
|
43
|
+
raise "The #{@name} extension is not installed"
|
44
|
+
end
|
45
|
+
|
46
|
+
run_tasks({
|
47
|
+
:migrate => "VERSION=0",
|
48
|
+
:update => :psa
|
49
|
+
})
|
50
|
+
FileUtils.rm_rf "#{Ray::EXT_DIR}/#{@name}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def download
|
54
|
+
raise "The extension name is required" unless @name
|
55
|
+
raise "The extension URI is required" unless @uri
|
56
|
+
|
57
|
+
puts "#{@name} => Downloading..."
|
58
|
+
FileUtils.mkdir_p Ray::TMP_DIR
|
59
|
+
tmpfile = open(@uri).path
|
60
|
+
FileUtils.cp tmpfile, "#{Ray::TMP_DIR}/#{@uri.split('/').last}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def vendor
|
64
|
+
puts "#{@name} => Vendoring..."
|
65
|
+
directory = Dir.glob("#{Ray::TMP_DIR}/*").first
|
66
|
+
FileUtils.mv directory, "#{Ray::EXT_DIR}/#{@name}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def run_tasks options = { :migrate => "", :update => "" }
|
70
|
+
tasks = load_tasks
|
71
|
+
tasks.each do |task|
|
72
|
+
case task
|
73
|
+
when "radiant:extensions:#{@name}:install"
|
74
|
+
run_task "install"
|
75
|
+
break
|
76
|
+
when "radiant:extensions:#{@name}:migrate"
|
77
|
+
run_task "migrate", options[:migrate]
|
78
|
+
when "radiant:extensions:#{@name}:update"
|
79
|
+
run_task "update", options[:update]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def run_task task, options = {}
|
85
|
+
puts "#{@name} => Running #{task} task..."
|
86
|
+
if task == "update" and options == :psa
|
87
|
+
public_service_announcement
|
88
|
+
else
|
89
|
+
`rake radiant:extensions:#{@name}:#{task} #{options}`
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def load_tasks
|
94
|
+
puts "#{@name} => Loading tasks..."
|
95
|
+
rake_file = "#{Ray::ROOT}/vendor/extensions/#{@name}/lib/tasks/#{@name}_extension_tasks.rake"
|
96
|
+
load rake_file if File.exist? rake_file
|
97
|
+
Rake.application.tasks.map(&:name)
|
98
|
+
end
|
99
|
+
|
100
|
+
def cleanup
|
101
|
+
puts "#{@name} => Removing temporary files..."
|
102
|
+
FileUtils.rm_rf Ray::TMP_DIR
|
103
|
+
end
|
104
|
+
|
105
|
+
def public_service_announcement path = nil
|
106
|
+
path ||= "#{Ray::EXT_DIR}/#{@name}"
|
107
|
+
Dir.glob("#{path}/public/**/*.*").each do |f|
|
108
|
+
FileUtils.rm_rf File.expand_path(f.sub! /#{path}\//, "")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def name= name
|
113
|
+
@name = name.to_extension_name
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require "multi_json"
|
2
|
+
require "ray/extension"
|
3
|
+
|
4
|
+
module Ray
|
5
|
+
|
6
|
+
class Gem
|
7
|
+
|
8
|
+
include Extension
|
9
|
+
|
10
|
+
def initialize options = {}
|
11
|
+
@author = options[:author]
|
12
|
+
@description = options[:description]
|
13
|
+
@homepage = options[:homepage]
|
14
|
+
@name = options[:name].to_s.to_extension_name
|
15
|
+
@uri = options[:uri]
|
16
|
+
@version = options[:version] || version
|
17
|
+
end
|
18
|
+
|
19
|
+
def install
|
20
|
+
unless @name
|
21
|
+
raise "The extension name is required"
|
22
|
+
end
|
23
|
+
|
24
|
+
add_gem
|
25
|
+
bundle
|
26
|
+
copy_tasks
|
27
|
+
run_tasks
|
28
|
+
end
|
29
|
+
alias enable install
|
30
|
+
|
31
|
+
def add_gem
|
32
|
+
puts "#{@name} => Adding to Gemfile..."
|
33
|
+
File.open GEMFILE, "a" do |gemfile|
|
34
|
+
gemfile.puts "gem \"radiant-#{@name}-extension\", \"~> #{@version}\""
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def version
|
39
|
+
return 0 unless @name
|
40
|
+
uri = "#{RG_V1_API}/gems/radiant-#{@name}-extension.json"
|
41
|
+
response = open(uri).read
|
42
|
+
MultiJson.decode(response)["version"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def bundle
|
46
|
+
puts "#{@name} => Bundling..."
|
47
|
+
FileUtils.rm "#{Ray::GEMFILE}.lock"
|
48
|
+
`bundle update`
|
49
|
+
end
|
50
|
+
|
51
|
+
def copy_tasks
|
52
|
+
puts "#{@name} => Copying tasks..."
|
53
|
+
path = `bundle show radiant-#{@name}-extension`.chomp
|
54
|
+
tasks = "#{path}/lib/tasks/#{@name}_extension_tasks.rake"
|
55
|
+
if File.exist? tasks
|
56
|
+
FileUtils.cp tasks, "#{Ray::ROOT}/lib/tasks/"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def load_tasks
|
61
|
+
puts "#{@name} => Loading tasks..."
|
62
|
+
rake_file = "#{Ray::ROOT}/lib/tasks/#{@name}_extension_tasks.rake"
|
63
|
+
load rake_file if File.exist? rake_file
|
64
|
+
Rake.application.tasks.map(&:name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def disable
|
68
|
+
puts "#{@name} => Removing from Gemfile..."
|
69
|
+
current_gemfile = File.read GEMFILE
|
70
|
+
updated_gemfile = current_gemfile.sub /gem "radiant-#{@name}-extension".+\n/, ""
|
71
|
+
File.open GEMFILE, "w" do |gemfile|
|
72
|
+
gemfile.puts updated_gemfile
|
73
|
+
end
|
74
|
+
bundle
|
75
|
+
end
|
76
|
+
|
77
|
+
def uninstall
|
78
|
+
run_tasks({
|
79
|
+
:migrate => "VERSION=0",
|
80
|
+
:update => :psa
|
81
|
+
})
|
82
|
+
disable
|
83
|
+
end
|
84
|
+
|
85
|
+
def run_task task, options = ""
|
86
|
+
puts "#{@name} => Running #{task} task..."
|
87
|
+
if task == "update" and options == :psa
|
88
|
+
public_service_announcement `bundle show radiant-#{@name}-extension`.chop
|
89
|
+
else
|
90
|
+
`rake radiant:extensions:#{@name}:#{task} #{options}`
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "ray/extension"
|
2
|
+
|
3
|
+
module Ray
|
4
|
+
|
5
|
+
class Git
|
6
|
+
|
7
|
+
include Extension
|
8
|
+
|
9
|
+
def install
|
10
|
+
if File.exist? "#{Ray::EXT_DIR}/#{@name}"
|
11
|
+
raise "The #{@name} extension is already installed"
|
12
|
+
end
|
13
|
+
|
14
|
+
clone
|
15
|
+
vendor
|
16
|
+
run_tasks
|
17
|
+
cleanup
|
18
|
+
end
|
19
|
+
|
20
|
+
def clone
|
21
|
+
puts "#{@name} => Cloning..."
|
22
|
+
raise "The extension name is required" unless @name
|
23
|
+
raise "The repository URI is required" unless @uri
|
24
|
+
`git clone --depth=1 --quiet #{@uri} #{Ray::TMP_DIR}/#{@name}`
|
25
|
+
FileUtils.rm_rf "#{Ray::TMP_DIR}/#{@name}/.git"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "zip"
|
2
|
+
require "ray/extension"
|
3
|
+
|
4
|
+
# set StringMax to 0 so open-uri always creates a tmp file
|
5
|
+
OpenURI::Buffer.send :remove_const, "StringMax"
|
6
|
+
OpenURI::Buffer.const_set "StringMax", 0
|
7
|
+
|
8
|
+
module Ray
|
9
|
+
|
10
|
+
class Zip
|
11
|
+
|
12
|
+
include Extension
|
13
|
+
|
14
|
+
def install
|
15
|
+
if File.exist? "#{Ray::EXT_DIR}/#{@name}"
|
16
|
+
raise "The #{@name} extension is already installed"
|
17
|
+
end
|
18
|
+
|
19
|
+
download
|
20
|
+
extract
|
21
|
+
vendor
|
22
|
+
run_tasks
|
23
|
+
cleanup
|
24
|
+
end
|
25
|
+
|
26
|
+
def extract
|
27
|
+
if Dir.glob("#{Ray::TMP_DIR}/*").size != 1
|
28
|
+
raise "The file does not exist"
|
29
|
+
end
|
30
|
+
|
31
|
+
archive = Dir.glob("#{Ray::TMP_DIR}/*").first
|
32
|
+
::Zip::ZipFile.open archive do |zip_file|
|
33
|
+
zip_file.each do |f|
|
34
|
+
f_path = File.join "#{Ray::TMP_DIR}", f.name
|
35
|
+
FileUtils.mkdir_p File.dirname f_path
|
36
|
+
zip_file.extract f, f_path unless File.exist? f_path
|
37
|
+
end
|
38
|
+
end
|
39
|
+
FileUtils.rm archive
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/ray/search.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "multi_json"
|
3
|
+
require "open-uri"
|
4
|
+
require "ray/string"
|
5
|
+
require "yaml"
|
6
|
+
|
7
|
+
module Search
|
8
|
+
|
9
|
+
def search
|
10
|
+
normalize open(@uri).read
|
11
|
+
end
|
12
|
+
|
13
|
+
def cache
|
14
|
+
if File.exist? Ray::CACHE
|
15
|
+
cache = YAML.load_file Ray::CACHE
|
16
|
+
else
|
17
|
+
FileUtils.mkdir_p Ray::RAY
|
18
|
+
FileUtils.touch Ray::CACHE
|
19
|
+
cache = {}
|
20
|
+
end
|
21
|
+
File.open Ray::CACHE, "w" do |f|
|
22
|
+
f.write cache.merge(@results).to_yaml
|
23
|
+
end
|
24
|
+
return self
|
25
|
+
end
|
26
|
+
|
27
|
+
def output
|
28
|
+
output = ""
|
29
|
+
if @results.empty?
|
30
|
+
output += %Q{
|
31
|
+
No extensions matched: #{@query}
|
32
|
+
# URI: #{@uri}
|
33
|
+
}.lstrip
|
34
|
+
else
|
35
|
+
@results.each do |extension|
|
36
|
+
name = extension.first.to_extension_name
|
37
|
+
info = extension.last
|
38
|
+
output += %Q{
|
39
|
+
#{"-" * 80}
|
40
|
+
#{name} (#{info[:version]}) by #{info[:author][0..(78 - " #{name} (#{info[:version]}) by ".size)]}
|
41
|
+
#{info[:description].wrap(78, 2)}
|
42
|
+
#{info[:homepage]}
|
43
|
+
ray install #{name}\n
|
44
|
+
}.lstrip
|
45
|
+
end
|
46
|
+
return output
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def multiple_choice
|
51
|
+
puts output
|
52
|
+
print "Which extension do you want to install? "
|
53
|
+
choice = STDIN.gets.chomp
|
54
|
+
@results[choice]
|
55
|
+
end
|
56
|
+
|
57
|
+
def merge other
|
58
|
+
self.results.merge! other.results
|
59
|
+
return self
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "ray/search"
|
3
|
+
require "ray/string"
|
4
|
+
require "yaml"
|
5
|
+
|
6
|
+
module Ray
|
7
|
+
|
8
|
+
class Cache
|
9
|
+
|
10
|
+
include Search
|
11
|
+
|
12
|
+
attr_reader :query, :uri
|
13
|
+
attr_accessor :results
|
14
|
+
|
15
|
+
def initialize query
|
16
|
+
@query = query
|
17
|
+
@results = search
|
18
|
+
@uri = Ray::CACHE
|
19
|
+
end
|
20
|
+
|
21
|
+
def search
|
22
|
+
return {} unless File.exist? Ray::CACHE
|
23
|
+
cache = YAML.load_file Ray::CACHE
|
24
|
+
results = {}
|
25
|
+
cache.each do |extension|
|
26
|
+
name = extension.first
|
27
|
+
info = extension.last
|
28
|
+
if match? name, info[:description]
|
29
|
+
results[name] = {
|
30
|
+
:author => info[:author],
|
31
|
+
:description => info[:description],
|
32
|
+
:homepage => info[:homepage],
|
33
|
+
:name => name,
|
34
|
+
:uri => info[:uri],
|
35
|
+
:version => info[:version]
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return results
|
40
|
+
end
|
41
|
+
|
42
|
+
def match? name, description
|
43
|
+
if "#{name} #{description}".include?(@query)
|
44
|
+
return true
|
45
|
+
elsif name.include?(@query.to_extension_name)
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.clear
|
52
|
+
FileUtils.rm Ray::CACHE
|
53
|
+
end
|
54
|
+
|
55
|
+
def cache
|
56
|
+
return self
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "ray/search"
|
2
|
+
|
3
|
+
module Ray
|
4
|
+
|
5
|
+
class GitHub
|
6
|
+
|
7
|
+
include Search
|
8
|
+
|
9
|
+
attr_reader :query, :results, :uri
|
10
|
+
|
11
|
+
def initialize query
|
12
|
+
@query = query
|
13
|
+
@uri = "#{Ray::GH_V2_API}/repos/search/radiant+#{@query}"
|
14
|
+
@results = search
|
15
|
+
end
|
16
|
+
|
17
|
+
def normalize response
|
18
|
+
response = MultiJson.decode response
|
19
|
+
results = {}
|
20
|
+
response["repositories"].each do |extension|
|
21
|
+
results[extension["name"].to_extension_name] = {
|
22
|
+
:author => real_name(extension["owner"]),
|
23
|
+
:description => extension["description"],
|
24
|
+
:homepage => extension["url"],
|
25
|
+
:name => extension["name"].to_extension_name,
|
26
|
+
:uri => extension["url"],
|
27
|
+
:version => "latest"
|
28
|
+
}
|
29
|
+
end
|
30
|
+
return results
|
31
|
+
end
|
32
|
+
|
33
|
+
def real_name owner
|
34
|
+
response = open("#{GH_V3_API}/users/#{owner}").read
|
35
|
+
MultiJson.decode(response)["name"]
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|