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
@@ -0,0 +1,64 @@
|
|
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/Config'
|
9
|
+
|
10
|
+
global_option('--[no-]color', %(Disable fancy output)) do |value|
|
11
|
+
HighLine.use_color = value
|
12
|
+
Rainbow.enabled = value
|
13
|
+
end
|
14
|
+
|
15
|
+
global_option('-c', '--config KEY=VALUE', %(Set a single config key)) do |param|
|
16
|
+
key, value = param.split('=', 2)
|
17
|
+
# a=b :> ["a", "b"]
|
18
|
+
# a= :> ["a", ""]
|
19
|
+
# a :> ["a"]
|
20
|
+
raise "Bad config '#{param}'" if key.nil?
|
21
|
+
if value.nil?
|
22
|
+
$cfg[key] = 'true'
|
23
|
+
else
|
24
|
+
$cfg[key] = value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
global_option('-C', '--configfile FILE', %(Load additional configuration file)) do |file|
|
29
|
+
# This is called after all of the top level code in this file.
|
30
|
+
$cfg.load_specific(file)
|
31
|
+
end
|
32
|
+
|
33
|
+
global_option('-L', '--curl', %(Print out a curl command for each network call)) do
|
34
|
+
$cfg['tool.curldebug'] = true
|
35
|
+
end
|
36
|
+
|
37
|
+
global_option('-n', '--dry', %(Do not run actions that make changes)) do
|
38
|
+
$cfg['tool.dry'] = true
|
39
|
+
# Running dry implies verbose.
|
40
|
+
$cfg['tool.verbose'] = true
|
41
|
+
end
|
42
|
+
|
43
|
+
exclude_help = %(
|
44
|
+
Except config values from the specified scope(s).
|
45
|
+
SCOPES can be 1 scope or comma-separated list of
|
46
|
+
#{MrMurano::Config::CFG_SCOPES.map(&:to_s)}
|
47
|
+
).strip
|
48
|
+
global_option('--exclude-scopes SCOPES', Array, exclude_help) do |value|
|
49
|
+
$cfg.exclude_scopes = value.map(&:to_sym)
|
50
|
+
end
|
51
|
+
|
52
|
+
# --no-page is handled early on, in bin/murano.
|
53
|
+
global_option('--no-page', %(Do not page --help output))
|
54
|
+
|
55
|
+
global_option('--[no-]plugins', %(Do not load plugins. Good for when one goes bad))
|
56
|
+
|
57
|
+
global_option('--[no-]progress', %(Disable spinner and progress message)) do |value|
|
58
|
+
$cfg['tool.no-progress'] = !value
|
59
|
+
end
|
60
|
+
|
61
|
+
global_option('-V', '--verbose', %(Be chatty)) do
|
62
|
+
$cfg['tool.verbose'] = true
|
63
|
+
end
|
64
|
+
|
@@ -1,192 +1,414 @@
|
|
1
|
+
# Last Modified: 2017.08.17 /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 'erb'
|
9
|
+
require 'rainbow'
|
10
|
+
require 'MrMurano/verbosing'
|
1
11
|
require 'MrMurano/Account'
|
12
|
+
require 'MrMurano/Business'
|
13
|
+
require 'MrMurano/Config'
|
2
14
|
require 'MrMurano/Config-Migrate'
|
3
|
-
require '
|
15
|
+
require 'MrMurano/ReCommander'
|
16
|
+
require 'MrMurano/Solution-Services'
|
17
|
+
require 'MrMurano/SyncRoot'
|
18
|
+
require 'MrMurano/commands/business'
|
19
|
+
require 'MrMurano/commands/solution'
|
20
|
+
require 'MrMurano/commands/sync'
|
21
|
+
|
22
|
+
def init_cmd_description
|
23
|
+
%(
|
24
|
+
|
25
|
+
The init command helps you create a new Murano project
|
26
|
+
======================================================
|
27
|
+
|
28
|
+
Example
|
29
|
+
-------
|
30
|
+
|
31
|
+
Create a new project in a new directory:
|
32
|
+
|
33
|
+
#{MrMurano::EXE_NAME} init my-new-app
|
34
|
+
|
35
|
+
Example
|
36
|
+
-------
|
37
|
+
|
38
|
+
Create a project in the current directory, or rewrite an existing project:
|
39
|
+
|
40
|
+
cd project/path
|
41
|
+
#{MrMurano::EXE_NAME} init
|
42
|
+
|
43
|
+
Solutions
|
44
|
+
---------
|
45
|
+
|
46
|
+
The init command configures two new Solutions for your new Murano project:
|
47
|
+
|
48
|
+
1. An Application
|
49
|
+
|
50
|
+
The Application is what users see.
|
51
|
+
|
52
|
+
Use the Application to control, monitor, and consume values from products.
|
53
|
+
|
54
|
+
2. A Product
|
55
|
+
|
56
|
+
A Product is something that captures data and reports it to the Application.
|
57
|
+
|
58
|
+
A Product can be a physical device connected to the Internet. It can be
|
59
|
+
a simulator running on your local network. It can be anything that
|
60
|
+
triggers events or supplies input data to the Application.
|
61
|
+
|
62
|
+
How it Works
|
63
|
+
------------
|
64
|
+
|
65
|
+
You will be asked to log on to your Business account.
|
66
|
+
|
67
|
+
- To create a new Murano business account, visit:
|
4
68
|
|
69
|
+
#{MrMurano::SIGN_UP_URL}
|
70
|
+
|
71
|
+
- Once logged on, you can choose to store your logon token so you
|
72
|
+
can skip this step when using Murano CLI.
|
73
|
+
|
74
|
+
After logon, name your Application, and then name your Product.
|
75
|
+
|
76
|
+
- Please choose names that contain only lowercase letters and numbers.
|
77
|
+
|
78
|
+
The names are used as variable names in scripts, and as domain names,
|
79
|
+
so they cannot contain underscores, dashes, or other punctuation.
|
80
|
+
|
81
|
+
After creating the two Solutions, they will be linked.
|
82
|
+
|
83
|
+
- Linking Solutions allows data and events to flow between the two.
|
84
|
+
|
85
|
+
For example, a Product device generates data that will be consumed
|
86
|
+
or processed by the Application.
|
87
|
+
|
88
|
+
The init command will pull down Product and Application services
|
89
|
+
that you can edit.
|
90
|
+
|
91
|
+
- The services, or event handlers, let you control how data is
|
92
|
+
processed and how your application behaves.
|
93
|
+
|
94
|
+
Take a look at the new directories and files created in your
|
95
|
+
Project after running init to see what services are available.
|
96
|
+
|
97
|
+
There are many other resources that are not downloaded that
|
98
|
+
you can also create and edit. Visit our docs site for more!
|
99
|
+
|
100
|
+
http://docs.exosite.com/
|
101
|
+
|
102
|
+
).strip
|
103
|
+
end
|
5
104
|
|
6
105
|
command :init do |c|
|
7
|
-
c.syntax = %
|
8
|
-
c.summary = %
|
9
|
-
c.description =
|
106
|
+
c.syntax = %(murano init)
|
107
|
+
c.summary = %(The easy way to start a project)
|
108
|
+
c.description = init_cmd_description
|
109
|
+
|
110
|
+
c.example %(
|
111
|
+
Initialize Murano project using specific Business and Solutions
|
112
|
+
).strip, 'murano init --business-id 12345 --product-name myprod --application-name myapp'
|
113
|
+
|
114
|
+
# Let user specify existing business and/or solution IDs and/or names.
|
115
|
+
cmd_option_business_pickers(c)
|
116
|
+
cmd_option_application_pickers(c)
|
117
|
+
cmd_option_product_pickers(c)
|
118
|
+
|
119
|
+
c.option('--refresh', %(Ignore Business and Solution IDs found in the config))
|
120
|
+
c.option('--purge', %(Remove Project directories and files, and recreate anew))
|
121
|
+
c.option('--[no-]sync', %(Pull down existing remote files (generally a good thing) (default: true)))
|
122
|
+
c.option('--[no-]mkdirs', %(Create default directories))
|
10
123
|
|
11
|
-
|
12
|
-
c.
|
124
|
+
# This command can be run without a project config.
|
125
|
+
c.project_not_required = true
|
126
|
+
# This command should not walk up the directory tree
|
127
|
+
# looking for a .murano/config project config file.
|
128
|
+
c.restrict_to_cur_dir = true
|
129
|
+
# Ask for user password if not found.
|
130
|
+
c.prompt_if_logged_off = true
|
13
131
|
|
14
132
|
c.action do |args, options|
|
15
|
-
|
16
|
-
|
17
|
-
puts ''
|
133
|
+
c.verify_arg_count!(args, 1)
|
134
|
+
options.default(refresh: false, purge: false, sync: true, mkdirs: true)
|
18
135
|
|
19
|
-
|
20
|
-
|
21
|
-
|
136
|
+
acc = MrMurano::Account.instance
|
137
|
+
validate_dir!(acc, args, options)
|
138
|
+
|
139
|
+
puts('')
|
140
|
+
if $cfg.project_exists
|
141
|
+
verbage = 'Rebasing'
|
142
|
+
else
|
143
|
+
verbage = 'Creating'
|
22
144
|
end
|
145
|
+
say("#{verbage} project at #{Rainbow($cfg['location.base'].to_s).underline}")
|
23
146
|
|
24
|
-
|
25
|
-
puts ''
|
147
|
+
puts('')
|
26
148
|
|
27
|
-
# Try to import a .Solutionfile.secret
|
149
|
+
# Try to import a .Solutionfile.secret.
|
150
|
+
# NOTE/2017-06-29: .Solutionfile.secret and SolutionFile (see ProjectFile.rb)
|
151
|
+
# are old MurCLI constructs; here we just try to migrate from the old format
|
152
|
+
# to the new format (where config goes in .murano/config and there's an
|
153
|
+
# explicit directory structure; the user cannot specify a different file
|
154
|
+
# hierarchy).
|
28
155
|
MrMurano::ConfigMigrate.new.import_secret
|
29
156
|
|
30
|
-
#
|
31
|
-
#
|
32
|
-
|
33
|
-
|
157
|
+
# See if the config already specifies a Business ID. If not, see if the
|
158
|
+
# config contains a username and password; otherwise, ask for them. With
|
159
|
+
# a username and password, get the list of businesses from Murano; if
|
160
|
+
# just one found, use that; if more than one found, ask user which one
|
161
|
+
# to use; else, if no businesses found, spit out the new-account URL
|
162
|
+
# and tell the user to use their browser to create a new Business.
|
163
|
+
unless $cfg['user.name'].to_s.empty?
|
164
|
+
say("Found User #{Rainbow($cfg['user.name']).underline}")
|
165
|
+
puts('')
|
166
|
+
end
|
34
167
|
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
168
|
+
# Find and verify Business by ID (from $cfg) or by name (from --business),
|
169
|
+
# or ask user which business to use. If user has not logged on, they will
|
170
|
+
# be asked for their username and/or password first.
|
171
|
+
biz = business_find_or_ask!(acc, options)
|
172
|
+
# Save the 'business.id' and 'business.name' to the project config.
|
173
|
+
# ([lb] guessing biz guaranteed to be not nil, but checking anyway.)
|
174
|
+
biz.write unless biz.nil?
|
175
|
+
|
176
|
+
# Verify or ask user to create Solutions.
|
177
|
+
sol_opts = {
|
178
|
+
create_ok: true,
|
179
|
+
update_cfg: true,
|
180
|
+
ignore_cfg: options.refresh,
|
181
|
+
verbose: true,
|
182
|
+
}
|
183
|
+
# Get/Create Application ID
|
184
|
+
sol_opts[:match_sid] = options.application_id
|
185
|
+
sol_opts[:match_name] = options.application_name
|
186
|
+
sol_opts[:match_fuzzy] = options.application
|
187
|
+
appl = solution_find_or_create(biz: biz, type: :application, **sol_opts)
|
188
|
+
# Get/Create Product ID
|
189
|
+
sol_opts[:match_sid] = options.product_id
|
190
|
+
sol_opts[:match_name] = options.product_name
|
191
|
+
sol_opts[:match_fuzzy] = options.product
|
192
|
+
prod = solution_find_or_create(biz: biz, type: :product, **sol_opts)
|
193
|
+
|
194
|
+
# Automatically link solutions.
|
195
|
+
link_opts = { verbose: true }
|
196
|
+
link_solutions(appl, prod, link_opts)
|
197
|
+
|
198
|
+
# If no ProjectFile, then write a ProjectFile.
|
199
|
+
write_project_file
|
200
|
+
|
201
|
+
if options.mkdirs
|
202
|
+
# Make the directory structure.
|
203
|
+
make_directories(purge: options.purge)
|
204
|
+
|
205
|
+
# For new solutions, Murano creates a few empty and example event handlers.
|
206
|
+
# For existing solutions, the user might already have created some files.
|
207
|
+
# Grab them now.
|
208
|
+
syncdown_new_and_existing if options.sync
|
59
209
|
end
|
60
|
-
puts '' # blank line
|
61
210
|
|
62
|
-
|
63
|
-
|
64
|
-
|
211
|
+
blather_success
|
212
|
+
end
|
213
|
+
|
214
|
+
def highlight_id(id)
|
215
|
+
Rainbow(id).aliceblue.bright.underline
|
216
|
+
end
|
217
|
+
|
218
|
+
def validate_dir!(acc, args, options)
|
219
|
+
# 2017-06-21: You can run init --dry and not have any files touched or
|
220
|
+
# any Murano elements changed. But there's not much utility in that.
|
221
|
+
# So maybe we should just not let users run a --dry init.
|
222
|
+
#if $cfg['tool.dry']
|
223
|
+
# acc.error 'Cannot run a --dry init.'
|
224
|
+
# exit 2
|
225
|
+
#end
|
226
|
+
|
227
|
+
if args.count > 1
|
228
|
+
acc.error('Please only specify 1 path')
|
229
|
+
exit(2)
|
230
|
+
end
|
231
|
+
|
232
|
+
if args.empty?
|
233
|
+
target_dir = Pathname.new(Dir.pwd)
|
65
234
|
else
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
elsif solz.count == 0 then
|
73
|
-
say "You don't have any solutions; lets create one"
|
74
|
-
solname = ask("Solution Name? ")
|
75
|
-
ret = acc.new_solution(solname)
|
76
|
-
if ret.nil? then
|
77
|
-
acc.error "Create Solution failed"
|
78
|
-
exit 5
|
79
|
-
end
|
80
|
-
if not ret.kind_of?(Hash) and not ret.empty? then
|
81
|
-
acc.error "Create Solution failed: #{ret.to_s}"
|
82
|
-
exit 2
|
235
|
+
target_dir = Pathname.new(args[0])
|
236
|
+
unless Dir.exist?(target_dir.to_path)
|
237
|
+
if target_dir.exist?
|
238
|
+
acc.error("Target exists but is not a directory: #{target_dir.to_path}")
|
239
|
+
exit 1
|
83
240
|
end
|
241
|
+
# FIXME/2017-07-02: Add test for this
|
242
|
+
target_dir.mkpath
|
243
|
+
end
|
244
|
+
Dir.chdir target_dir
|
245
|
+
end
|
84
246
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
247
|
+
# The home directory already has its own .murano/ folder,
|
248
|
+
# so we cannot create a project therein.
|
249
|
+
if Pathname.new(Dir.pwd).realpath == Pathname.new(Dir.home).realpath
|
250
|
+
acc.error('Cannot init a project in your HOME directory.')
|
251
|
+
exit(2)
|
252
|
+
end
|
253
|
+
# Might as well block root path, too.
|
254
|
+
if Pathname.new(Dir.pwd).realpath == File::SEPARATOR
|
255
|
+
acc.error('Cannot init a project in your root directory.')
|
256
|
+
exit(2)
|
257
|
+
end
|
95
258
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
259
|
+
# Only create a new project in an empty directory,
|
260
|
+
# or a recognized Murano CLI project.
|
261
|
+
unless $cfg.project_exists || options.refresh
|
262
|
+
# Get a list of files, ignoring the dot meta entries.
|
263
|
+
files = Dir.entries(target_dir.to_path)
|
264
|
+
files -= %w[. ..]
|
265
|
+
# If there are files (and it's not just .byebug_history which
|
266
|
+
# gets created when you develop with byebug), then ask to proceed.
|
267
|
+
unless files.empty? || (files.length == 1 && files[0] == '.byebug_history')
|
268
|
+
# Check for a .murano/ directory. It might be empty, which
|
269
|
+
# is why $cfg.project_exists might have been false.
|
270
|
+
unless files.include?(MrMurano::Config::CFG_DIR_NAME)
|
271
|
+
acc.warning 'The project directory contains unknown files.'
|
272
|
+
confirmed = acc.ask_yes_no('Really init project? [y/N] ', false)
|
273
|
+
unless confirmed
|
274
|
+
acc.warning('abort!')
|
275
|
+
exit 1
|
104
276
|
end
|
105
277
|
end
|
106
278
|
end
|
107
279
|
end
|
108
|
-
puts '' # blank line
|
109
280
|
|
110
|
-
|
111
|
-
|
112
|
-
say "Using Product ID already set to #{$cfg['product.id']}"
|
113
|
-
else
|
114
|
-
podz = acc.products
|
115
|
-
if podz.count == 1 then
|
116
|
-
prd = podz.first
|
117
|
-
say "You only have one product; using #{prd[:label]}"
|
118
|
-
$cfg.set('product.id', prd[:modelId], :project)
|
119
|
-
|
120
|
-
elsif podz.count == 0 then
|
121
|
-
say "You don't have any products; lets create one"
|
122
|
-
podname = ask("Product Name? ")
|
123
|
-
ret = acc.new_product(podname)
|
124
|
-
if ret.nil? then
|
125
|
-
acc.error "Create Product failed"
|
126
|
-
exit 5
|
127
|
-
end
|
128
|
-
if not ret.kind_of?(Hash) and not ret.empty? then
|
129
|
-
acc.error "Create Product failed: #{ret.to_s}"
|
130
|
-
exit 2
|
131
|
-
end
|
281
|
+
target_dir
|
282
|
+
end
|
132
283
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
284
|
+
def write_project_file
|
285
|
+
return if $project.using_projectfile
|
286
|
+
tmpl = File.read(
|
287
|
+
File.join(
|
288
|
+
File.dirname(__FILE__), '..', 'template', 'projectFile.murano.erb'
|
289
|
+
)
|
290
|
+
)
|
291
|
+
tmpl = ERB.new(tmpl)
|
292
|
+
res = tmpl.result($project.data_binding)
|
293
|
+
pr_file = $project['info.name'] + '.murano'
|
294
|
+
say("Writing Project file to #{pr_file}")
|
295
|
+
puts('')
|
296
|
+
File.open(pr_file, 'w') { |io| io << res }
|
297
|
+
end
|
141
298
|
|
299
|
+
def make_directories(purge: false)
|
300
|
+
base = $cfg['location.base']
|
301
|
+
base = Pathname.new(base) unless base.is_a?(Pathname)
|
302
|
+
num_locats = 0
|
303
|
+
num_mkpaths = 0
|
304
|
+
num_rmpaths = 0
|
305
|
+
%w[
|
306
|
+
location.files
|
307
|
+
location.endpoints
|
308
|
+
location.modules
|
309
|
+
location.eventhandlers
|
310
|
+
location.resources
|
311
|
+
].each do |cfgi|
|
312
|
+
num_locats += 1
|
313
|
+
n_mkdirs, n_rmdirs = make_directory(cfgi, base, purge)
|
314
|
+
num_mkpaths += n_mkdirs
|
315
|
+
num_rmpaths += n_rmdirs
|
316
|
+
end
|
317
|
+
if num_rmpaths > 0
|
318
|
+
say('Removed existing directories')
|
319
|
+
puts('')
|
320
|
+
end
|
321
|
+
if num_mkpaths > 0
|
322
|
+
if num_mkpaths == num_locats
|
323
|
+
say('Created default directories')
|
142
324
|
else
|
143
|
-
|
144
|
-
menu.prompt = "Select which Product to use:"
|
145
|
-
menu.flow = :columns_across
|
146
|
-
podz.sort{|a,b| a[:label]<=>b[:label]}.each do |p|
|
147
|
-
menu.choice(p[:label]) do
|
148
|
-
$cfg.set('product.id', p[:modelId], :project)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
325
|
+
say('Created some default directories')
|
152
326
|
end
|
327
|
+
else
|
328
|
+
say('Default directories already exist')
|
153
329
|
end
|
330
|
+
puts('')
|
331
|
+
end
|
154
332
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
base = $cfg['location.base']
|
170
|
-
base = Pathname.new(base) unless base.kind_of? Pathname
|
171
|
-
%w{
|
172
|
-
location.files
|
173
|
-
location.endpoints
|
174
|
-
location.modules
|
175
|
-
location.eventhandlers
|
176
|
-
location.specs
|
177
|
-
}.each do |cfgi|
|
178
|
-
path = $cfg[cfgi]
|
179
|
-
path = Pathname.new(path) unless path.kind_of? Pathname
|
180
|
-
path = base + path
|
181
|
-
unless path.exist? then
|
182
|
-
path = path.dirname unless path.extname.empty?
|
183
|
-
path.mkpath
|
184
|
-
end
|
333
|
+
def make_directory(cfgi, base, purge)
|
334
|
+
path = $cfg[cfgi]
|
335
|
+
path = Pathname.new(path) unless path.is_a?(Pathname)
|
336
|
+
path = base + path
|
337
|
+
# The path is generally a directory, but sometimes
|
338
|
+
# it's a file (e.g., spec/resources.yaml).
|
339
|
+
basedir = path
|
340
|
+
basedir = basedir.dirname unless basedir.extname.empty?
|
341
|
+
raise 'Unexpected: bad basedir' if basedir.to_s.empty? || basedir == File::SEPARATOR
|
342
|
+
found_basedir = false
|
343
|
+
basedir.ascend do |ancestor|
|
344
|
+
if ancestor == base
|
345
|
+
found_basedir = true
|
346
|
+
break
|
185
347
|
end
|
186
|
-
say "Default directories created"
|
187
348
|
end
|
349
|
+
unless found_basedir
|
350
|
+
say("Please fix your config: location.* values should be a subdir of location.base (#{base})")
|
351
|
+
exit 1
|
352
|
+
end
|
353
|
+
dry = $cfg['tool.dry']
|
354
|
+
num_rmdir = 0
|
355
|
+
if purge
|
356
|
+
MrMurano::Verbose.warning("--dry: Not purging existing directory: #{basedir}") if dry
|
357
|
+
files = Dir.glob("#{basedir}/*")
|
358
|
+
FileUtils.rm_rf(files, noop: dry)
|
359
|
+
FileUtils.rmdir(basedir, noop: dry)
|
360
|
+
MrMurano::Verbose.verbose("Removed #{basedir}")
|
361
|
+
num_rmdir += 1
|
362
|
+
end
|
363
|
+
return 0, num_rmdir if path.exist?
|
364
|
+
MrMurano::Verbose.warning("--dry: Not creating default directory: #{basedir}") if dry
|
365
|
+
FileUtils.mkdir_p(basedir, noop: dry)
|
366
|
+
FileUtils.touch(path, noop: dry) if path != basedir
|
367
|
+
[1, num_rmdir]
|
368
|
+
end
|
188
369
|
|
370
|
+
def syncdown_new_and_existing
|
371
|
+
# If the user already has an existing project, grab its files.
|
372
|
+
#
|
373
|
+
# If Murano creates any default eventhandlers, grab those
|
374
|
+
# (e.g., the timer event, tsdb exportJob, and user account
|
375
|
+
# are all created by the platform; and our own method,
|
376
|
+
# link_solutions, creates a boilerplate event handler that
|
377
|
+
# yeti-ui expects to find (you'll have issues in the web UI
|
378
|
+
# if this script doesn't exist)).
|
379
|
+
#
|
380
|
+
# See:
|
381
|
+
# sphinx-api/src/views/interface/productService.swagger.json
|
382
|
+
num_synced = syncdown_files(delete: false, create: true, update: false)
|
383
|
+
if num_synced > 0
|
384
|
+
inflection = MrMurano::Verbose.pluralize?('item', num_synced)
|
385
|
+
say("Synced #{num_synced} #{inflection}")
|
386
|
+
else
|
387
|
+
say('Items already synced')
|
388
|
+
end
|
389
|
+
puts('')
|
189
390
|
end
|
190
|
-
end
|
191
391
|
|
192
|
-
|
392
|
+
def blather_success
|
393
|
+
say('Success!')
|
394
|
+
puts('')
|
395
|
+
id_postfix = ' ID'
|
396
|
+
important_ids = %w[business application product].freeze
|
397
|
+
importantest_width = important_ids.map do |id_name|
|
398
|
+
cfg_key = id_name + '.id'
|
399
|
+
$cfg[cfg_key].length + id_postfix.length
|
400
|
+
end.max # Max the map; get the length of the longest ID.
|
401
|
+
important_ids.each do |id_name|
|
402
|
+
# cfg_key is, e.g., 'business.id', 'product.id', 'application.id'
|
403
|
+
cfg_key = id_name + '.id'
|
404
|
+
next if $cfg[cfg_key].nil?
|
405
|
+
#say "#{id_name.capitalize} ID: #{highlight_id($cfg[cfg_key])}"
|
406
|
+
# Right-aligned:
|
407
|
+
tmpl = format('%%%ds: %%s', importantest_width)
|
408
|
+
# Left-aligned:
|
409
|
+
#tmpl = format('%%-%ds: %%s', importantest_width)
|
410
|
+
say(format(tmpl, id_name.capitalize + id_postfix, highlight_id($cfg[cfg_key])))
|
411
|
+
end
|
412
|
+
puts('')
|
413
|
+
end
|
414
|
+
end
|