vmc_knife 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|