MuranoCLI 2.2.4 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.agignore +3 -0
- data/.gitignore +18 -1
- data/.rubocop.yml +222 -0
- data/.trustme.sh +185 -0
- data/.trustme.vim +24 -0
- data/Gemfile +23 -4
- data/LICENSE.txt +1 -1
- data/MuranoCLI.gemspec +43 -8
- data/README.markdown +9 -11
- data/Rakefile +187 -143
- data/TODO.taskpaper +2 -2
- data/bin/murano +51 -52
- data/docs/basic_example.rst +436 -0
- data/docs/completions/murano_completion-bash +3484 -0
- data/docs/demo.md +32 -32
- data/docs/develop.rst +391 -0
- data/lib/MrMurano.rb +21 -7
- data/lib/MrMurano/Account.rb +159 -174
- data/lib/MrMurano/Business.rb +381 -0
- data/lib/MrMurano/Config-Migrate.rb +32 -26
- data/lib/MrMurano/Config.rb +407 -128
- data/lib/MrMurano/Content.rb +191 -0
- data/lib/MrMurano/Gateway.rb +489 -0
- data/lib/MrMurano/Keystore.rb +48 -0
- data/lib/MrMurano/Passwords.rb +103 -0
- data/lib/MrMurano/ProjectFile.rb +121 -79
- data/lib/MrMurano/ReCommander.rb +114 -10
- data/lib/MrMurano/Setting.rb +90 -0
- data/lib/MrMurano/Solution-ServiceConfig.rb +89 -45
- data/lib/MrMurano/Solution-Services.rb +461 -166
- data/lib/MrMurano/Solution-Users.rb +70 -31
- data/lib/MrMurano/Solution.rb +372 -13
- data/lib/MrMurano/SolutionId.rb +73 -0
- data/lib/MrMurano/SyncRoot.rb +137 -0
- data/lib/MrMurano/SyncUpDown.rb +594 -284
- data/lib/MrMurano/Webservice-Cors.rb +71 -0
- data/lib/MrMurano/Webservice-Endpoint.rb +234 -0
- data/lib/MrMurano/Webservice-File.rb +193 -0
- data/lib/MrMurano/Webservice.rb +51 -0
- data/lib/MrMurano/commands.rb +18 -15
- data/lib/MrMurano/commands/business.rb +300 -6
- data/lib/MrMurano/commands/completion-bash.erb +166 -0
- data/lib/MrMurano/commands/{zshcomplete.erb → completion-zsh.erb} +0 -0
- data/lib/MrMurano/commands/completion.rb +76 -39
- data/lib/MrMurano/commands/config.rb +108 -44
- data/lib/MrMurano/commands/content.rb +115 -72
- data/lib/MrMurano/commands/cors.rb +29 -14
- data/lib/MrMurano/commands/devices.rb +286 -0
- data/lib/MrMurano/commands/domain.rb +52 -12
- data/lib/MrMurano/commands/gb.rb +24 -9
- data/lib/MrMurano/commands/globals.rb +64 -0
- data/lib/MrMurano/commands/init.rb +377 -155
- data/lib/MrMurano/commands/keystore.rb +92 -82
- data/lib/MrMurano/commands/link.rb +300 -0
- data/lib/MrMurano/commands/login.rb +74 -11
- data/lib/MrMurano/commands/logs.rb +63 -32
- data/lib/MrMurano/commands/mock.rb +57 -29
- data/lib/MrMurano/commands/password.rb +57 -39
- data/lib/MrMurano/commands/postgresql.rb +127 -94
- data/lib/MrMurano/commands/settings.rb +203 -0
- data/lib/MrMurano/commands/show.rb +79 -38
- data/lib/MrMurano/commands/solution.rb +423 -5
- data/lib/MrMurano/commands/solution_picker.rb +547 -0
- data/lib/MrMurano/commands/status.rb +195 -61
- data/lib/MrMurano/commands/sync.rb +78 -39
- data/lib/MrMurano/commands/timeseries.rb +71 -55
- data/lib/MrMurano/commands/tsdb.rb +113 -87
- data/lib/MrMurano/commands/usage.rb +57 -15
- data/lib/MrMurano/hash.rb +100 -10
- data/lib/MrMurano/http.rb +187 -43
- data/lib/MrMurano/makePretty.rb +16 -14
- data/lib/MrMurano/optparse.rb +2178 -0
- data/lib/MrMurano/progress.rb +138 -0
- data/lib/MrMurano/schema/resource-v1.0.0.yaml +32 -0
- data/lib/MrMurano/template/projectFile.murano.erb +16 -13
- data/lib/MrMurano/verbosing.rb +166 -29
- data/lib/MrMurano/version.rb +30 -1
- data/spec/Account-Passwords_spec.rb +21 -4
- data/spec/Account_spec.rb +69 -146
- data/spec/Business_spec.rb +290 -0
- data/spec/ConfigFile_spec.rb +1 -0
- data/spec/ConfigMigrate_spec.rb +12 -8
- data/spec/Config_spec.rb +40 -34
- data/spec/Content_spec.rb +363 -0
- data/spec/GatewayBase_spec.rb +54 -0
- data/spec/GatewayDevice_spec.rb +321 -0
- data/spec/GatewayResource_spec.rb +266 -0
- data/spec/GatewaySettings_spec.rb +120 -0
- data/spec/Http_spec.rb +18 -8
- data/spec/Mock_spec.rb +2 -2
- data/spec/ProjectFile_spec.rb +25 -14
- data/spec/Setting_spec.rb +110 -0
- data/spec/Solution-ServiceConfig_spec.rb +44 -5
- data/spec/Solution-ServiceEventHandler_spec.rb +23 -14
- data/spec/Solution-ServiceModules_spec.rb +47 -37
- data/spec/Solution-UsersRoles_spec.rb +10 -8
- data/spec/Solution_spec.rb +17 -8
- data/spec/SyncRoot_spec.rb +46 -20
- data/spec/SyncUpDown_spec.rb +437 -201
- data/spec/Verbosing_spec.rb +12 -4
- data/spec/{Solution-Cors_spec.rb → Webservice-Cors_spec.rb} +23 -20
- data/spec/{Solution-Endpoint_spec.rb → Webservice-Endpoint_spec.rb} +43 -41
- data/spec/{Solution-File_spec.rb → Webservice-File_spec.rb} +44 -33
- data/spec/Webservice-Setting_spec.rb +89 -0
- data/spec/_workspace.rb +4 -4
- data/spec/cmd_business_spec.rb +9 -4
- data/spec/cmd_common.rb +44 -1
- data/spec/cmd_content_spec.rb +43 -17
- data/spec/cmd_cors_spec.rb +4 -4
- data/spec/cmd_device_spec.rb +61 -16
- data/spec/cmd_domain_spec.rb +29 -6
- data/spec/cmd_init_spec.rb +281 -126
- data/spec/cmd_keystore_spec.rb +3 -3
- data/spec/cmd_link_spec.rb +98 -0
- data/spec/cmd_password_spec.rb +1 -1
- data/spec/cmd_setting_application_spec.rb +260 -0
- data/spec/cmd_setting_product_spec.rb +220 -0
- data/spec/cmd_status_spec.rb +223 -114
- data/spec/cmd_syncdown_spec.rb +115 -35
- data/spec/cmd_syncup_spec.rb +68 -15
- data/spec/cmd_usage_spec.rb +35 -8
- data/spec/fixtures/dumped_config +6 -4
- data/spec/fixtures/gateway_resource_files/resources.notyaml +12 -0
- data/spec/fixtures/gateway_resource_files/resources.yaml +13 -0
- data/spec/fixtures/gateway_resource_files/resources_invalid.yaml +13 -0
- data/spec/fixtures/mrmuranorc_deleted_bob +0 -2
- data/spec/fixtures/product_spec_files/lightbulb.yaml +20 -13
- data/spec/fixtures/{syncable_content → syncable_conflict}/services/devdata.lua +1 -1
- data/spec/fixtures/{syncable_content → syncable_conflict}/services/timers.lua +0 -0
- data/spec/spec_helper.rb +5 -0
- metadata +262 -171
- data/bin/mr +0 -8
- data/lib/MrMurano/Product-1P-Device.rb +0 -145
- data/lib/MrMurano/Product-Resources.rb +0 -205
- data/lib/MrMurano/Product.rb +0 -358
- data/lib/MrMurano/Solution-Cors.rb +0 -47
- data/lib/MrMurano/Solution-Endpoint.rb +0 -191
- data/lib/MrMurano/Solution-File.rb +0 -166
- data/lib/MrMurano/commands/assign.rb +0 -57
- data/lib/MrMurano/commands/businessList.rb +0 -45
- data/lib/MrMurano/commands/product.rb +0 -14
- data/lib/MrMurano/commands/productCreate.rb +0 -39
- data/lib/MrMurano/commands/productDelete.rb +0 -33
- data/lib/MrMurano/commands/productDevice.rb +0 -87
- data/lib/MrMurano/commands/productDeviceIdCmds.rb +0 -89
- data/lib/MrMurano/commands/productList.rb +0 -45
- data/lib/MrMurano/commands/productWrite.rb +0 -27
- data/lib/MrMurano/commands/solutionCreate.rb +0 -41
- data/lib/MrMurano/commands/solutionDelete.rb +0 -34
- data/lib/MrMurano/commands/solutionList.rb +0 -45
- data/spec/ProductBase_spec.rb +0 -113
- data/spec/ProductContent_spec.rb +0 -162
- data/spec/ProductResources_spec.rb +0 -329
- data/spec/Product_1P_Device_spec.rb +0 -202
- data/spec/Product_1P_RPC_spec.rb +0 -175
- data/spec/Product_spec.rb +0 -153
- data/spec/Solution-ServiceDevice_spec.rb +0 -176
- data/spec/cmd_assign_spec.rb +0 -51
File without changes
|
@@ -1,31 +1,50 @@
|
|
1
|
-
|
1
|
+
# Last Modified: 2017.08.16 /coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright © 2016-2017 Exosite LLC.
|
5
|
+
# License: MIT. See LICENSE.txt.
|
6
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
7
|
+
|
2
8
|
require 'erb'
|
9
|
+
require 'pp'
|
10
|
+
require 'MrMurano/ReCommander'
|
11
|
+
|
12
|
+
# USAGE: See: lib/MrMurano/commands.rb
|
3
13
|
|
4
14
|
class CompletionContext < ::Commander::HelpFormatter::Context
|
5
15
|
end
|
6
16
|
|
17
|
+
# rubocop:disable Style/ClassAndModuleChildren
|
18
|
+
# "Use nested module/class definitions instead of compact style."
|
19
|
+
# except that nested style (class [::]Commander\nclass Runner)
|
20
|
+
# does not work.
|
7
21
|
class ::Commander::Runner
|
8
|
-
|
9
22
|
# Not so sure this should go in Runner, but where else?
|
10
23
|
|
24
|
+
# rubocop:disable Style/MethodName "Use snake_case for method names."
|
25
|
+
|
26
|
+
# The shells for which we have completion templates.
|
27
|
+
SHELL_TYPES = %i[bash zsh].freeze
|
28
|
+
|
11
29
|
##
|
12
30
|
# Change the '--[no-]foo' switch into '--no-foo' and '--foo'
|
13
31
|
def flatswitches(option)
|
14
32
|
# if there is a --[no-]foo format, break that into two switches.
|
15
|
-
option[:switches].map
|
16
|
-
switch = switch.sub(/\s.*$/,'') # drop argument spec if exists.
|
17
|
-
if switch =~ /\[no-\]/
|
18
|
-
[switch.sub(/\[no-\]/, ''), switch.gsub(/[\[\]]/,'')]
|
33
|
+
switches = option[:switches].map do |switch|
|
34
|
+
switch = switch.sub(/\s.*$/, '') # drop argument spec if exists.
|
35
|
+
if switch =~ /\[no-\]/
|
36
|
+
[switch.sub(/\[no-\]/, ''), switch.gsub(/[\[\]]/, '')]
|
19
37
|
else
|
20
38
|
switch
|
21
39
|
end
|
22
|
-
|
40
|
+
end
|
41
|
+
switches.flatten
|
23
42
|
end
|
24
43
|
|
25
44
|
##
|
26
|
-
# If the switches take an argument,
|
45
|
+
# If the switches take an argument, return =
|
27
46
|
def takesArg(option, yes='=', no='')
|
28
|
-
if option[:switches].select { |switch| switch =~ /\s\S+$/ }.empty?
|
47
|
+
if option[:switches].select { |switch| switch =~ /\s\S+$/ }.empty?
|
29
48
|
no
|
30
49
|
else
|
31
50
|
yes
|
@@ -35,18 +54,18 @@ class ::Commander::Runner
|
|
35
54
|
##
|
36
55
|
# truncate the description of an option
|
37
56
|
def optionDesc(option)
|
38
|
-
option[:description].sub(/\n.*$/,'')
|
57
|
+
option[:description].sub(/\n.*$/, '')
|
39
58
|
end
|
40
59
|
|
41
60
|
##
|
42
61
|
# Get a tree of all commands and sub commands
|
43
62
|
def cmdTree
|
44
|
-
tree={}
|
45
|
-
@commands.sort.each do |name,cmd|
|
63
|
+
tree = {}
|
64
|
+
@commands.sort.each do |name, cmd|
|
46
65
|
levels = name.split
|
47
66
|
pos = tree
|
48
67
|
levels.each do |step|
|
49
|
-
pos[step] = {} unless pos.
|
68
|
+
pos[step] = {} unless pos.key? step
|
50
69
|
pos = pos[step]
|
51
70
|
end
|
52
71
|
pos["\0cmd"] = cmd
|
@@ -57,8 +76,8 @@ class ::Commander::Runner
|
|
57
76
|
##
|
58
77
|
# Get maximum depth of sub-commands.
|
59
78
|
def cmdMaxDepth
|
60
|
-
depth=0
|
61
|
-
@commands.sort.each do |name,
|
79
|
+
depth = 0
|
80
|
+
@commands.sort.each do |name, _cmd|
|
62
81
|
levels = name.split
|
63
82
|
depth = levels.count if levels.count > depth
|
64
83
|
end
|
@@ -68,17 +87,17 @@ class ::Commander::Runner
|
|
68
87
|
##
|
69
88
|
# Alternate tree of sub-commands.
|
70
89
|
def cmdTreeB
|
71
|
-
tree={}
|
72
|
-
@commands.sort.each do |name,cmd|
|
90
|
+
tree = {}
|
91
|
+
@commands.sort.each do |name, cmd|
|
73
92
|
levels = name.split
|
74
|
-
tree[levels.join(' ')] = {:cmd
|
93
|
+
tree[levels.join(' ')] = { cmd: cmd }
|
75
94
|
|
76
95
|
# load parent.
|
77
96
|
left = levels[0..-2]
|
78
97
|
right = levels[-1]
|
79
98
|
key = left.join(' ')
|
80
|
-
tree[key] = {} unless tree.
|
81
|
-
if tree[key].
|
99
|
+
tree[key] = {} unless tree.key? key
|
100
|
+
if tree[key].key?(:subs)
|
82
101
|
tree[key][:subs] << right
|
83
102
|
else
|
84
103
|
tree[key][:subs] = [right]
|
@@ -86,31 +105,44 @@ class ::Commander::Runner
|
|
86
105
|
end
|
87
106
|
tree
|
88
107
|
end
|
89
|
-
|
90
108
|
end
|
91
109
|
|
92
110
|
command :completion do |c|
|
93
|
-
c.syntax = %
|
94
|
-
c.summary = %
|
95
|
-
c.description = %
|
111
|
+
c.syntax = %(murano completion)
|
112
|
+
c.summary = %(Generate a completion file)
|
113
|
+
c.description = %(
|
114
|
+
Create a Tab completion file for either the Bash or Z shell.
|
115
|
+
|
116
|
+
E.g.,
|
117
|
+
|
118
|
+
eval "$(murano completion)"
|
96
119
|
|
97
|
-
eval "$(murano completion)"
|
98
120
|
or
|
99
|
-
|
100
|
-
|
101
|
-
|
121
|
+
|
122
|
+
murano completion > _murano
|
123
|
+
source _murano
|
124
|
+
).strip
|
125
|
+
c.project_not_required = true
|
126
|
+
|
102
127
|
c.option '--subs', 'List sub commands'
|
103
128
|
#c.option '--opts CMD', 'List options for subcommand'
|
104
129
|
#c.option '--gopts', 'List global options'
|
130
|
+
c.option(
|
131
|
+
'--shell TYPE',
|
132
|
+
Commander::Runner::SHELL_TYPES,
|
133
|
+
%(Shell flavor of output (default: Bash))
|
134
|
+
)
|
105
135
|
|
106
136
|
# Changing direction.
|
107
137
|
# Will poop out the file to be included as the completion script.
|
108
138
|
|
109
139
|
c.action do |args, options|
|
140
|
+
c.verify_arg_count!(args)
|
141
|
+
options.default shell: :bash
|
110
142
|
|
111
143
|
runner = ::Commander::Runner.instance
|
112
144
|
|
113
|
-
if options.gopts
|
145
|
+
if options.gopts
|
114
146
|
opts = runner.instance_variable_get(:@options)
|
115
147
|
pp opts.first
|
116
148
|
pp runner.takesArg(opts.first)
|
@@ -118,14 +150,14 @@ source _murano
|
|
118
150
|
# puts runner.optionLine o, 'GlobalOption'
|
119
151
|
# end
|
120
152
|
|
121
|
-
elsif options.subs
|
122
|
-
runner.instance_variable_get(:@commands).sort.each do |name,
|
123
|
-
#desc =
|
153
|
+
elsif options.subs
|
154
|
+
runner.instance_variable_get(:@commands).sort.each do |name, _cmd|
|
155
|
+
#desc = _cmd.instance_variable_get(:@summary) #.lines[0]
|
124
156
|
#say "#{name}:'#{desc}'"
|
125
|
-
say
|
157
|
+
say name.to_s
|
126
158
|
end
|
127
159
|
|
128
|
-
elsif options.opts
|
160
|
+
elsif options.opts
|
129
161
|
cmds = runner.instance_variable_get(:@commands)
|
130
162
|
cmd = cmds[options.opts]
|
131
163
|
pp cmd.syntax
|
@@ -138,15 +170,20 @@ source _murano
|
|
138
170
|
end
|
139
171
|
|
140
172
|
else
|
141
|
-
|
142
|
-
|
173
|
+
case options.shell
|
174
|
+
when :bash
|
175
|
+
cmpltn_tmplt = 'completion-bash.erb'
|
176
|
+
when :zsh
|
177
|
+
cmpltn_tmplt = 'completion-zsh.erb'
|
178
|
+
else
|
179
|
+
MrMurano::Verbose.error "Impossible shell option specified: #{options.shell}"
|
180
|
+
exit 2
|
181
|
+
end
|
182
|
+
tmpl = ERB.new(File.read(File.join(File.dirname(__FILE__), cmpltn_tmplt)), nil, '-<>')
|
143
183
|
|
144
184
|
pc = CompletionContext.new(runner)
|
145
185
|
puts tmpl.result(pc.get_binding)
|
146
186
|
end
|
147
|
-
|
148
|
-
|
149
187
|
end
|
150
188
|
end
|
151
189
|
|
152
|
-
# vim: set ai et sw=2 ts=2 :
|
@@ -1,23 +1,54 @@
|
|
1
|
+
# Last Modified: 2017.08.16 /coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright © 2016-2017 Exosite LLC.
|
5
|
+
# License: MIT. See LICENSE.txt.
|
6
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
7
|
+
|
8
|
+
require 'MrMurano/ReCommander'
|
1
9
|
|
2
10
|
command :config do |c|
|
3
|
-
c.syntax = %
|
4
|
-
c.summary = %
|
5
|
-
c.description = %
|
6
|
-
|
7
|
-
|
8
|
-
|
11
|
+
c.syntax = %(murano config [--options] [<key> [<new value>]])
|
12
|
+
c.summary = %(Get and set options)
|
13
|
+
c.description = %(
|
14
|
+
Get, set, or query config options.
|
15
|
+
|
16
|
+
All config options are in a 'section.key' format.
|
17
|
+
|
18
|
+
There is also a layer of scopes that the keys can be saved in.
|
19
|
+
|
20
|
+
If section is left out, then key is assumed to be in the 'tool' section.
|
21
|
+
).strip
|
22
|
+
|
23
|
+
c.example %(
|
24
|
+
View the combined config
|
25
|
+
).strip, 'murano config --dump'
|
26
|
+
|
27
|
+
c.example %(
|
28
|
+
View the config and path for each config file
|
29
|
+
).strip, 'murano config --locations'
|
9
30
|
|
10
|
-
|
31
|
+
c.example %(
|
32
|
+
Query a value
|
33
|
+
).strip, 'murano config application.id'
|
11
34
|
|
12
|
-
|
35
|
+
c.example %(
|
36
|
+
Show all ID values
|
37
|
+
).strip, %(murano config '*.id')
|
13
38
|
|
14
|
-
c.example %
|
15
|
-
|
16
|
-
|
17
|
-
c.example %{Set a new value; writing to the user config file}, 'murano config --user user.name my@email.address'
|
18
|
-
c.example %{Unset a value in a configfile. (lower scopes will become visible when unset)},
|
19
|
-
'murano config diff.cmd --unset'
|
39
|
+
c.example %(
|
40
|
+
Set a new value, which writes to the project config file
|
41
|
+
).strip, 'murano config application.id XXXXXXXX'
|
20
42
|
|
43
|
+
c.example %(
|
44
|
+
Set a new value, and write it to the user config file
|
45
|
+
).strip, 'murano config user.name my@email.address --user'
|
46
|
+
|
47
|
+
c.example %(
|
48
|
+
Unset a value. If the value is set in multiple config files,
|
49
|
+
# this unsets it from the outermost config file and unmasks
|
50
|
+
# a value set in a lower scope
|
51
|
+
).strip, 'murano config diff.cmd --unset'
|
21
52
|
|
22
53
|
c.option '--user', 'Use only the config file in $HOME (.mrmuranorc)'
|
23
54
|
c.option '--project', 'Use only the config file in the project (.mrmuranorc)'
|
@@ -26,42 +57,75 @@ command :config do |c|
|
|
26
57
|
|
27
58
|
c.option '--unset', 'Remove key from config file.'
|
28
59
|
c.option '--dump', 'Dump the current combined view of the config'
|
60
|
+
c.option '--locations', 'List the locations of all known configs'
|
61
|
+
|
62
|
+
c.project_not_required = true
|
29
63
|
|
30
64
|
c.action do |args, options|
|
65
|
+
c.verify_arg_count!(args, 2)
|
66
|
+
options.default(
|
67
|
+
user: false,
|
68
|
+
project: false,
|
69
|
+
env: false,
|
70
|
+
specified: false,
|
71
|
+
unset: false,
|
72
|
+
dump: false,
|
73
|
+
locations: false,
|
74
|
+
)
|
31
75
|
|
32
|
-
if options.dump
|
33
|
-
puts $cfg.dump
|
34
|
-
elsif
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# For read, if no scopes, than all. Otherwise just those specified
|
41
|
-
scopes = []
|
42
|
-
scopes << :user if options.user
|
43
|
-
scopes << :project if options.project
|
44
|
-
scopes << :env if options.env
|
45
|
-
scopes << :specified if options.specified
|
46
|
-
scopes = MrMurano::Config::CFG_SCOPES if scopes.empty?
|
47
|
-
|
48
|
-
say $cfg.get(args[0], scopes)
|
76
|
+
if options.dump
|
77
|
+
puts $cfg.dump
|
78
|
+
elsif options.locations
|
79
|
+
puts 'This list is ordered. The first value found for a key is the value used.'
|
80
|
+
puts $cfg.locations
|
81
|
+
elsif args.count.zero?
|
82
|
+
say_error 'Need a config key'
|
49
83
|
else
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
84
|
+
scope = get_scope_from_options(options)
|
85
|
+
if args.count == 1 && !options.unset
|
86
|
+
# For read, if no scopes, than all. Otherwise just those specified
|
87
|
+
scopes = []
|
88
|
+
scopes << scope unless scope.nil?
|
89
|
+
scopes = MrMurano::Config::CFG_SCOPES if scopes.empty?
|
90
|
+
is_wild = $cfg.wild?(args[0])
|
91
|
+
if !is_wild
|
92
|
+
puts $cfg.get(args[0], scopes)
|
93
|
+
else
|
94
|
+
kvals = $cfg.get_wild(args[0], scopes)
|
95
|
+
# LATER/2017-08-16: Honor --json option.
|
96
|
+
kvals.each { |kv| puts %(#{kv[0]} => "#{kv[1]}" (#{kv[2]})) }
|
97
|
+
end
|
98
|
+
else
|
99
|
+
# For write, if scope is specified, only write to that scope.
|
100
|
+
scope = :project if scope.nil?
|
101
|
+
args[1] = nil if options.unset
|
102
|
+
$cfg.set(args[0], args[1], scope)
|
103
|
+
end
|
62
104
|
end
|
63
105
|
end
|
64
106
|
|
107
|
+
def get_scope_from_options(options)
|
108
|
+
num_scopes = verify_scope_options!(options)
|
109
|
+
return nil if num_scopes.zero?
|
110
|
+
scope = nil
|
111
|
+
scope = :user if options.user
|
112
|
+
scope = :project if options.project
|
113
|
+
scope = :env if options.env
|
114
|
+
scope = :specified if options.specified
|
115
|
+
scope
|
116
|
+
end
|
117
|
+
|
118
|
+
def verify_scope_options!(options)
|
119
|
+
num_scopes = 0
|
120
|
+
num_scopes += 1 if options.user
|
121
|
+
num_scopes += 1 if options.project
|
122
|
+
num_scopes += 1 if options.env
|
123
|
+
num_scopes += 1 if options.specified
|
124
|
+
return num_scopes unless num_scopes > 1
|
125
|
+
MrMurano::Verbose.error(
|
126
|
+
'Ambiguous: Please specify only one of --user, --project, --env, or --specified'
|
127
|
+
)
|
128
|
+
exit 1
|
129
|
+
end
|
65
130
|
end
|
66
131
|
|
67
|
-
# vim: set ai et sw=2 ts=2 :
|
@@ -1,130 +1,173 @@
|
|
1
|
-
|
1
|
+
# Last Modified: 2017.08.16 /coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright © 2016-2017 Exosite LLC.
|
5
|
+
# License: MIT. See LICENSE.txt.
|
6
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
7
|
+
|
8
|
+
require 'MrMurano/Content'
|
9
|
+
require 'MrMurano/ReCommander'
|
2
10
|
|
3
11
|
command :content do |c|
|
4
|
-
c.syntax = %
|
5
|
-
c.summary = %
|
6
|
-
c.description = %
|
12
|
+
c.syntax = %(murano content)
|
13
|
+
c.summary = %(About Content Area)
|
14
|
+
c.description = %(
|
15
|
+
This set of commands let you interact with the content area for a product.
|
7
16
|
|
8
17
|
This is where OTA data can be stored so that devices can easily download it.
|
9
|
-
|
18
|
+
).strip
|
19
|
+
c.project_not_required = true
|
10
20
|
|
11
|
-
c.action do |
|
21
|
+
c.action do |_args, _options|
|
12
22
|
::Commander::UI.enable_paging
|
13
23
|
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
14
24
|
end
|
15
25
|
end
|
16
26
|
|
17
27
|
command 'content list' do |c|
|
18
|
-
c.syntax = %
|
19
|
-
c.summary = %
|
20
|
-
c.description = %
|
28
|
+
c.syntax = %(murano content list)
|
29
|
+
c.summary = %(List downloadable content for a product)
|
30
|
+
c.description = %(
|
31
|
+
List downloadable content for a product.
|
21
32
|
|
22
33
|
Data uploaded to a product's content area can be downloaded by devices using
|
23
34
|
the HTTP Device API.
|
24
|
-
|
35
|
+
).strip
|
36
|
+
|
37
|
+
c.option '-l', '--long', %(Include more info for each file)
|
38
|
+
|
25
39
|
c.action do |args, options|
|
26
|
-
|
27
|
-
|
40
|
+
c.verify_arg_count!(args)
|
41
|
+
|
42
|
+
prd = MrMurano::Content::Base.new
|
43
|
+
|
44
|
+
MrMurano::Verbose.whirly_start 'Looking for content...'
|
45
|
+
items = prd.list
|
46
|
+
exit 2 if items.nil?
|
47
|
+
MrMurano::Verbose.whirly_stop
|
48
|
+
if !items.empty?
|
49
|
+
prd.outf(items) do |dd, ios|
|
50
|
+
if options.long
|
51
|
+
headers = %i[Name Size 'Last Modified' MIME]
|
52
|
+
rows = dd.map { |d| [d[:id], d[:length], d[:last_modified], d[:type]] }
|
53
|
+
else
|
54
|
+
headers = %i[Name Size]
|
55
|
+
rows = dd.map { |d| [d[:id], d[:length]] }
|
56
|
+
end
|
57
|
+
prd.tabularize({ headers: headers, rows: rows }, ios)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
prd.warning 'Did not find any content'
|
61
|
+
end
|
28
62
|
end
|
29
63
|
end
|
30
64
|
|
31
65
|
command 'content info' do |c|
|
32
|
-
c.syntax = %
|
33
|
-
c.summary = %
|
34
|
-
c.description = %
|
66
|
+
c.syntax = %(murano content info <content name>)
|
67
|
+
c.summary = %(Show more info for a content item)
|
68
|
+
c.description = %(
|
69
|
+
Show more info for a content item.
|
35
70
|
|
36
71
|
Data uploaded to a product's content area can be downloaded by devices using
|
37
72
|
the HTTP Device API.
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
73
|
+
).strip
|
74
|
+
|
75
|
+
c.action do |args, _options|
|
76
|
+
c.verify_arg_count!(args, 1, ['Missing <content name>'])
|
77
|
+
prd = MrMurano::Content::Base.new
|
78
|
+
info = prd.info(args[0])
|
79
|
+
prd.outf(info) do |dd, ios|
|
80
|
+
ios.puts Hash.transform_keys_to_strings(dd).to_yaml
|
45
81
|
end
|
46
82
|
end
|
47
83
|
end
|
48
84
|
|
49
85
|
command 'content delete' do |c|
|
50
|
-
c.syntax = %
|
51
|
-
c.summary = %
|
52
|
-
c.description = %
|
86
|
+
c.syntax = %(murano content delete <content name>)
|
87
|
+
c.summary = %(Delete a content item)
|
88
|
+
c.description = %(
|
89
|
+
Delete a content item.
|
53
90
|
|
54
91
|
Data uploaded to a product's content area can be downloaded by devices using
|
55
92
|
the HTTP Device API.
|
56
|
-
|
93
|
+
).strip
|
94
|
+
|
95
|
+
c.option('-y', '--[no-]yes', %(Answer "yes" to all prompts and run non-interactively))
|
96
|
+
|
57
97
|
c.action do |args, options|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
prd.outf(ret) unless ret.nil? or ret.empty?
|
64
|
-
end
|
98
|
+
c.verify_arg_count!(args, 1, ['Missing <content name>'])
|
99
|
+
prd = MrMurano::Content::Base.new
|
100
|
+
prd.cmd_confirm_delete!(args[0], options.yes, 'abort!')
|
101
|
+
ret = prd.remove(args[0])
|
102
|
+
prd.outf(ret) if !ret.nil? && ret.count > 1
|
65
103
|
end
|
66
104
|
end
|
67
105
|
|
68
106
|
command 'content upload' do |c|
|
69
|
-
|
70
|
-
c.
|
71
|
-
c.
|
107
|
+
tags = {}
|
108
|
+
c.syntax = %(murano content upload <file>)
|
109
|
+
c.summary = %(Upload content)
|
110
|
+
c.description = %(
|
111
|
+
Upload a content item.
|
72
112
|
|
73
113
|
Data uploaded to a product's content area can be downloaded by devices using
|
74
114
|
the HTTP Device API.
|
75
|
-
|
76
|
-
|
115
|
+
).strip
|
116
|
+
|
117
|
+
c.option('--tags KEY=VALUE', %(Add extra meta info to the content item)) do |ec|
|
118
|
+
key, value = ec.split('=', 2)
|
119
|
+
# a=b :> ["a","b"]
|
120
|
+
# a= :> ["a",""]
|
121
|
+
# a :> ["a"]
|
122
|
+
raise "Bad tag key '#{param}'" if key.to_s.empty?
|
123
|
+
raise "Bad tag value '#{param}'" if value.to_s.empty?
|
124
|
+
key = key.downcase if key.casecmp('name').zero?
|
125
|
+
tags[key] = value
|
126
|
+
end
|
77
127
|
|
78
128
|
c.action do |args, options|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
if args[0].nil? then
|
83
|
-
prd.error "Missing <content id>"
|
84
|
-
elsif args[1].nil? then
|
85
|
-
prd.error "Missing <file>"
|
86
|
-
else
|
129
|
+
c.verify_arg_count!(args, 1, ['Missing <file>'])
|
130
|
+
options.default meta: ' '
|
87
131
|
|
88
|
-
|
89
|
-
if ret.nil? then
|
90
|
-
ret = prd.create(args[0], options.meta)
|
91
|
-
prd.outf(ret) unless ret.nil? or ret.empty?
|
92
|
-
end
|
132
|
+
prd = MrMurano::Content::Base.new
|
93
133
|
|
94
|
-
|
95
|
-
|
134
|
+
name = ::File.basename(args[0])
|
135
|
+
name = tags['name'] if tags.key? 'name'
|
136
|
+
if name.to_s.empty?
|
137
|
+
prd.error 'Bad file name'
|
138
|
+
exit 2
|
96
139
|
end
|
140
|
+
|
141
|
+
tags = nil if tags.empty?
|
142
|
+
prd.upload(name, args[0], tags)
|
97
143
|
end
|
98
144
|
end
|
99
145
|
|
100
146
|
command 'content download' do |c|
|
101
|
-
c.syntax = %
|
102
|
-
c.summary = %
|
103
|
-
c.description = %
|
147
|
+
c.syntax = %(murano content download <content name>)
|
148
|
+
c.summary = %(Download a content item)
|
149
|
+
c.description = %(
|
150
|
+
Download a content item.
|
104
151
|
|
105
152
|
Data uploaded to a product's content area can be downloaded by devices using
|
106
153
|
the HTTP Device API.
|
107
|
-
|
108
|
-
|
154
|
+
).strip
|
155
|
+
|
156
|
+
c.option '-o', '--output FILE', %(Save content to a file)
|
157
|
+
|
109
158
|
c.action do |args, options|
|
110
|
-
|
111
|
-
|
112
|
-
|
159
|
+
c.verify_arg_count!(args, 1, ['Missing <content name>'])
|
160
|
+
prd = MrMurano::Content::Base.new
|
161
|
+
if options.output.nil?
|
162
|
+
prd.download(args[0]) # to stdout
|
113
163
|
else
|
114
|
-
|
115
|
-
|
116
|
-
prd.download(args[0])
|
117
|
-
|
118
|
-
outFile = Pathname.new(options.output)
|
119
|
-
outFile.open('w') do |io|
|
120
|
-
prd.download(args[0]) do |chunk|
|
121
|
-
io << chunk
|
122
|
-
end
|
164
|
+
out_file = Pathname.new(options.output)
|
165
|
+
out_file.open('w') do |io|
|
166
|
+
prd.download(args[0]) do |chunk|
|
167
|
+
io << chunk
|
123
168
|
end
|
124
169
|
end
|
125
170
|
end
|
126
171
|
end
|
127
172
|
end
|
128
173
|
|
129
|
-
|
130
|
-
# vim: set ai et sw=2 ts=2 :
|