killbill 3.2.4 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -2
- data/.travis.yml +26 -5
- data/Gemfile +1 -1
- data/Gemfile.head +5 -0
- data/Gemfile.lock +125 -0
- data/Jarfile +9 -9
- data/Jarfile.lock +54 -0
- data/NEWS +3 -0
- data/README.md +13 -0
- data/VERSION +1 -1
- data/generators/active_merchant/templates/.gitignore.rb +2 -3
- data/generators/active_merchant/templates/.travis.yml.rb +22 -3
- data/generators/active_merchant/templates/Gemfile.head.rb +5 -0
- data/generators/active_merchant/templates/Gemfile.rb +1 -1
- data/generators/active_merchant/templates/Jarfile.rb +9 -8
- data/generators/active_merchant/templates/LICENSE.rb +2 -2
- data/generators/active_merchant/templates/config.yml.rb +16 -6
- data/generators/active_merchant/templates/lib/plugin.rb +0 -1
- data/generators/active_merchant/templates/plugin.gemspec.rb +17 -15
- data/generators/active_merchant/templates/pom.xml.rb +1 -1
- data/generators/active_merchant/templates/release.sh.rb +34 -14
- data/generators/active_merchant/templates/spec/base_plugin_spec.rb +5 -7
- data/generators/active_merchant/templates/spec/integration_spec.rb +7 -18
- data/killbill.gemspec +21 -15
- data/lib/killbill/ext/active_merchant/typhoeus_connection.rb +3 -4
- data/lib/killbill/gen/api/account.rb +1 -1
- data/lib/killbill/gen/api/account_data.rb +1 -1
- data/lib/killbill/gen/api/audit_log.rb +2 -2
- data/lib/killbill/gen/api/audit_user_api.rb +3 -3
- data/lib/killbill/gen/api/block.rb +1 -1
- data/lib/killbill/gen/api/blocking_state.rb +1 -1
- data/lib/killbill/gen/api/call_context.rb +2 -2
- data/lib/killbill/gen/api/control_tag.rb +2 -2
- data/lib/killbill/gen/api/currency_conversion.rb +1 -1
- data/lib/killbill/gen/api/currency_conversion_api.rb +2 -2
- data/lib/killbill/gen/api/custom_field.rb +1 -1
- data/lib/killbill/gen/api/custom_field_user_api.rb +2 -2
- data/lib/killbill/gen/api/dry_run_arguments.rb +22 -3
- data/lib/killbill/gen/api/duration.rb +1 -1
- data/lib/killbill/gen/api/entitlement.rb +3 -3
- data/lib/killbill/gen/api/entitlement_ao_status_dry_run.rb +3 -3
- data/lib/killbill/gen/api/entitlement_api.rb +25 -7
- data/lib/killbill/gen/api/fixed.rb +1 -1
- data/lib/killbill/gen/api/invoice.rb +1 -1
- data/lib/killbill/gen/api/invoice_formatter.rb +2 -2
- data/lib/killbill/gen/api/invoice_item.rb +2 -2
- data/lib/killbill/gen/api/invoice_item_formatter.rb +2 -2
- data/lib/killbill/gen/api/invoice_payment.rb +3 -3
- data/lib/killbill/gen/api/invoice_user_api.rb +2 -2
- data/lib/killbill/gen/api/migration_plan.rb +1 -1
- data/lib/killbill/gen/api/mutable_account_data.rb +1 -1
- data/lib/killbill/gen/api/payment.rb +1 -1
- data/lib/killbill/gen/api/payment_api.rb +11 -11
- data/lib/killbill/gen/api/payment_transaction.rb +4 -4
- data/lib/killbill/gen/api/plan.rb +1 -1
- data/lib/killbill/gen/api/plan_change_result.rb +2 -2
- data/lib/killbill/gen/api/plan_phase.rb +1 -1
- data/lib/killbill/gen/api/plan_phase_price_override.rb +93 -0
- data/lib/killbill/gen/api/plan_phase_price_overrides_with_call_context.rb +77 -0
- data/lib/killbill/gen/api/plan_phase_specifier.rb +3 -3
- data/lib/killbill/gen/api/plan_specifier.rb +2 -2
- data/lib/killbill/gen/api/price.rb +1 -1
- data/lib/killbill/gen/api/product.rb +1 -1
- data/lib/killbill/gen/api/rate.rb +2 -2
- data/lib/killbill/gen/api/record_id_api.rb +1 -1
- data/lib/killbill/gen/api/recurring.rb +1 -1
- data/lib/killbill/gen/api/refund.rb +2 -2
- data/lib/killbill/gen/api/require_gen.rb +2 -0
- data/lib/killbill/gen/api/static_catalog.rb +2 -2
- data/lib/killbill/gen/api/subscription.rb +3 -3
- data/lib/killbill/gen/api/subscription_event.rb +3 -3
- data/lib/killbill/gen/api/tag.rb +1 -1
- data/lib/killbill/gen/api/tag_definition.rb +1 -1
- data/lib/killbill/gen/api/tag_user_api.rb +6 -6
- data/lib/killbill/gen/api/tiered_block.rb +1 -1
- data/lib/killbill/gen/api/usage.rb +3 -3
- data/lib/killbill/gen/plugin-api/currency_plugin_api.rb +1 -1
- data/lib/killbill/gen/plugin-api/ext_bus_event.rb +2 -2
- data/lib/killbill/gen/plugin-api/payment_transaction_info_plugin.rb +3 -3
- data/lib/killbill/helpers/active_merchant.rb +2 -2
- data/lib/killbill/helpers/active_merchant/active_record.rb +1 -1
- data/lib/killbill/helpers/active_merchant/active_record/active_record_helper.rb +14 -0
- data/lib/killbill/helpers/active_merchant/active_record/models/helpers.rb +8 -0
- data/lib/killbill/helpers/active_merchant/active_record/models/payment_method.rb +10 -8
- data/lib/killbill/helpers/active_merchant/active_record/models/response.rb +16 -3
- data/lib/killbill/helpers/active_merchant/active_record/models/streamy_result_set.rb +1 -3
- data/lib/killbill/helpers/active_merchant/active_record/models/transaction.rb +2 -0
- data/lib/killbill/helpers/active_merchant/configuration.rb +119 -27
- data/lib/killbill/helpers/active_merchant/gateway.rb +40 -27
- data/lib/killbill/helpers/active_merchant/killbill_spec_helper.rb +63 -45
- data/lib/killbill/helpers/active_merchant/payment_plugin.rb +121 -95
- data/lib/killbill/helpers/active_merchant/private_payment_plugin.rb +1 -1
- data/lib/killbill/helpers/active_merchant/properties.rb +9 -2
- data/lib/killbill/helpers/active_merchant/sinatra.rb +4 -8
- data/lib/killbill/helpers/active_merchant/utils.rb +44 -0
- data/lib/killbill/helpers/properties_helper.rb +41 -0
- data/lib/killbill/http_servlet.rb +11 -4
- data/lib/killbill/killbill_api.rb +6 -4
- data/lib/killbill/rake_task.rb +542 -102
- data/spec/killbill/helpers/configuration_spec.rb +117 -33
- data/spec/killbill/helpers/payment_method_spec.rb +20 -17
- data/spec/killbill/helpers/payment_plugin_spec.rb +401 -201
- data/spec/killbill/helpers/private_payment_plugin_spec.rb +3 -16
- data/spec/killbill/helpers/response_spec.rb +92 -22
- data/spec/killbill/helpers/streamy_result_set_spec.rb +3 -2
- data/spec/killbill/helpers/test_payment_method.rb +9 -0
- data/spec/killbill/helpers/test_response.rb +11 -0
- data/spec/killbill/helpers/test_schema.rb +6 -6
- data/spec/killbill/helpers/test_transaction.rb +11 -0
- data/spec/killbill/helpers/transaction_spec.rb +3 -13
- data/spec/killbill/helpers/utils_spec.rb +127 -69
- data/spec/spec_helper.rb +69 -18
- metadata +77 -71
- data/lib/killbill/ext/active_merchant/jdbc_connection.rb +0 -92
- data/lib/killbill/ext/active_merchant/proxy_support.rb +0 -58
- data/spec/killbill/helpers/gateway_spec.rb +0 -36
@@ -87,7 +87,7 @@ module Killbill
|
|
87
87
|
|
88
88
|
def gateway(payment_processor_account_id=:default, kb_tenant_id=nil)
|
89
89
|
gateway = ::Killbill::Plugin::ActiveMerchant.gateways(kb_tenant_id)[payment_processor_account_id.to_sym]
|
90
|
-
raise "Unable to lookup gateway for payment_processor_account_id #{payment_processor_account_id},
|
90
|
+
raise "Unable to lookup gateway for payment_processor_account_id #{payment_processor_account_id}, kb_tenant_id = #{kb_tenant_id}, gateways: #{::Killbill::Plugin::ActiveMerchant.gateways(kb_tenant_id)}" if gateway.nil?
|
91
91
|
gateway
|
92
92
|
end
|
93
93
|
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'yaml'
|
3
|
+
|
1
4
|
module Killbill
|
2
5
|
module Plugin
|
3
6
|
module ActiveMerchant
|
@@ -8,13 +11,17 @@ module Killbill
|
|
8
11
|
|
9
12
|
def parse!
|
10
13
|
raise "#{@config_file} is not a valid file" unless @config_file.file?
|
11
|
-
@config = YAML.
|
14
|
+
@config = YAML.load(ERB.new(File.read(@config_file.to_s)).result)
|
12
15
|
end
|
13
16
|
|
14
17
|
def [](key)
|
15
18
|
@config[key]
|
16
19
|
end
|
20
|
+
|
21
|
+
def to_hash
|
22
|
+
@config.dup
|
23
|
+
end
|
17
24
|
end
|
18
25
|
end
|
19
26
|
end
|
20
|
-
end
|
27
|
+
end
|
@@ -5,10 +5,11 @@ module Killbill
|
|
5
5
|
enable :sessions
|
6
6
|
|
7
7
|
include ::ActionView::Helpers::FormTagHelper
|
8
|
+
include ::Killbill::Plugin::ActiveMerchant::ActiveRecordHelper
|
8
9
|
|
9
10
|
helpers do
|
10
|
-
def config
|
11
|
-
::Killbill::Plugin::ActiveMerchant.config
|
11
|
+
def config(kb_tenant_id=nil)
|
12
|
+
::Killbill::Plugin::ActiveMerchant.config(kb_tenant_id)
|
12
13
|
end
|
13
14
|
|
14
15
|
def logger
|
@@ -22,12 +23,7 @@ module Killbill
|
|
22
23
|
|
23
24
|
after do
|
24
25
|
# return DB connections to the Pool if required
|
25
|
-
|
26
|
-
if pool.active_connection?
|
27
|
-
connection = ::ActiveRecord::Base.connection
|
28
|
-
pool.remove(connection)
|
29
|
-
connection.disconnect!
|
30
|
-
end
|
26
|
+
close_connection(logger)
|
31
27
|
end
|
32
28
|
end
|
33
29
|
end
|
@@ -31,6 +31,33 @@ module Killbill
|
|
31
31
|
Socket.ip_address_list.detect { |intf| intf.ipv4? and !intf.ipv4_loopback? and !intf.ipv4_multicast? and !intf.ipv4_private? }
|
32
32
|
end
|
33
33
|
|
34
|
+
# Note: we assume options only contains keys as symbols
|
35
|
+
def self.normalized(options, key)
|
36
|
+
if !options.has_key?(key)
|
37
|
+
# Be friendly with Java-style conventions
|
38
|
+
camelized_key = key.to_s.camelize(false).to_sym
|
39
|
+
options.has_key?(camelized_key) ? normalize(options[camelized_key]) : nil
|
40
|
+
else
|
41
|
+
normalize(options[key])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.normalize(value)
|
46
|
+
case value.respond_to?(:strip) ? value.strip : value
|
47
|
+
when 'true' then true
|
48
|
+
when :true then true
|
49
|
+
when 'yes' then true
|
50
|
+
when :yes then true
|
51
|
+
when 'false' then false
|
52
|
+
when :false then false
|
53
|
+
when 'no' then false
|
54
|
+
when :no then false
|
55
|
+
when '' then nil
|
56
|
+
when 'null' then nil
|
57
|
+
else value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
34
61
|
class KBWiredumpDevice < IO
|
35
62
|
|
36
63
|
# Required for compatibility, but unused
|
@@ -48,6 +75,23 @@ module Killbill
|
|
48
75
|
end
|
49
76
|
end
|
50
77
|
|
78
|
+
class LazyEvaluator
|
79
|
+
|
80
|
+
def initialize(&instantiator)
|
81
|
+
@instantiator = instantiator
|
82
|
+
end
|
83
|
+
|
84
|
+
def method_missing(method, *args)
|
85
|
+
__instance_object__.send(method, *args)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def __instance_object__
|
91
|
+
@__instance_object__ ||= @instantiator.call
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
51
95
|
class BoundedLRUCache
|
52
96
|
include ThreadSafe::Util::CheapLockable
|
53
97
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Killbill
|
2
|
+
module Plugin
|
3
|
+
module PropertiesHelper
|
4
|
+
|
5
|
+
def find_value_from_properties(properties, key = nil)
|
6
|
+
return nil if key.nil?
|
7
|
+
prop = (properties.find { |kv| kv.key.to_s == key.to_s })
|
8
|
+
prop.nil? ? nil : prop.value
|
9
|
+
end
|
10
|
+
|
11
|
+
def hash_to_properties(options = {})
|
12
|
+
merge_properties([], options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def properties_to_hash(properties, options = {})
|
16
|
+
merged = {}
|
17
|
+
(properties || []).each do |p|
|
18
|
+
merged[p.key.to_sym] = p.value
|
19
|
+
end
|
20
|
+
merged.merge(options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def merge_properties(properties, options = {})
|
24
|
+
merged = properties_to_hash(properties, options)
|
25
|
+
|
26
|
+
properties = []
|
27
|
+
merged.each do |k, v|
|
28
|
+
properties << build_property(k, v)
|
29
|
+
end
|
30
|
+
properties
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_property(key, value = nil)
|
34
|
+
prop = ::Killbill::Plugin::Model::PluginProperty.new
|
35
|
+
prop.key = key
|
36
|
+
prop.value = value
|
37
|
+
prop
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -55,7 +55,14 @@ module Killbill
|
|
55
55
|
headers[name] = servlet_request.get_headers(name).to_a
|
56
56
|
end
|
57
57
|
|
58
|
-
|
58
|
+
# Pass original attributes (e.g. to get access to killbill_tenant)
|
59
|
+
attributes = {}
|
60
|
+
servlet_request.attribute_names.each do |name|
|
61
|
+
value = servlet_request.get_attribute(name)
|
62
|
+
attributes[name] = value
|
63
|
+
end
|
64
|
+
|
65
|
+
response_status, response_headers, response_body = rack_service(request_uri, method, query_string, input, scheme, server_name, server_port, content_type, content_length, headers, attributes)
|
59
66
|
|
60
67
|
# Set status
|
61
68
|
servlet_response.status = response_status
|
@@ -80,10 +87,10 @@ module Killbill
|
|
80
87
|
response_body.close if response_body.respond_to? :close
|
81
88
|
end
|
82
89
|
|
83
|
-
def rack_service(request_uri = '/', method = 'GET', query_string = '', input = '', scheme = 'http', server_name = 'localhost', server_port = 4567, content_type = 'text/plain', content_length = 0, headers = {})
|
90
|
+
def rack_service(request_uri = '/', method = 'GET', query_string = '', input = '', scheme = 'http', server_name = 'localhost', server_port = 4567, content_type = 'text/plain', content_length = 0, headers = {}, attributes = {})
|
84
91
|
return 503, {}, [] if @app.nil?
|
85
92
|
|
86
|
-
rack_env = {
|
93
|
+
rack_env = attributes.merge({
|
87
94
|
'rack.version' => Rack::VERSION,
|
88
95
|
'rack.multithread' => true,
|
89
96
|
'rack.multiprocess' => false,
|
@@ -99,7 +106,7 @@ module Killbill
|
|
99
106
|
'QUERY_STRING' => (query_string || ""),
|
100
107
|
'SERVER_NAME' => server_name,
|
101
108
|
'SERVER_PORT' => server_port.to_s
|
102
|
-
}
|
109
|
+
})
|
103
110
|
|
104
111
|
rack_env['CONTENT_TYPE'] = content_type unless content_type.nil?
|
105
112
|
rack_env['CONTENT_LENGTH'] = content_length unless content_length.nil?
|
@@ -8,10 +8,14 @@ module Killbill
|
|
8
8
|
#
|
9
9
|
class KillbillApi
|
10
10
|
|
11
|
-
|
11
|
+
# @VisibleForTesting
|
12
|
+
attr_reader :proxied_services
|
13
|
+
|
14
|
+
def initialize(plugin_name, proxied_services)
|
12
15
|
@plugin_name = plugin_name
|
16
|
+
@proxied_services = proxied_services
|
13
17
|
@services = {}
|
14
|
-
|
18
|
+
proxied_services.each do |k,v|
|
15
19
|
@services[k.to_sym] = create_proxy_api(k, v)
|
16
20
|
end
|
17
21
|
end
|
@@ -24,7 +28,6 @@ module Killbill
|
|
24
28
|
raise NoMethodError.new("undefined method `#{m}' for #{self}")
|
25
29
|
end
|
26
30
|
|
27
|
-
|
28
31
|
def create_context(tenant_id=nil, user_token=nil, reason_code=nil, comments=nil)
|
29
32
|
context = Killbill::Plugin::Model::CallContext.new
|
30
33
|
context.tenant_id= tenant_id
|
@@ -45,7 +48,6 @@ module Killbill
|
|
45
48
|
proxy_class_name = "Killbill::Plugin::Api::#{api_name.to_s.split('_').map{|e| e.capitalize}.join}"
|
46
49
|
proxy_class_name.to_class.new(java_api)
|
47
50
|
end
|
48
|
-
|
49
51
|
end
|
50
52
|
end
|
51
53
|
end
|
data/lib/killbill/rake_task.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
require 'logger'
|
3
3
|
require 'pathname'
|
4
|
+
require 'tmpdir'
|
4
5
|
require 'rake'
|
5
|
-
require 'rake/packagetask'
|
6
6
|
require 'rubygems/installer'
|
7
7
|
|
8
8
|
module Killbill
|
@@ -11,12 +11,13 @@ module Killbill
|
|
11
11
|
|
12
12
|
class << self
|
13
13
|
def install_tasks(opts = {})
|
14
|
-
|
15
|
-
|
16
|
-
opts[:
|
17
|
-
opts[:
|
18
|
-
opts[:
|
19
|
-
opts[:
|
14
|
+
gemfile_name = ENV['BUNDLE_GEMFILE'] || 'Gemfile'
|
15
|
+
new(opts[:base_name] || Dir.pwd, # Path to the plugin root directory (where the gempec and/or Gemfile should be)
|
16
|
+
opts[:plugin_name], # Plugin name, e.g. 'klogger'
|
17
|
+
opts[:gem_name], # Gem file name, e.g. 'klogger-1.0.0.gem'
|
18
|
+
opts[:gemfile_name] || gemfile_name, # Gemfile name
|
19
|
+
opts[:gemfile_lock_name] || "#{gemfile_name}.lock",
|
20
|
+
opts.key?(:verbose) ? opts[:verbose] : ENV['VERBOSE'] == 'true')
|
20
21
|
.install
|
21
22
|
end
|
22
23
|
end
|
@@ -25,6 +26,14 @@ module Killbill
|
|
25
26
|
@verbose = verbose
|
26
27
|
|
27
28
|
@logger = Logger.new(STDOUT)
|
29
|
+
@logger.formatter = proc do |severity, datetime, _, msg|
|
30
|
+
date_format = datetime.strftime('%Y-%m-%d %H:%M:%S.%L')
|
31
|
+
if severity == "INFO" || severity == "WARN"
|
32
|
+
"KillBill [#{date_format}] #{severity} : #{msg}\n"
|
33
|
+
else
|
34
|
+
"KillBill [#{date_format}] #{severity} : #{msg}\n"
|
35
|
+
end
|
36
|
+
end
|
28
37
|
@logger.level = @verbose ? Logger::DEBUG : Logger::INFO
|
29
38
|
|
30
39
|
@base_name = base_name
|
@@ -37,27 +46,70 @@ module Killbill
|
|
37
46
|
@base = Pathname.new(@base_name).expand_path
|
38
47
|
|
39
48
|
# Find the gemspec to determine name and version
|
40
|
-
@plugin_gemspec =
|
49
|
+
@plugin_gemspec = load_plugin_gemspec
|
41
50
|
|
51
|
+
@package_dir = Pathname.new('pkg').expand_path
|
52
|
+
FileUtils.mkdir_p @package_dir
|
42
53
|
# Temporary build directory
|
43
|
-
#
|
44
|
-
#
|
45
|
-
@
|
54
|
+
# will hard link all files from @package_tmp_dir to pkg to avoid tar'ing
|
55
|
+
# up symbolic links (similar to how Rake::PackageTask does prepare files)
|
56
|
+
@package_tmp_dir = Pathname.new(File.join('tmp', name)).expand_path
|
57
|
+
|
58
|
+
@root_dir_path = 'ROOT' # plugin's ROOT directory
|
59
|
+
@gems_dir_path = File.join(@root_dir_path, 'gems')
|
60
|
+
# Staging area to install the killbill.properties and config.ru files
|
61
|
+
@plugin_target_dir = @package_tmp_dir.join("#{version}").expand_path
|
62
|
+
@plugin_root_target_dir = @plugin_target_dir.join(@root_dir_path)
|
46
63
|
|
47
64
|
# Staging area to install gem dependencies
|
48
65
|
# Note the Killbill friendly structure (which we will keep in the tarball)
|
49
|
-
@
|
66
|
+
@plugin_gem_target_dir = @plugin_target_dir.join(@gems_dir_path)
|
67
|
+
end
|
50
68
|
|
51
|
-
|
52
|
-
|
69
|
+
attr_reader :base
|
70
|
+
|
71
|
+
def name
|
72
|
+
@plugin_gemspec.name
|
73
|
+
end
|
74
|
+
|
75
|
+
def version
|
76
|
+
@plugin_gemspec.version
|
53
77
|
end
|
54
78
|
|
55
79
|
def specs
|
56
80
|
# Rely on the Gemfile definition, if it exists, to get all dependencies
|
57
81
|
# (we assume the Gemfile includes the plugin gemspec, as it should).
|
58
|
-
# Otherwise, use
|
59
|
-
#
|
60
|
-
@specs ||=
|
82
|
+
# Otherwise, use recursively retrieve the plugin gemspec' runtime dependencies
|
83
|
+
# ... resolves all gems as they are currently installed with RubyGems
|
84
|
+
@specs ||=
|
85
|
+
if @gemfile_definition
|
86
|
+
# don't include the :development group
|
87
|
+
@gemfile_definition.specs_for([:default])
|
88
|
+
else
|
89
|
+
get_dependencies = lambda do |spec|
|
90
|
+
deps = ( spec.runtime_dependencies || [] ).map(&:to_spec)
|
91
|
+
deps.dup.each { |spec| deps += get_dependencies.call(spec) }
|
92
|
+
deps.uniq
|
93
|
+
end
|
94
|
+
all_dependencies = get_dependencies.call(@plugin_gemspec)
|
95
|
+
all_dependencies.dup.each do |spec|
|
96
|
+
next unless all_dependencies.include?(spec) # removed previously
|
97
|
+
|
98
|
+
# duplicate gemspec of same name might get included since we did
|
99
|
+
# not really do through the gem activation hustle, lowest version
|
100
|
+
# should win since those tend to be matched by strict requirements
|
101
|
+
if other_spec = all_dependencies.find { |s| s.name == spec.name && s != spec }
|
102
|
+
if other_spec.version > spec.version
|
103
|
+
@logger.debug "Discarding matched gem '#{spec.name}' version #{other_spec.version} in favor of #{spec.version}"
|
104
|
+
all_dependencies.delete(other_spec)
|
105
|
+
else # other_spec.version < spec.version
|
106
|
+
@logger.debug "Discarding matched gem '#{spec.name}' version #{spec.version} in favor of #{other_spec.version}"
|
107
|
+
all_dependencies.delete(spec)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
[ @plugin_gemspec ] + all_dependencies
|
112
|
+
end
|
61
113
|
end
|
62
114
|
|
63
115
|
def install
|
@@ -69,64 +121,175 @@ module Killbill
|
|
69
121
|
validate
|
70
122
|
end
|
71
123
|
|
72
|
-
|
73
|
-
task :package, [:verbose] => :stage
|
74
|
-
|
75
|
-
|
76
|
-
|
124
|
+
desc "Build all package files for #{name} plugin #{version}"
|
125
|
+
task :package, [:verbose] => :stage # builds .tar.gz & .zip packages
|
126
|
+
|
127
|
+
package_name = "#{name}-#{version}"
|
128
|
+
package_dir = @package_dir.realpath # pkg
|
129
|
+
package_dir_path = File.join(package_dir, package_name) # pkg/killbill-xxx-0.1.2
|
130
|
+
|
131
|
+
task :package => [ tar_gz_file = File.join(package_dir, "#{package_name}.tar.gz") ]
|
132
|
+
file tar_gz_file => [ package_dir_path, 'package:files' ] do
|
133
|
+
chdir(package_dir) do
|
134
|
+
tar_command = 'tar'
|
135
|
+
sh tar_command, "zcvf", tar_gz_file, package_name
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
task :package => [ zip_file = File.join(package_dir, "#{package_name}.zip") ]
|
140
|
+
file zip_file => [ package_dir_path, 'package:files' ] do
|
141
|
+
chdir(package_dir) do
|
142
|
+
zip_command = 'zip'
|
143
|
+
sh zip_command, "-r", zip_file, package_name
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
directory package_dir_path
|
148
|
+
task 'package:files' do
|
149
|
+
# move files from tmp directory to pkg (based on how rake does)
|
150
|
+
basename = Regexp.escape(@package_tmp_dir.basename.to_s)
|
151
|
+
tmp_path = @package_tmp_dir.realpath.to_s
|
152
|
+
realpath_tmp_prefix = tmp_path.sub(/\/#{basename}$/, '')
|
153
|
+
package_files = Rake::FileList.new("#{tmp_path}/**/*")
|
154
|
+
|
155
|
+
package_files.each do |fn|
|
156
|
+
f = File.join(package_dir_path, fn.sub(realpath_tmp_prefix, ''))
|
157
|
+
fdir = File.dirname(f)
|
158
|
+
mkdir_p(fdir) unless File.exist?(fdir)
|
159
|
+
if File.directory?(fn)
|
160
|
+
mkdir_p(f)
|
161
|
+
else
|
162
|
+
rm_f f
|
163
|
+
safe_ln(fn, f)
|
164
|
+
end
|
165
|
+
end
|
77
166
|
end
|
78
167
|
|
79
|
-
desc "
|
80
|
-
task :
|
168
|
+
desc "Force a rebuild of package files for #{name} plugin #{version}"
|
169
|
+
task :repackage => [:clobber_package, :package]
|
170
|
+
|
171
|
+
task :clobber_tmp do
|
172
|
+
rm_f @package_tmp_dir rescue nil
|
173
|
+
end
|
174
|
+
|
175
|
+
desc "Remove package files from #{@package_dir}"
|
176
|
+
task :clobber_package do
|
177
|
+
rm_f tar_gz_file if File.exist?(tar_gz_file)
|
178
|
+
rm_f zip_file if File.exist?(zip_file)
|
179
|
+
rm_r package_dir_path rescue nil
|
180
|
+
end
|
181
|
+
task :clobber => [:clobber_tmp, :clobber_package]
|
182
|
+
|
183
|
+
task 'stage:init' do
|
184
|
+
# NOOP task for plugins to hook up if they need some sort of initialization
|
185
|
+
# (task will be run in the context of the Killbill::PluginHelper instance)
|
186
|
+
# NOTE: no need for post (stage:done) hook since it's easy using Rake :
|
187
|
+
# Rake::Task["killbill:package"].enhance { ... }
|
188
|
+
end
|
189
|
+
|
190
|
+
desc "Stage dependencies for #{name} plugin #{version}"
|
191
|
+
task :stage, [:verbose] => [ :validate, 'stage:init' ] do |t, args|
|
81
192
|
set_verbosity(args)
|
82
193
|
|
194
|
+
mkdir_p @plugin_target_dir.to_s, :verbose => @verbose
|
195
|
+
|
83
196
|
stage_dependencies
|
84
197
|
stage_extra_files
|
85
|
-
|
86
|
-
# Small hack! Update the list of files to package (Rake::FileList is evaluated too early above)
|
87
|
-
package_task.package_files = Rake::FileList.new("#{@package_dir.basename}/**/*")
|
88
198
|
end
|
89
199
|
|
90
|
-
desc "Deploy
|
200
|
+
desc "Deploy #{name} plugin #{version} to KillBill server"
|
91
201
|
task :deploy, [:force, :plugin_dir, :verbose] => :stage do |t, args|
|
92
|
-
|
202
|
+
plugins_dir = prepare_deploy(t, args)
|
93
203
|
|
94
|
-
plugins_dir
|
95
|
-
mkdir_p plugins_dir, :verbose => @verbose
|
204
|
+
cp_r @package_tmp_dir, plugins_dir, :verbose => @verbose
|
96
205
|
|
97
|
-
plugin_path
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
206
|
+
deploy_config_files plugin_path(plugins_dir) # .../[name]/[version]
|
207
|
+
end
|
208
|
+
|
209
|
+
desc "Deploy plugin in development mode (without staging)"
|
210
|
+
task 'deploy:dev', [:force, :plugin_dir, :verbose] => :validate do |t, args|
|
211
|
+
raise 'development deployment only works with Bundler' unless bundler?
|
212
|
+
|
213
|
+
plugins_dir = prepare_deploy(t, args)
|
106
214
|
|
107
|
-
|
215
|
+
# prepare "temporary" deployment at tmp/deploy:dev
|
216
|
+
package_tmp_dir = Pathname.new(File.join('tmp', 'deploy:dev')).expand_path
|
217
|
+
rm_r package_tmp_dir if File.exist?(package_tmp_dir)
|
218
|
+
mkdir_p package_tmp_dir.to_s, :verbose => @verbose
|
108
219
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
220
|
+
mkdir target_dir = package_tmp_dir.join(version.to_s)
|
221
|
+
|
222
|
+
# NOTE: although same _boot.rb_ as with regular deploys might not work
|
223
|
+
stage_extra_files target_dir
|
224
|
+
if boot_rb_file.nil?
|
225
|
+
generate_dev_boot_rb target_dir
|
226
|
+
else
|
227
|
+
@logger.info "Make sure the suplied #{boot_rb_file} is removed/adjusted before doing a regular killbill:deploy (same boot.rb won't likely work)"
|
113
228
|
end
|
229
|
+
|
230
|
+
# here we assume Gemfile declares gemspec and we link ROOT to base :
|
231
|
+
ln_s @base, target_dir.join(@root_dir_path), :verbose => @verbose
|
232
|
+
|
233
|
+
# ln -s /var/tmp/bundles/plugins/ruby/killbill-xxx -> tmp/deploy:dev
|
234
|
+
ln_s package_tmp_dir, plugins_dir.join(name), :verbose => @verbose
|
235
|
+
|
236
|
+
deploy_config_files target_dir
|
114
237
|
end
|
115
238
|
|
116
239
|
desc "List all dependencies"
|
117
|
-
task :
|
240
|
+
task :dependencies => :validate do
|
118
241
|
print_dependencies
|
119
242
|
end
|
243
|
+
task :dependency => :dependencies
|
120
244
|
|
121
245
|
desc "Delete #{@package_dir}"
|
122
|
-
task :clean => :
|
123
|
-
|
246
|
+
task :clean => :clobber do
|
247
|
+
rm_r @package_dir if File.exist?(@package_dir)
|
124
248
|
end
|
125
249
|
end
|
126
250
|
end
|
127
251
|
|
128
252
|
private
|
129
253
|
|
254
|
+
def plugin_path(plugins_dir, versioned = true)
|
255
|
+
plugin_path = plugins_dir.join(name)
|
256
|
+
versioned ? plugin_path.join(version.to_s) : plugin_path
|
257
|
+
end
|
258
|
+
|
259
|
+
# (shared) deploy task(s) helper
|
260
|
+
# @return _plugins_ directory
|
261
|
+
def prepare_deploy(t, args)
|
262
|
+
set_verbosity(args)
|
263
|
+
|
264
|
+
plugins_dir = Pathname.new("#{args.plugin_dir || '/var/tmp/bundles/plugins/ruby'}").expand_path
|
265
|
+
mkdir_p plugins_dir, :verbose => @verbose
|
266
|
+
|
267
|
+
plugin_path = plugin_path(plugins_dir, false) # "#{plugins_dir}/#{name}"
|
268
|
+
if plugin_path.exist?
|
269
|
+
if args.force == "true"
|
270
|
+
safe_unlink plugin_path # if link (deploy:dev) just remove the link
|
271
|
+
if plugin_path.exist?
|
272
|
+
@logger.info "Deleting previous plugin deployment #{plugin_path}"
|
273
|
+
rm_rf plugin_path, :verbose => @verbose if plugin_path.exist?
|
274
|
+
else
|
275
|
+
@logger.info "Unlinked previous plugin deployment #{plugin_path}"
|
276
|
+
end
|
277
|
+
else
|
278
|
+
raise "Cowardly not deleting previous plugin deployment #{plugin_path} - override with rake #{t.name}[true]"
|
279
|
+
end
|
280
|
+
end
|
281
|
+
plugins_dir
|
282
|
+
end
|
283
|
+
|
284
|
+
# (shared) deploy task(s) helper
|
285
|
+
def deploy_config_files(path, config_files = Rake::FileList.new("#{@base}/*.yml"))
|
286
|
+
config_files.each do |config_file|
|
287
|
+
config_file_path = File.join(path, File.basename(config_file))
|
288
|
+
@logger.info "Deploying #{config_file} to #{config_file_path}"
|
289
|
+
cp config_file, config_file_path, :verbose => @verbose
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
130
293
|
def set_verbosity(args)
|
131
294
|
return unless args.verbose == 'true'
|
132
295
|
@verbose = true
|
@@ -134,106 +297,257 @@ module Killbill
|
|
134
297
|
end
|
135
298
|
|
136
299
|
def validate
|
137
|
-
@gemfile_definition =
|
300
|
+
if @gemfile_definition = build_gemfile
|
301
|
+
@gemfile_definition.resolve
|
302
|
+
end
|
303
|
+
true
|
138
304
|
end
|
139
305
|
|
306
|
+
def bundler?; !! @gemfile_definition end
|
307
|
+
|
140
308
|
def print_dependencies
|
141
|
-
|
309
|
+
# NOTE: can be improved to include :git info and warn on gem :path
|
142
310
|
specs.each { |spec| puts " #{spec.name} (#{spec.version})" }
|
143
311
|
end
|
144
312
|
|
145
|
-
def name
|
146
|
-
@plugin_gemspec.name
|
147
|
-
end
|
148
|
-
|
149
|
-
def version
|
150
|
-
@plugin_gemspec.version
|
151
|
-
end
|
152
|
-
|
153
313
|
# Parse the <plugin_name>.gemspec file
|
154
|
-
def
|
314
|
+
def load_plugin_gemspec
|
155
315
|
gemspecs = @plugin_name ? [File.join(@base, "#{@plugin_name}.gemspec")] : Dir[File.join(@base, "{,*}.gemspec")]
|
156
|
-
raise "Unable to find your plugin gemspec in #{@base}"
|
316
|
+
raise "Unable to find your plugin gemspec in #{@base}" if gemspecs.size == 0
|
317
|
+
raise "Found multiple plugin gemspec in #{@base} : #{gemspecs.inspect}" if gemspecs.size > 1
|
157
318
|
spec_path = gemspecs.first
|
158
|
-
@logger.debug "
|
159
|
-
|
319
|
+
@logger.debug "Loading #{spec_path}"
|
320
|
+
Gem::Specification.load(spec_path)
|
160
321
|
end
|
161
322
|
|
162
323
|
def find_plugin_gem(spec)
|
163
|
-
gem_name
|
164
|
-
# spec.loaded_from is the path to the gemspec file
|
165
|
-
base = Pathname.new(File.dirname(spec.loaded_from)).expand_path
|
324
|
+
gem_name = spec.file_name
|
166
325
|
|
167
326
|
# Try in the base directory first
|
168
327
|
plugin_gem_file = Pathname.new(gem_name).expand_path
|
169
|
-
|
328
|
+
unless plugin_gem_file.file? # `rake build` (./pkg)
|
329
|
+
plugin_gem_file = Pathname.new(File.join('pkg', gem_name))
|
330
|
+
end
|
170
331
|
|
171
|
-
# Try in subdirectories next
|
172
332
|
unless plugin_gem_file.file?
|
173
|
-
|
174
|
-
@logger.debug "Gem candidates found: #{plugin_gem_files}"
|
175
|
-
# Take the first one, assume the other ones are from build directories (e.g. pkg)
|
176
|
-
plugin_gem_file = Pathname.new(plugin_gem_files.first).expand_path unless plugin_gem_files.empty?
|
333
|
+
raise "Unable to find #{gem_name}. Did you build it? (`rake build')"
|
177
334
|
end
|
178
335
|
|
179
|
-
raise "Unable to find #{gem_name} in #{base}. Did you build it? (`rake build')" unless plugin_gem_file.file?
|
180
|
-
|
181
336
|
@logger.debug "Found #{plugin_gem_file}"
|
182
|
-
|
337
|
+
plugin_gem_file.expand_path
|
338
|
+
end
|
339
|
+
|
340
|
+
def find_missing_gem(spec, silent = nil)
|
341
|
+
base = nil
|
342
|
+
if spec.loaded_from
|
343
|
+
# spec.loaded_from is (usually) the path to the gemspec file
|
344
|
+
base = Pathname.new(File.dirname(spec.loaded_from)).expand_path
|
345
|
+
if ! base.file?
|
346
|
+
base = nil unless base.directory?
|
347
|
+
end
|
348
|
+
end
|
349
|
+
unless base
|
350
|
+
base = spec.gems_dir if spec.respond_to?(:gems_dir)
|
351
|
+
base = spec.base_dir if spec.respond_to?(:base_dir)
|
352
|
+
end
|
353
|
+
# might end-up with a slightly incorrect resolution (due Bundler) :
|
354
|
+
# e.g. .../rvm/gems/jruby-1.7.19@global/gems/bundler-1.7.9/lib/bundler/gems
|
355
|
+
if base
|
356
|
+
parent = base
|
357
|
+
parent = parent.parent while ! parent.join('cache').directory?
|
358
|
+
base = parent if parent && parent.join('gems').directory? # RGs layout
|
359
|
+
end
|
360
|
+
|
361
|
+
gem_file = nil
|
362
|
+
gem_name = spec.file_name
|
363
|
+
gem_paths = Gem.paths.path.dup; gem_paths.unshift(base) if base
|
364
|
+
gem_paths.each do |gem_path| # e.g. /opt/rvm/gems/jruby-1.7.16@global
|
365
|
+
if File.directory? cache_dir = File.join(gem_path, 'cache')
|
366
|
+
if File.file? gem_file = File.join(cache_dir, gem_name)
|
367
|
+
gem_file = Pathname.new(gem_file); break
|
368
|
+
else
|
369
|
+
gem_file = nil
|
370
|
+
end
|
371
|
+
else
|
372
|
+
gem_files = Dir[File.join(gem_path, "**/#{gem_name}")]
|
373
|
+
unless gem_files.empty?
|
374
|
+
@logger.debug "Gem candidates found: #{gem_files.inspect}"
|
375
|
+
gem_file = Pathname.new(gem_files.first); break
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
if gem_file.nil? || ! gem_file.file?
|
381
|
+
return nil if silent
|
382
|
+
raise "Unable to find #{gem_name} under #{gem_paths.inspect}"
|
383
|
+
end
|
384
|
+
|
385
|
+
@logger.debug "Found #{gem_file}"
|
386
|
+
gem_file.expand_path
|
183
387
|
end
|
184
388
|
|
185
389
|
# Parse the existing Gemfile and Gemfile.lock files
|
186
|
-
def
|
187
|
-
gemfile =
|
390
|
+
def build_gemfile
|
391
|
+
gemfile = gemfile_path
|
188
392
|
# Don't make the Gemfile a requirement, a gemspec should be enough
|
189
393
|
return nil unless gemfile.file?
|
190
394
|
|
191
395
|
# Make sure the developer ran `bundle install' first. We could probably run
|
192
|
-
# Bundler::Installer::install(@
|
396
|
+
# Bundler::Installer::install(@plugin_gem_target_dir, @definition, {})
|
193
397
|
# but it may be better to make sure all dependencies are resolved first,
|
194
398
|
# before attempting to build the plugin
|
195
|
-
gemfile_lock =
|
196
|
-
raise "Unable to find the
|
399
|
+
gemfile_lock = gemfile_lock_path
|
400
|
+
raise "Unable to find the bundle .lock at #{gemfile_lock} for your plugin. Please run `bundle install' first" unless gemfile_lock.file?
|
197
401
|
|
198
402
|
@logger.debug "Parsing #{gemfile} and #{gemfile_lock}"
|
199
403
|
Bundler::Definition.build(gemfile, gemfile_lock, nil)
|
200
404
|
end
|
201
405
|
|
406
|
+
def gemfile_path
|
407
|
+
@base.join(@gemfile_name).expand_path
|
408
|
+
end
|
409
|
+
|
410
|
+
def gemfile_lock_path
|
411
|
+
@base.join(@gemfile_lock_name).expand_path
|
412
|
+
end
|
413
|
+
|
202
414
|
def stage_dependencies
|
203
415
|
# Create the target directory
|
204
|
-
mkdir_p @
|
416
|
+
mkdir_p @plugin_gem_target_dir.to_s, :verbose => @verbose
|
205
417
|
|
206
|
-
@logger.debug "Installing all gem dependencies to #{@
|
418
|
+
@logger.debug "Installing all gem dependencies to #{@plugin_gem_target_dir}"
|
207
419
|
# We can't simply use Bundler::Installer unfortunately, because we can't tell it to copy the gems for cached ones
|
208
420
|
# (it will default to using Bundler::Source::Path references to the gemspecs on "install").
|
421
|
+
|
422
|
+
generate_boot_rb if boot_rb_file.nil?
|
423
|
+
# else user-suplied boot.rb will be copied into the package
|
424
|
+
|
425
|
+
# part of copying the dependencies is getting Gemfile/Gemfile.lock in
|
426
|
+
# otherwise :git => gem dependencies would need work-arounds to work
|
427
|
+
copy_gemfile if bundler? # plugin gem build might re-copy, that's fine!
|
428
|
+
|
209
429
|
specs.each do |spec|
|
210
|
-
|
211
|
-
|
212
|
-
|
430
|
+
if ! gem_path = valid_gem_path(spec)
|
431
|
+
if gem_path == false # spec.name == name
|
432
|
+
# Gemfile very likely declares gemspec ... so we need to get that in
|
433
|
+
# yet the current way (the plugin gem must be built first) we can
|
434
|
+
# not simply copy spec.loaded_from into the package's root directory
|
435
|
+
# (the actual [PLUGIN_ROOT]/killbill-plugin.gemspec) as that depends
|
436
|
+
# on `git' binary on PATH (to get the actual gem.files)
|
437
|
+
@logger.info "Building #{spec.name} gem from #{spec.loaded_from}"
|
438
|
+
Dir.mktmpdir do |dir|
|
439
|
+
plugin_gem = Gem::Package.new(File.join(dir, spec.file_name))
|
440
|
+
plugin_gem.spec = spec
|
441
|
+
plugin_gem.build(true) # skip_validation
|
442
|
+
gemspec_name = File.basename(spec.loaded_from)
|
443
|
+
puts_to_root plugin_gem.spec.to_ruby, gemspec_name
|
444
|
+
# NOTE: further the unpacked gemspec will be read by Bundler and assumes
|
445
|
+
# the unpacked gem structure to be found on the file-system, extract :
|
446
|
+
plugin_gem.extract_files @plugin_root_target_dir
|
447
|
+
end
|
448
|
+
next
|
449
|
+
end
|
450
|
+
if bundler?
|
451
|
+
# gem not under gem cache_dir (default gem or multiple gem paths)
|
452
|
+
gem_path = find_missing_gem(spec)
|
453
|
+
@logger.debug "Staging #{spec.name} (#{spec.version}) from #{gem_path}"
|
454
|
+
do_install_gem(gem_path, spec)
|
455
|
+
else # mostly Bunder-less backwards-compatibility
|
456
|
+
gem_path = find_missing_gem(spec, :silent) || find_plugin_gem(spec)
|
457
|
+
@logger.info "Staging #{spec.full_name} from #{gem_path}"
|
458
|
+
do_install_gem(gem_path, spec)
|
459
|
+
end
|
460
|
+
elsif gem_path.file?
|
461
|
+
@logger.debug "Staging #{spec.name} (#{spec.version}) from #{gem_path}"
|
462
|
+
do_install_gem(gem_path, spec)
|
463
|
+
elsif gem_path.directory?
|
464
|
+
@logger.debug "Staging #{spec.name} (#{spec.version}) from #{gem_path}"
|
465
|
+
do_install_bundler(gem_path, spec)
|
213
466
|
else
|
214
|
-
|
215
|
-
@logger.info "Staging custom gem #{spec.full_name} from #{plugin_gem_file}"
|
467
|
+
raise "#{spec.name} gem path #{gem_path.inspect} does not exist"
|
216
468
|
end
|
469
|
+
end
|
470
|
+
end
|
217
471
|
|
218
|
-
|
472
|
+
def valid_gem_path(spec)
|
473
|
+
cache_file = File.join(spec.cache_dir, "#{spec.full_name}.gem")
|
474
|
+
cache_path = Pathname.new(cache_file).expand_path
|
475
|
+
return cache_path if cache_path.file?
|
476
|
+
return false if spec.name == name # it's the plugin gem itself
|
477
|
+
|
478
|
+
if spec.source && bundler? && spec.source.is_a?(Bundler::Source)
|
479
|
+
# Path < Source and Git < Path :
|
480
|
+
case spec.source
|
481
|
+
when Bundler::Source::Git
|
482
|
+
# NOTE cache_path only works with `bundle cache --all`
|
483
|
+
# when bundle cached install path points to cache
|
484
|
+
# e.g. ./vendor/cache/killbill-plugin-framework-ruby-ce5e19f45bc9
|
485
|
+
# otherwise it's the path from under RG (as usual for Bundler)
|
486
|
+
# e.g. [RVM]/gems/jruby-1.7.19@kb/bundler/gems/killbill-plugin-framework-ruby-ce5e19f45bc9
|
487
|
+
return spec.source.install_path
|
488
|
+
when Bundler::Source::Path
|
489
|
+
@logger.warn "gem '#{spec.name}' declares :path => '#{spec.source.path}' packaging will only work locally (while the path exists) !"
|
490
|
+
return spec.source.path
|
491
|
+
end
|
219
492
|
end
|
493
|
+
nil
|
494
|
+
end
|
495
|
+
|
496
|
+
def do_install_bundler(path, spec)
|
497
|
+
#full_gem_path = Pathname.new(spec.full_gem_path)
|
498
|
+
|
499
|
+
#gem_relative_path = full_gem_path.relative_path_from(Bundler.install_path)
|
500
|
+
#filenames = []; gem_relative_path.each_filename { |f| filenames << f }
|
501
|
+
|
502
|
+
#exclude_gems = true
|
503
|
+
#unless filenames.empty?
|
504
|
+
# full_gem_path = Pathname.new(Bundler.install_path) + filenames.first
|
505
|
+
# exclude_gems = false
|
506
|
+
#end
|
507
|
+
|
508
|
+
FileUtils.mkdir_p target_dir = File.join(@plugin_gem_target_dir, "bundler/gems")
|
509
|
+
|
510
|
+
if spec.groups.include?(:killbill_excluded)
|
511
|
+
Dir.glob("#{path}/**/#{spec.name}.gemspec").each do |file|
|
512
|
+
gem_target_file = File.join(target_dir, File.basename(file))
|
513
|
+
FileUtils.rm(gem_target_file) if File.exist?(gem_target_file)
|
514
|
+
FileUtils.cp(file, target_dir) # gemspec only to avert Bundler error
|
515
|
+
end
|
516
|
+
else
|
517
|
+
gem_target_dir = File.join(target_dir, File.basename(path))
|
518
|
+
FileUtils.rm_r(gem_target_dir) if File.exist?(gem_target_dir)
|
519
|
+
FileUtils.cp_r(path, target_dir)
|
520
|
+
# the copied .git directory is not needed (might be large) :
|
521
|
+
git_target_dir = File.join(gem_target_dir, '.git')
|
522
|
+
FileUtils.rm_r(git_target_dir) if File.exist?(git_target_dir)
|
523
|
+
end
|
524
|
+
rescue => e
|
525
|
+
@logger.warn "Unable to stage #{spec.name} from #{path}: #{e}"
|
526
|
+
raise e
|
220
527
|
end
|
221
528
|
|
222
|
-
def do_install_gem(path,
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
529
|
+
def do_install_gem(path, spec)
|
530
|
+
name, version = spec.name, spec.version
|
531
|
+
options = {
|
532
|
+
:force => true,
|
533
|
+
:install_dir => @plugin_gem_target_dir,
|
534
|
+
#:only_install_dir => true,
|
535
|
+
# Should be redundant with the tweaks below
|
536
|
+
:development => false,
|
537
|
+
:wrappers => true
|
538
|
+
}
|
539
|
+
if Gem::Installer.respond_to?(:at)
|
540
|
+
gem_installer = Gem::Installer.at(path.to_s, options)
|
541
|
+
else # constructing an Installer object with a string is deprecated
|
542
|
+
gem_installer = Gem::Installer.new(path.to_s, options)
|
543
|
+
end
|
231
544
|
|
232
545
|
# Tweak the spec file as there are a lot of things we don't care about
|
233
546
|
gem_installer.spec.executables = nil
|
234
|
-
gem_installer.spec.extensions = nil
|
235
547
|
gem_installer.spec.extra_rdoc_files = nil
|
236
548
|
gem_installer.spec.test_files = nil
|
549
|
+
# avoid the annoying post_install_message from money gem (and others)
|
550
|
+
gem_installer.spec.post_install_message = nil
|
237
551
|
|
238
552
|
gem_installer.install
|
239
553
|
rescue => e
|
@@ -241,17 +555,143 @@ module Killbill
|
|
241
555
|
raise e
|
242
556
|
end
|
243
557
|
|
244
|
-
def
|
558
|
+
def generate_boot_rb(target_dir = @plugin_target_dir)
|
559
|
+
@logger.debug "Generating boot.rb into #{target_dir}"
|
560
|
+
# NOTE: previously the same WD was used dependent on server startup
|
561
|
+
puts_to target_dir, <<-END, 'boot.rb'
|
562
|
+
Dir.chdir File.expand_path('#{@root_dir_path}', File.dirname(__FILE__))
|
563
|
+
|
564
|
+
ENV["GEM_HOME"] = File.join(File.dirname(__FILE__), '#{@gems_dir_path}')
|
565
|
+
ENV["GEM_PATH"] = ENV["GEM_HOME"]
|
566
|
+
# environment is set statically, as soon as Sinatra is loaded
|
567
|
+
ENV["RACK_ENV"] = 'production'
|
568
|
+
# prepare to boot using Bundler :
|
569
|
+
ENV["BUNDLE_WITHOUT"] = "#{ENV["BUNDLE_WITHOUT"] || 'development:test'}"
|
570
|
+
ENV["BUNDLE_GEMFILE"] = File.expand_path('Gemfile')
|
571
|
+
ENV["JBUNDLE_SKIP"] = 'true' # we only use JBundler for development/testing
|
572
|
+
|
573
|
+
require 'rubygems' unless defined? Gem
|
574
|
+
if File.exists?(ENV["BUNDLE_GEMFILE"])
|
575
|
+
require 'bundler'; Bundler.setup
|
576
|
+
else
|
577
|
+
#{adjust_plugin_load_path}
|
578
|
+
end
|
579
|
+
|
580
|
+
# try loading killbill (Bunler-less deploys or in case plugin forgot to require)
|
581
|
+
begin
|
582
|
+
require 'killbill'
|
583
|
+
rescue LoadError => e # not fatal for un-usual cases where plugins vendor the gem
|
584
|
+
warn "WARN: failed to load killbill gem: \#\{e.inspect\}"
|
585
|
+
end
|
586
|
+
|
587
|
+
#{plugin_require_line}
|
588
|
+
|
589
|
+
END
|
590
|
+
end
|
591
|
+
|
592
|
+
def generate_dev_boot_rb(target_dir, env = 'production')
|
593
|
+
@logger.debug "Generating (dev) boot.rb into #{target_dir}"
|
594
|
+
puts_to target_dir, <<-END, 'boot.rb'
|
595
|
+
Dir.chdir File.expand_path('#{@root_dir_path}', File.dirname(__FILE__))
|
596
|
+
|
597
|
+
ENV["GEM_HOME"] = '#{Gem.paths.home}'
|
598
|
+
ENV["GEM_PATH"] = '#{Gem.paths.path.join(':')}'
|
599
|
+
# environment is set statically, as soon as Sinatra is loaded
|
600
|
+
ENV["RACK_ENV"] = '#{env}'
|
601
|
+
# prepare to boot using Bundler :
|
602
|
+
ENV["BUNDLE_WITHOUT"] = "#{ENV["BUNDLE_WITHOUT"] || ''}"
|
603
|
+
ENV["BUNDLE_GEMFILE"] = File.expand_path('Gemfile')
|
604
|
+
|
605
|
+
require 'rubygems' unless defined? Gem
|
606
|
+
require 'bundler'; Bundler.setup
|
607
|
+
|
608
|
+
# require 'killbill'
|
609
|
+
|
610
|
+
#{plugin_require_line}
|
611
|
+
|
612
|
+
END
|
613
|
+
end
|
614
|
+
|
615
|
+
def plugin_require_line
|
616
|
+
files = @plugin_gemspec.files; require_path = "#{@plugin_gemspec.require_path}/"
|
617
|
+
files = files.select { |file| file.start_with?(require_path) && file[-3..-1] == '.rb' }
|
618
|
+
# [ "lib/stripe.rb", "lib/stripe/api.rb", "lib/stripe/application.rb", ... ]
|
619
|
+
files.map! { |file| file.sub(require_path, '') }
|
620
|
+
# [ "stripe.rb", "stripe/api.rb", "stripe/application.rb", ... ]
|
621
|
+
|
622
|
+
# 0. if killbill-stripe gem name has a killbill-stripe.rb use it
|
623
|
+
return "require '#{name}'" if files.include?("#{name}.rb")
|
624
|
+
|
625
|
+
# 1. RG convention: killbill-stripe -> require 'killbill/stripe'
|
626
|
+
filename = "#{name.sub('-', '/')}"
|
627
|
+
return "require '#{filename}'" if files.include?("#{filename}.rb")
|
628
|
+
|
629
|
+
# 2. killbill-paypal-express -> require 'paypal-express' (not used)
|
630
|
+
filename = "#{name.sub(/^killbill\-/, '')}"
|
631
|
+
return "require '#{filename}'" if files.include?("#{filename}.rb")
|
632
|
+
|
633
|
+
# 3. killbill-paypal-express -> require 'paypal_express'
|
634
|
+
filename = filename.sub('-', '_')
|
635
|
+
return "require '#{filename}'" if files.include?("#{filename}.rb")
|
636
|
+
|
637
|
+
# not likely to happen - fallback to root file (warn when multiple) :
|
638
|
+
files = files.select { |file| file.index('/').nil? }
|
639
|
+
return "require '#{files[0]}'" if files.size == 1
|
640
|
+
|
641
|
+
raise "could not resolve main require file from gemspec,\n please follow our naming convention for the bootstrap require e.g. \"#{name.sub('-', '/')}.rb\""
|
642
|
+
end
|
643
|
+
|
644
|
+
def adjust_plugin_load_path
|
645
|
+
# NOTE: assuming Dir.chdir [ROOT]
|
646
|
+
@plugin_gemspec.require_paths.map do |path|
|
647
|
+
"$LOAD_PATH << File.expand_path('#{path}')" # $LOAD_PATH << 'lib'
|
648
|
+
end.join('; ')
|
649
|
+
end
|
650
|
+
|
651
|
+
def copy_gemfile(target_dir = @plugin_root_target_dir)
|
652
|
+
copy_to target_dir, gemfile_path, 'Gemfile'
|
653
|
+
copy_to target_dir, gemfile_lock_path, 'Gemfile.lock'
|
654
|
+
end
|
655
|
+
|
656
|
+
def stage_extra_files(target_dir = @plugin_target_dir)
|
657
|
+
unless boot_rb_file.nil?
|
658
|
+
@logger.info "Staging (user-suplied) #{boot_rb_file}"
|
659
|
+
copy_to target_dir, boot_rb_file
|
660
|
+
end
|
245
661
|
unless killbill_properties_file.nil?
|
246
|
-
@logger.debug "Staging #{killbill_properties_file}
|
247
|
-
|
662
|
+
@logger.debug "Staging #{killbill_properties_file}"
|
663
|
+
copy_to target_dir, killbill_properties_file
|
248
664
|
end
|
249
665
|
unless config_ru_file.nil?
|
250
|
-
@logger.debug "Staging #{config_ru_file}
|
251
|
-
|
666
|
+
@logger.debug "Staging #{config_ru_file}"
|
667
|
+
copy_to target_dir, config_ru_file
|
252
668
|
end
|
253
669
|
end
|
254
670
|
|
671
|
+
def copy_to(target_dir, file_path, base_name = File.basename(file_path))
|
672
|
+
target_file = File.join(target_dir, base_name)
|
673
|
+
cp file_path, target_file, :verbose => @verbose
|
674
|
+
end
|
675
|
+
|
676
|
+
def puts_to(target_dir, content, base_name)
|
677
|
+
target_file = File.join(target_dir, base_name)
|
678
|
+
File.open(target_file, 'w') { |file| file << content }
|
679
|
+
end
|
680
|
+
|
681
|
+
def puts_to_base(content, base_name)
|
682
|
+
target_file = File.join(@plugin_target_dir, base_name)
|
683
|
+
File.open(target_file, 'w') { |file| file << content }
|
684
|
+
end
|
685
|
+
|
686
|
+
def puts_to_root(content, base_name)
|
687
|
+
target_file = File.join(@plugin_root_target_dir, base_name)
|
688
|
+
File.open(target_file, 'w') { |file| file << content }
|
689
|
+
end
|
690
|
+
|
691
|
+
def boot_rb_file
|
692
|
+
path_to_string @base.join("boot.rb").expand_path
|
693
|
+
end
|
694
|
+
|
255
695
|
def killbill_properties_file
|
256
696
|
path_to_string @base.join("killbill.properties").expand_path
|
257
697
|
end
|