killbill 3.2.4 → 4.0.0
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.
- 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
|