rave 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/bin/rave CHANGED
@@ -1,24 +1,28 @@
1
- #!/usr/bin/env ruby
2
-
3
- here = File.dirname(__FILE__)
4
- %w( create server usage war ).each do |cmd|
5
- require File.join(here, "..", "lib", "commands", cmd)
6
- end
7
-
8
- args = ARGV
9
- cmd = args.shift
10
-
11
- if cmd
12
- case cmd
13
- when "create"
14
- create_robot(args)
15
- when "server"
16
- start_robot(args)
17
- when "war"
18
- create_war(args)
19
- else
20
- display_usage
21
- end
22
- else
23
- usage
1
+ #!/usr/bin/env ruby
2
+
3
+ here = File.dirname(__FILE__)
4
+ %w( create server usage war appcfg ).each do |cmd|
5
+ require File.join(here, "..", "lib", "commands", cmd)
6
+ end
7
+
8
+ args = ARGV
9
+ cmd = args.shift
10
+
11
+ if cmd
12
+ case cmd
13
+ when "create"
14
+ create_robot(args)
15
+ when "server"
16
+ start_robot(args)
17
+ when "war"
18
+ create_war(args)
19
+ when "cleanup"
20
+ cleanup_war(args)
21
+ when "appengine_deploy"
22
+ appcfg_update(args)
23
+ else
24
+ display_usage
25
+ end
26
+ else
27
+ display_usage
24
28
  end
