vmc_knife 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/vmc_knife/cli_extensions.rb +9 -1
- data/lib/vmc_knife/commands/knife_cmds.rb +44 -7
- data/lib/vmc_knife/json_expander.rb +42 -0
- data/lib/vmc_knife/vmc_helper.rb +115 -0
- data/lib/vmc_knife/vmc_knife.rb +34 -2
- data/lib/vmc_knife.rb +1 -2
- metadata +6 -6
- data/lib/vmc_knife/json_diff.rb +0 -83
@@ -128,8 +128,16 @@ class VMC::Cli::KnifeRunner < VMC::Cli::Runner
|
|
128
128
|
else
|
129
129
|
set_cmd(:knifeapps, :restart_applications, @args.size) # too many
|
130
130
|
end
|
131
|
+
when 'delete-all'
|
132
|
+
usage('vmc_knife delete-all [<applications_regexp>]')
|
133
|
+
@args.shift # consumes the argument.
|
134
|
+
if @args.size <= 2
|
135
|
+
set_cmd(:knifeapps, :delete_all, @args.size)
|
136
|
+
else
|
137
|
+
set_cmd(:knifeapps, :delete_all, @args.size) # too many
|
138
|
+
end
|
131
139
|
when 'help'
|
132
|
-
display "vmc_knife expand-manifest|login|start/stop/restart-applications|upload-applications|configure|configure-recipes|configure-applications|configure-services|configure-vcap|configure-vcap-mdns|configure-vcap-etc-hosts [<manifest_path>]"
|
140
|
+
display "vmc_knife expand-manifest|login|start/stop/restart-applications|upload-applications|configure-all|configure-recipes|configure-applications|configure-services|delete-all|configure-vcap|configure-vcap-mdns|configure-vcap-etc-hosts [<manifest_path>]"
|
133
141
|
else
|
134
142
|
super
|
135
143
|
end
|
@@ -49,8 +49,29 @@ module VMC::Cli::Command
|
|
49
49
|
__update(manifest_file_path_or_uri,cloud_controller_yml,VMC::KNIFE::VCAPUpdateCloudControllerConfig,"cloud_controller")
|
50
50
|
end
|
51
51
|
# updates /etc/hosts
|
52
|
-
def configure_etc_hosts(etc_hosts=nil,
|
53
|
-
__update(manifest_file_path_or_uri,etc_hosts,VMC::KNIFE::VCAPUpdateEtcHosts,"/etc/hosts")
|
52
|
+
def configure_etc_hosts(etc_hosts=nil,manifest_file_path=nil,client=nil)
|
53
|
+
#__update(manifest_file_path_or_uri,etc_hosts,VMC::KNIFE::VCAPUpdateEtcHosts,"/etc/hosts")
|
54
|
+
|
55
|
+
# this will configure /etc/hosts with the urls of your applications as well as the cloudcontroller.
|
56
|
+
# it is not be necessary if avahi is correctly configured on your VM.
|
57
|
+
unless manifest_file_path.nil?
|
58
|
+
if File.exists? manifest_file_path
|
59
|
+
man = load_manifest(manifest_file_path)
|
60
|
+
uri = man['target']
|
61
|
+
else
|
62
|
+
uri = manifest_file_path
|
63
|
+
end
|
64
|
+
else
|
65
|
+
man = load_manifest(nil)
|
66
|
+
uri = man['target']
|
67
|
+
end
|
68
|
+
update_aliases = VMC::KNIFE::VCAPUpdateAvahiAliases.new(nil,man,client)
|
69
|
+
update_hosts = VMC::KNIFE::VCAPUpdateEtcHosts.new(uri,manifest_file_path,client)
|
70
|
+
update_hosts.set_all_uris(update_aliases.all_uris)
|
71
|
+
if update_hosts.update_pending()
|
72
|
+
display "Configuring /etc/hosts with uri: #{uri}" if VMC::Cli::Config.trace
|
73
|
+
update_hosts.execute()
|
74
|
+
end
|
54
75
|
end
|
55
76
|
# updates /etc/avahi/aliases
|
56
77
|
def configure_etc_avahi_aliases(etc_avahi_aliases=nil,manifest_file_path=nil)
|
@@ -61,20 +82,27 @@ module VMC::Cli::Command
|
|
61
82
|
end
|
62
83
|
|
63
84
|
def configure_all(manifest_file_path_or_uri=nil)
|
64
|
-
|
65
|
-
|
85
|
+
begin
|
86
|
+
display "Stop applications ..."
|
87
|
+
VMC::Cli::Command::Knifeapps.new(@options).stop_applications(nil,manifest_file_path_or_uri)
|
88
|
+
rescue
|
89
|
+
#nevermind. sometimes a wrong config we can't login and we can't stop the apps.
|
90
|
+
end
|
66
91
|
display "Configure_cloud_controller ..."
|
67
|
-
configure_cloud_controller(nil,manifest_file_path_or_uri)
|
92
|
+
change = configure_cloud_controller(nil,manifest_file_path_or_uri)
|
68
93
|
display "Configure_etc_hosts ..."
|
69
94
|
configure_etc_hosts(nil,manifest_file_path_or_uri)
|
70
95
|
display "Login again ..."
|
71
|
-
VMC::Cli::Command::Knifemisc.new(@options)
|
96
|
+
new_knife = VMC::Cli::Command::Knifemisc.new(@options)
|
97
|
+
new_knife.login(manifest_file_path_or_uri)
|
98
|
+
# set the new client object to the old command.
|
99
|
+
@client = new_knife.client
|
72
100
|
display "Configure_applications ..."
|
73
101
|
VMC::Cli::Command::Knifeapps.new(@options).configure_applications(nil,manifest_file_path_or_uri)
|
74
102
|
display "Configure_etc_avahi_aliases ..."
|
75
103
|
configure_etc_avahi_aliases(nil,manifest_file_path_or_uri)
|
76
104
|
display "Start applications ..."
|
77
|
-
VMC::Cli::Command::Knifeapps.new(@options).
|
105
|
+
VMC::Cli::Command::Knifeapps.new(@options).restart_applications(nil,manifest_file_path_or_uri)
|
78
106
|
end
|
79
107
|
|
80
108
|
private
|
@@ -95,6 +123,9 @@ module VMC::Cli::Command
|
|
95
123
|
if update_cc.update_pending()
|
96
124
|
display "Configuring #{msg_label} with uri: #{uri}" if VMC::Cli::Config.trace
|
97
125
|
update_cc.execute()
|
126
|
+
true
|
127
|
+
else
|
128
|
+
false
|
98
129
|
end
|
99
130
|
end
|
100
131
|
|
@@ -108,6 +139,7 @@ module VMC::Cli::Command
|
|
108
139
|
man = load_manifest(manifest_file_path)
|
109
140
|
target_url = man['target']
|
110
141
|
raise "No target defined in the manifest #{@manifest_path}" if target_url.nil?
|
142
|
+
puts "set_target #{target_url}"
|
111
143
|
set_target(target_url)
|
112
144
|
|
113
145
|
email = man['email']
|
@@ -117,6 +149,8 @@ module VMC::Cli::Command
|
|
117
149
|
|
118
150
|
tries ||= 0
|
119
151
|
# login_and_save_token:
|
152
|
+
|
153
|
+
puts "login with #{email} #{password}"
|
120
154
|
token = client.login(email, password)
|
121
155
|
VMC::Cli::Config.store_token(token)
|
122
156
|
|
@@ -173,6 +207,9 @@ module VMC::Cli::Command
|
|
173
207
|
def restart_applications(app_names_regexp=nil,manifest_file_path=nil)
|
174
208
|
recipe_configuror(:restart,nil,nil,app_names_regexp,manifest_file_path)
|
175
209
|
end
|
210
|
+
def delete_all(app_names_regexp=nil,manifest_file_path=nil)
|
211
|
+
recipe_configuror(:delete,nil,nil,app_names_regexp,manifest_file_path)
|
212
|
+
end
|
176
213
|
|
177
214
|
def recipe_configuror(method_sym_name,recipes_regexp=nil,app_names_regexp=nil,service_names_regexp=nil,manifest_file_path=nil)
|
178
215
|
man = load_manifest(manifest_file_path)
|
@@ -4,6 +4,47 @@ require 'json'
|
|
4
4
|
module VMC
|
5
5
|
module KNIFE
|
6
6
|
module JSON_EXPANDER
|
7
|
+
|
8
|
+
# Reads the ip of a given interface and the mask
|
9
|
+
# defaults on eth0 then on wlan0 and then whatever it can find that is not 127.0.0.1
|
10
|
+
def self.ip_auto(interface='eth0')
|
11
|
+
res=`ifconfig | sed -n '/#{interface}/{n;p;}' | grep 'inet addr:' | grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}' | head -1`
|
12
|
+
if interface == 'eth0' && (res.nil? || res.strip.empty?)
|
13
|
+
res = VcapUtilities.ip_auto "wlan0"
|
14
|
+
if res.strip.empty?
|
15
|
+
#nevermind fetch the first IP you can find that is not 127.0.0.1
|
16
|
+
res=`ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}' | head -1`
|
17
|
+
end
|
18
|
+
end
|
19
|
+
res.strip! if res
|
20
|
+
unless res.empty?
|
21
|
+
# gets the Mask
|
22
|
+
line=`ifconfig | grep 'inet addr:#{res}' | awk '{ print $1}' | head -1`
|
23
|
+
puts "parsing ip and mask in line #{line}"
|
24
|
+
mask=`ifconfig | grep 'inet addr:#{res}' | grep -v '127.0.0.1' | cut -d: -f4 | awk '{ print $1}' | head -1`
|
25
|
+
mask.strip!
|
26
|
+
puts "got ip #{res} and mask #{mask}"
|
27
|
+
return [ res, mask ]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Derive a seed guaranteed unique on the local network according to the IP.
|
32
|
+
def self.ip_seed()
|
33
|
+
ip_mask=ip_auto()
|
34
|
+
ip = ip_mask[0]
|
35
|
+
mask = ip_mask[1]
|
36
|
+
ip_segs = ip.split('.')
|
37
|
+
if mask == "255.255.255.0"
|
38
|
+
ip_segs[3]
|
39
|
+
elsif mask == "255.255.0.0"
|
40
|
+
"#{ip_segs[2]}-#{ip_segs[3]}"
|
41
|
+
elsif mask == "255.0.0.0"
|
42
|
+
"#{ip_segs[1]}-#{ip_segs[2]}-#{ip_segs[3]}"
|
43
|
+
else
|
44
|
+
#hum why are we here?
|
45
|
+
"#{ip_segs[0]}-#{ip_segs[1]}-#{ip_segs[2]}-#{ip_segs[3]}"
|
46
|
+
end
|
47
|
+
end
|
7
48
|
|
8
49
|
# Loads a json file.
|
9
50
|
# Makes up to 10 passes evaluating ruby in the values that contain #{}.
|
@@ -20,6 +61,7 @@ module VMC
|
|
20
61
|
puts data.to_json unless passes < 100
|
21
62
|
raise "More than 100 passes evaluating the ruby template in the json file" unless passes < 100
|
22
63
|
#puts "got data #{data.to_json}"
|
64
|
+
|
23
65
|
data
|
24
66
|
end
|
25
67
|
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'json'
|
2
|
+
module VMC
|
3
|
+
module KNIFE
|
4
|
+
module HELPER
|
5
|
+
|
6
|
+
def self.static_upload_app_bits(client,appname, path)
|
7
|
+
display "Uploading Application #{appname} from #{path}:"
|
8
|
+
|
9
|
+
upload_file, file = "#{Dir.tmpdir}/#{appname}.zip", nil
|
10
|
+
FileUtils.rm_f(upload_file)
|
11
|
+
|
12
|
+
explode_dir = "#{Dir.tmpdir}/.vmc_#{appname}_files"
|
13
|
+
FileUtils.rm_rf(explode_dir) # Make sure we didn't have anything left over..
|
14
|
+
|
15
|
+
Dir.chdir(path) do
|
16
|
+
# Stage the app appropriately and do the appropriate fingerprinting, etc.
|
17
|
+
if war_file = Dir.glob('*.war').first
|
18
|
+
puts "Exploding the war"
|
19
|
+
VMC::Cli::ZipUtil.unpack(war_file, explode_dir)
|
20
|
+
puts "Done Exploding the war"
|
21
|
+
else
|
22
|
+
puts "Copying the files"
|
23
|
+
FileUtils.mkdir(explode_dir)
|
24
|
+
files = Dir.glob('{*,.[^\.]*}')
|
25
|
+
# Do not process .git files
|
26
|
+
files.delete('.git') if files
|
27
|
+
FileUtils.cp_r(files, explode_dir)
|
28
|
+
puts "Done copying the files"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Send the resource list to the cloudcontroller, the response will tell us what it already has..
|
32
|
+
### unless @options[:noresources]
|
33
|
+
display ' Checking for available resources: ', false
|
34
|
+
fingerprints = []
|
35
|
+
total_size = 0
|
36
|
+
puts "About to compute the fingerprints"
|
37
|
+
resource_files = Dir.glob("#{explode_dir}/**/*", File::FNM_DOTMATCH)
|
38
|
+
resource_files.each do |filename|
|
39
|
+
next if (File.directory?(filename) || !File.exists?(filename))
|
40
|
+
fingerprints << {
|
41
|
+
:size => File.size(filename),
|
42
|
+
:sha1 => Digest::SHA1.file(filename).hexdigest,
|
43
|
+
:fn => filename
|
44
|
+
}
|
45
|
+
total_size += File.size(filename)
|
46
|
+
end
|
47
|
+
puts "Finished computing the fingerprints"
|
48
|
+
# Check to see if the resource check is worth the round trip
|
49
|
+
if (total_size > (64*1024)) # 64k for now
|
50
|
+
# Send resource fingerprints to the cloud controller
|
51
|
+
puts "Invoking check_resources with the fingerprints"
|
52
|
+
appcloud_resources = client.check_resources(fingerprints)
|
53
|
+
end
|
54
|
+
display 'OK'.green
|
55
|
+
|
56
|
+
if appcloud_resources
|
57
|
+
display ' Processing resources: ', false
|
58
|
+
# We can then delete what we do not need to send.
|
59
|
+
appcloud_resources.each do |resource|
|
60
|
+
FileUtils.rm_f resource[:fn]
|
61
|
+
# adjust filenames sans the explode_dir prefix
|
62
|
+
resource[:fn].sub!("#{explode_dir}/", '')
|
63
|
+
end
|
64
|
+
display 'OK'.green
|
65
|
+
end
|
66
|
+
|
67
|
+
### end
|
68
|
+
|
69
|
+
# Perform Packing of the upload bits here.
|
70
|
+
unless VMC::Cli::ZipUtil.get_files_to_pack(explode_dir).empty?
|
71
|
+
display ' Packing application: ', false
|
72
|
+
VMC::Cli::ZipUtil.pack(explode_dir, upload_file)
|
73
|
+
display 'OK'.green
|
74
|
+
|
75
|
+
upload_size = File.size(upload_file);
|
76
|
+
if upload_size > 1024*1024
|
77
|
+
upload_size = (upload_size/(1024.0*1024.0)).round.to_s + 'M'
|
78
|
+
elsif upload_size > 0
|
79
|
+
upload_size = (upload_size/1024.0).round.to_s + 'K'
|
80
|
+
end
|
81
|
+
else
|
82
|
+
upload_size = '0K'
|
83
|
+
end
|
84
|
+
|
85
|
+
upload_str = " Uploading (#{upload_size}): "
|
86
|
+
display upload_str, false
|
87
|
+
|
88
|
+
unless VMC::Cli::ZipUtil.get_files_to_pack(explode_dir).empty?
|
89
|
+
VMC::Cli::Command::FileWithPercentOutput.display_str = upload_str
|
90
|
+
VMC::Cli::Command::FileWithPercentOutput.upload_size = File.size(upload_file);
|
91
|
+
file = VMC::Cli::Command::FileWithPercentOutput.open(upload_file, 'rb')
|
92
|
+
end
|
93
|
+
puts "client.upload_app about to start"
|
94
|
+
retries = 5
|
95
|
+
begin
|
96
|
+
client.upload_app(appname, file, appcloud_resources)
|
97
|
+
rescue Exception => e
|
98
|
+
retry if (retries -= 1) > 0
|
99
|
+
end
|
100
|
+
puts "Done client.upload_app"
|
101
|
+
display 'OK'.green if VMC::Cli::ZipUtil.get_files_to_pack(explode_dir).empty?
|
102
|
+
|
103
|
+
display 'Push Status: ', false
|
104
|
+
display 'OK'.green
|
105
|
+
end
|
106
|
+
|
107
|
+
ensure
|
108
|
+
# Cleanup if we created an exploded directory.
|
109
|
+
FileUtils.rm_f(upload_file) if upload_file
|
110
|
+
FileUtils.rm_rf(explode_dir) if explode_dir
|
111
|
+
end
|
112
|
+
|
113
|
+
end # end of HELPER
|
114
|
+
end # end of KNIFE
|
115
|
+
end
|
data/lib/vmc_knife/vmc_knife.rb
CHANGED
@@ -253,6 +253,16 @@ module VMC
|
|
253
253
|
application_updater.upload
|
254
254
|
end
|
255
255
|
end
|
256
|
+
def delete()
|
257
|
+
@applications.each do |application|
|
258
|
+
application_updater = ApplicationManifestApplier.new application, @client
|
259
|
+
application_updater.delete
|
260
|
+
end
|
261
|
+
@data_services.each do |data_service|
|
262
|
+
data_service_updater = DataServiceManifestApplier.new data_service, @client, @current_services, @current_services_info
|
263
|
+
data_service_updater.delete
|
264
|
+
end
|
265
|
+
end
|
256
266
|
def restart()
|
257
267
|
stop()
|
258
268
|
start()
|
@@ -323,6 +333,11 @@ module VMC
|
|
323
333
|
puts "Calling client.create_service #{@data_service_json['vendor']}, #{@data_service_json['name']}"
|
324
334
|
client.create_service @data_service_json['vendor'], @data_service_json['name']
|
325
335
|
end
|
336
|
+
def delete()
|
337
|
+
raise "The service #{@data_service_json['name']} does not exist." if current().empty?
|
338
|
+
client.delete_service(@data_service_json['name'])
|
339
|
+
end
|
340
|
+
|
326
341
|
# Returns the service manifest for the vendor.
|
327
342
|
# If the service vendor ( = type) is not provided by this vcap install
|
328
343
|
# An exception is raised.
|
@@ -414,7 +429,13 @@ module VMC
|
|
414
429
|
#empty directory.
|
415
430
|
`wget --output-document=_download_.zip #{url}`
|
416
431
|
raise "Unable to download #{url}" unless $? == 0
|
417
|
-
|
432
|
+
if /\.tgz$/ =~ url || /\.tar\.gz$/ =~ url
|
433
|
+
`tar zxvf _download_.zip`
|
434
|
+
elsif /\.tar$/ =~ url
|
435
|
+
`tar xvf _download_.zip`
|
436
|
+
else
|
437
|
+
`unzip _download_.zip`
|
438
|
+
end
|
418
439
|
`rm _download_.zip`
|
419
440
|
end
|
420
441
|
VMC::KNIFE::HELPER.static_upload_app_bits(@client,@application_json['name'],Dir.pwd)
|
@@ -436,6 +457,11 @@ module VMC
|
|
436
457
|
client.update_app(@application_json['name'], current())
|
437
458
|
end
|
438
459
|
|
460
|
+
def delete()
|
461
|
+
raise "The application #{@application_json['name']} does not exist yet" if current().empty?
|
462
|
+
client.delete_app(@application_json['name'])
|
463
|
+
end
|
464
|
+
|
439
465
|
# Generate the updated application manifest:
|
440
466
|
# take the manifest defined in the saas recipe
|
441
467
|
# merge it with the current manifest of the application.
|
@@ -624,12 +650,18 @@ module VMC
|
|
624
650
|
# This is really a server-side feature.
|
625
651
|
# Replace the 127.0.0.1 localhost #{old_uri} with the new uri
|
626
652
|
class VCAPUpdateEtcHosts
|
627
|
-
def initialize(uri, etc_hosts_path=nil)
|
653
|
+
def initialize(uri, etc_hosts_path=nil,man=nil)
|
628
654
|
@config = etc_hosts_path
|
629
655
|
@config ||="/etc/hosts"
|
630
656
|
@uri = uri
|
631
657
|
raise "The config file #{@config} does not exist." unless File.exists? @config
|
632
658
|
end
|
659
|
+
def set_all_uris(uris_arr)
|
660
|
+
uris_arr.push @uri unless @uri.nil?
|
661
|
+
uris_arr.sort!
|
662
|
+
uris_arr.uniq!
|
663
|
+
@uri = uris_arr.join(' ')
|
664
|
+
end
|
633
665
|
def update_pending()
|
634
666
|
#could also use:
|
635
667
|
found_it=`sed -n '/^127\.0\.0\.1[[:space:]]*localhost[[:space:]]*#{@uri}/p' #{@config}`
|
data/lib/vmc_knife.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vmc_knife
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Intalio Pte
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-11-
|
18
|
+
date: 2011-11-30 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: vmc
|
@@ -106,9 +106,9 @@ files:
|
|
106
106
|
- lib/restclient/restclient_add_timeout.rb
|
107
107
|
- lib/vmc_knife/cli_extensions.rb
|
108
108
|
- lib/vmc_knife/commands/knife_cmds.rb
|
109
|
-
- lib/vmc_knife/json_diff.rb
|
110
109
|
- lib/vmc_knife/json_expander.rb
|
111
110
|
- lib/vmc_knife/version.rb
|
111
|
+
- lib/vmc_knife/vmc_helper.rb
|
112
112
|
- lib/vmc_knife/vmc_knife.rb
|
113
113
|
- lib/vmc_knife.rb
|
114
114
|
- bin/vmc_knife
|
@@ -141,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
141
|
requirements: []
|
142
142
|
|
143
143
|
rubyforge_project:
|
144
|
-
rubygems_version: 1.8.
|
144
|
+
rubygems_version: 1.8.11
|
145
145
|
signing_key:
|
146
146
|
specification_version: 3
|
147
147
|
summary: Extensions for VMC the CLI of VMWare's Cloud Foundry
|
data/lib/vmc_knife/json_diff.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
module VMC
|
3
|
-
module KNIFE
|
4
|
-
module JSON_DIFF
|
5
|
-
|
6
|
-
DIFF_NODE_NAME = "__diff__"
|
7
|
-
TYPE_NODE_NAME = "__type__"
|
8
|
-
PLUS="+"
|
9
|
-
MINUS="-"
|
10
|
-
CHANGED="=>"
|
11
|
-
DISPLAY_TYPE_ONLY_WHEN_CHANGE=true
|
12
|
-
|
13
|
-
def self.compare(a,b,pretty=true)
|
14
|
-
if a.kind_of?(String) && b.kind_of?(String) && File.exists?(a) && File.exists?(b)
|
15
|
-
a = JSON.parse File.open(a).read
|
16
|
-
b = JSON.parse File.open(b).read
|
17
|
-
end
|
18
|
-
if pretty
|
19
|
-
JSON.pretty_generate compare_tree(a, b)
|
20
|
-
else
|
21
|
-
compare_tree(a, b).to_json
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.compare_tree(a, b)
|
26
|
-
typeA = a.class.name
|
27
|
-
typeB = b.class.name
|
28
|
-
|
29
|
-
aString = a.to_s unless is_array_or_hash?(a)
|
30
|
-
bString = b.to_s unless is_array_or_hash?(b)
|
31
|
-
|
32
|
-
node = Hash.new
|
33
|
-
if a.nil?
|
34
|
-
node[DIFF_NODE_NAME]=PLUS
|
35
|
-
node[TYPE_NODE_NAME]=typeB unless DISPLAY_TYPE_ONLY_WHEN_CHANGE
|
36
|
-
node['value']=bString if bString
|
37
|
-
elsif b.nil?
|
38
|
-
node[DIFF_NODE_NAME]=MINUS
|
39
|
-
node[TYPE_NODE_NAME]=typeA unless DISPLAY_TYPE_ONLY_WHEN_CHANGE
|
40
|
-
node['value']=aString if aString
|
41
|
-
elsif (typeA != typeB) || (!aString.nil? && a != b)
|
42
|
-
node[DIFF_NODE_NAME]=CHANGED
|
43
|
-
if typeA != typeB
|
44
|
-
node[TYPE_NODE_NAME]="#{typeA} => #{typeB}"
|
45
|
-
else
|
46
|
-
node[TYPE_NODE_NAME]=typeA unless DISPLAY_TYPE_ONLY_WHEN_CHANGE
|
47
|
-
end
|
48
|
-
node['value']="#{aString} => #{bString}" if aString
|
49
|
-
else
|
50
|
-
node[TYPE_NODE_NAME]=typeA unless DISPLAY_TYPE_ONLY_WHEN_CHANGE
|
51
|
-
node['value']=aString if aString
|
52
|
-
end
|
53
|
-
|
54
|
-
if aString
|
55
|
-
return node
|
56
|
-
end
|
57
|
-
child_node=node
|
58
|
-
# child_node = Hash.new
|
59
|
-
# node['child']=child_node
|
60
|
-
keys = Array.new
|
61
|
-
keys = collect_keys(a,keys)
|
62
|
-
keys = collect_keys(b,keys)
|
63
|
-
keys.sort!
|
64
|
-
for i in 0..(keys.length-1)
|
65
|
-
if (keys[i] != keys[i-1])
|
66
|
-
value = compare_tree(a && a[keys[i]], b && b[keys[i]]);
|
67
|
-
child_node[keys[i]]=value
|
68
|
-
end
|
69
|
-
end
|
70
|
-
node
|
71
|
-
end
|
72
|
-
private
|
73
|
-
def self.is_array_or_hash?(obj)
|
74
|
-
obj.kind_of?(Array) || obj.kind_of?(Hash)
|
75
|
-
end
|
76
|
-
def self.collect_keys(obj, collector)
|
77
|
-
return Array.new unless obj.kind_of? Hash
|
78
|
-
collector + obj.keys
|
79
|
-
end
|
80
|
-
|
81
|
-
end # end of JSON_DIFF
|
82
|
-
end # end of KNIFE
|
83
|
-
end
|