MuranoCLI 2.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.
Files changed (151) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +21 -0
  5. data/Gemfile +27 -0
  6. data/LICENSE.txt +19 -0
  7. data/MuranoCLI.gemspec +50 -0
  8. data/MuranoCLI.iss +50 -0
  9. data/README.markdown +208 -0
  10. data/Rakefile +188 -0
  11. data/TODO.taskpaper +122 -0
  12. data/bin/mr +8 -0
  13. data/bin/murano +84 -0
  14. data/docs/demo.md +109 -0
  15. data/lib/MrMurano/Account.rb +211 -0
  16. data/lib/MrMurano/Config-Migrate.rb +47 -0
  17. data/lib/MrMurano/Config.rb +286 -0
  18. data/lib/MrMurano/Mock.rb +63 -0
  19. data/lib/MrMurano/Product-1P-Device.rb +145 -0
  20. data/lib/MrMurano/Product-Resources.rb +195 -0
  21. data/lib/MrMurano/Product.rb +358 -0
  22. data/lib/MrMurano/ProjectFile.rb +349 -0
  23. data/lib/MrMurano/Solution-Cors.rb +46 -0
  24. data/lib/MrMurano/Solution-Endpoint.rb +177 -0
  25. data/lib/MrMurano/Solution-File.rb +150 -0
  26. data/lib/MrMurano/Solution-ServiceConfig.rb +140 -0
  27. data/lib/MrMurano/Solution-Services.rb +326 -0
  28. data/lib/MrMurano/Solution-Users.rb +129 -0
  29. data/lib/MrMurano/Solution.rb +59 -0
  30. data/lib/MrMurano/SubCmdGroupContext.rb +49 -0
  31. data/lib/MrMurano/SyncUpDown.rb +565 -0
  32. data/lib/MrMurano/commands/assign.rb +57 -0
  33. data/lib/MrMurano/commands/businessList.rb +45 -0
  34. data/lib/MrMurano/commands/completion.rb +152 -0
  35. data/lib/MrMurano/commands/config.rb +67 -0
  36. data/lib/MrMurano/commands/content.rb +130 -0
  37. data/lib/MrMurano/commands/cors.rb +30 -0
  38. data/lib/MrMurano/commands/domain.rb +17 -0
  39. data/lib/MrMurano/commands/gb.rb +33 -0
  40. data/lib/MrMurano/commands/init.rb +138 -0
  41. data/lib/MrMurano/commands/keystore.rb +157 -0
  42. data/lib/MrMurano/commands/logs.rb +78 -0
  43. data/lib/MrMurano/commands/mock.rb +63 -0
  44. data/lib/MrMurano/commands/password.rb +88 -0
  45. data/lib/MrMurano/commands/postgresql.rb +41 -0
  46. data/lib/MrMurano/commands/product.rb +14 -0
  47. data/lib/MrMurano/commands/productCreate.rb +39 -0
  48. data/lib/MrMurano/commands/productDelete.rb +33 -0
  49. data/lib/MrMurano/commands/productDevice.rb +84 -0
  50. data/lib/MrMurano/commands/productDeviceIdCmds.rb +86 -0
  51. data/lib/MrMurano/commands/productList.rb +45 -0
  52. data/lib/MrMurano/commands/productWrite.rb +27 -0
  53. data/lib/MrMurano/commands/show.rb +80 -0
  54. data/lib/MrMurano/commands/solution.rb +14 -0
  55. data/lib/MrMurano/commands/solutionCreate.rb +39 -0
  56. data/lib/MrMurano/commands/solutionDelete.rb +34 -0
  57. data/lib/MrMurano/commands/solutionList.rb +45 -0
  58. data/lib/MrMurano/commands/status.rb +92 -0
  59. data/lib/MrMurano/commands/sync.rb +60 -0
  60. data/lib/MrMurano/commands/timeseries.rb +115 -0
  61. data/lib/MrMurano/commands/tsdb.rb +271 -0
  62. data/lib/MrMurano/commands/usage.rb +23 -0
  63. data/lib/MrMurano/commands/zshcomplete.erb +112 -0
  64. data/lib/MrMurano/commands.rb +32 -0
  65. data/lib/MrMurano/hash.rb +20 -0
  66. data/lib/MrMurano/http.rb +153 -0
  67. data/lib/MrMurano/makePretty.rb +75 -0
  68. data/lib/MrMurano/schema/pf-v1.0.0.yaml +114 -0
  69. data/lib/MrMurano/schema/sf-v0.2.0.yaml +77 -0
  70. data/lib/MrMurano/schema/sf-v0.3.0.yaml +78 -0
  71. data/lib/MrMurano/template/mock.erb +9 -0
  72. data/lib/MrMurano/template/projectFile.murano.erb +81 -0
  73. data/lib/MrMurano/verbosing.rb +99 -0
  74. data/lib/MrMurano/version.rb +4 -0
  75. data/lib/MrMurano.rb +20 -0
  76. data/spec/Account-Passwords_spec.rb +242 -0
  77. data/spec/Account_spec.rb +272 -0
  78. data/spec/ConfigFile_spec.rb +50 -0
  79. data/spec/ConfigMigrate_spec.rb +89 -0
  80. data/spec/Config_spec.rb +409 -0
  81. data/spec/Http_spec.rb +204 -0
  82. data/spec/MakePretties_spec.rb +118 -0
  83. data/spec/Mock_spec.rb +53 -0
  84. data/spec/ProductBase_spec.rb +113 -0
  85. data/spec/ProductContent_spec.rb +162 -0
  86. data/spec/ProductResources_spec.rb +329 -0
  87. data/spec/Product_1P_Device_spec.rb +202 -0
  88. data/spec/Product_1P_RPC_spec.rb +175 -0
  89. data/spec/Product_spec.rb +153 -0
  90. data/spec/ProjectFile_spec.rb +324 -0
  91. data/spec/Solution-Cors_spec.rb +164 -0
  92. data/spec/Solution-Endpoint_spec.rb +581 -0
  93. data/spec/Solution-File_spec.rb +212 -0
  94. data/spec/Solution-ServiceConfig_spec.rb +202 -0
  95. data/spec/Solution-ServiceDevice_spec.rb +176 -0
  96. data/spec/Solution-ServiceEventHandler_spec.rb +385 -0
  97. data/spec/Solution-ServiceModules_spec.rb +465 -0
  98. data/spec/Solution-UsersRoles_spec.rb +207 -0
  99. data/spec/Solution_spec.rb +92 -0
  100. data/spec/SyncRoot_spec.rb +83 -0
  101. data/spec/SyncUpDown_spec.rb +495 -0
  102. data/spec/Verbosing_spec.rb +279 -0
  103. data/spec/_workspace.rb +27 -0
  104. data/spec/cmd_assign_spec.rb +51 -0
  105. data/spec/cmd_business_spec.rb +59 -0
  106. data/spec/cmd_common.rb +72 -0
  107. data/spec/cmd_config_spec.rb +68 -0
  108. data/spec/cmd_content_spec.rb +71 -0
  109. data/spec/cmd_cors_spec.rb +50 -0
  110. data/spec/cmd_device_spec.rb +96 -0
  111. data/spec/cmd_domain_spec.rb +32 -0
  112. data/spec/cmd_init_spec.rb +30 -0
  113. data/spec/cmd_keystore_spec.rb +97 -0
  114. data/spec/cmd_password_spec.rb +62 -0
  115. data/spec/cmd_status_spec.rb +239 -0
  116. data/spec/cmd_syncdown_spec.rb +86 -0
  117. data/spec/cmd_syncup_spec.rb +62 -0
  118. data/spec/cmd_usage_spec.rb +36 -0
  119. data/spec/fixtures/.mrmuranorc +9 -0
  120. data/spec/fixtures/ProjectFiles/invalid.yaml +9 -0
  121. data/spec/fixtures/ProjectFiles/only_meta.yaml +24 -0
  122. data/spec/fixtures/ProjectFiles/with_routes.yaml +27 -0
  123. data/spec/fixtures/SolutionFiles/0.2.0.json +20 -0
  124. data/spec/fixtures/SolutionFiles/0.2.0_invalid.json +18 -0
  125. data/spec/fixtures/SolutionFiles/0.2.json +21 -0
  126. data/spec/fixtures/SolutionFiles/0.3.0.json +20 -0
  127. data/spec/fixtures/SolutionFiles/0.3.0_invalid.json +19 -0
  128. data/spec/fixtures/SolutionFiles/0.3.json +20 -0
  129. data/spec/fixtures/SolutionFiles/basic.json +20 -0
  130. data/spec/fixtures/SolutionFiles/secret.json +6 -0
  131. data/spec/fixtures/configfile +9 -0
  132. data/spec/fixtures/dumped_config +42 -0
  133. data/spec/fixtures/mrmuranorc_deleted_bob +8 -0
  134. data/spec/fixtures/mrmuranorc_tool_bob +3 -0
  135. data/spec/fixtures/product_spec_files/example.exoline.spec.yaml +116 -0
  136. data/spec/fixtures/product_spec_files/example.murano.spec.yaml +14 -0
  137. data/spec/fixtures/product_spec_files/gwe.exoline.spec.yaml +21 -0
  138. data/spec/fixtures/product_spec_files/gwe.murano.spec.yaml +16 -0
  139. data/spec/fixtures/product_spec_files/lightbulb-no-state.yaml +11 -0
  140. data/spec/fixtures/product_spec_files/lightbulb.yaml +14 -0
  141. data/spec/fixtures/roles-three.yaml +11 -0
  142. data/spec/fixtures/syncable_content/assets/icon.png +0 -0
  143. data/spec/fixtures/syncable_content/assets/index.html +0 -0
  144. data/spec/fixtures/syncable_content/assets/js/script.js +0 -0
  145. data/spec/fixtures/syncable_content/modules/table_util.lua +58 -0
  146. data/spec/fixtures/syncable_content/routes/manyRoutes.lua +11 -0
  147. data/spec/fixtures/syncable_content/routes/singleRoute.lua +5 -0
  148. data/spec/fixtures/syncable_content/services/devdata.lua +18 -0
  149. data/spec/fixtures/syncable_content/services/timers.lua +4 -0
  150. data/spec/spec_helper.rb +119 -0
  151. metadata +498 -0