@@ -0,0 +1,9 @@
1
+ #Does an appcfg update to deploy the tmp/war folder to appengine
2
+ def appcfg_update(args)
3
+ Rake.application.standard_exception_handling do
4
+ Rake.application.init
5
+ Rave::Task.new
6
+ task(:default => "rave:appcfg_update")
7
+ Rake.application.top_level
8
+ end
9
+ end
@@ -1,147 +1,153 @@
1
- require 'ftools'
2
-
3
- #Creates a project for a robot. Args are:
4
- # => robot_name (required)
5
- # => image_url=http://imageurl.com/ (optional)
6
- # => profile_url=http://profileurl.com/ (optional)
7
- # e.g. rave my_robot image_url=http://appropriate-casey.appspot.com/image.png profile_url=http://appropriate-casey.appspot.com/profile.json
8
- def create_robot(args)
9
- robot_name = args.first
10
- module_name = robot_name.split(/_|-/).collect { |word| word[0, 1].upcase + word[1, word.length-1] }.join("")
11
- robot_class_name = "#{module_name}::Robot"
12
- options = { :name => robot_name }
13
- args[1, args.length-1].each do |arg|
14
- key, value = arg.split("=").collect { |part| part.strip }
15
- options[key.to_sym] = value
16
- end
17
- dir = File.join(".", robot_name)
18
- lib = File.join(dir, "lib")
19
- config_dir = File.join(dir, "config")
20
- file = File.join(dir, "robot.rb")
21
- appengine_web = File.join(dir, "appengine-web.xml")
22
- config = File.join(dir, "config.ru")
23
- here = File.dirname(__FILE__)
24
- jar_dir = File.join(here, "..", "jars")
25
- jars = %w( appengine-api-1.0-sdk-1.2.1.jar jruby-core.jar ruby-stdlib.jar )
26
- #Create the project dir
27
- puts "Creating directory #{File.expand_path(dir)}"
28
- Dir.mkdir(dir)
29
- puts "Creating robot class #{File.expand_path(file)}"
30
- #Make the base robot class
31
- File.open(file, "w") do |f|
32
- f.puts robot_file_contents(module_name)
33
- end
34
- #Make the rackup config file
35
- puts "Creating rackup config file #{File.expand_path(config)}"
36
- options_str = options.collect { |key, val| ":#{key} => \"#{val}\"" }.join(", ")
37
- File.open(config, "w") do |f|
38
- f.puts config_file_contents(robot_class_name, options_str)
39
- end
40
- #Make the appengine web xml file
41
- puts "Creating appengine config file #{File.expand_path(appengine_web)}"
42
- File.open(appengine_web, "w") do |f|
43
- f.puts appengine_web_contents(robot_name)
44
- end
45
- #Copy jars over
46
- puts "Creating lib directory #{File.expand_path(lib)}"
47
- Dir.mkdir(lib)
48
- jars.each do |jar|
49
- puts "Adding jar #{jar}"
50
- File.copy(File.join(jar_dir, jar), File.join(lib, jar))
51
- end
52
- #Make the wabler config file
53
- puts "Creating config directory #{File.expand_path(config_dir)}"
54
- Dir.mkdir(config_dir)
55
- warble_file = File.join(config_dir, "warble.rb")
56
- puts "Creating warble config file #{File.expand_path(warble_file)}"
57
- File.open(warble_file, "w") do |f|
58
- f.puts warble_config_contents()
59
- end
60
- end
61
-
62
- def robot_file_contents(module_name)
63
- <<-ROBOT
64
- require 'rubygems'
65
- require 'rave'
66
-
67
- module #{module_name}
68
- class Robot < Rave::Models::Robot
69
-
70
- ME = "appropriate-casey@appspot.com"
71
-
72
- #Define handlers here:
73
- # e.g. if the robot should act on a DOCUMENT_CHANGED event:
74
- #
75
- # def document_changed(event, context)
76
- # #Do some stuff
77
- # end
78
- #
79
- # Events are:
80
- #
81
- # WAVELET_BLIP_CREATED, WAVELET_BLIP_REMOVED, WAVELET_PARTICIPANTS_CHANGED,
82
- # WAVELET_TIMESTAMP_CHANGED, WAVELET_TITLE_CHANGED, WAVELET_VERSION_CHANGED,
83
- # BLIP_CONTRIBUTORS_CHANGED, BLIP_DELETED, BLIP_SUBMITTED, BLIP_TIMESTAMP_CHANGED,
84
- # BLIP_VERSION_CHANGED, DOCUMENT_CHANGED, FORM_BUTTON_CLICKED
85
- #
86
- # If you want to name your event handler something other than the default name,
87
- # or you need to have more than one handler for an event, you can register handlers
88
- # in the robot's constructor:
89
- #
90
- # def initialize(options={})
91
- # super
92
- # register_handler(Rave::Models::Event::DOCUMENT_CHANGED, :custom_doc_changed_handler)
93
- # end
94
- #
95
- # def custom_doc_changed_handler(event, context)
96
- # #Do some stuff
97
- # end
98
- #
99
- # Note: Don't forget to call super if you define #initialize
100
-
101
- end
102
- end
103
- ROBOT
104
- end
105
-
106
- def config_file_contents(robot_class_name, options_str)
107
- <<-CONFIG
108
- require 'robot'
109
- run #{robot_class_name}.new( #{options_str} )
110
- CONFIG
111
- end
112
-
113
- def appengine_web_contents(robot_name)
114
- <<-APPENGINE
115
- <?xml version="1.0" encoding="utf-8"?>
116
- <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
117
- <application>#{robot_name}</application>
118
- <version>1</version>
119
- <static-files />
120
- <resource-files />
121
- <sessions-enabled>false</sessions-enabled>
122
- <system-properties>
123
- <property name="jruby.management.enabled" value="false" />
124
- <property name="os.arch" value="" />
125
- <property name="jruby.compile.mode" value="JIT"/> <!-- JIT|FORCE|OFF -->
126
- <property name="jruby.compile.fastest" value="true"/>
127
- <property name="jruby.compile.frameless" value="true"/>
128
- <property name="jruby.compile.positionless" value="true"/>
129
- <property name="jruby.compile.threadless" value="false"/>
130
- <property name="jruby.compile.fastops" value="false"/>
131
- <property name="jruby.compile.fastcase" value="false"/>
132
- <property name="jruby.compile.chainsize" value="500"/>
133
- <property name="jruby.compile.lazyHandles" value="false"/>
134
- <property name="jruby.compile.peephole" value="true"/>
135
- </system-properties>
136
- </appengine-web-app>
137
- APPENGINE
138
- end
139
-
140
- def warble_config_contents
141
- <<-WARBLE
142
- Warbler::Config.new do |config|
143
- config.gems = %w( rave json-jruby rack builder )
144
- config.includes = %w( robot.rb appengine-web.xml )
145
- end
146
- WARBLE
147
- end
1
+ require 'ftools'
2
+
3
+ #Creates a project for a robot. Args are:
4
+ # => robot_name (required)
5
+ # => image_url=http://imageurl.com/icon.png (optional)
6
+ # => profile_url=http://profileurl.com/ (optional)
7
+ # e.g. rave my_robot image_url=http://appropriate-casey.appspot.com/image.png profile_url=http://appropriate-casey.appspot.com/profile.json
8
+ def create_robot(args)
9
+ robot_name = args.first
10
+ module_name = robot_name.split(/_|-/).collect { |word| word.capitalize }.join
11
+ robot_class_name = "#{module_name}::Robot"
12
+
13
+ options = { :name => robot_name, :version => 1, :id => "#{robot_name}@appspot.com" }
14
+ args[1, args.length-1].each do |arg|
15
+ key, value = arg.split("=").collect { |part| part.strip }
16
+ options[key.to_sym] = value
17
+ end
18
+
19
+ dir = File.join(".", robot_name)
20
+ if File.exist? dir
21
+ puts "Directory #{dir}/ already exists. Exiting..."
22
+ exit
23
+ end
24
+
25
+ lib = File.join(dir, "lib")
26
+ config_dir = File.join(dir, "config")
27
+ file = File.join(dir, "robot.rb")
28
+ run = File.join(dir, "config.ru")
29
+ config = File.join(dir, "config.yaml")
30
+ public_folder = File.join(dir, "public")
31
+ html = File.join(public_folder, "index.html")
32
+
33
+ #Create the project dir
34
+ puts "Creating directory #{File.expand_path(dir)}"
35
+ Dir.mkdir(dir)
36
+
37
+ puts "Creating robot class #{File.expand_path(file)}"
38
+ #Make the base robot class
39
+ File.open(file, "w") do |f|
40
+ f.puts robot_file_contents(module_name)
41
+ end
42
+
43
+ # Make the rackup run file.
44
+ puts "Creating rackup config file #{File.expand_path(run)}"
45
+ File.open(run, "w") do |f|
46
+ f.puts run_file_contents(robot_class_name, file)
47
+ end
48
+
49
+ # Make up the yaml config file.
50
+ puts "Creating configuration file #{File.expand_path(config)}"
51
+ File.open(config, "w") do |f|
52
+ f.puts config_file_contents(options)
53
+ end
54
+
55
+ #Make the public folder for static resources
56
+ puts "Creating public folder"
57
+ Dir.mkdir(public_folder)
58
+
59
+ # Make up the html index file.
60
+ puts "Creating html index file #{File.expand_path(html)}"
61
+ File.open(html, "w") do |f|
62
+ f.puts html_file_contents(robot_name, options[:id], options[:image_url])
63
+ end
64
+
65
+ #Create lib directory
66
+ puts "Creating lib directory #{File.expand_path(lib)}"
67
+ Dir.mkdir(lib)
68
+ end
69
+
70
+ def robot_file_contents(module_name)
71
+ <<-ROBOT
72
+ require 'rubygems'
73
+ require 'rave'
74
+
75
+ module #{module_name}
76
+ class Robot < Rave::Models::Robot
77
+ #Define handlers here:
78
+ # e.g. if the robot should act on a DOCUMENT_CHANGED event:
79
+ #
80
+ # def document_changed(event, context)
81
+ # #Do some stuff
82
+ # end
83
+ #
84
+ # Events are:
85
+ #
86
+ # WAVELET_BLIP_CREATED, WAVELET_BLIP_REMOVED, WAVELET_PARTICIPANTS_CHANGED,
87
+ # WAVELET_TIMESTAMP_CHANGED, WAVELET_TITLE_CHANGED, WAVELET_VERSION_CHANGED,
88
+ # BLIP_CONTRIBUTORS_CHANGED, BLIP_DELETED, BLIP_SUBMITTED, BLIP_TIMESTAMP_CHANGED,
89
+ # BLIP_VERSION_CHANGED, DOCUMENT_CHANGED, FORM_BUTTON_CLICKED
90
+ #
91
+ # If you want to name your event handler something other than the default name,
92
+ # or you need to have more than one handler for an event, you can register handlers
93
+ # in the robot's constructor:
94
+ #
95
+ # def initialize(options={})
96
+ # super
97
+ # register_handler(Rave::Models::Event::DOCUMENT_CHANGED, :custom_doc_changed_handler)
98
+ # end
99
+ #
100
+ # def custom_doc_changed_handler(event, context)
101
+ # #Do some stuff
102
+ # end
103
+ #
104
+ # Note: Don't forget to call super if you define #initialize
105
+
106
+ end
107
+ end
108
+ ROBOT
109
+ end
110
+
111
+ def run_file_contents(robot_class_name, robot_file)
112
+ <<-CONFIG
113
+ require '#{File.basename(robot_file).chomp(File.extname(robot_file))}'
114
+ run #{robot_class_name}.instance
115
+ CONFIG
116
+ end
117
+
118
+ def config_file_contents(options)
119
+ <<-CONFIG
120
+ robot:
121
+ id: #{options[:id]}
122
+ name: #{options[:name]}
123
+ image_url: #{options[:image_url]}
124
+ profile_url: #{options[:profile_url]}
125
+ version: #{options[:version]}
126
+ appcfg:
127
+ version: 1
128
+ # Uncomment this section to add gems required by your robot.
129
+ # They will unpacked in your project at appengine deploy time
130
+ # gems:
131
+ # - some_gem # Replace this with the name of the gem you require
132
+ # - some_other_gem # Replace this with the name of the gem you require
133
+ CONFIG
134
+ end
135
+
136
+ def html_file_contents(name, id, image_url)
137
+ img_tag = image_url ? "\n <img src=\"#{image_url}\" alt=\"#{name} icon\" />\n" : ""
138
+ <<-HTML
139
+ <html>
140
+ <head>
141
+ <title>#{name}</title>
142
+ </head>
143
+ <body>
144
+ <h1>#{name}</h1>
145
+ #{img_tag}
146
+ <p>This is a Google Wave robot using <a href="http://github.com/diminish7/rave">Rave</a> running in JRuby.
147
+ Use this robot in your Google Waves by adding <em>#{id}</em> as a participant</p>
148
+
149
+ <img src="http://code.google.com/appengine/images/appengine-silver-120x30.gif" alt="Powered by Google App Engine" />
150
+ </body>
151
+ </html>
152
+ HTML
153
+ end
@@ -1,8 +1,8 @@
1
- #Starts up rack based on the config.ru file in the working directory
2
- # Note that this is of limited use right now, because robots have to
3
- # run on appengine. Better to test locally with the appengine sdk
4
- def start_robot(args)
5
- cmd = (RUBY_PLATFORM == 'java') ? "jruby -S rackup" : "rackup"
6
- cmd += " " + args.join(" ") if args
7
- exec(cmd)
1
+ #Starts up rack based on the config.ru file in the working directory
2
+ # Note that this is of limited use right now, because robots have to
3
+ # run on appengine. Better to test locally with the appengine sdk
4
+ def start_robot(args)
5
+ cmd = (RUBY_PLATFORM == 'java') ? "jruby -S rackup" : "rackup"
6
+ cmd += " " + args.join(" ") if args
7
+ exec(cmd)
8
8
  end
