yuyi 1.0.8 → 1.1.3
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.
- checksums.yaml +4 -4
- data/.new +1 -1
- data/.ruby-version +1 -0
- data/Gemfile +7 -2
- data/Gemfile.lock +16 -21
- data/Guardfile +1 -1
- data/README.md +41 -24
- data/Rakefile +38 -0
- data/bin/yuyi +9 -1
- data/lib/yuyi/cli.rb +32 -363
- data/lib/yuyi/core.rb +4 -0
- data/lib/yuyi/dsl.rb +131 -0
- data/lib/yuyi/menu.rb +174 -166
- data/lib/yuyi/roll.rb +95 -140
- data/lib/yuyi/source.rb +4 -3
- data/lib/yuyi/ui.rb +103 -0
- data/lib/yuyi.rb +17 -2
- data/spec/fixtures/menu.yaml +3 -2
- data/spec/fixtures/menu2.yaml +5 -2
- data/spec/fixtures/roll_dir/{nested/foo_roll.rb → foo_roll.rb} +0 -0
- data/spec/fixtures/roll_dir/foo_roll_model.rb +2 -0
- data/spec/fixtures/roll_dir/nested/bar_roll.rb +1 -1
- data/spec/fixtures/roll_zip.zip +0 -0
- data/spec/lib/yuyi/cli_spec.rb +11 -310
- data/spec/lib/yuyi/core_spec.rb +1 -1
- data/spec/lib/yuyi/dsl_spec.rb +135 -0
- data/spec/lib/yuyi/menu_spec.rb +177 -117
- data/spec/lib/yuyi/roll_spec.rb +38 -227
- data/spec/lib/yuyi/source_spec.rb +6 -2
- data/spec/lib/yuyi/ui_spec.rb +36 -0
- data/spec/roll_validator.rb +51 -0
- data/spec/spec_helper.rb +2 -0
- data/yuyi_menu +8 -0
- metadata +36 -10
- data/bin/install +0 -42
data/lib/yuyi/menu.rb
CHANGED
@@ -1,155 +1,65 @@
|
|
1
|
-
|
2
|
-
@rolls = {}
|
1
|
+
require 'readline'
|
3
2
|
|
4
|
-
|
3
|
+
class Yuyi::Menu
|
4
|
+
# Stores a single menu instance on the class
|
5
|
+
# If a new menu is initialized, it will become the only menu accessible through Yuyi::Menu.menu
|
5
6
|
#
|
6
|
-
|
7
|
-
|
8
|
-
def self.object; @object; end
|
9
|
-
def object; self.class.object; end
|
10
|
-
|
11
|
-
def self.sources; @@instance.sources; end
|
12
|
-
def sources; @sources; end
|
13
|
-
|
14
|
-
def self.rolls; @rolls; end
|
15
|
-
def rolls; self.class.rolls; end
|
16
|
-
|
17
|
-
def self.path
|
18
|
-
@@instance.path
|
19
|
-
end
|
20
|
-
def path; @path; end
|
7
|
+
@@menu = nil
|
21
8
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@@
|
28
|
-
|
9
|
+
# Create a new menu that stores the raw yaml file
|
10
|
+
# along with source, roll, and roll model instances
|
11
|
+
#
|
12
|
+
def initialize path
|
13
|
+
# make menu instance accessible by the class
|
14
|
+
@@menu = self
|
15
|
+
@rolls = {}
|
16
|
+
@sources = []
|
29
17
|
|
30
|
-
|
31
|
-
|
32
|
-
end
|
18
|
+
# load a yaml file
|
19
|
+
load_from_file path
|
33
20
|
|
34
|
-
|
35
|
-
|
21
|
+
# create objects from the menu
|
22
|
+
set_sources
|
23
|
+
set_roll_models
|
24
|
+
set_rolls
|
36
25
|
end
|
37
26
|
|
38
|
-
def
|
39
|
-
|
27
|
+
def options roll
|
28
|
+
@yaml[:rolls][roll] || {}
|
40
29
|
end
|
41
30
|
|
42
|
-
#
|
31
|
+
# DSL METHODS
|
43
32
|
#
|
44
|
-
def self.
|
45
|
-
menu
|
46
|
-
File.open(File.expand_path(path))
|
47
|
-
rescue
|
48
|
-
response = Yuyi.run "curl -sS #{path}"
|
49
|
-
$?.success? ? response : nil
|
50
|
-
end
|
51
|
-
|
52
|
-
@object = begin
|
53
|
-
YAML.load(menu).deep_symbolize_keys!
|
54
|
-
rescue
|
55
|
-
nil
|
56
|
-
end
|
33
|
+
def self.sources
|
34
|
+
menu.send :sources
|
57
35
|
end
|
58
36
|
|
59
37
|
# Add rolls to hash in format of {file_name: RollInstance}
|
60
|
-
# Called from
|
38
|
+
# Called from Yuyi::Roll when a roll is inherited
|
61
39
|
#
|
62
40
|
def self.add_roll file_name, klass
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
# Get/Set upgrade flag
|
67
|
-
#
|
68
|
-
def upgrade? boolean = nil
|
69
|
-
@upgrade = boolean.nil? ? @upgrade : boolean
|
70
|
-
end
|
71
|
-
|
72
|
-
# Check if a roll is on the menu
|
73
|
-
#
|
74
|
-
def on_the_menu? roll
|
75
|
-
object[:rolls].keys.include? roll
|
76
|
-
end
|
77
|
-
|
78
|
-
# Download & create all sources on the menu
|
79
|
-
#
|
80
|
-
def set_sources
|
81
|
-
if object[:sources].empty?
|
82
|
-
Yuyi.say 'No rolls could be found because no sources were set in your menu.'
|
83
|
-
return
|
41
|
+
unless klass.to_s.include? 'RollModel'
|
42
|
+
rolls[file_name] = klass.new
|
84
43
|
end
|
85
|
-
|
86
|
-
@sources = []
|
87
|
-
object[:sources].each do |source|
|
88
|
-
source.each do |name, path|
|
89
|
-
@sources << Yuyi::Source.new(name, path)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
@sources
|
94
44
|
end
|
95
45
|
|
96
|
-
def
|
97
|
-
|
46
|
+
def self.on_the_menu? roll
|
47
|
+
menu.send :on_the_menu?, roll
|
98
48
|
end
|
99
49
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
header_length = 80
|
104
|
-
all_rolls = sorted_rolls
|
105
|
-
|
106
|
-
|
107
|
-
# pre installs
|
108
|
-
#
|
109
|
-
Yuyi.say '=' * header_length, :color => 35
|
110
|
-
Yuyi.say 'APPETIZERS', :color => 35, :justify => :center, :padding => header_length
|
111
|
-
Yuyi.say 'Pre Install', :justify => :center, :padding => header_length
|
112
|
-
Yuyi.say
|
113
|
-
|
114
|
-
all_rolls.each do |file_name|
|
115
|
-
rolls[file_name].appetizers
|
116
|
-
end
|
117
|
-
|
118
|
-
|
119
|
-
# main installs
|
120
|
-
#
|
121
|
-
Yuyi.say '=' * header_length, :color => 36
|
122
|
-
Yuyi.say 'ENTREES', :color => 36, :justify => :center, :padding => header_length
|
123
|
-
Yuyi.say 'Main Install', :justify => :center, :padding => header_length
|
124
|
-
Yuyi.say
|
125
|
-
|
126
|
-
all_rolls.each do |file_name|
|
127
|
-
rolls[file_name].entree
|
128
|
-
end
|
129
|
-
|
130
|
-
|
131
|
-
# post installs
|
132
|
-
#
|
133
|
-
Yuyi.say '=' * header_length, :color => 35
|
134
|
-
Yuyi.say 'DESSERT', :color => 35, :justify => :center, :padding => header_length
|
135
|
-
Yuyi.say 'Post Install', :justify => :center, :padding => header_length
|
136
|
-
Yuyi.say
|
137
|
-
|
138
|
-
all_rolls.each do |file_name|
|
139
|
-
rolls[file_name].dessert
|
140
|
-
end
|
141
|
-
|
50
|
+
def self.find_roll name, options = {}
|
51
|
+
menu.send :find_roll, name, options
|
52
|
+
end
|
142
53
|
|
143
|
-
|
144
|
-
|
145
|
-
Yuyi.say '=' * header_length, :color => 36
|
146
|
-
Yuyi.say
|
54
|
+
def self.load_from_file
|
55
|
+
menu.send :load_from_file
|
147
56
|
end
|
148
57
|
|
149
|
-
# Find the best roll
|
58
|
+
# Find the best roll match from the sources and require it
|
150
59
|
#
|
151
60
|
def find_roll name, options = {}
|
152
|
-
|
61
|
+
return if on_the_menu? name
|
62
|
+
|
153
63
|
# return specific source roll if specified in the menu
|
154
64
|
#
|
155
65
|
if source = options[:source]
|
@@ -159,8 +69,8 @@ class Yuyi::Menu
|
|
159
69
|
# look through the sources for the first roll that matches.
|
160
70
|
# sources are listed in the menu in order of priority
|
161
71
|
else
|
162
|
-
sources.each do |source|
|
163
|
-
if path = source.
|
72
|
+
@sources.each do |source|
|
73
|
+
if path = source.rolls[name]
|
164
74
|
require_roll name, path
|
165
75
|
return
|
166
76
|
end
|
@@ -173,62 +83,111 @@ class Yuyi::Menu
|
|
173
83
|
Yuyi.say
|
174
84
|
end
|
175
85
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
#
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
86
|
+
private
|
87
|
+
|
88
|
+
# CLASS METHODS
|
89
|
+
#
|
90
|
+
def self.menu; @@menu; end
|
91
|
+
def self.menu_path; @@menu.send :menu_path; end
|
92
|
+
def self.order; @@menu.send :order; end
|
93
|
+
def self.rolls; @@menu.send :rolls; end
|
94
|
+
def self.sources; @@menu.send :sources; end
|
95
|
+
|
96
|
+
def self.options roll
|
97
|
+
@@menu.options roll
|
98
|
+
end
|
99
|
+
|
100
|
+
# INSTANCE METHODS
|
101
|
+
#
|
102
|
+
def menu_path; @menu_path; end
|
103
|
+
def rolls; @rolls; end
|
104
|
+
def sources; @sources; end
|
105
|
+
|
106
|
+
# Attempt to load a menu from a file path
|
107
|
+
#
|
108
|
+
def load_from_file menu_path = @menu_path
|
109
|
+
if !menu_path || menu_path.empty?
|
110
|
+
get_menu_path
|
184
111
|
return
|
185
112
|
end
|
186
|
-
end
|
187
|
-
end
|
188
113
|
|
189
|
-
|
114
|
+
unless @menu_path
|
115
|
+
# check if path is local first
|
116
|
+
begin
|
117
|
+
File.open(File.expand_path(menu_path))
|
118
|
+
|
119
|
+
@menu_path = File.expand_path(menu_path)
|
190
120
|
|
191
|
-
|
192
|
-
|
121
|
+
# otherwise assume it is remote and try to download it
|
122
|
+
rescue
|
123
|
+
# try to download the menu path
|
124
|
+
response = Yuyi.run "curl -sS #{menu_path}"
|
193
125
|
|
194
|
-
|
195
|
-
|
126
|
+
# save a local copy of the remote menu
|
127
|
+
if $?.success?
|
128
|
+
# if a menu was downloaded, save the response to a local file
|
129
|
+
local_file_name = Yuyi::DEFAULT_MENU.clone << '_remote'
|
196
130
|
|
197
|
-
|
198
|
-
|
199
|
-
|
131
|
+
File.open local_file_name, 'w+' do |f|
|
132
|
+
f.write response
|
133
|
+
end
|
134
|
+
|
135
|
+
@menu_path = local_file_name
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
begin
|
141
|
+
@yaml = YAML.load(File.open(@menu_path)).deep_symbolize_keys!
|
142
|
+
rescue
|
143
|
+
Yuyi.say "No menu could be loaded from `#{menu_path}`", :type => :fail
|
144
|
+
get_menu_path
|
145
|
+
end
|
200
146
|
end
|
201
147
|
|
202
|
-
#
|
148
|
+
# prompt the user to enter a path to menu file
|
149
|
+
# keep prompting until path is valid
|
203
150
|
#
|
204
|
-
def
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
object[:roll_models][name] = path
|
151
|
+
def get_menu_path
|
152
|
+
until @yaml
|
153
|
+
Yuyi.say 'Navigate to a menu file...', :type => :success
|
154
|
+
Yuyi.ask "...or just press enter to load `#{Yuyi::DEFAULT_MENU}`", :readline => true, :color => 36 do |user_path|
|
155
|
+
menu_path = user_path.empty? ? Yuyi::DEFAULT_MENU : user_path
|
156
|
+
load_from_file menu_path
|
211
157
|
end
|
212
158
|
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Initialize sources from menu
|
162
|
+
#
|
163
|
+
def set_sources
|
164
|
+
@yaml[:sources].each do |name, path|
|
165
|
+
@sources << Yuyi::Source.new(name, path)
|
166
|
+
end
|
167
|
+
end
|
213
168
|
|
214
|
-
|
215
|
-
|
169
|
+
# Loop through the roll models in the yaml file and find a matching roll
|
170
|
+
def set_roll_models
|
171
|
+
@sources.each do |source|
|
172
|
+
source.roll_models.values.each do |roll_model_path|
|
173
|
+
require roll_model_path
|
174
|
+
end
|
216
175
|
end
|
217
176
|
end
|
218
177
|
|
219
|
-
#
|
178
|
+
# Loop through the rolls in the yaml file and find a matching roll
|
220
179
|
#
|
221
180
|
def set_rolls
|
222
|
-
|
223
|
-
find_roll
|
181
|
+
@yaml[:rolls].each do |roll_name, roll_options|
|
182
|
+
find_roll roll_name, roll_options || {}
|
224
183
|
end
|
225
184
|
end
|
226
185
|
|
227
|
-
#
|
186
|
+
# Add a single roll to the menu
|
228
187
|
#
|
229
188
|
def require_roll name, path
|
230
189
|
# check if already on the roll for when requiring dependencies
|
231
|
-
return if
|
190
|
+
return if on_the_menu? name
|
232
191
|
|
233
192
|
begin
|
234
193
|
require path
|
@@ -239,17 +198,66 @@ private
|
|
239
198
|
end
|
240
199
|
end
|
241
200
|
|
242
|
-
# Check if roll has already been
|
201
|
+
# Check if roll has already been added
|
243
202
|
#
|
244
|
-
def
|
245
|
-
rolls.keys.include? roll
|
203
|
+
def on_the_menu? roll
|
204
|
+
@rolls.keys.include? roll
|
205
|
+
end
|
206
|
+
|
207
|
+
# Initialize all the rolls in order
|
208
|
+
#
|
209
|
+
def order
|
210
|
+
header_length = 80
|
211
|
+
all_rolls = sorted_rolls
|
212
|
+
|
213
|
+
|
214
|
+
# pre installs
|
215
|
+
#
|
216
|
+
Yuyi.say '=' * header_length, :color => 35
|
217
|
+
Yuyi.say 'APPETIZERS', :color => 35, :justify => :center, :padding => header_length
|
218
|
+
Yuyi.say 'Pre Install', :justify => :center, :padding => header_length
|
219
|
+
Yuyi.say
|
220
|
+
|
221
|
+
all_rolls.each do |file_name|
|
222
|
+
@rolls[file_name].appetizers
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
# main installs
|
227
|
+
#
|
228
|
+
Yuyi.say '=' * header_length, :color => 36
|
229
|
+
Yuyi.say 'ENTREES', :color => 36, :justify => :center, :padding => header_length
|
230
|
+
Yuyi.say 'Main Install', :justify => :center, :padding => header_length
|
231
|
+
Yuyi.say
|
232
|
+
|
233
|
+
all_rolls.each do |file_name|
|
234
|
+
@rolls[file_name].entree
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
# post installs
|
239
|
+
#
|
240
|
+
Yuyi.say '=' * header_length, :color => 35
|
241
|
+
Yuyi.say 'DESSERT', :color => 35, :justify => :center, :padding => header_length
|
242
|
+
Yuyi.say 'Post Install', :justify => :center, :padding => header_length
|
243
|
+
Yuyi.say
|
244
|
+
|
245
|
+
all_rolls.each do |file_name|
|
246
|
+
@rolls[file_name].dessert
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
Yuyi.say '=' * header_length, :color => 36
|
251
|
+
Yuyi.say 'YUYI COMPLETED', :color => 36, :justify => :center, :padding => header_length
|
252
|
+
Yuyi.say '=' * header_length, :color => 36
|
253
|
+
Yuyi.say
|
246
254
|
end
|
247
255
|
|
248
256
|
# Return an array of the topologically sorted rolls from the menu
|
249
257
|
#
|
250
258
|
def sorted_rolls
|
251
259
|
tsort_hash = {}
|
252
|
-
rolls.each do |file_name, roll|
|
260
|
+
@rolls.each do |file_name, roll|
|
253
261
|
tsort_hash[file_name.to_s] = roll.dependencies.map(&:to_s)
|
254
262
|
end
|
255
263
|
|