MuranoCLI 3.0.1 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.agignore +1 -0
- data/.rubocop.yml +67 -5
- data/Gemfile +6 -3
- data/MuranoCLI.gemspec +14 -10
- data/README.markdown +299 -126
- data/Rakefile +6 -1
- data/bin/murano +2 -2
- data/docs/completions/murano_completion-bash +93 -0
- data/lib/MrMurano.rb +19 -2
- data/lib/MrMurano/Business.rb +22 -19
- data/lib/MrMurano/Config.rb +19 -9
- data/lib/MrMurano/Content.rb +4 -4
- data/lib/MrMurano/Exchange-Element.rb +99 -0
- data/lib/MrMurano/Exchange.rb +137 -0
- data/lib/MrMurano/Gateway.rb +9 -9
- data/lib/MrMurano/Keystore.rb +4 -2
- data/lib/MrMurano/ReCommander.rb +3 -5
- data/lib/MrMurano/Solution-ServiceConfig.rb +12 -12
- data/lib/MrMurano/Solution-Services.rb +15 -14
- data/lib/MrMurano/Solution-Users.rb +2 -2
- data/lib/MrMurano/Solution.rb +43 -49
- data/lib/MrMurano/SolutionId.rb +28 -28
- data/lib/MrMurano/SyncUpDown.rb +32 -22
- data/lib/MrMurano/Webservice-Endpoint.rb +2 -1
- data/lib/MrMurano/Webservice.rb +5 -5
- data/lib/MrMurano/commands.rb +2 -1
- data/lib/MrMurano/commands/business.rb +21 -19
- data/lib/MrMurano/commands/domain.rb +16 -2
- data/lib/MrMurano/commands/exchange.rb +272 -0
- data/lib/MrMurano/commands/globals.rb +17 -1
- data/lib/MrMurano/commands/init.rb +3 -3
- data/lib/MrMurano/commands/link.rb +16 -16
- data/lib/MrMurano/commands/postgresql.rb +2 -2
- data/lib/MrMurano/commands/show.rb +13 -7
- data/lib/MrMurano/commands/solution.rb +23 -17
- data/lib/MrMurano/commands/solution_picker.rb +49 -44
- data/lib/MrMurano/commands/sync.rb +2 -1
- data/lib/MrMurano/commands/timeseries.rb +2 -2
- data/lib/MrMurano/commands/tsdb.rb +2 -2
- data/lib/MrMurano/hash.rb +19 -7
- data/lib/MrMurano/http.rb +12 -2
- data/lib/MrMurano/orderedhash.rb +200 -0
- data/lib/MrMurano/spec_commander.rb +98 -0
- data/lib/MrMurano/verbosing.rb +2 -2
- data/lib/MrMurano/version.rb +2 -2
- data/spec/Business_spec.rb +8 -6
- data/spec/Solution-ServiceConfig_spec.rb +1 -1
- data/spec/SyncUpDown_spec.rb +6 -6
- data/spec/_workspace.rb +9 -4
- data/spec/cmd_business_spec.rb +8 -2
- data/spec/cmd_common.rb +266 -25
- data/spec/cmd_exchange_spec.rb +118 -0
- data/spec/cmd_help_spec.rb +54 -13
- data/spec/cmd_init_spec.rb +1 -12
- data/spec/cmd_link_spec.rb +94 -72
- data/spec/spec_helper.rb +11 -16
- metadata +23 -17
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.07 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -13,6 +13,7 @@ def sync_add_options(c, locale)
|
|
13
13
|
c.option '--[no-]delete', %(Don't delete things from #{locale})
|
14
14
|
c.option '--[no-]create', %(Don't create things on #{locale})
|
15
15
|
c.option '--[no-]update', %(Don't update things on #{locale})
|
16
|
+
c.option '--ignore-errors', %(Don't die on sync errors)
|
16
17
|
end
|
17
18
|
|
18
19
|
def syncdown_files(options, args=nil)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.11 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -11,7 +11,7 @@ require 'MrMurano/Solution-ServiceConfig'
|
|
11
11
|
|
12
12
|
module MrMurano
|
13
13
|
class Timeseries < ServiceConfig
|
14
|
-
def initialize(
|
14
|
+
def initialize(api_id=nil)
|
15
15
|
# FIXME/2017-07-03: What soln types have timeseries?
|
16
16
|
@solntype = 'application.id'
|
17
17
|
super
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.11 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -13,7 +13,7 @@ require 'MrMurano/SubCmdGroupContext'
|
|
13
13
|
module MrMurano
|
14
14
|
module ServiceConfigs
|
15
15
|
class Tsdb < ServiceConfig
|
16
|
-
def initialize(
|
16
|
+
def initialize(api_id=nil)
|
17
17
|
# FIXME/2017-07-03: What soln types have TSDBs?
|
18
18
|
@solntype = 'application.id'
|
19
19
|
super
|
data/lib/MrMurano/hash.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
# Last Modified: 2017.
|
1
|
+
# Last Modified: 2017.09.07 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
5
5
|
# License: MIT. See LICENSE.txt.
|
6
6
|
# vim:tw=0:ts=2:sw=2:et:ai
|
7
7
|
|
8
|
-
require 'orderedhash'
|
8
|
+
require 'MrMurano/orderedhash'
|
9
9
|
|
10
10
|
class Hash
|
11
11
|
# From:
|
@@ -73,9 +73,10 @@ def elevate_hash(hsh)
|
|
73
73
|
end
|
74
74
|
# build a hash where the default is 'false' instead of 'nil'
|
75
75
|
Hash.new(false).merge(Hash.transform_keys_to_symbols(hsh))
|
76
|
-
# 2017-
|
77
|
-
#
|
78
|
-
#
|
76
|
+
# 2017-09-07: Note that after elevate_hash, the Hash returns
|
77
|
+
# false on unknown keys. This is because of the parameter to
|
78
|
+
# new: Hash.new(false). Unknown keys would return nil before,
|
79
|
+
# but after, they return false. E.g.,
|
79
80
|
#
|
80
81
|
# (byeebug) options
|
81
82
|
# {:delete=>false, :create=>true, :update=>false}
|
@@ -89,8 +90,6 @@ def elevate_hash(hsh)
|
|
89
90
|
# false
|
90
91
|
# (byeebug) options
|
91
92
|
# {:delete=>false, :create=>true, :update=>false, :fff=>nil}
|
92
|
-
#
|
93
|
-
# Work around is to test with hash.key?
|
94
93
|
end
|
95
94
|
|
96
95
|
##
|
@@ -108,3 +107,16 @@ def ensure_array(item)
|
|
108
107
|
end
|
109
108
|
end
|
110
109
|
|
110
|
+
module HashInit
|
111
|
+
def initialize(*hash)
|
112
|
+
return unless hash.length == 1 && hash.first.is_a?(Hash)
|
113
|
+
hash.first.each do |key, val|
|
114
|
+
if respond_to? key
|
115
|
+
send("#{key}=", val)
|
116
|
+
else
|
117
|
+
$stderr.puts %(HashInit: missing hash key "#{key}")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
data/lib/MrMurano/http.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.08.
|
1
|
+
# Last Modified: 2017.08.24 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -84,7 +84,17 @@ module MrMurano
|
|
84
84
|
if !defined?(@http) || @http.nil?
|
85
85
|
@http = Net::HTTP.new(uri.host, uri.port)
|
86
86
|
@http.use_ssl = true
|
87
|
-
|
87
|
+
begin
|
88
|
+
@http.start
|
89
|
+
rescue SocketError => err
|
90
|
+
# E.g., "error: Failed to open TCP connection to true:443
|
91
|
+
# (Hostname not known: true)."
|
92
|
+
error %(Net socket error: #{err.message})
|
93
|
+
exit 2
|
94
|
+
rescue StandardError => err
|
95
|
+
error %(Net request failed: #{err.message})
|
96
|
+
exit 2
|
97
|
+
end
|
88
98
|
end
|
89
99
|
@http
|
90
100
|
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
|
2
|
+
# AUTHOR
|
3
|
+
# jan molic /mig/at/1984/dot/cz/
|
4
|
+
#
|
5
|
+
# DESCRIPTION
|
6
|
+
# Hash with preserved order and some array-like extensions
|
7
|
+
# Public domain.
|
8
|
+
#
|
9
|
+
# THANKS
|
10
|
+
# Andrew Johnson for his suggestions and fixes of Hash[],
|
11
|
+
# merge, to_a, inspect and shift
|
12
|
+
class OrderedHash < ::Hash
|
13
|
+
attr_accessor :order
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def [] *args
|
17
|
+
hsh = OrderedHash.new
|
18
|
+
if Hash === args[0]
|
19
|
+
hsh.replace args[0]
|
20
|
+
elsif (args.size % 2) != 0
|
21
|
+
raise ArgumentError, "odd number of elements for Hash"
|
22
|
+
else
|
23
|
+
0.step(args.size - 1, 2) do |a|
|
24
|
+
b = a + 1
|
25
|
+
hsh[args[a]] = args[b]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
hsh
|
29
|
+
end
|
30
|
+
end
|
31
|
+
def initialize(*a, &b)
|
32
|
+
super
|
33
|
+
@order = []
|
34
|
+
end
|
35
|
+
def store_only a,b
|
36
|
+
store a,b
|
37
|
+
end
|
38
|
+
alias orig_store store
|
39
|
+
def store a,b
|
40
|
+
@order.push a unless has_key? a
|
41
|
+
super a,b
|
42
|
+
end
|
43
|
+
alias []= store
|
44
|
+
def == hsh2
|
45
|
+
return false if @order != hsh2.order
|
46
|
+
super hsh2
|
47
|
+
end
|
48
|
+
def clear
|
49
|
+
@order = []
|
50
|
+
super
|
51
|
+
end
|
52
|
+
def delete key
|
53
|
+
@order.delete key
|
54
|
+
super
|
55
|
+
end
|
56
|
+
def each_key
|
57
|
+
@order.each { |k| yield k }
|
58
|
+
self
|
59
|
+
end
|
60
|
+
def each_value
|
61
|
+
@order.each { |k| yield self[k] }
|
62
|
+
self
|
63
|
+
end
|
64
|
+
def each
|
65
|
+
@order.each { |k| yield k,self[k] }
|
66
|
+
self
|
67
|
+
end
|
68
|
+
alias each_pair each
|
69
|
+
def delete_if
|
70
|
+
@order.clone.each { |k|
|
71
|
+
delete k if yield(k)
|
72
|
+
}
|
73
|
+
self
|
74
|
+
end
|
75
|
+
def values
|
76
|
+
ary = []
|
77
|
+
@order.each { |k| ary.push self[k] }
|
78
|
+
ary
|
79
|
+
end
|
80
|
+
def keys
|
81
|
+
@order
|
82
|
+
end
|
83
|
+
def first
|
84
|
+
{@order.first => self[@order.first]}
|
85
|
+
end
|
86
|
+
def last
|
87
|
+
{@order.last => self[@order.last]}
|
88
|
+
end
|
89
|
+
def invert
|
90
|
+
hsh2 = Hash.new
|
91
|
+
@order.each { |k| hsh2[self[k]] = k }
|
92
|
+
hsh2
|
93
|
+
end
|
94
|
+
def reject &block
|
95
|
+
self.dup.delete_if(&block)
|
96
|
+
end
|
97
|
+
def reject! &block
|
98
|
+
hsh2 = reject(&block)
|
99
|
+
self == hsh2 ? nil : hsh2
|
100
|
+
end
|
101
|
+
def replace hsh2
|
102
|
+
@order = hsh2.keys
|
103
|
+
super hsh2
|
104
|
+
end
|
105
|
+
def shift
|
106
|
+
key = @order.first
|
107
|
+
key ? [key,delete(key)] : super
|
108
|
+
end
|
109
|
+
def unshift k,v
|
110
|
+
unless self.include? k
|
111
|
+
@order.unshift k
|
112
|
+
orig_store(k,v)
|
113
|
+
true
|
114
|
+
else
|
115
|
+
false
|
116
|
+
end
|
117
|
+
end
|
118
|
+
def push k,v
|
119
|
+
unless self.include? k
|
120
|
+
@order.push k
|
121
|
+
orig_store(k,v)
|
122
|
+
true
|
123
|
+
else
|
124
|
+
false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
def pop
|
128
|
+
key = @order.last
|
129
|
+
key ? [key,delete(key)] : nil
|
130
|
+
end
|
131
|
+
def to_a
|
132
|
+
ary = []
|
133
|
+
each { |k,v| ary << [k,v] }
|
134
|
+
ary
|
135
|
+
end
|
136
|
+
def to_s
|
137
|
+
self.to_a.to_s
|
138
|
+
end
|
139
|
+
def inspect
|
140
|
+
ary = []
|
141
|
+
each {|k,v| ary << k.inspect + "=>" + v.inspect}
|
142
|
+
'{' + ary.join(", ") + '}'
|
143
|
+
end
|
144
|
+
def update hsh2
|
145
|
+
hsh2.each { |k,v| self[k] = v }
|
146
|
+
self
|
147
|
+
end
|
148
|
+
alias :merge! update
|
149
|
+
def merge hsh2
|
150
|
+
self.dup update(hsh2)
|
151
|
+
end
|
152
|
+
def select
|
153
|
+
ary = []
|
154
|
+
each { |k,v| ary << [k,v] if yield k,v }
|
155
|
+
ary
|
156
|
+
end
|
157
|
+
def class
|
158
|
+
Hash
|
159
|
+
end
|
160
|
+
def __class__
|
161
|
+
OrderedHash
|
162
|
+
end
|
163
|
+
|
164
|
+
attr_accessor "to_yaml_style"
|
165
|
+
def yaml_inline= bool
|
166
|
+
if respond_to?("to_yaml_style")
|
167
|
+
self.to_yaml_style = :inline
|
168
|
+
else
|
169
|
+
unless defined? @__yaml_inline_meth
|
170
|
+
@__yaml_inline_meth =
|
171
|
+
lambda {|opts|
|
172
|
+
YAML::quick_emit(object_id, opts) {|emitter|
|
173
|
+
emitter << '{ ' << map{|kv| kv.join ': '}.join(', ') << ' }'
|
174
|
+
}
|
175
|
+
}
|
176
|
+
class << self
|
177
|
+
def to_yaml opts = {}
|
178
|
+
begin
|
179
|
+
@__yaml_inline ? @__yaml_inline_meth[ opts ] : super
|
180
|
+
rescue
|
181
|
+
@to_yaml_style = :inline
|
182
|
+
super
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
@__yaml_inline = bool
|
189
|
+
end
|
190
|
+
def yaml_inline!() self.yaml_inline = true end
|
191
|
+
|
192
|
+
def each_with_index
|
193
|
+
@order.each_with_index { |k, index| yield k, self[k], index }
|
194
|
+
self
|
195
|
+
end
|
196
|
+
end # class OrderedHash
|
197
|
+
|
198
|
+
def OrderedHash(*a, &b)
|
199
|
+
OrderedHash.new(*a, &b)
|
200
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Last Modified: 2017.08.30 /coding: utf-8
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
# Copyright © 2016-2017 Exosite LLC.
|
6
|
+
# License: MIT. See LICENSE.txt.
|
7
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
8
|
+
|
9
|
+
require 'commander/import'
|
10
|
+
require 'dotenv'
|
11
|
+
require 'English'
|
12
|
+
require 'highline'
|
13
|
+
require 'pathname'
|
14
|
+
#require 'pp'
|
15
|
+
require 'rainbow'
|
16
|
+
require 'rubygems'
|
17
|
+
require 'MrMurano'
|
18
|
+
require 'MrMurano/Config'
|
19
|
+
require 'MrMurano/ProjectFile'
|
20
|
+
|
21
|
+
# DEVs: Store environs in an .env file that gets loaded here. Alternatively,
|
22
|
+
# run a Bash or similar script before you start developing.
|
23
|
+
Dotenv.load
|
24
|
+
|
25
|
+
# Don't drop traces on ^C.
|
26
|
+
# EXPLAIN/2017-06-30: [lb] not sure what "drop traces" means.
|
27
|
+
# What happens if we don't trap Ctrl-C?
|
28
|
+
# NOTE: The second parameter is either a string, or a command or block to
|
29
|
+
# call or run. Ruby honors certain special strings, like 'EXIT':
|
30
|
+
# "If the command is “EXIT”, the script will be terminated by the signal."
|
31
|
+
# Per https://ruby-doc.org/core-2.2.0/Signal.html
|
32
|
+
Signal.trap('INT', 'EXIT')
|
33
|
+
|
34
|
+
program :version, MrMurano::VERSION
|
35
|
+
|
36
|
+
program :description, %(
|
37
|
+
Manage Applications and Products in Exosite's Murano
|
38
|
+
).strip
|
39
|
+
|
40
|
+
# If being piped, e.g.,
|
41
|
+
# murano command ... | ...
|
42
|
+
# or
|
43
|
+
# VAR=$(murano command ...)
|
44
|
+
# etc., then do not do progress.
|
45
|
+
# TEST/2017-08-23: Does this work on Windows?
|
46
|
+
ARGV.push('--no-progress') unless $stdout.tty? || ARGV.include?('--no-progress')
|
47
|
+
|
48
|
+
default_command :help
|
49
|
+
|
50
|
+
# Look for plug-ins.
|
51
|
+
pgds = [
|
52
|
+
Pathname.new(Dir.home) + '.mrmurano' + 'plugins',
|
53
|
+
Pathname.new(Dir.home) + '.murano' + 'plugins',
|
54
|
+
]
|
55
|
+
# Add plugin dirs from configs
|
56
|
+
# This is run before the command line options are parsed, so need to check old way.
|
57
|
+
unless ARGV.include? '--skip-plugins'
|
58
|
+
pgds << Pathname.new(ENV['MR_MURANO_PLUGIN_DIR']) if ENV.key? 'MR_MURANO_PLUGIN_DIR'
|
59
|
+
pgds << Pathname.new(ENV['MURANO_PLUGIN_DIR']) if ENV.key? 'MURANO_PLUGIN_DIR'
|
60
|
+
pgds.each do |path|
|
61
|
+
next unless path.exist?
|
62
|
+
path.each_child do |plugin|
|
63
|
+
next if plugin.directory?
|
64
|
+
next unless plugin.readable?
|
65
|
+
next if plugin.basename.fnmatch('.*') # don't read anything starting with .
|
66
|
+
begin
|
67
|
+
require plugin.to_s
|
68
|
+
#rescue Exception => err
|
69
|
+
rescue StandardError => err
|
70
|
+
$stderr.puts "Failed to load plugin at #{plugin} because #{err}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Look for .murano/config files.
|
77
|
+
$cfg = MrMurano::Config.new(::Commander::Runner.instance)
|
78
|
+
$cfg.load
|
79
|
+
$cfg.validate_cmd
|
80
|
+
|
81
|
+
# Look for a (legacy) Solutionfile.json.
|
82
|
+
$project = MrMurano::ProjectFile.new
|
83
|
+
$project.load
|
84
|
+
|
85
|
+
# The Commander defaults to paged help.
|
86
|
+
# The user can disable with --no-page, e.g.,
|
87
|
+
# alias murano='murano --no-page'
|
88
|
+
# We define this here and not in globals.rb because
|
89
|
+
# `murano --help` does not cause globals.rb to be sourced.
|
90
|
+
paging = nil
|
91
|
+
paging = true if ARGV.include?('--page')
|
92
|
+
paging = false if ARGV.include?('--no-page')
|
93
|
+
unless paging.nil?
|
94
|
+
program :help_paging, paging
|
95
|
+
$cfg['tool.no-page'] = !paging
|
96
|
+
end
|
97
|
+
# else, commander defaults to paging.
|
98
|
+
|
data/lib/MrMurano/verbosing.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.08.
|
1
|
+
# Last Modified: 2017.08.28 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -104,7 +104,7 @@ module MrMurano
|
|
104
104
|
|
105
105
|
## Format and print the object
|
106
106
|
# Handles many of the raw 'unpolished' formats.
|
107
|
-
def outf(obj, ios=nil
|
107
|
+
def outf(obj, ios=nil)
|
108
108
|
fmt = $cfg['tool.outformat']
|
109
109
|
ios = $stdout if ios.nil?
|
110
110
|
case fmt
|
data/lib/MrMurano/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Last Modified: 2017.08.
|
1
|
+
# Last Modified: 2017.08.31 /coding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# Copyright © 2016-2017 Exosite LLC.
|
@@ -26,7 +26,7 @@ module MrMurano
|
|
26
26
|
# '3.0.0-beta.2' is changed to '3.0.0.pre.beta.2'
|
27
27
|
# which breaks our build (which expects the version to match herein).
|
28
28
|
# So stick to using the '.pre.X' syntax, which ruby/gems knows.
|
29
|
-
VERSION = '3.0.
|
29
|
+
VERSION = '3.0.2'
|
30
30
|
EXE_NAME = File.basename($PROGRAM_NAME)
|
31
31
|
SIGN_UP_URL = 'https://exosite.com/signup/'
|
32
32
|
end
|