@@ -0,0 +1,156 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+ require 'fileutils'
4
+ require 'yaml'
5
+ require 'warbler'
6
+
7
+ module Rave
8
+ class Task < Warbler::Task
9
+
10
+ REQUIRED_GEMS = ["rave", "json-jruby", "rack", "builder", "RedCloth"]
11
+
12
+ def initialize
13
+ warbler_config = Warbler::Config.new do |config|
14
+ config.gems = ((robot_config['gems'] || []) + REQUIRED_GEMS).uniq
15
+ config.includes = %w( robot.rb config.yaml )
16
+ end
17
+ super(:rave, warbler_config)
18
+ define_post_war_processes
19
+ define_deploy_task
20
+ end
21
+
22
+ private
23
+
24
+ def robot_config
25
+ @robot_config ||= YAML::load(File.open(File.join(".", "config.yaml")))
26
+ end
27
+
28
+ def define_post_war_processes
29
+ namespace :rave do
30
+ desc "Post-War cleanup"
31
+ task :create_war => 'rave' do
32
+ #TODO: This needs to only run through this if the files have changed
33
+ #Get config info
34
+ web_inf = File.join(".", "tmp", "war", "WEB-INF")
35
+ rave_jars = File.join(File.dirname(__FILE__), "..", "jars")
36
+ #Cleanup unneeded gems that warbler copies in
37
+ cleanup_gems(File.join(web_inf, "gems", "gems"), robot_config['gems'] || [])
38
+ #Copy the appengine sdk jar to the robot
39
+ copy_appengine_jar_to_robot(rave_jars, File.join(web_inf, "lib"))
40
+ #Fix the broken paths in json-jruby
41
+ fix_json_jruby_paths(File.join(web_inf, "gems", "gems"))
42
+ #Add the appengine-web.xml file
43
+ robot_name = robot_config['robot']['id'].gsub(/@.+/, '')
44
+ version = robot_config['appcfg'] && robot_config['appcfg']['version'] ? robot_config['appcfg']['version'] : 1
45
+ create_appengine_web(File.join(web_inf, "appengine-web.xml"), robot_name, version)
46
+ end
47
+ end
48
+ end
49
+
50
+ def define_deploy_task
51
+ namespace :rave do
52
+ desc "Deploy to Appengine"
53
+ task :appcfg_update => :create_war do
54
+ staging_folder = File.join(".", "tmp", "war")
55
+ sdk_path = find_sdk
56
+ if sdk_path
57
+ appcfg_jar = File.expand_path(File.join(sdk_path, 'lib', 'appengine-tools-api.jar'))
58
+ require appcfg_jar
59
+ Java::ComGoogleAppengineToolsAdmin::AppCfg.main(["update", staging_folder].to_java(:string))
60
+ else
61
+ puts "Unable to find the Google Appengine Java SDK"
62
+ puts "You can either"
63
+ puts "1. Define the path to the main SDK folder in config.yaml - e.g.:"
64
+ puts "appcfg:"
65
+ puts " sdk: /usr/local/appengine-java-sdk/"
66
+ puts "2. Add the SDK bin folder to your PATH, or"
67
+ puts "3. Create an environment variable APPENGINE_JAVA_SDK that defines the path to the main SDK folder"
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ #Remove warbler and jruby-jars - added by warbler but unneeded
74
+ def cleanup_gems(gem_dir, gems)
75
+ ["warbler", "jruby-jars"].each do |g|
76
+ dir = Dir[File.join(gem_dir, "#{g}*")].first
77
+ unless dir.nil? || gems.include?(g)
78
+ puts "Removing #{g} from war"
79
+ FileUtils.rm_rf(dir)
80
+ end
81
+ end
82
+ end
83
+
84
+ def copy_appengine_jar_to_robot(rave_jar_dir, warbler_jar_dir)
85
+ jar = "appengine-api-1.0-sdk-1.3.0.jar"
86
+ rave_jar = File.join(rave_jar_dir, jar)
87
+ warbler_jar = File.join(warbler_jar_dir, jar)
88
+ puts "Copying appengine jar from #{rave_jar} to #{warbler_jar}"
89
+ File.copy(rave_jar, warbler_jar)
90
+ end
91
+
92
+ def fix_json_jruby_paths(web_inf_gems)
93
+ #TODO: Why is this necessary? Is this an appengine issue?
94
+ puts "Fixing paths in json-jruby"
95
+ ext = Dir[File.join(web_inf_gems, "json-jruby-*", "lib", "json", "ext.rb")].first
96
+ if ext
97
+ text = File.open(ext, "r") { |f| f.read }
98
+ text.gsub!("require 'json/ext/parser'", "require 'ext/parser'")
99
+ text.gsub!("require 'json/ext/generator'", "require 'ext/generator'")
100
+ File.open(ext, "w") { |f| f.write(text) }
101
+ end
102
+ end
103
+
104
+ def create_appengine_web(path, robot_name, version)
105
+ puts "Creating appengine config file #{File.expand_path(path)}"
106
+ File.open(path, "w") do |f|
107
+ f.puts appengine_web_contents(robot_name, version)
108
+ end
109
+ end
110
+
111
+ def appengine_web_contents(robot_name, version)
112
+ <<-APPENGINE
113
+ <?xml version="1.0" encoding="utf-8"?>
114
+ <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
115
+ <application>#{robot_name}</application>
116
+ <version>#{version}</version>
117
+ <static-files />
118
+ <resource-files />
119
+ <sessions-enabled>false</sessions-enabled>
120
+ <system-properties>
121
+ <property name="jruby.management.enabled" value="false" />
122
+ <property name="os.arch" value="" />
123
+ <property name="jruby.compile.mode" value="JIT"/> <!-- JIT|FORCE|OFF -->
124
+ <property name="jruby.compile.fastest" value="true"/>
125
+ <property name="jruby.compile.frameless" value="true"/>
126
+ <property name="jruby.compile.positionless" value="true"/>
127
+ <property name="jruby.compile.threadless" value="false"/>
128
+ <property name="jruby.compile.fastops" value="false"/>
129
+ <property name="jruby.compile.fastcase" value="false"/>
130
+ <property name="jruby.compile.chainsize" value="500"/>
131
+ <property name="jruby.compile.lazyHandles" value="false"/>
132
+ <property name="jruby.compile.peephole" value="true"/>
133
+ </system-properties>
134
+ </appengine-web-app>
135
+ APPENGINE
136
+ end
137
+
138
+ def find_sdk
139
+ unless @sdk_path
140
+ @sdk_path = robot_config['appcfg']['sdk'] if robot_config['appcfg'] && robot_config['appcfg']['sdk'] # Points at main SDK dir.
141
+ @sdk_path ||= ENV['APPENGINE_JAVA_SDK'] # Points at main SDK dir.
142
+ unless @sdk_path
143
+ # Check everything in the PATH, which would point at the bin directory in the SDK.
144
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
145
+ if File.exists?(File.join(path, "appcfg.sh")) or File.exists?(File.join("appcfg.cmd"))
146
+ @sdk_path = File.dirname(path)
147
+ break
148
+ end
149
+ end
150
+ end
151
+ end
152
+ @sdk_path
153
+ end
154
+
155
+ end
156
+ end