appengine-tools 0.0.7 → 0.0.8.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +9 -0
- data/README.rdoc +31 -6
- data/Rakefile +18 -11
- data/lib/appengine-tools/appcfg.rb +25 -3
- data/lib/appengine-tools/bundler.rb +36 -34
- data/lib/appengine-tools/com/google/appengine/jruby/AppVersionUploadDelegate.class +0 -0
- data/lib/appengine-tools/com/google/appengine/jruby/JRubyAppVersionUpload.class +0 -0
- data/lib/appengine-tools/gem_bundler.rb +22 -17
- data/lib/jruby-rack-0.9.6.jar +0 -0
- data/lib/jruby-rack-jar.rb +26 -0
- metadata +18 -9
data/COPYING
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
= Appengine-Tools
|
2
|
+
|
3
|
+
This software is provided under the terms of the Apache license. For details
|
4
|
+
see http://appengine-jruby.googlecode.com/hg/appengine-tools/LICENSE
|
5
|
+
|
6
|
+
= Additional Bundled Software
|
7
|
+
|
8
|
+
JRuby-Rack (jruby-rack-*.jar) is distributed under the terms of the MIT license.
|
9
|
+
See http://svn.codehaus.org/jruby-contrib/trunk/rack/LICENSE.txt for details.
|
data/README.rdoc
CHANGED
@@ -1,10 +1,35 @@
|
|
1
|
-
|
2
|
-
This works from standard Ruby or JRuby, but you'll need the rack gem.
|
1
|
+
= AppEngine Tools
|
3
2
|
|
4
|
-
|
3
|
+
AppEngine Tools gem provides dev_appserver.rb and appcfg.rb. The development
|
4
|
+
server runs your application on your local computer for testing your
|
5
|
+
application. The server simulates the App Engine datastore, services and
|
6
|
+
sandbox restrictions. A multipurpose tool called appcfg.rb handles all
|
7
|
+
command-line interaction with your application running on App Engine.
|
5
8
|
|
6
|
-
|
9
|
+
== Extending the Java Platform to JRuby
|
7
10
|
|
8
|
-
|
11
|
+
These tools work from standard Ruby, no need to install JRuby separately,
|
12
|
+
everything you need installs as gems. Your app has access to all the Java APIs.
|
9
13
|
|
10
|
-
|
14
|
+
== Rackup for app configuration
|
15
|
+
|
16
|
+
The required XML configuration files are generated from the 'config.ru' file.
|
17
|
+
|
18
|
+
require 'appengine-rack'
|
19
|
+
AppEngine::Rack.configure_app(
|
20
|
+
:application => "application-id",
|
21
|
+
:precompilation_enabled => true,
|
22
|
+
:version => "1")
|
23
|
+
run lambda { Rack::Response.new("Hello").finish }
|
24
|
+
|
25
|
+
== Bundler for Gem Management
|
26
|
+
|
27
|
+
Simply list the gems you require in the 'Gemfile'
|
28
|
+
|
29
|
+
# Critical default settings:
|
30
|
+
disable_system_gems
|
31
|
+
disable_rubygems
|
32
|
+
bundle_path ".gems/bundler_gems"
|
33
|
+
|
34
|
+
# List gems to bundle here:
|
35
|
+
gem "appengine-rack"
|
data/Rakefile
CHANGED
@@ -4,12 +4,15 @@ require 'rubygems/specification'
|
|
4
4
|
require 'date'
|
5
5
|
require 'spec/rake/spectask'
|
6
6
|
|
7
|
+
require File.dirname(__FILE__) + '/lib/jruby-rack-jar'
|
8
|
+
|
7
9
|
GEM = "appengine-tools"
|
8
|
-
GEM_VERSION = "0.0.
|
9
|
-
AUTHOR = "Ryan Brown"
|
10
|
-
EMAIL = "ribrdb@gmail.com"
|
10
|
+
GEM_VERSION = "0.0.8.pre"
|
11
11
|
HOMEPAGE = "http://code.google.com/p/appengine-jruby"
|
12
|
-
|
12
|
+
JRUBYRACK_VERSION = AppEngine::JRubyJars::JRUBYRACK_VERSION
|
13
|
+
JRUBYRACK_JAR = "jruby-rack-#{JRUBYRACK_VERSION}.jar"
|
14
|
+
JRUBYRACK_URL = "http://repository.codehaus.org/org/jruby/rack/" +
|
15
|
+
"jruby-rack/#{JRUBYRACK_VERSION}/#{JRUBYRACK_JAR}"
|
13
16
|
|
14
17
|
spec = Gem::Specification.new do |s|
|
15
18
|
s.name = GEM
|
@@ -17,20 +20,23 @@ spec = Gem::Specification.new do |s|
|
|
17
20
|
s.platform = Gem::Platform::RUBY
|
18
21
|
s.has_rdoc = true
|
19
22
|
s.extra_rdoc_files = ["README.rdoc", "LICENSE"]
|
20
|
-
s.summary =
|
21
|
-
s.description =
|
22
|
-
|
23
|
-
|
23
|
+
s.summary = "Tools for developing and deploying apps to Google App Engine"
|
24
|
+
s.description = <<-EOF
|
25
|
+
Tools and SDK for developing Ruby applications for Google App Engine.
|
26
|
+
Includes a local development server and tools for testing and deployment."
|
27
|
+
EOF
|
28
|
+
s.authors = ["Ryan Brown", "John Woodell"]
|
29
|
+
s.email = ["ribrdb@google.com", "woodie@google.com"]
|
24
30
|
s.homepage = HOMEPAGE
|
25
31
|
|
26
32
|
s.require_path = 'lib'
|
27
|
-
s.files = %w(LICENSE README.rdoc Rakefile) +
|
28
|
-
|
33
|
+
s.files = %w(COPYING LICENSE README.rdoc Rakefile) +
|
34
|
+
["lib/#{JRUBYRACK_JAR}"] + Dir.glob("{lib,spec}/**/*.{rb,class}")
|
29
35
|
s.executables = [ 'appcfg.rb', 'dev_appserver.rb' ]
|
30
36
|
s.add_dependency('appengine-rack')
|
31
37
|
s.add_dependency('appengine-sdk')
|
32
38
|
s.add_dependency('appengine-jruby-jars')
|
33
|
-
s.add_dependency('bundler', ["~> 0.
|
39
|
+
s.add_dependency('bundler', ["~> 0.8.1"])
|
34
40
|
s.add_dependency('rubyzip')
|
35
41
|
end
|
36
42
|
|
@@ -44,6 +50,7 @@ end
|
|
44
50
|
|
45
51
|
|
46
52
|
Rake::GemPackageTask.new(spec) do |pkg|
|
53
|
+
system("curl -s -o lib/#{JRUBYRACK_JAR} #{JRUBYRACK_URL}")
|
47
54
|
pkg.gem_spec = spec
|
48
55
|
end
|
49
56
|
|
@@ -81,7 +81,7 @@ module AppEngine
|
|
81
81
|
|
82
82
|
class JRubyAppCfg
|
83
83
|
NO_XML_COMMANDS = %w{version}
|
84
|
-
RUBY_COMMANDS = %w{gem bundle help run}
|
84
|
+
RUBY_COMMANDS = %w{gem bundle help run generate_app}
|
85
85
|
COMMAND_SUMMARY = <<EOF
|
86
86
|
run: run jruby in your application environment.
|
87
87
|
bundle: package your application for deployment.
|
@@ -114,7 +114,29 @@ EOF
|
|
114
114
|
Logging.initializeLogging
|
115
115
|
AppCfg.new(factory, args.to_java(java.lang.String))
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
|
+
def generate_app(*args)
|
119
|
+
if args and args.size > 0
|
120
|
+
appdir = args.pop
|
121
|
+
webinf = File.join(appdir, 'WEB-INF')
|
122
|
+
FileUtils.mkdir_p(webinf)
|
123
|
+
AppEngine::Admin.bundle_app(appdir)
|
124
|
+
else
|
125
|
+
generate_app_help
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def generate_app_help
|
130
|
+
help = <<EOF
|
131
|
+
#{$0} generate_app app_dir
|
132
|
+
|
133
|
+
Generates a sample Rack application in app_dir.
|
134
|
+
The directory is created if it doesn't exist.
|
135
|
+
|
136
|
+
EOF
|
137
|
+
puts help
|
138
|
+
end
|
139
|
+
|
118
140
|
def bundle(*args)
|
119
141
|
if File.directory?(args[-1] || '')
|
120
142
|
AppEngine::Admin.bundle_app(*args)
|
@@ -122,7 +144,7 @@ EOF
|
|
122
144
|
bundle_help
|
123
145
|
end
|
124
146
|
end
|
125
|
-
|
147
|
+
|
126
148
|
def bundle_help
|
127
149
|
help = <<EOF
|
128
150
|
#{$0} bundle [gem bundle options] app_dir
|
@@ -97,10 +97,8 @@ module AppEngine
|
|
97
97
|
|
98
98
|
class AppBundler
|
99
99
|
EXISTING_JRUBY = /^(jruby-abridged|appengine-jruby)-.*jar$/
|
100
|
-
EXISTING_RACK =
|
100
|
+
EXISTING_RACK = /^jruby-rack.*jar$/
|
101
101
|
EXISTING_APIS = /^appengine-api.*jar$/
|
102
|
-
JRUBY_RACK = 'jruby-rack-0.9.5.jar'
|
103
|
-
JRUBY_RACK_URL = "http://kenai.com/downloads/jruby-rack/#{JRUBY_RACK}"
|
104
102
|
RACKUP = %q{Dir.chdir('..') if Dir.pwd =~ /WEB-INF$/; } +
|
105
103
|
%q{begin; require 'bundler_gems/environment'; } +
|
106
104
|
%q{rescue LoadError; end;} +
|
@@ -116,6 +114,7 @@ module AppEngine
|
|
116
114
|
end
|
117
115
|
|
118
116
|
def bundle_deps(args=[])
|
117
|
+
confirm_appdir
|
119
118
|
create_webinf
|
120
119
|
bundle_gems(args)
|
121
120
|
copy_jruby
|
@@ -133,6 +132,19 @@ module AppEngine
|
|
133
132
|
@app
|
134
133
|
end
|
135
134
|
|
135
|
+
def confirm_appdir
|
136
|
+
unless File.exists?(app.config_ru) or
|
137
|
+
File.exists?(app.gemfile) or File.exists?(app.webinf)
|
138
|
+
puts ""
|
139
|
+
puts "Oops, this does not look like an application directory."
|
140
|
+
puts "You need a #{app.gemfile} or #{app.config_ru} file."
|
141
|
+
puts ""
|
142
|
+
puts "Run 'appcfg.rb generate #{app.path}'"
|
143
|
+
puts "to generate a skeleton application."
|
144
|
+
exit 1
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
136
148
|
def create_webinf
|
137
149
|
Dir.mkdir(app.webinf) unless File.exists?(app.webinf)
|
138
150
|
Dir.mkdir(app.webinf_lib) unless File.exists?(app.webinf_lib)
|
@@ -149,22 +161,22 @@ module AppEngine
|
|
149
161
|
end
|
150
162
|
|
151
163
|
def convert_config_ru
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
generate_xml
|
166
|
-
create_public
|
164
|
+
unless File.exists?(app.config_ru)
|
165
|
+
puts "=> Generating rackup"
|
166
|
+
app_id = File.basename(File.expand_path(app.path)).
|
167
|
+
downcase.gsub('_', '-').gsub(/[^-a-z0-9]/, '')
|
168
|
+
stock_rackup = <<EOF
|
169
|
+
require 'appengine-rack'
|
170
|
+
AppEngine::Rack.configure_app(
|
171
|
+
:application => "#{app_id}",
|
172
|
+
:precompilation_enabled => true,
|
173
|
+
:version => "1")
|
174
|
+
run lambda { Rack::Response.new("Hello").finish }
|
175
|
+
EOF
|
176
|
+
File.open(app.config_ru, 'w') {|f| f.write(stock_rackup) }
|
167
177
|
end
|
178
|
+
generate_xml
|
179
|
+
create_public
|
168
180
|
end
|
169
181
|
|
170
182
|
def copy_jruby
|
@@ -173,19 +185,9 @@ module AppEngine
|
|
173
185
|
end
|
174
186
|
|
175
187
|
def copy_rack
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
open(JRUBY_RACK_URL) do |src|
|
180
|
-
open(File.join(app.webinf_lib, JRUBY_RACK), 'wb') do |dest|
|
181
|
-
dest.write(src.read)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
rescue SocketError
|
185
|
-
puts "Unable to download jruby-rack."
|
186
|
-
puts "Please check your internet connection."
|
187
|
-
end
|
188
|
-
end
|
188
|
+
require 'jruby-rack-jar'
|
189
|
+
update_jars('JRuby-Rack', EXISTING_RACK,
|
190
|
+
[AppEngine::JRubyJars.jrubyrack_jar])
|
189
191
|
end
|
190
192
|
|
191
193
|
def copy_sdk
|
@@ -257,9 +259,9 @@ module AppEngine
|
|
257
259
|
app_root = app.root
|
258
260
|
builder = WebXmlBuilder.new do
|
259
261
|
# First read the user's rackup file
|
260
|
-
# TODO generate a skeleton if it's missing
|
261
262
|
Dir.chdir(app_root) do
|
262
|
-
require
|
263
|
+
require File.join(".gems", "bundler_gems",
|
264
|
+
TARGET_ENGINE, TARGET_VERSION, "environment")
|
263
265
|
eval IO.read('config.ru'), nil, 'config.ru', 1
|
264
266
|
end
|
265
267
|
|
@@ -286,7 +288,7 @@ module AppEngine
|
|
286
288
|
end
|
287
289
|
end
|
288
290
|
end
|
289
|
-
|
291
|
+
|
290
292
|
def self.bundle_app(*args)
|
291
293
|
AppBundler.new(args.pop).bundle(args)
|
292
294
|
end
|
Binary file
|
Binary file
|
@@ -22,15 +22,11 @@ require 'zip/zipfilesystem'
|
|
22
22
|
require 'rubygems/command_manager'
|
23
23
|
require 'appengine-tools/bundler'
|
24
24
|
|
25
|
-
# Support Ruby 1.6, without active_support/extensions/facets
|
26
|
-
class Symbol
|
27
|
-
def to_proc
|
28
|
-
Proc.new { |*args| args.shift.__send__(self, *args) }
|
29
|
-
end unless :to_proc.respond_to?(:to_proc)
|
30
|
-
end
|
31
|
-
|
32
25
|
module AppEngine
|
33
26
|
module Admin
|
27
|
+
TARGET_VERSION = '1.8'
|
28
|
+
TARGET_ENGINE = 'jruby'
|
29
|
+
GEM_PLATFORM = Gem::Platform.new("universal-java-1.6")
|
34
30
|
|
35
31
|
class GemBundler
|
36
32
|
|
@@ -60,9 +56,11 @@ module AppEngine
|
|
60
56
|
|
61
57
|
def gem_bundle(args)
|
62
58
|
return unless args.include?('--update') || gems_out_of_date
|
63
|
-
Gem.platforms = [Gem::Platform::RUBY,
|
64
|
-
Gem::Platform.new('universal-java')]
|
59
|
+
Gem.platforms = [Gem::Platform::RUBY, GEM_PLATFORM]
|
65
60
|
Gem.configuration = Gem::ConfigFile.new(args.unshift('bundle'))
|
61
|
+
ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : nil
|
62
|
+
# Override RUBY_ENGINE (we bundle from MRI for JRuby)
|
63
|
+
Object.const_set('RUBY_ENGINE', TARGET_ENGINE)
|
66
64
|
puts "=> Bundling gems"
|
67
65
|
begin
|
68
66
|
Dir.chdir(@root) do
|
@@ -71,15 +69,26 @@ module AppEngine
|
|
71
69
|
rescue Gem::SystemExitException => e
|
72
70
|
exit e.exit_code unless e.exit_code == 0
|
73
71
|
end
|
72
|
+
# Restore RUBY_ENGINE (limit the scope of this hack)
|
73
|
+
Object.const_set('RUBY_ENGINE', ruby_engine) unless ruby_engine.nil?
|
74
74
|
bundler_dir = "#{app.gems_dir}/bundler_gems"
|
75
|
+
target_pair = "#{TARGET_ENGINE}/#{TARGET_VERSION}"
|
76
|
+
gem_patch = "require 'bundler_gems/#{target_pair}/environment'"
|
77
|
+
File.open("#{bundler_dir}/environment.rb",'w') {|f| f << gem_patch }
|
75
78
|
FileUtils.rm app.gems_jar, :force => true # blow away the old jar
|
76
79
|
puts "=> Packaging gems"
|
77
|
-
gem_files = Dir["#{bundler_dir}/
|
78
|
-
Dir["#{bundler_dir}/
|
80
|
+
gem_files = Dir["#{bundler_dir}/#{target_pair}/dirs/**/**"] +
|
81
|
+
Dir["#{bundler_dir}/#{target_pair}/gems/**/**"] +
|
82
|
+
Dir["#{bundler_dir}/#{target_pair}/environment.rb"] +
|
79
83
|
Dir["#{bundler_dir}/environment.rb"]
|
80
84
|
Zip::ZipFile.open(app.gems_jar, 'w') do |jar|
|
81
85
|
gem_files.reject {|f| f == app.gems_jar}.each do |file|
|
82
|
-
|
86
|
+
if file[-4..-1].eql? '.jar'
|
87
|
+
puts "Installing #{File.basename(file)}"
|
88
|
+
FileUtils.cp file, app.webinf_lib
|
89
|
+
else
|
90
|
+
jar.add(file.sub("#{app.gems_dir}/",''), file)
|
91
|
+
end
|
83
92
|
end
|
84
93
|
end
|
85
94
|
end
|
@@ -87,9 +96,7 @@ module AppEngine
|
|
87
96
|
def verify_gemfile
|
88
97
|
return if File.exists?(app.gemfile)
|
89
98
|
puts "=> Generating gemfile"
|
90
|
-
|
91
|
-
# TODO: Maybe we should include the latest
|
92
|
-
# versions from updatecheck here?
|
99
|
+
# TODO: include the latest versions from updatecheck here?
|
93
100
|
stock_gemfile = <<EOF
|
94
101
|
# Critical default settings:
|
95
102
|
disable_system_gems
|
@@ -98,8 +105,6 @@ bundle_path ".gems/bundler_gems"
|
|
98
105
|
|
99
106
|
# List gems to bundle here:
|
100
107
|
gem "appengine-rack"
|
101
|
-
#gem "dm-appengine"
|
102
|
-
#gem "sinatra"
|
103
108
|
EOF
|
104
109
|
File.open(app.gemfile,'w') {|f| f.write(stock_gemfile) }
|
105
110
|
end
|
Binary file
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# Copyright:: Copyright 2010 Google Inc.
|
3
|
+
# Original Author:: John Woodell (mailto:woodie@google.com)
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module AppEngine
|
18
|
+
module JRubyJars
|
19
|
+
JRUBYRACK_VERSION = '0.9.6'
|
20
|
+
|
21
|
+
def self.jrubyrack_jar
|
22
|
+
File.join(File.dirname(__FILE__), "jruby-rack-#{JRUBYRACK_VERSION}.jar")
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
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.8.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Brown
|
8
|
+
- John Woodell
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
12
|
|
12
|
-
date:
|
13
|
+
date: 2010-01-20 00:00:00 -08:00
|
13
14
|
default_executable:
|
14
15
|
dependencies:
|
15
16
|
- !ruby/object:Gem::Dependency
|
@@ -50,7 +51,7 @@ dependencies:
|
|
50
51
|
requirements:
|
51
52
|
- - ~>
|
52
53
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.
|
54
|
+
version: 0.8.1
|
54
55
|
version:
|
55
56
|
- !ruby/object:Gem::Dependency
|
56
57
|
name: rubyzip
|
@@ -62,8 +63,13 @@ dependencies:
|
|
62
63
|
- !ruby/object:Gem::Version
|
63
64
|
version: "0"
|
64
65
|
version:
|
65
|
-
description:
|
66
|
-
|
66
|
+
description: |
|
67
|
+
Tools and SDK for developing Ruby applications for Google App Engine.
|
68
|
+
Includes a local development server and tools for testing and deployment."
|
69
|
+
|
70
|
+
email:
|
71
|
+
- ribrdb@google.com
|
72
|
+
- woodie@google.com
|
67
73
|
executables:
|
68
74
|
- appcfg.rb
|
69
75
|
- dev_appserver.rb
|
@@ -73,9 +79,11 @@ extra_rdoc_files:
|
|
73
79
|
- README.rdoc
|
74
80
|
- LICENSE
|
75
81
|
files:
|
82
|
+
- COPYING
|
76
83
|
- LICENSE
|
77
84
|
- README.rdoc
|
78
85
|
- Rakefile
|
86
|
+
- lib/jruby-rack-0.9.6.jar
|
79
87
|
- lib/appengine-tools/appcfg.rb
|
80
88
|
- lib/appengine-tools/boot.rb
|
81
89
|
- lib/appengine-tools/bundler.rb
|
@@ -84,12 +92,13 @@ files:
|
|
84
92
|
- lib/appengine-tools/update_check.rb
|
85
93
|
- lib/appengine-tools/web-xml.rb
|
86
94
|
- lib/appengine-tools/xml-formatter.rb
|
95
|
+
- lib/jruby-rack-jar.rb
|
96
|
+
- lib/appengine-tools/com/google/appengine/jruby/AppVersionUploadDelegate.class
|
97
|
+
- lib/appengine-tools/com/google/appengine/jruby/JRubyAppVersionUpload.class
|
87
98
|
- spec/rack_spec.rb
|
88
99
|
- spec/spec_helper.rb
|
89
100
|
- spec/update_check_spec.rb
|
90
101
|
- spec/web-xml_spec.rb
|
91
|
-
- lib/appengine-tools/com/google/appengine/jruby/AppVersionUploadDelegate.class
|
92
|
-
- lib/appengine-tools/com/google/appengine/jruby/JRubyAppVersionUpload.class
|
93
102
|
has_rdoc: true
|
94
103
|
homepage: http://code.google.com/p/appengine-jruby
|
95
104
|
licenses: []
|
@@ -107,9 +116,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
107
116
|
version:
|
108
117
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
118
|
requirements:
|
110
|
-
- - "
|
119
|
+
- - ">"
|
111
120
|
- !ruby/object:Gem::Version
|
112
|
-
version:
|
121
|
+
version: 1.3.1
|
113
122
|
version:
|
114
123
|
requirements: []
|
115
124
|
|