@@ -0,0 +1,30 @@
1
+ require 'yaml'
2
+ require 'MrMurano/Solution-Cors'
3
+
4
+ command :cors do |c|
5
+ c.syntax = %{murano cors}
6
+ c.summary = %{Get the CORS for the project.}
7
+ c.description = %{Get the CORS for the project.
8
+
9
+ Set the CORS with `murano cors set`
10
+ }
11
+
12
+ c.action do |args,options|
13
+ sol = MrMurano::Cors.new
14
+ ret = sol.fetch()
15
+ sol.outf ret
16
+ end
17
+ end
18
+
19
+ command 'cors set' do |c|
20
+ c.syntax = %{murano cors set [<file>]}
21
+ c.summary = %{Set the CORS for the project.}
22
+
23
+ c.action do |args,options|
24
+ crs = MrMurano::Cors.new
25
+ file = args.shift
26
+ crs.upload(file)
27
+ end
28
+ end
29
+
30
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,17 @@
1
+ require 'MrMurano/Solution'
2
+ command :domain do |c|
3
+ c.syntax = %{murano domain}
4
+ c.summary = %{Print the domain for this solution}
5
+ c.option '--[no-]raw', %{Don't add scheme}
6
+ c.action do |args,options|
7
+ options.default :raw=>true
8
+ sol = MrMurano::Solution.new
9
+ ret = sol.info()
10
+ if options.raw then
11
+ say ret[:domain]
12
+ else
13
+ say "https://#{ret[:domain]}"
14
+ end
15
+ end
16
+ end
17
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,33 @@
1
+ require 'pp'
2
+
3
+ # You don't need this.
4
+ # To use this:
5
+ # - mkdir -p ~/.mrmurano/plugins
6
+ # - ln gb.rb ~/.mrmurano/plugins
7
+
8
+ command :_gb do |c|
9
+ c.syntax = %{murano _gb <class> <method> (<args>)}
10
+ c.summary = %{Call internal class methods directly.}
11
+ c.description = %{Call internal class methods directly.}
12
+
13
+ c.action do |args, options|
14
+ cls = args[0]
15
+ meth = args[1].to_sym
16
+ args.shift(2)
17
+
18
+ begin
19
+ gb = Object::const_get("MrMurano::#{cls}").new
20
+ if gb.respond_to? meth then
21
+ pp gb.__send__(meth, *args)
22
+ else
23
+ say_error "'#{cls}' doesn't '#{meth}'"
24
+ end
25
+ rescue Exception => e
26
+ say_error e.message
27
+ pp e
28
+ end
29
+ end
30
+ end
31
+
32
+
33
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,138 @@
1
+ require 'MrMurano/Account'
2
+ require 'MrMurano/Config-Migrate'
3
+ require 'erb'
4
+
5
+
6
+ command :init do |c|
7
+ c.syntax = %{murano init}
8
+ c.summary = %{The easy way to start a project}
9
+ c.description = %{}
10
+
11
+ c.option '--force', %{Override existing business, solution, or product ids}
12
+ c.option '--[no-]mkdirs', %{Create default directories}
13
+
14
+ c.action do |args, options|
15
+ options.default :force=>false, :mkdirs=>true
16
+ acc = MrMurano::Account.new
17
+ puts ''
18
+
19
+ if Pathname.new(Dir.pwd).realpath == Pathname.new(Dir.home).realpath then
20
+ acc.error "Cannot init a project in your HOME directory."
21
+ exit 2
22
+ end
23
+
24
+ say "Found project base directory at #{$cfg['location.base'].to_s}"
25
+ puts ''
26
+
27
+ # Try to import a .Solutionfile.secret
28
+ MrMurano::ConfigMigrate.new.import_secret
29
+
30
+ # If they have never logged in, then asking for the business.id will also ask
31
+ # for their username and password.
32
+ say "Using account #{$cfg['user.name']}"
33
+ say ''
34
+
35
+ # 1. Get business id
36
+ if not options.force and not $cfg['business.id'].nil? then
37
+ say "Using Business ID already set to #{$cfg['business.id']}"
38
+ else
39
+ bizz = acc.businesses
40
+ if bizz.count == 1 then
41
+ bizid = bizz.first
42
+ say "You are only part of one business; using #{bizid[:name]}"
43
+ $cfg.set('businesses.id', bizid[:bizid], :project)
44
+
45
+ else
46
+ choose do |menu|
47
+ menu.prompt = "Select which Business to use:"
48
+ menu.flow = :columns_across
49
+ bizz.sort{|a,b| a[:name]<=>b[:name]}.each do |b|
50
+ menu.choice(b[:name]) do
51
+ $cfg.set('business.id', b[:bizid], :project)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ puts '' # blank line
58
+
59
+ # 2. Get Solution id
60
+ if not options.force and not $cfg['solution.id'].nil? then
61
+ say "Using Solution ID already set to #{$cfg['solution.id']}"
62
+ else
63
+ solz = acc.solutions
64
+ if solz.count == 1 then
65
+ sol = solz.first
66
+ say "You only have one solution; using #{sol[:domain]}"
67
+ $cfg.set('solution.id', sol[:apiId], :project)
68
+ else
69
+ choose do |menu|
70
+ menu.prompt = "Select which Solution to use:"
71
+ menu.flow = :columns_across
72
+ solz.sort{|a,b| a[:domain]<=>b[:domain]}.each do |s|
73
+ menu.choice(s[:domain].sub(/\..*$/,'')) do
74
+ $cfg.set('solution.id', s[:apiId], :project)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ puts '' # blank line
81
+
82
+ # 3. Get Product id
83
+ if not options.force and not $cfg['product.id'].nil? then
84
+ say "Using Product ID already set to #{$cfg['product.id']}"
85
+ else
86
+ podz = acc.products
87
+ if podz.count == 1 then
88
+ prd = podz.first
89
+ say "You only have one product; using #{prd[:label]}"
90
+ $cfg.set('product.id', prd[:modelId], :project)
91
+ else
92
+ choose do |menu|
93
+ menu.prompt = "Select which Product to use:"
94
+ menu.flow = :columns_across
95
+ podz.sort{|a,b| a[:label]<=>b[:label]}.each do |p|
96
+ menu.choice(p[:label]) do
97
+ $cfg.set('product.id', p[:modelId], :project)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ puts ''
105
+ say "Ok, In business ID: #{$cfg['business.id']} using Solution ID: #{$cfg['solution.id']} with Product ID: #{$cfg['product.id']}"
106
+
107
+ # If no ProjectFile or Solutionfile, then write a ProjectFile
108
+ if $project.project_file.nil? then
109
+ tmpl = File.read(File.join(File.dirname(__FILE__),'..','template','projectFile.murano.erb'))
110
+ tmpl = ERB.new(tmpl)
111
+ res = tmpl.result($project.data_binding)
112
+ prFile = $project['info.name'] + '.murano'
113
+ say "Writing an initial Project file: #{prFile}"
114
+ File.open(prFile, 'w') {|io| io << res}
115
+ end
116
+
117
+ if options.mkdirs then
118
+ base = $cfg['location.base']
119
+ base = Pathname.new(base) unless base.kind_of? Pathname
120
+ %w{
121
+ location.files
122
+ location.endpoints
123
+ location.modules
124
+ location.eventhandlers
125
+ location.specs
126
+ }.each do |cfgi|
127
+ path = $cfg[cfgi]
128
+ path = Pathname.new(path) unless path.kind_of? Pathname
129
+ path = base + path
130
+ path.mkpath unless path.exist?
131
+ end
132
+ say "Default directories created"
133
+ end
134
+
135
+ end
136
+ end
137
+
138
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,157 @@
1
+ require 'MrMurano/Solution-ServiceConfig'
2
+
3
+ module MrMurano
4
+ class Keystore < ServiceConfig
5
+ def initialize
6
+ super
7
+ @serviceName = 'keystore'
8
+ end
9
+
10
+ def keyinfo
11
+ call(:info)
12
+ end
13
+
14
+ def listkeys
15
+ ret = call(:list)
16
+ ret[:keys]
17
+ end
18
+
19
+ def getkey(key)
20
+ ret = call(:get, :post, {:key=>key})
21
+ ret[:value]
22
+ end
23
+
24
+ def setkey(key, value)
25
+ call(:set, :post, { :key=>key, :value=>value })
26
+ end
27
+
28
+ def delkey(key)
29
+ call(:delete, :post, {:key=>key})
30
+ end
31
+
32
+ def command(key, cmd, args)
33
+ call(:command, :post, {:key=>key, :command=>cmd, :args=>args})
34
+ end
35
+
36
+ def clearall()
37
+ call(:clear, :post, {})
38
+ end
39
+
40
+ end
41
+ end
42
+
43
+ command :keystore do |c|
44
+ c.syntax = %{murano keystore}
45
+ c.summary = %{About Keystore}
46
+ c.description = %{The Keystore sub-commands let you interact directly with the Keystore instance
47
+ in a solution. This allows for easier debugging, being able to quickly get and
48
+ set data. As well as calling any of the other supported REDIS commands.}
49
+ c.action do |args, options|
50
+ ::Commander::UI.enable_paging
51
+ say MrMurano::SubCmdGroupHelp.new(c).get_help
52
+ end
53
+ end
54
+
55
+ command 'keystore clearAll' do |c|
56
+ c.syntax = %{murano keystore clearAll}
57
+ c.description = %{Delete all keys in the keystore}
58
+ c.action do |args,options|
59
+ sol = MrMurano::Keystore.new
60
+ sol.clearall
61
+ end
62
+ end
63
+
64
+ command 'keystore info' do |c|
65
+ c.syntax = %{murano keystore info}
66
+ c.description = %{Show info about the Keystore}
67
+ c.action do |args,options|
68
+ sol = MrMurano::Keystore.new
69
+ sol.outf sol.keyinfo
70
+ end
71
+ end
72
+
73
+ command 'keystore list' do |c|
74
+ c.syntax = %{murano keystore list}
75
+ c.description = %{List all of the keys in the Keystore}
76
+ c.action do |args,options|
77
+ sol = MrMurano::Keystore.new
78
+ sol.outf sol.listkeys
79
+ end
80
+ end
81
+
82
+ command 'keystore get' do |c|
83
+ c.syntax = %{murano keystore get <key>}
84
+ c.description = %{Get the value of a key in the Keystore}
85
+ c.action do |args,options|
86
+ sol = MrMurano::Keystore.new
87
+ ret = sol.getkey(args[0])
88
+ sol.outf ret
89
+ end
90
+ end
91
+
92
+ command 'keystore set' do |c|
93
+ c.syntax = %{murano keystore set <key> <value...>}
94
+ c.description = %{Set the value of a key in the Keystore}
95
+ c.action do |args,options|
96
+ sol = MrMurano::Keystore.new
97
+ sol.setkey(args[0], args[1..-1].join(' '))
98
+ end
99
+ end
100
+
101
+ command 'keystore delete' do |c|
102
+ c.syntax = %{murano keystore delete <key>}
103
+ c.description = %{Delete a key from the Keystore}
104
+ c.action do |args,options|
105
+ sol = MrMurano::Keystore.new
106
+ sol.delkey(args[0])
107
+ end
108
+ end
109
+ alias_command 'keystore rm', 'keystore delete'
110
+ alias_command 'keystore del', 'keystore delete'
111
+
112
+ command 'keystore command' do |c|
113
+ c.syntax = %{murano keystore command <command> <key> <args...>}
114
+ c.summary = %{Call some Redis commands in the Keystore}
115
+ c.description = %{Call some Redis commands in the Keystore.
116
+
117
+ Only a subset of all Redis commands is supported.
118
+ See http://docs.exosite.com/murano/services/keystore/#command for current list.
119
+ }
120
+ c.example %{murano keystore command lpush mykey myvalue}, %{Push a value onto list}
121
+ c.example %{murano keystore command lpush mykey A B C}, %{Push three values onto list}
122
+ c.example %{murano keystore command lrem mykey 0 B}, %{Remove all B values from list}
123
+ c.action do |args,options|
124
+ sol = MrMurano::Keystore.new
125
+ if args.count < 2 then
126
+ sol.error "Not enough params"
127
+ else
128
+ ret = sol.command(args[1], args[0], args[2..-1])
129
+ if ret.has_key?(:value) then
130
+ sol.outf ret[:value]
131
+ else
132
+ sol.error "#{ret[:code]}: #{ret.message}"
133
+ sol.outf ret[:error] if ($cfg['tool.debug'] and ret.has_key?(:error))
134
+ end
135
+ end
136
+ end
137
+ end
138
+ alias_command 'keystore cmd', 'keystore command'
139
+
140
+ # A bunch of common REDIS commands that are suported in Murano
141
+ alias_command 'keystore lpush', 'keystore command', 'lpush'
142
+ alias_command 'keystore lindex', 'keystore command', 'lindex'
143
+ alias_command 'keystore llen', 'keystore command', 'llen'
144
+ alias_command 'keystore linsert', 'keystore command', 'linsert'
145
+ alias_command 'keystore lrange', 'keystore command', 'lrange'
146
+ alias_command 'keystore lrem', 'keystore command', 'lrem'
147
+ alias_command 'keystore lset', 'keystore command', 'lset'
148
+ alias_command 'keystore ltrim', 'keystore command', 'ltrim'
149
+ alias_command 'keystore rpop', 'keystore command', 'rpop'
150
+ alias_command 'keystore rpush', 'keystore command', 'rpush'
151
+ alias_command 'keystore sadd', 'keystore command', 'sadd'
152
+ alias_command 'keystore srem', 'keystore command', 'srem'
153
+ alias_command 'keystore scard', 'keystore command', 'scard'
154
+ alias_command 'keystore smembers', 'keystore command', 'smembers'
155
+ alias_command 'keystore spop', 'keystore command', 'spop'
156
+
157
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,78 @@
1
+ require 'MrMurano/Solution'
2
+ require 'MrMurano/makePretty'
3
+
4
+ command :logs do |c|
5
+ c.syntax = %{murano logs [options]}
6
+ c.description = %{Get the logs for a solution}
7
+ c.option '-f','--follow', %{Follow logs from server}
8
+ c.option('--[no-]color', %{Toggle colorizing of logs}) {
9
+ Rainbow.enabled = false
10
+ }
11
+ c.option '--[no-]pretty', %{Reformat JSON blobs in logs.}
12
+ c.option '--[no-]localtime', %{Adjust Timestamps to be in local time}
13
+ c.option '--raw', %{Don't do any formating of the log data}
14
+
15
+ c.action do |args,options|
16
+ options.default :pretty=>true, :localtime=>true, :raw => false
17
+
18
+ sol = MrMurano::Solution.new
19
+
20
+ if options.follow then
21
+ # open a lasting connection and continueally feed makePretty()
22
+ begin
23
+ sol.get('/logs?polling=true') do |request, http|
24
+ request["Accept-Encoding"] = "None"
25
+ http.request(request) do |response|
26
+ remainder=''
27
+ response.read_body do |chunk|
28
+ chunk = remainder + chunk unless remainder.empty?
29
+
30
+ # for all complete JSON blobs, make them pretty.
31
+ chunk.gsub!(/\{(?>[^}{]+|\g<0>)*\}/m) do |m|
32
+ if options.raw then
33
+ puts m
34
+ else
35
+ begin
36
+ js = JSON.parse(m, {:allow_nan=>true,
37
+ :symbolize_names => true,
38
+ :create_additions=>false})
39
+ puts MrMurano::Pretties::makePretty(js, options)
40
+ rescue
41
+ sol.error '=== JSON parse error, showing raw instead ==='
42
+ puts m
43
+ end
44
+ end
45
+ '' #remove (we're kinda abusing gsub here.)
46
+ end
47
+
48
+ # is there an incomplete one?
49
+ if chunk.match(/(\{.*$)/m) then
50
+ remainder = $1
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+ rescue Interrupt => _
57
+ end
58
+
59
+ else
60
+ ret = sol.get('/logs')
61
+
62
+ if ret.kind_of?(Hash) and ret.has_key?(:items) then
63
+ ret[:items].reverse.each do |line|
64
+ if options.raw then
65
+ puts line
66
+ else
67
+ puts MrMurano::Pretties::makePretty(line, options)
68
+ end
69
+ end
70
+ else
71
+ sol.error "Couldn't get logs: #{ret}"
72
+ break
73
+ end
74
+
75
+ end
76
+ end
77
+ end
78
+ # vim: set ai et sw=2 ts=2 :