yuyi 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 433f29c3dd527456989fd397c0689ef37be6f26f
4
+ data.tar.gz: df06a761e812cf8f42ad0b15f4b87e9260088678
5
+ SHA512:
6
+ metadata.gz: afb1b75d2ba6783ea9b6ae84412a399a1919db287e23eac4300224632243df22a8afe639ef803565a0553169b538b87bf3f257985e5c10a17faed62a430561a4
7
+ data.tar.gz: a76fb8393af349ea7194cecc18c2d75147d21dc91faeba0611510f41b72f970bfd14f737f1e10d914c831ed8f1023a427f820a6708ec15863e3bc62dc6749e21
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .ruby-version
data/.new ADDED
@@ -0,0 +1,20 @@
1
+ ---
2
+ license: MIT
3
+ developer:
4
+ name: Ryan Brewster
5
+ email: brewster1134@gmail.com
6
+ tasks:
7
+ gem:
8
+ gemspec:
9
+ summary: Automation for installing/uninstalling/updating your machine environment
10
+ description: Maintain a menu of applications and services to automate the installation
11
+ of.
12
+ homepage: https://github.com/brewster1134/Yuyi
13
+ executables:
14
+ - yuyi
15
+ bindir: bin
16
+ test_files:
17
+ - spec/**/*.rb
18
+ project_name: Yuyi
19
+ type: ruby
20
+ version: 0.0.3
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ install: ruby -S bundle install --without development
3
+ script: bundle exec rspec
4
+ rvm:
5
+ - 1.8.7
6
+ - 1.9.3
7
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+ gem 'rspec'
3
+
4
+ group :development do
5
+ gem 'new'
6
+ gem 'guard'
7
+ gem 'guard-rspec', :require => false
8
+ gem 'terminal-notifier-guard'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,80 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activesupport (4.1.1)
5
+ i18n (~> 0.6, >= 0.6.9)
6
+ json (~> 1.7, >= 1.7.7)
7
+ minitest (~> 5.1)
8
+ thread_safe (~> 0.1)
9
+ tzinfo (~> 1.1)
10
+ celluloid (0.15.2)
11
+ timers (~> 1.1.0)
12
+ coderay (1.1.0)
13
+ colorize (0.7.3)
14
+ diff-lcs (1.2.5)
15
+ ffi (1.9.3)
16
+ formatador (0.2.5)
17
+ guard (2.6.1)
18
+ formatador (>= 0.2.4)
19
+ listen (~> 2.7)
20
+ lumberjack (~> 1.0)
21
+ pry (>= 0.9.12)
22
+ thor (>= 0.18.1)
23
+ guard-rspec (4.2.10)
24
+ guard (~> 2.1)
25
+ rspec (>= 2.14, < 4.0)
26
+ i18n (0.6.9)
27
+ json (1.8.1)
28
+ listen (2.7.7)
29
+ celluloid (>= 0.15.2)
30
+ rb-fsevent (>= 0.9.3)
31
+ rb-inotify (>= 0.9)
32
+ lumberjack (1.0.6)
33
+ method_source (0.8.2)
34
+ minitest (5.3.4)
35
+ new (0.0.13)
36
+ activesupport (~> 4.0)
37
+ colorize
38
+ rake
39
+ recursive-open-struct
40
+ semantic
41
+ thor
42
+ pry (0.10.0)
43
+ coderay (~> 1.1.0)
44
+ method_source (~> 0.8.1)
45
+ slop (~> 3.4)
46
+ rake (10.3.2)
47
+ rb-fsevent (0.9.4)
48
+ rb-inotify (0.9.5)
49
+ ffi (>= 0.5.0)
50
+ recursive-open-struct (0.4.5)
51
+ rspec (3.0.0)
52
+ rspec-core (~> 3.0.0)
53
+ rspec-expectations (~> 3.0.0)
54
+ rspec-mocks (~> 3.0.0)
55
+ rspec-core (3.0.0)
56
+ rspec-support (~> 3.0.0)
57
+ rspec-expectations (3.0.0)
58
+ diff-lcs (>= 1.2.0, < 2.0)
59
+ rspec-support (~> 3.0.0)
60
+ rspec-mocks (3.0.1)
61
+ rspec-support (~> 3.0.0)
62
+ rspec-support (3.0.0)
63
+ semantic (1.3.0)
64
+ slop (3.5.0)
65
+ terminal-notifier-guard (1.5.3)
66
+ thor (0.19.1)
67
+ thread_safe (0.3.4)
68
+ timers (1.1.0)
69
+ tzinfo (1.2.1)
70
+ thread_safe (~> 0.1)
71
+
72
+ PLATFORMS
73
+ ruby
74
+
75
+ DEPENDENCIES
76
+ guard
77
+ guard-rspec
78
+ new
79
+ rspec
80
+ terminal-notifier-guard
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard :rspec do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { 'spec' }
5
+ end
data/README.md ADDED
@@ -0,0 +1,122 @@
1
+ ![Travis CI](https://travis-ci.org/brewster1134/Yuyi.svg?branch=master)
2
+ # Yuyi
3
+ Opinionated automation for installing/uninstalling/upgrading your machine environment
4
+
5
+ ###### Support
6
+ * Mac OS X
7
+
8
+ ###### Dependencies
9
+ Nothing! Well thats not entirely true... the dependencies are already available by default on OS X
10
+ * Ruby >= 1.8.7
11
+ * Bash >= 3.2
12
+
13
+ #### Quick Usage
14
+ * Create a `yuyi_menu` file in your home folder _(see below for examples)_
15
+ * Run `ruby -e "$(curl -fsSL https://raw.github.com/brewster1134/Yuyi/master/bin/install)"` in Terminal
16
+
17
+ #### Example Menu
18
+
19
+ ```yaml
20
+ sources:
21
+ local: ~/Documents/Rolls
22
+ yuyi: https://github.com/brewster1134/Yuyi-Rolls.git
23
+ rolls:
24
+ google_chrome:
25
+ ruby:
26
+ versions: ['2.0.0-p353']
27
+ ```
28
+
29
+ Make sure to include a colon (:) at the end of each roll name.
30
+
31
+ If a roll accepts arguments, indent the key/value pairs below the roll name. You will be prompted with roll options when Yuyi runs, and the opportunity to change them before anything is installed.
32
+
33
+ ### Development
34
+
35
+ ##### Dependencies
36
+ * ruby
37
+ * bundler
38
+
39
+ ##### Running Tests
40
+ Run tests using rspec through guard
41
+
42
+ ```sh
43
+ bundle exec guard
44
+ ```
45
+
46
+ ##### Writing Rolls
47
+ ###### _required_
48
+ * `< Yuyu::Roll` The roll class needs to inherit from Yuyi::Roll
49
+ * `install` A block to install a roll
50
+ * `uninstall` A block to uninstall a roll
51
+ * `upgrade` A block to upgrade a roll
52
+ * `installed?` A block to tests if your roll is already installed or not
53
+
54
+ ###### _optional_
55
+ * `dependencies` Declare dependencies (supports multiple arguments) that your roll depends on
56
+ * `options` A hash of options (and a nested hash of option meta data _* see example below *_)
57
+
58
+ ###### _available methods_
59
+ * `title` Returns a string of the roll title.
60
+ * `options` Returns the roll options.
61
+ * `run` This will run a system command.
62
+ * `command` A string of the command you wish to run
63
+ * `verbose` If true, will show formatted output & errors. This is enabled when running yuyi with the `-V` or `--VERBOSE` flag
64
+ * `command?` Returns true or false if a command succeeds or fails. Good for using in the `installed?` block
65
+ * `write_to_file` Will add lines of text to a file. Good for using in the `install` block. Accepts multiple string arguments to be written as separate lines.
66
+ * `delete_from_file` Will remove lines of text to a file. Good for using in the `uninstall` block. Accepts multiple string arguments to be written as separate lines.
67
+
68
+ ```ruby
69
+ class MyRoll < Yuyi::Roll
70
+ install do
71
+ run 'brew install my_roll', :verbose => true
72
+
73
+ write_to_file '~/.bash_profile', "# #{title}"
74
+ end
75
+
76
+ uninstall do
77
+ run 'brew uninstall my_roll'
78
+
79
+ delete_from_file '~/.bash_profile', "# #{title}"
80
+ end
81
+
82
+ upgrade do
83
+ run 'brew upgrade my_roll'
84
+ end
85
+
86
+ installed? do
87
+ # simply check for a command
88
+ command? 'brew'
89
+
90
+ # or check the output of a command
91
+ # using `run` will return true or false, so use
92
+ `brew list` =~ /myroll/
93
+ end
94
+
95
+ dependencies :homebrew, :foo
96
+ dependencies :hombrew_cask if options[:version] == '2.0' # add dependencies conditionally
97
+
98
+ options(
99
+ :version => {
100
+ :description => 'The specific version you would like to install',
101
+ :example => '1.0', # optional
102
+ :default => '2.0', # optional
103
+ :required => true # optional - shows option in red
104
+ }
105
+ )
106
+ end
107
+ ```
108
+
109
+ ### TODO
110
+ * create yuyi gem with new
111
+ * setup (post suite install tasks)
112
+ * write to file checks for existing lines
113
+ * Enforce required options
114
+ * New roll generator (use new!)
115
+ * DOCS!
116
+ * show roll options on -l
117
+ * home brew/home brew cask roll to inherit
118
+ * installation summary
119
+ * abort install if required options arent set
120
+ * post install commands
121
+
122
+ [.](http://www.comedycentral.com/video-clips/3myds9/upright-citizens-brigade-sushi-chef)
data/bin/install ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # THIS CODE INSPIRED BY (COPIED FROM) HOMEBREW'S INSTALL SCRIPT. THANKS! :)
4
+
5
+ def download_app
6
+ Dir.chdir install_dir do
7
+ # -m to stop tar erroring out if it can't modify the mtime for root owned directories
8
+ # pipefail to cause the exit status from curl to propogate if it fails
9
+ # we use -k for curl because Leopard has a bunch of bad SSL certificates
10
+ curl_flags = 'fsSL'
11
+ curl_flags << 'k' if macos_version <= '10.5'
12
+ `/bin/bash -o pipefail -c '/usr/bin/curl -#{curl_flags} https://github.com/brewster1134/Yuyi/tarball/master | /usr/bin/tar xz -m --strip 1'`
13
+ end
14
+ end
15
+
16
+ def install
17
+ system "ruby #{install_dir}/bin/yuyi -V"
18
+ end
19
+
20
+ def cleanup
21
+ `rm -rf #{install_dir}`
22
+ end
23
+
24
+ # Create the directory to download to and install from
25
+ def install_dir
26
+ dir = "#{ENV['TMPDIR']}Yuyi"
27
+
28
+ unless File.directory? dir
29
+ `/bin/mkdir #{dir}`
30
+ end
31
+
32
+ dir
33
+ end
34
+
35
+ # Get OSX minor version
36
+ def macos_version
37
+ @macos_version ||= `/usr/bin/sw_vers -productVersion`.chomp[/10\.\d+/]
38
+ end
39
+
40
+ download_app
41
+ install
42
+ cleanup
data/bin/yuyi ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.dirname(__FILE__) + '/../lib'
3
+
4
+ require 'yuyi'
5
+
6
+ Yuyi.init ARGV
data/lib/yuyi/cli.rb ADDED
@@ -0,0 +1,355 @@
1
+ require 'open3'
2
+ require 'readline'
3
+ require 'yaml'
4
+
5
+ module Yuyi::Cli
6
+ # Configure readline
7
+ Readline.completion_append_character = '/'
8
+
9
+ # Define available command line options
10
+ # Each key must start with a unique letter
11
+ # Flags are automatically created based on the first letter (eg. -h, --help)
12
+ #
13
+ CLI_OPTIONS = {
14
+ :help => 'Shows these options.',
15
+ :list => 'List all rolls available to be included in your menu.',
16
+ :version => 'Shows the current version of Yuyi.',
17
+ :VERBOSE => 'Shows the output of all commands being run'
18
+ }
19
+
20
+ # Called by the install script
21
+ #
22
+ def init args
23
+ # get the first argument as the command
24
+ command, *rest = *args
25
+
26
+ # Call options method if valid argument is passed
27
+ # This checks for the full name or the first letter, proceeded by '--' or '-' respectively
28
+ CLI_OPTIONS.keys.each do |option|
29
+ if command == "--#{option}" || command == "-#{option.to_s.chars.first}"
30
+ begin
31
+ send option.to_s.downcase, rest
32
+ rescue
33
+ send option.to_s.downcase
34
+ end
35
+ return
36
+ end
37
+ end
38
+
39
+ # Show a warning if an invalid argument is passed and then show the help menu
40
+ if command
41
+ say 'INVALID ARGUMENT', :type => :fail
42
+ send :help
43
+ else
44
+ start
45
+ end
46
+ end
47
+
48
+ # Replacement for `puts` that accepts various stylistic arguments
49
+ # type: => [symbol] Preset colors for [:fail, :success, :warn]
50
+ # color: => [integer] See docs for #colorize for color codes
51
+ # justify: => [center|ljust|rjust] The type of justification to use
52
+ # padding: => [integer] The maximum string size to justify text in
53
+ # indent: => [integer] The maximum string size to justify text in
54
+ # newline: => [boolean] True if you want a newline after the output
55
+ #
56
+ def say text = '', args = {}
57
+ # defaults
58
+ args = {
59
+ :newline => true
60
+ }.merge args
61
+
62
+ # Justify options
63
+ if args[:justify] && args[:padding]
64
+ text = text.send args[:justify], args[:padding]
65
+ end
66
+
67
+ # Type options
68
+ # process last due to the addition of special color codes
69
+ text = case args[:type]
70
+ when :fail
71
+ colorize text, 31
72
+ when :success
73
+ colorize text, 32
74
+ when :warn
75
+ colorize text, 33
76
+ else
77
+ colorize text, args[:color]
78
+ end
79
+
80
+ if args[:indent]
81
+ text = (' ' * args[:indent]) + text
82
+ end
83
+
84
+ if args[:newline]
85
+ STDOUT.puts text
86
+ else
87
+ STDOUT.print text
88
+ end
89
+ end
90
+
91
+ # Accepts the same arguments as #say
92
+ #
93
+ def ask question, options = {}, &block
94
+ prompt = '>>> '
95
+ options = {
96
+ :readline => false,
97
+ :color => 1
98
+ }.merge(options)
99
+
100
+ say question, options
101
+
102
+ output = if options[:readline]
103
+ Readline.readline(prompt).chomp('/')
104
+ else
105
+ say prompt, :color => 1, :newline => false
106
+ STDIN.gets
107
+ end.rstrip
108
+
109
+ say
110
+ yield output
111
+ end
112
+
113
+ # Run a command and output formatting success/errors
114
+ #
115
+ def run command, args = {}
116
+ # check if in verbose mode
117
+ verbose = args[:verbose] || @verbose
118
+ output = `echo | #{command} 2>&1`
119
+ success = $?.success?
120
+
121
+ if verbose
122
+ say "RUNNING: #{command}", :type => (success ? :success : :fail)
123
+ say output
124
+ end
125
+
126
+ args[:boolean] ? success : output
127
+ end
128
+
129
+ def command? command
130
+ run command, :verbose => false, :boolean => true
131
+ end
132
+
133
+ # Write several lines to to an existing file
134
+ #
135
+ def write_to_file file, *text
136
+ File.open(File.expand_path(file), 'a') do |file|
137
+ file.write text * "\n"
138
+ file.write "\n"
139
+ end
140
+ end
141
+
142
+ # Delete specific lines from an existing file
143
+ #
144
+ def delete_from_file file, *text
145
+ # get file text
146
+ new_text = File.read(File.expand_path(file))
147
+
148
+ # iterate through text and remove it
149
+ text.each do |t|
150
+ regex = /^.*#{Regexp.escape(t)}.*\n/
151
+ new_text.gsub!(regex, '')
152
+ end
153
+
154
+ # write new text back to file
155
+ File.open(File.expand_path(file), 'w') { |f| f.write(new_text) }
156
+ end
157
+
158
+ def osx_version
159
+ run '/usr/bin/sw_vers -productVersion'.chomp[/10\.\d+/].to_f
160
+ end
161
+
162
+ private
163
+
164
+ def start
165
+ header
166
+ get_menu
167
+ confirm_upgrade
168
+ confirm_options
169
+ authenticate
170
+ Yuyi::Menu.instance.order_rolls
171
+ end
172
+
173
+ def header
174
+ line_length = 50
175
+ say
176
+ say '-' * line_length, :color => 4
177
+ say
178
+ say '____ ____ __ __ ____ ____ __ ', :color => 31, :justify => :center, :padding => line_length
179
+ say '\ \ / / | | | | \ \ / / | | ', :color => 32, :justify => :center, :padding => line_length
180
+ say ' \ \/ / | | | | \ \/ / | | ', :color => 33, :justify => :center, :padding => line_length
181
+ say ' \_ _/ | | | | \_ _/ | | ', :color => 34, :justify => :center, :padding => line_length
182
+ say ' | | | `--\' | | | | | ', :color => 35, :justify => :center, :padding => line_length
183
+ say ' |__| \______/ |__| |__| ', :color => 36, :justify => :center, :padding => line_length
184
+ say
185
+ say "VERSION #{Yuyi::VERSION}", :justify => :center, :padding => line_length
186
+ say
187
+ say '-' * line_length, :color => 4
188
+ say
189
+ end
190
+
191
+ # Ask the user for a menu file to load
192
+ #
193
+ def get_menu
194
+ menu = nil
195
+
196
+ until menu
197
+ say 'Navigate to a menu file...', :type => :success
198
+ menu = ask "...or just press enter to load `#{Yuyi::DEFAULT_MENU}`", :readline => true, :color => 36 do |path|
199
+ path = path.empty? ? Yuyi::DEFAULT_MENU : path
200
+
201
+ if Yuyi::Menu.load_from_file path
202
+ say 'Downloading Sources... Please Wait', :type => :warn
203
+ say
204
+
205
+ Yuyi::Menu.new path
206
+ else
207
+ say 'Invalid Path... Please check the location of your menu file', :type => :fail
208
+ say
209
+
210
+ nil
211
+ end
212
+ end
213
+ end
214
+ end
215
+
216
+ # Ask to check for upgrades
217
+ #
218
+ def confirm_upgrade
219
+ ask 'Do you want to check for upgrades for already installed rolls? (Yn)', :type => :warn do |upgrade|
220
+ Yuyi::Menu.upgrade? upgrade == 'Y'
221
+ end
222
+ end
223
+
224
+ # If any rolls on the menu have options, confirm the options before continuing
225
+ #
226
+ def confirm_options
227
+ confirm = false
228
+ Yuyi::Menu.rolls.each do |name, roll|
229
+
230
+ unless roll.class.options.empty?
231
+ present_options roll
232
+ confirm = true
233
+ end
234
+ end
235
+
236
+ if confirm
237
+ ask 'Hit any key when you have your options set correctly in your menu file', :type => :warn do
238
+ Yuyi::Menu.load_from_file
239
+ end
240
+ end
241
+ end
242
+
243
+ def authenticate
244
+ say 'Please enter the admin password', :type => :warn
245
+ say 'NOTE: This is passed directly to sudo and is not saved.'
246
+ say ' This will ensure all your installs run unsupervised.'
247
+
248
+ # clear sudo timestamp & run any command as admin to force a password prompt
249
+ system 'sudo -k; sudo echo >> /dev/null 2>&1'
250
+ say
251
+ end
252
+
253
+ # Show formatted options
254
+ #
255
+ def present_options roll, examples = true
256
+ indent = 2
257
+ longest_option = roll.options.keys.map(&:to_s).max_by(&:length).length + indent
258
+
259
+ say "Available options for #{roll.title}...", :color => 32
260
+
261
+ roll.option_defs.each do |k, v|
262
+ option_color = v[:required] ? 31 : 36
263
+
264
+ say "#{k.to_s.rjust(longest_option)}: ", :color => option_color, :newline => false
265
+ say v[:description]
266
+ say (' ' * (longest_option + indent)), :newline => false
267
+ say 'default: ', :color => 36, :newline => false
268
+ say v[:default]
269
+ end
270
+
271
+ if examples
272
+ examples_hash = {}
273
+ example_indent = longest_option + indent
274
+ options = roll.options.dup
275
+
276
+ # merge examples from roll source in
277
+ options.each do |option, value|
278
+ if example = roll.option_defs[option][:example]
279
+ options[option] = example
280
+ end
281
+ end
282
+
283
+ examples_hash[roll.file_name.to_s] = options
284
+
285
+
286
+ say
287
+ say 'Example', :color => 33, :indent => example_indent, :newline => false
288
+ say examples_hash.deep_stringify_keys!.to_yaml.sub("--- ", '').gsub(/\n(\s*)/, "\n\\1#{' ' * example_indent}")
289
+ end
290
+ end
291
+
292
+ # Output text with a certain color (or style)
293
+ # Reference for color codes
294
+ # https://github.com/flori/term-ansicolor/blob/master/lib/term/ansicolor.rb
295
+ #
296
+ def colorize text, color_code
297
+ return text unless color_code
298
+ "\e[#{color_code}m#{text}\e[0m"
299
+ end
300
+
301
+ # METHODS FOR FLAGS
302
+ #
303
+ def help
304
+ longest_option = CLI_OPTIONS.keys.map(&:to_s).max.length
305
+
306
+ say
307
+ CLI_OPTIONS.each do |option, description|
308
+ string = ''
309
+ string << "-#{option.to_s.chars.first}"
310
+ string << ', '
311
+ string << "--#{option.to_s.ljust(longest_option)}"
312
+ string << ' '
313
+ string << description
314
+ say string
315
+ end
316
+ say
317
+ end
318
+
319
+ # List all available rolls
320
+ #
321
+ def list
322
+ get_menu
323
+ Yuyi::Menu.set_sources
324
+
325
+ # Collect all rolls from all sources
326
+ #
327
+ rolls = []
328
+ Yuyi::Menu.sources.each do |source|
329
+ rolls |= source.available_rolls.keys
330
+ end
331
+
332
+ # alphabatize rolls
333
+ rolls = rolls.map(&:to_s).sort.map(&:to_sym)
334
+
335
+ say 'Available Rolls', :type => :success
336
+ say '---------------', :type => :success
337
+ rolls.each do |roll|
338
+ say roll.to_s
339
+ end
340
+ say
341
+ end
342
+
343
+ # Return current version
344
+ #
345
+ def version
346
+ say "#{Yuyi::NAME} #{Yuyi::VERSION}"
347
+ end
348
+
349
+ # Return current version
350
+ #
351
+ def verbose
352
+ @verbose = true
353
+ start
354
+ end
355
+ end