appengine-tools 0.0.2 → 0.0.3
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.
- data/Rakefile +1 -1
- data/lib/appengine-tools/appcfg.rb +62 -10
- data/lib/appengine-tools/boot.rb +28 -5
- data/lib/appengine-tools/bundler.rb +87 -52
- data/lib/appengine-tools/dev_appserver.rb +50 -14
- data/lib/appengine-tools/update_check.rb +118 -0
- data/spec/appengine-web.xml +8 -1
- data/spec/config.ru +3 -0
- data/spec/update_check_spec.rb +176 -0
- metadata +4 -2
data/Rakefile
CHANGED
@@ -17,6 +17,7 @@
|
|
17
17
|
require 'appengine-sdk'
|
18
18
|
require 'appengine-tools/boot'
|
19
19
|
require 'appengine-tools/bundler'
|
20
|
+
require 'appengine-tools/update_check'
|
20
21
|
require 'yaml'
|
21
22
|
|
22
23
|
module AppEngine
|
@@ -26,6 +27,9 @@ module AppEngine
|
|
26
27
|
import Java.ComGoogleAppengineToolsAdmin.AppAdminFactory
|
27
28
|
import Java.ComGoogleAppengineToolsAdmin.AppVersionUpload
|
28
29
|
import Java.ComGoogleAppengineToolsUtil.Logging
|
30
|
+
import java.io.FileOutputStream
|
31
|
+
import java.util.jar.JarOutputStream
|
32
|
+
import java.util.zip.ZipEntry
|
29
33
|
|
30
34
|
class JRubyAppVersionUpload < AppVersionUpload
|
31
35
|
def initialize(connection, app)
|
@@ -88,12 +92,16 @@ EOF
|
|
88
92
|
return
|
89
93
|
end
|
90
94
|
if command && ! NO_XML_COMMANDS.include?(command)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
95
|
+
path = parsed_args[0]
|
96
|
+
AppEngine::Admin.bundle_app(path)
|
97
|
+
AppEngine::Development.boot_jruby
|
98
|
+
updater = AppEngine::Admin::UpdateCheck.new(path)
|
99
|
+
updater.nag
|
100
|
+
else
|
101
|
+
AppEngine::Development.boot_jruby
|
96
102
|
end
|
103
|
+
puts "running AppCfg"
|
104
|
+
run_appcfg(args)
|
97
105
|
end
|
98
106
|
|
99
107
|
def run_appcfg(args)
|
@@ -119,27 +127,33 @@ EOF
|
|
119
127
|
end
|
120
128
|
|
121
129
|
def gem(*args)
|
130
|
+
AppEngine::Admin.bundle_deps('.')
|
122
131
|
AppEngine::Development.boot_jruby
|
132
|
+
puts "=> Running RubyGems"
|
123
133
|
require 'rubygems'
|
124
134
|
require 'rubygems/command_manager'
|
125
135
|
Gem.configuration = Gem::ConfigFile.new(args)
|
126
136
|
Gem.use_paths('.gems')
|
127
137
|
Gem::Command.add_specific_extra_args(
|
128
138
|
'install', %w(--no-rdoc --no-ri))
|
139
|
+
saved_gems = all_gem_specs
|
129
140
|
begin
|
130
141
|
Gem::CommandManager.instance.run(Gem.configuration.args)
|
131
142
|
rescue Gem::SystemExitException => e
|
132
143
|
exit e.exit_code unless e.exit_code == 0
|
133
144
|
end
|
134
|
-
unless
|
145
|
+
unless ((all_gem_specs == saved_gems) &&
|
146
|
+
File.exist?('WEB-INF/lib/gems.jar'))
|
135
147
|
Dir.mkdir 'WEB-INF' unless File.exists? 'WEB-INF'
|
136
148
|
Dir.mkdir 'WEB-INF/lib' unless File.exists? 'WEB-INF/lib'
|
137
149
|
Dir.chdir '.gems'
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
150
|
+
puts '=> Packaging gems'
|
151
|
+
write_jar('../WEB-INF/lib/gems.jar') do |jar|
|
152
|
+
add_to_jar('gems', jar)
|
153
|
+
add_to_jar('specifications', jar)
|
142
154
|
end
|
155
|
+
puts 'If you upgraded any gems, please run `appcfg.rb gem cleanup`'
|
156
|
+
puts 'to remove the old versions.'
|
143
157
|
end
|
144
158
|
end
|
145
159
|
|
@@ -154,7 +168,45 @@ Must be run from the application directory.
|
|
154
168
|
EOF
|
155
169
|
end
|
156
170
|
|
171
|
+
def all_gem_specs
|
172
|
+
Gem.source_index.map do |_, spec|
|
173
|
+
spec
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def write_jar(filename)
|
178
|
+
filename = File.expand_path(filename)
|
179
|
+
jar = JarOutputStream.new(FileOutputStream.new(filename))
|
180
|
+
begin
|
181
|
+
yield jar
|
182
|
+
ensure
|
183
|
+
jar.close
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def add_to_jar(path, jar)
|
188
|
+
directory = File.directory?(path)
|
189
|
+
if directory
|
190
|
+
path << '/'
|
191
|
+
end
|
192
|
+
entry = ZipEntry.new(path)
|
193
|
+
jar.put_next_entry(entry)
|
194
|
+
unless directory
|
195
|
+
data = IO.read(path)
|
196
|
+
jar.write(data.to_java_bytes, 0, data.size)
|
197
|
+
end
|
198
|
+
jar.close_entry
|
199
|
+
if directory
|
200
|
+
Dir.entries(path).each do |filename|
|
201
|
+
unless ['.', '..'].include?(filename)
|
202
|
+
add_to_jar(path + filename, jar)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
157
208
|
def run(*args)
|
209
|
+
AppEngine::Admin.bundle_deps('.')
|
158
210
|
AppEngine::Development.boot_app('.', args)
|
159
211
|
end
|
160
212
|
|
data/lib/appengine-tools/boot.rb
CHANGED
@@ -20,7 +20,7 @@ module AppEngine
|
|
20
20
|
module Development
|
21
21
|
|
22
22
|
class << self
|
23
|
-
def boot_jruby(root=nil)
|
23
|
+
def boot_jruby(root=nil, options={})
|
24
24
|
unless defined?(JRUBY_VERSION)
|
25
25
|
require 'rubygems'
|
26
26
|
require 'appengine-jruby-jars'
|
@@ -31,8 +31,19 @@ module AppEngine
|
|
31
31
|
AppEngine::SDK::TOOLS_JAR,
|
32
32
|
]
|
33
33
|
|
34
|
+
args = options[:args] || ARGV
|
35
|
+
should_exec = options[:exec]
|
36
|
+
should_exec ||= should_exec.nil?
|
37
|
+
|
34
38
|
ENV['GEM_HOME'] = Gem.dir
|
35
|
-
|
39
|
+
ENV['GEM_PATH'] = Gem.path.compact.join(File::SEPARATOR)
|
40
|
+
appcfg = [File.expand_path(File.join(File.dirname($0),
|
41
|
+
'appcfg.rb'))]
|
42
|
+
if should_exec
|
43
|
+
exec_jruby(root, jars, appcfg + args)
|
44
|
+
else
|
45
|
+
run_jruby(root, jars, appcfg + args)
|
46
|
+
end
|
36
47
|
end
|
37
48
|
end
|
38
49
|
|
@@ -48,16 +59,28 @@ module AppEngine
|
|
48
59
|
exec_jruby(root, jars, jruby_args)
|
49
60
|
end
|
50
61
|
|
51
|
-
def
|
62
|
+
def build_command(root, jars, args)
|
52
63
|
app_jars = root ? Dir.glob("#{root}/WEB-INF/lib/*.jar") : []
|
53
64
|
classpath = (app_jars + jars).join(File::PATH_SEPARATOR)
|
54
65
|
utf = "-Dfile.encoding=UTF-8"
|
55
|
-
|
66
|
+
command = %W(java #{utf} -cp #{classpath} org.jruby.Main) + args
|
56
67
|
if ENV['VERBOSE']
|
57
|
-
puts
|
68
|
+
puts command.map {|a| a.inspect}.join(' ')
|
58
69
|
end
|
70
|
+
command
|
71
|
+
end
|
72
|
+
|
73
|
+
def exec_jruby(root, jars, args)
|
74
|
+
java_command = build_command(root, jars, args)
|
59
75
|
exec *java_command
|
60
76
|
end
|
77
|
+
|
78
|
+
def run_jruby(root, jars, args)
|
79
|
+
java_command = build_command(root, jars, args)
|
80
|
+
if !system(*java_command)
|
81
|
+
puts 'Error executing jruby'
|
82
|
+
end
|
83
|
+
end
|
61
84
|
end
|
62
85
|
end
|
63
86
|
end
|
@@ -16,6 +16,7 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
18
|
require 'appengine-rack'
|
19
|
+
require 'appengine-tools/boot'
|
19
20
|
require 'appengine-tools/web-xml'
|
20
21
|
require 'appengine-tools/xml-formatter'
|
21
22
|
require 'fileutils'
|
@@ -78,10 +79,10 @@ module AppEngine
|
|
78
79
|
end
|
79
80
|
|
80
81
|
class AppBundler
|
81
|
-
EXISTING_JRUBY = /^appengine-jruby-.*jar$/
|
82
|
+
EXISTING_JRUBY = /^(jruby-abridged|appengine-jruby)-.*jar$/
|
82
83
|
EXISTING_RACK = /jruby-rack.*jar$/
|
83
84
|
EXISTING_APIS = /^appengine-api.*jar$/
|
84
|
-
JRUBY_RACK = 'jruby-rack-0.9.
|
85
|
+
JRUBY_RACK = 'jruby-rack-0.9.5.jar'
|
85
86
|
JRUBY_RACK_URL = 'http://kenai.com/projects/jruby-rack/' +
|
86
87
|
"downloads/download/#{JRUBY_RACK}"
|
87
88
|
RACKUP = %q{Dir.chdir('..') if Dir.pwd =~ /WEB-INF$/;} +
|
@@ -92,11 +93,15 @@ module AppEngine
|
|
92
93
|
end
|
93
94
|
|
94
95
|
def bundle
|
96
|
+
bundle_deps
|
97
|
+
convert_config_ru
|
98
|
+
end
|
99
|
+
|
100
|
+
def bundle_deps
|
95
101
|
create_webinf
|
96
102
|
copy_jruby
|
97
103
|
copy_rack
|
98
104
|
copy_sdk
|
99
|
-
convert_config_ru
|
100
105
|
end
|
101
106
|
|
102
107
|
def app
|
@@ -117,7 +122,6 @@ module AppEngine
|
|
117
122
|
end
|
118
123
|
|
119
124
|
def convert_config_ru
|
120
|
-
AppEngine::Development.boot_jruby(app.root)
|
121
125
|
if !File.exists?(app.config_ru)
|
122
126
|
if File.exists?(app.web_xml)
|
123
127
|
unless File.exists?(app.aeweb_xml)
|
@@ -137,22 +141,14 @@ module AppEngine
|
|
137
141
|
end
|
138
142
|
|
139
143
|
def copy_jruby
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
FileUtils.cp([AppEngine::JRubyJars.jruby_jar,
|
145
|
-
AppEngine::JRubyJars.rubygems_jar],
|
146
|
-
app.webinf_lib)
|
147
|
-
end
|
148
|
-
# TODO else warn if out of date
|
144
|
+
require 'appengine-jruby-jars'
|
145
|
+
update_jars(
|
146
|
+
"JRuby", EXISTING_JRUBY, [AppEngine::JRubyJars.jruby_jar],
|
147
|
+
/rubygems/, [AppEngine::JRubyJars.rubygems_jar])
|
149
148
|
end
|
150
149
|
|
151
150
|
def copy_rack
|
152
|
-
|
153
|
-
if current_rack.empty?
|
154
|
-
# TODO cache this somewhere
|
155
|
-
puts "=> Retrieving jruby-rack"
|
151
|
+
update_jars('jruby-rack', EXISTING_RACK, [JRUBY_RACK]) do
|
156
152
|
require 'open-uri'
|
157
153
|
open(JRUBY_RACK_URL) do |src|
|
158
154
|
open(File.join(app.webinf_lib, JRUBY_RACK), 'wb') do |dest|
|
@@ -163,15 +159,10 @@ module AppEngine
|
|
163
159
|
end
|
164
160
|
|
165
161
|
def copy_sdk
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
jars = Dir.glob(
|
171
|
-
"#{AppEngine::SDK::SDK_ROOT}/lib/user/appengine-api*.jar")
|
172
|
-
# TODO if there's more than 1 we need to check the api version.
|
173
|
-
FileUtils.cp(jars[0], app.webinf_lib)
|
174
|
-
end
|
162
|
+
require 'appengine-sdk'
|
163
|
+
glob = "appengine-api-1.0-sdk-*.jar"
|
164
|
+
jars = Dir.glob("#{AppEngine::SDK::SDK_ROOT}/lib/user/#{glob}")
|
165
|
+
update_jars('appengine-sdk', EXISTING_APIS, jars)
|
175
166
|
end
|
176
167
|
|
177
168
|
private
|
@@ -180,6 +171,40 @@ module AppEngine
|
|
180
171
|
Dir.entries(app.webinf_lib).grep(regex) rescue []
|
181
172
|
end
|
182
173
|
|
174
|
+
def update_jars(name, regex, jars, opt_regex=nil, opt_jars=[])
|
175
|
+
existing = find_jars(regex)
|
176
|
+
if existing.empty?
|
177
|
+
message = "Installing #{name}"
|
178
|
+
jars_to_install = jars + opt_jars
|
179
|
+
else
|
180
|
+
has_optional_jars = existing.any? {|j| j =~ opt_regex}
|
181
|
+
expected_jars = jars
|
182
|
+
expected_jars.concat(opt_jars) if has_optional_jars
|
183
|
+
expected = expected_jars.map {|path| File.basename(path)}
|
184
|
+
if existing.size != expected.size ||
|
185
|
+
(expected & existing) != expected
|
186
|
+
message = "Updating #{name}"
|
187
|
+
jars_to_install = expected_jars
|
188
|
+
end
|
189
|
+
end
|
190
|
+
if jars_to_install
|
191
|
+
puts message
|
192
|
+
remove_jars(existing)
|
193
|
+
if block_given?
|
194
|
+
yield
|
195
|
+
else
|
196
|
+
FileUtils.cp(jars_to_install, app.webinf_lib)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def remove_jars(jars)
|
202
|
+
paths = jars.map do |jar|
|
203
|
+
"#{app.webinf_lib}/#{jar}"
|
204
|
+
end
|
205
|
+
FileUtils.rm_f(paths)
|
206
|
+
end
|
207
|
+
|
183
208
|
def valid_build
|
184
209
|
return false unless File.exists? app.build_status
|
185
210
|
return false unless File.exists? app.web_xml
|
@@ -193,41 +218,51 @@ module AppEngine
|
|
193
218
|
end
|
194
219
|
|
195
220
|
def generate_xml
|
196
|
-
return if valid_build
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
221
|
+
return if valid_build
|
222
|
+
if defined? JRUBY_VERSION
|
223
|
+
puts "=> Generating configuration files"
|
224
|
+
Dir.glob("#{app.webinf_lib}/*.jar").each do |path|
|
225
|
+
$: << path
|
226
|
+
end
|
227
|
+
app_root = app.root
|
228
|
+
builder = WebXmlBuilder.new do
|
229
|
+
# First configure the basic jruby-rack settings.
|
230
|
+
add_jruby_rack_defaults(RACKUP)
|
205
231
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
232
|
+
# Now read the user's rackup file
|
233
|
+
# TODO generate a skeleton if it's missing
|
234
|
+
Dir.chdir(app_root) do
|
235
|
+
eval IO.read('config.ru'), nil, 'config.ru', 1
|
236
|
+
end
|
210
237
|
end
|
238
|
+
open(app.web_xml, 'w') do |webxml|
|
239
|
+
xml = AppEngine::Rack::XmlFormatter.format(builder.to_xml)
|
240
|
+
webxml.write(xml)
|
241
|
+
end
|
242
|
+
open(app.aeweb_xml, 'w') do |aeweb|
|
243
|
+
xml = AppEngine::Rack::XmlFormatter.format(app.rack_app.to_xml)
|
244
|
+
aeweb.write(xml)
|
245
|
+
end
|
246
|
+
yaml = {
|
247
|
+
:config_ru => File.stat(app.config_ru).mtime,
|
248
|
+
:aeweb_xml => File.stat(app.aeweb_xml).mtime,
|
249
|
+
:web_xml => File.stat(app.web_xml).mtime }
|
250
|
+
open(app.build_status, 'w') { |f| YAML.dump(yaml, f) }
|
251
|
+
else
|
252
|
+
AppEngine::Development.boot_jruby(app.root,
|
253
|
+
:args => ['bundle', app.root],
|
254
|
+
:exec => false)
|
211
255
|
end
|
212
|
-
open(app.web_xml, 'w') do |webxml|
|
213
|
-
xml = AppEngine::Rack::XmlFormatter.format(builder.to_xml)
|
214
|
-
webxml.write(xml)
|
215
|
-
end
|
216
|
-
open(app.aeweb_xml, 'w') do |aeweb|
|
217
|
-
xml = AppEngine::Rack::XmlFormatter.format(app.rack_app.to_xml)
|
218
|
-
aeweb.write(xml)
|
219
|
-
end
|
220
|
-
yaml = {
|
221
|
-
:config_ru => File.stat(app.config_ru).mtime,
|
222
|
-
:aeweb_xml => File.stat(app.aeweb_xml).mtime,
|
223
|
-
:web_xml => File.stat(app.web_xml).mtime }
|
224
|
-
open(app.build_status, 'w') { |f| YAML.dump(yaml, f) }
|
225
256
|
end
|
226
257
|
end
|
227
258
|
|
228
259
|
def self.bundle_app(root_path)
|
229
260
|
AppBundler.new(root_path).bundle
|
230
261
|
end
|
262
|
+
|
263
|
+
def self.bundle_deps(root_path)
|
264
|
+
AppBundler.new(root_path).bundle_deps
|
265
|
+
end
|
231
266
|
|
232
267
|
end
|
233
268
|
end
|
@@ -17,29 +17,65 @@
|
|
17
17
|
require 'appengine-sdk'
|
18
18
|
require 'appengine-tools/boot'
|
19
19
|
require 'appengine-tools/bundler'
|
20
|
+
require 'appengine-tools/update_check'
|
20
21
|
|
21
22
|
module AppEngine
|
22
23
|
module Development
|
23
|
-
DEV_APPSERVER = 'com.google.appengine.tools.development.DevAppServerMain'
|
24
|
+
DEV_APPSERVER = ['com.google.appengine.tools.development.DevAppServerMain']
|
24
25
|
class JRubyDevAppserver
|
25
26
|
class << self
|
26
27
|
def run(args)
|
27
|
-
path
|
28
|
-
if
|
29
|
-
|
30
|
-
|
31
|
-
puts "=> Press Ctrl-C to shutdown server"
|
32
|
-
ENV['BOOTING_DEVAPPSERVER'] = 'true'
|
33
|
-
end
|
28
|
+
path, java_args, server_args = parse_argv(ARGV)
|
29
|
+
if path and File::directory?(path)
|
30
|
+
puts "=> Booting DevAppServer"
|
31
|
+
puts "=> Press Ctrl-C to shutdown server"
|
34
32
|
AppEngine::Admin.bundle_app(path)
|
33
|
+
updater = AppEngine::Admin::UpdateCheck.new(path)
|
34
|
+
updater.nag if updater.can_nag?
|
35
|
+
end
|
36
|
+
start_java(path, java_args, server_args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_argv(argv)
|
40
|
+
java_args = []
|
41
|
+
server_args = ['--disable_update_check']
|
42
|
+
start_on_first_thread = false
|
43
|
+
if RUBY_PLATFORM =~ /darwin/ ||
|
44
|
+
(RUBY_PLATFORM == 'java' &&
|
45
|
+
java.lang.System.getProperty("os.name").downcase == "mac os x")
|
46
|
+
start_on_first_thread = true
|
47
|
+
end
|
48
|
+
argv.each do |arg|
|
49
|
+
if arg =~ /^--jvm_flag=(.+)/
|
50
|
+
java_args << $1
|
51
|
+
elsif arg =~ /--startOnFirstThread=(true|false)/
|
52
|
+
start_on_first_thread = ($1 == "true")
|
53
|
+
else
|
54
|
+
server_args << arg
|
55
|
+
end
|
56
|
+
end
|
57
|
+
if start_on_first_thread
|
58
|
+
java_args << '-XstartOnFirstThread'
|
59
|
+
end
|
60
|
+
return server_args[-1], java_args, server_args
|
61
|
+
end
|
62
|
+
|
63
|
+
def start_java(path, java_args, server_args)
|
64
|
+
if path
|
65
|
+
jruby_home = get_jruby_home(path)
|
66
|
+
java_args << "-Djruby.home=#{jruby_home}" if jruby_home
|
67
|
+
server_args[-1] = File.expand_path(path)
|
68
|
+
Dir.chdir(path)
|
35
69
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
70
|
+
ENV.delete 'GEM_HOME'
|
71
|
+
ENV.delete 'GEM_PATH'
|
72
|
+
java_args << '-classpath'
|
73
|
+
java_args << AppEngine::SDK::TOOLS_JAR
|
74
|
+
command = ['java'] + java_args + DEV_APPSERVER + server_args
|
75
|
+
if ENV['VERBOSE']
|
76
|
+
puts "exec #{command.map{|x| x.inspect}.join(' ')}"
|
41
77
|
end
|
42
|
-
|
78
|
+
exec(*command)
|
43
79
|
end
|
44
80
|
|
45
81
|
def get_jruby_home(path)
|
@@ -0,0 +1,118 @@
|
|
1
|
+
#!/usr/bin/ruby1.8 -w
|
2
|
+
#
|
3
|
+
# Copyright:: Copyright 2009 Google Inc.
|
4
|
+
# Original Author:: Ryan Brown (mailto:ribrdb@google.com)
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require 'yaml'
|
19
|
+
require 'open-uri'
|
20
|
+
begin
|
21
|
+
require 'google-appengine'
|
22
|
+
rescue LoadError
|
23
|
+
end
|
24
|
+
require 'rubygems/version'
|
25
|
+
|
26
|
+
module AppEngine
|
27
|
+
module Admin
|
28
|
+
class UpdateCheck
|
29
|
+
NAG_FILE = "~/.appcfg_rb_nag"
|
30
|
+
MAX_NAG_FREQUENCY = 60 * 60 * 24 * 7
|
31
|
+
DEFAULT_URL = 'http://appengine-jruby.googlecode.com/hg/updatecheck'
|
32
|
+
|
33
|
+
def initialize(approot, url=nil, nag_file=nil)
|
34
|
+
@url = url || DEFAULT_URL
|
35
|
+
@approot = approot
|
36
|
+
@nag_file = nag_file || File.expand_path(NAG_FILE)
|
37
|
+
end
|
38
|
+
|
39
|
+
def local_versions
|
40
|
+
sdk_version = Gem::Version.new(AppEngine::VERSION) rescue nil
|
41
|
+
{
|
42
|
+
'google-appengine' => sdk_version,
|
43
|
+
'appengine-apis' => find_gem_version('appengine-apis'),
|
44
|
+
'dm-appengine' => find_gem_version('dm-appengine'),
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_gem_version(name)
|
49
|
+
specs = Dir.glob("#{@approot}/.gems/specifications/#{name}-*.gemspec")
|
50
|
+
versions = specs.map do |filename|
|
51
|
+
if filename =~ /-(\w+\.\w+.\w+).gemspec$/
|
52
|
+
Gem::Version.new($1)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
versions.sort[-1]
|
56
|
+
end
|
57
|
+
|
58
|
+
def remote_versions
|
59
|
+
versions = YAML.load(open(@url).read)
|
60
|
+
versions.inject({}) do |versions, (name, version)|
|
61
|
+
versions[name] = Gem::Version.new(version)
|
62
|
+
versions
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def check_for_updates
|
67
|
+
local = local_versions
|
68
|
+
unless local['google-appengine']
|
69
|
+
puts 'Skipping update check'
|
70
|
+
return
|
71
|
+
end
|
72
|
+
latest = remote_versions
|
73
|
+
local.each do |name, version|
|
74
|
+
current = latest[name]
|
75
|
+
if version && version < current
|
76
|
+
prefix = if name == 'google-appengine'
|
77
|
+
"sudo"
|
78
|
+
else
|
79
|
+
"appcfg.rb"
|
80
|
+
end
|
81
|
+
puts "There is a new version of #{name}: #{current} " +
|
82
|
+
"(You have #{version})"
|
83
|
+
puts "Please run #{prefix} gem update #{name}."
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def parse_nag_file
|
89
|
+
@nag ||= if File.exist?(@nag_file)
|
90
|
+
YAML.load_file(@nag_file)
|
91
|
+
else
|
92
|
+
{'opt_in' => true, 'timestamp' => 0}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def write_nag_file(options)
|
97
|
+
open(@nag_file, 'w') do |file|
|
98
|
+
file.write(YAML.dump(options))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def nag
|
103
|
+
nag = parse_nag_file
|
104
|
+
return if Time.now.to_i - nag['timestamp'] < MAX_NAG_FREQUENCY
|
105
|
+
check_for_updates
|
106
|
+
nag['timestamp'] = Time.now.to_i
|
107
|
+
write_nag_file(nag)
|
108
|
+
rescue OpenURI::HTTPError, Errno::ENOENT
|
109
|
+
# check_for_updates will raise an error if we're not online
|
110
|
+
# just ignore it, and don't update the nag timestamp.
|
111
|
+
end
|
112
|
+
|
113
|
+
def can_nag?
|
114
|
+
parse_nag_file['opt_in']
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/spec/appengine-web.xml
CHANGED
@@ -2,11 +2,18 @@
|
|
2
2
|
<application>tools-test</application>
|
3
3
|
<version>foo</version>
|
4
4
|
<public-root>/public</public-root>
|
5
|
-
<static-files
|
5
|
+
<static-files>
|
6
|
+
<include expiration='365d' path='/public/images/**'/>
|
7
|
+
<include path='/public/**'/>
|
8
|
+
</static-files>
|
6
9
|
<resource-files/>
|
7
10
|
<system-properties>
|
8
11
|
<property name='os.arch' value=''/>
|
9
12
|
<property name='jruby.management.enabled' value='false'/>
|
13
|
+
<property name='jruby.rack.input.rewindable' value='false'/>
|
10
14
|
</system-properties>
|
11
15
|
<ssl-enabled>true</ssl-enabled>
|
16
|
+
<inbound-services>
|
17
|
+
<service>xmpp_message</service>
|
18
|
+
</inbound-services>
|
12
19
|
</appengine-web-app>
|
data/spec/config.ru
CHANGED
@@ -2,6 +2,9 @@ require 'appengine-rack'
|
|
2
2
|
|
3
3
|
AppEngine::Rack.configure_app(
|
4
4
|
:application => 'tools-test', :version => 'foo', :ssl_enabled => true)
|
5
|
+
AppEngine::Rack.app.inbound_services << :xmpp_message
|
6
|
+
AppEngine::Rack.app.static_files.include('/public/images/**', '365d')
|
7
|
+
AppEngine::Rack.app.static_files.include('/public/**')
|
5
8
|
|
6
9
|
ruby_app = lambda {|env| [200, {}, "Hello Rack!"]}
|
7
10
|
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
require 'appengine-tools/update_check'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module AppEngine
|
6
|
+
VERSION = "3.2.1"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe AppEngine::Admin::UpdateCheck do
|
10
|
+
before :each do
|
11
|
+
@update_check = AppEngine::Admin::UpdateCheck.new('approot', 'url', 'nag')
|
12
|
+
end
|
13
|
+
|
14
|
+
def versions(sdk, apis, dm)
|
15
|
+
keys = ['google-appengine', 'appengine-apis', 'dm-appengine']
|
16
|
+
hash = {}
|
17
|
+
keys.zip([sdk, apis, dm]) do |key, value|
|
18
|
+
hash[key] = value && Gem::Version.new(value)
|
19
|
+
end
|
20
|
+
hash
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should expand path' do
|
24
|
+
File.should_receive(:expand_path).with(
|
25
|
+
AppEngine::Admin::UpdateCheck::NAG_FILE)
|
26
|
+
uc = AppEngine::Admin::UpdateCheck.new('/')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should support local_versions' do
|
30
|
+
expected = versions('3.2.1', '1.2.3', nil)
|
31
|
+
@update_check.should_receive(:find_gem_version).twice.and_return(
|
32
|
+
Gem::Version.new("1.2.3"), nil)
|
33
|
+
@update_check.local_versions.should == expected
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should support find_gem_version' do
|
37
|
+
Dir.should_receive(:glob).and_return(
|
38
|
+
['appengine-apis-0.0.20.gemspec','appengine-apis-0.0.3.gemspec'])
|
39
|
+
@update_check.find_gem_version("appengine-apis").should ==
|
40
|
+
Gem::Version.new('0.0.20')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should support remote_versions' do
|
44
|
+
expected = versions('3.2.2', '1.2.4', '2.3.4')
|
45
|
+
io = StringIO.new(YAML.dump(expected))
|
46
|
+
@update_check.stub!(:open)
|
47
|
+
@update_check.should_receive(:open).with("url").and_return(io)
|
48
|
+
@update_check.remote_versions.should == expected
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'check_for_updates' do
|
52
|
+
before :each do
|
53
|
+
@update_check.stub!(:puts)
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def expect_puts(*messages)
|
58
|
+
length = messages.length
|
59
|
+
@update_check.should_receive(:puts) do |arg|
|
60
|
+
arg.should == messages.shift
|
61
|
+
end.exactly(length).times
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should skip check if no sdk version' do
|
65
|
+
@update_check.should_receive(:local_versions).and_return(
|
66
|
+
versions(nil, nil, nil))
|
67
|
+
expect_puts("Skipping update check")
|
68
|
+
@update_check.check_for_updates
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should warn about old sdk' do
|
72
|
+
@update_check.should_receive(:local_versions).and_return(
|
73
|
+
versions('0.0.1', nil, nil))
|
74
|
+
@update_check.should_receive(:remote_versions).and_return(
|
75
|
+
versions('0.0.2', '0.0.2', '0.0.2'))
|
76
|
+
expect_puts(
|
77
|
+
"There is a new version of google-appengine: 0.0.2 (You have 0.0.1)",
|
78
|
+
"Please run sudo gem update google-appengine."
|
79
|
+
)
|
80
|
+
@update_check.check_for_updates
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should warn about old apis' do
|
84
|
+
@update_check.should_receive(:local_versions).and_return(
|
85
|
+
versions('0.0.2', '0.0.2', '0.0.2'))
|
86
|
+
@update_check.should_receive(:remote_versions).and_return(
|
87
|
+
versions('0.0.2', '0.0.4', '0.0.2'))
|
88
|
+
expect_puts(
|
89
|
+
"There is a new version of appengine-apis: 0.0.4 (You have 0.0.2)",
|
90
|
+
"Please run appcfg.rb gem update appengine-apis."
|
91
|
+
)
|
92
|
+
@update_check.check_for_updates
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should warn about old dm adapter' do
|
96
|
+
@update_check.should_receive(:local_versions).and_return(
|
97
|
+
versions('0.0.2', '0.0.2', '0.0.2'))
|
98
|
+
@update_check.should_receive(:remote_versions).and_return(
|
99
|
+
versions('0.0.2', '0.0.2', '0.0.3'))
|
100
|
+
expect_puts(
|
101
|
+
"There is a new version of dm-appengine: 0.0.3 (You have 0.0.2)",
|
102
|
+
"Please run appcfg.rb gem update dm-appengine."
|
103
|
+
)
|
104
|
+
@update_check.check_for_updates
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
it 'should warn about multiple old gems' do
|
109
|
+
@update_check.should_receive(:local_versions).and_return(
|
110
|
+
versions('0.0.1', '0.0.3', '0.0.5'))
|
111
|
+
@update_check.should_receive(:remote_versions).and_return(
|
112
|
+
versions('0.0.2', '0.0.4', '0.0.5'))
|
113
|
+
expect_puts(
|
114
|
+
"There is a new version of google-appengine: 0.0.2 (You have 0.0.1)",
|
115
|
+
"Please run sudo gem update google-appengine.",
|
116
|
+
"There is a new version of appengine-apis: 0.0.4 (You have 0.0.3)",
|
117
|
+
"Please run appcfg.rb gem update appengine-apis."
|
118
|
+
)
|
119
|
+
@update_check.check_for_updates
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe 'parse_nag_file' do
|
124
|
+
it 'should support missing file' do
|
125
|
+
File.should_receive(:exist?).with('nag').and_return(false)
|
126
|
+
@update_check.parse_nag_file.should == {
|
127
|
+
'opt_in' => true,
|
128
|
+
'timestamp' => 0
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should parse existing file' do
|
133
|
+
File.should_receive(:exist?).with('nag').and_return(true)
|
134
|
+
YAML.should_receive(:load_file).with('nag').and_return("parsed_yaml")
|
135
|
+
@update_check.parse_nag_file.should == "parsed_yaml"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'nag' do
|
140
|
+
it 'should nag if old timestamp' do
|
141
|
+
@update_check.should_receive(:parse_nag_file).and_return({
|
142
|
+
'opt_in' => true,
|
143
|
+
'timestamp' => Time.now.to_i - (60 * 60 * 24 * 8)
|
144
|
+
})
|
145
|
+
@update_check.should_receive(:check_for_updates)
|
146
|
+
@update_check.should_receive(:write_nag_file)
|
147
|
+
@update_check.nag
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should not nag if new timestamp' do
|
151
|
+
@update_check.should_receive(:parse_nag_file).and_return({
|
152
|
+
'opt_in' => true,
|
153
|
+
'timestamp' => Time.now.to_i - (60 * 60 * 24 * 6)
|
154
|
+
})
|
155
|
+
@update_check.nag
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe 'can_nag?' do
|
160
|
+
it 'should return true of opted in' do
|
161
|
+
@update_check.should_receive(:parse_nag_file).and_return({
|
162
|
+
'opt_in' => true,
|
163
|
+
'timestamp' => Time.now.to_i
|
164
|
+
})
|
165
|
+
@update_check.can_nag?.should == true
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'should return false of opted out' do
|
169
|
+
@update_check.should_receive(:parse_nag_file).and_return({
|
170
|
+
'opt_in' => false,
|
171
|
+
'timestamp' => Time.now.to_i
|
172
|
+
})
|
173
|
+
@update_check.can_nag?.should == false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appengine-tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Brown
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-03 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -60,6 +60,7 @@ files:
|
|
60
60
|
- lib/appengine-tools/boot.rb
|
61
61
|
- lib/appengine-tools/bundler.rb
|
62
62
|
- lib/appengine-tools/dev_appserver.rb
|
63
|
+
- lib/appengine-tools/update_check.rb
|
63
64
|
- lib/appengine-tools/web-xml.rb
|
64
65
|
- lib/appengine-tools/xml-formatter.rb
|
65
66
|
- spec/appengine-web.xml
|
@@ -67,6 +68,7 @@ files:
|
|
67
68
|
- spec/rack_spec.rb
|
68
69
|
- spec/spec.opts
|
69
70
|
- spec/spec_helper.rb
|
71
|
+
- spec/update_check_spec.rb
|
70
72
|
- spec/web-xml_spec.rb
|
71
73
|
- spec/web.xml
|
72
74
|
has_rdoc: true
|