skytap-yf 0.2.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.
@@ -0,0 +1,216 @@
1
+ #TODO:NLA Move this monkey patch elsewhere.
2
+ module Terminal
3
+ class Table
4
+ def additional_column_widths
5
+ return [] if style.width.nil?
6
+ spacing = style.width - columns_width
7
+ if spacing < 0
8
+ # SKYTAP: Modify this line not to raise an execption.
9
+ return []
10
+ else
11
+ per_col = spacing / number_of_columns
12
+ arr = (1...number_of_columns).to_a.map { |i| per_col }
13
+ other_cols = arr.inject(0) { |s, i| s + i }
14
+ arr << spacing - other_cols
15
+ arr
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ module Skytap
22
+ module Templates
23
+ class Base < OpenStruct
24
+
25
+ # The template can refer to hash keys as if they were local variables.
26
+ def self.render(hash)
27
+ attrs = {'description' => 'DEFAULT DESCRIPTION HERE'}.merge(hash)
28
+ new(attrs).render
29
+ end
30
+
31
+ def template_str
32
+ raise 'must be overridden'
33
+ end
34
+
35
+ def render
36
+ # Allow -%> to trim surrounding whitespace in ERB.
37
+ trim_mode_char = '-'
38
+ ERB.new(template_str, nil, trim_mode_char).result(binding)
39
+ end
40
+
41
+ def indent(msg='', width=5)
42
+ msg ||= ''
43
+ msg.split("\n").collect do |line|
44
+ (' ' * width) << line
45
+ end.join("\n")
46
+ end
47
+ end
48
+
49
+ class Help < Base
50
+ TEMPLATE = File.expand_path(File.join(File.dirname(__FILE__), 'help_templates', 'help.erb'))
51
+
52
+ def self.render(command)
53
+ new('command' => command).render
54
+ end
55
+
56
+ def template_str
57
+ File.open(TEMPLATE, &:read)
58
+ end
59
+
60
+ def header(name)
61
+ name.bright
62
+ end
63
+
64
+ def error_msg
65
+ if command.error
66
+ "Error: ".color(:red).bright << command.error
67
+ end
68
+ end
69
+
70
+ def subcommands
71
+ @subcommands ||= command.class.subcommand_banners
72
+ end
73
+
74
+ #TODO:NLA These two methods are from
75
+ #https://github.com/cldwalker/hirb/blob/master/lib/hirb/util.rb#L61-71,
76
+ #which is under the MIT license. Figure out how to cite it properly.
77
+ def detect_terminal_size
78
+ if (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/)
79
+ [ENV['COLUMNS'].to_i, ENV['LINES'].to_i]
80
+ elsif (RUBY_PLATFORM =~ /java/ || (!STDIN.tty? && ENV['TERM'])) && command_exists?('tput')
81
+ [`tput cols`.to_i, `tput lines`.to_i]
82
+ elsif STDIN.tty? && command_exists?('stty')
83
+ `stty size`.scan(/\d+/).map { |s| s.to_i }.reverse
84
+ else
85
+ nil
86
+ end
87
+ rescue
88
+ nil
89
+ end
90
+ # Determines if a shell command exists by searching for it in ENV['PATH'].
91
+ def command_exists?(command)
92
+ ENV['PATH'].split(File::PATH_SEPARATOR).any? {|d| File.exists? File.join(d, command) }
93
+ end
94
+
95
+ def hard_wrap(text, line_width)
96
+ breaking_word_wrap(text, :line_width => line_width)
97
+ end
98
+
99
+ # Taken from http://apidock.com/rails/ActionView/Helpers/TextHelper/word_wrap#1023-word-wrap-with-breaking-long-words
100
+ def breaking_word_wrap(text, *args)
101
+ options = args.extract_options!
102
+ unless args.blank?
103
+ options[:line_width] = args[0] || 80
104
+ end
105
+ options.reverse_merge!(:line_width => 80)
106
+ text = text.split(" ").collect do |word|
107
+ word.length > options[:line_width] ? word.gsub(/(.{1,#{options[:line_width]}})/, "\\1 ") : word
108
+ end * " "
109
+ text.split("\n").collect do |line|
110
+ line.length > options[:line_width] ? line.gsub(/(.{1,#{options[:line_width]}})(\s+|$)/, "\\1\n").strip : line
111
+ end * "\n"
112
+ end
113
+
114
+ def global_options_table
115
+ min_width, max_width = 70, 120
116
+ indentation = 5
117
+ tty_cols = [detect_terminal_size.try(:first) || 80, min_width].max
118
+ width = [tty_cols, max_width].min - indentation
119
+ option_col_width = CommandLine.global_options.values.collect(&:signature).collect(&:length).max
120
+ padding = 7
121
+
122
+ table = Terminal::Table.new do |t|
123
+ t.style = {:width => width}
124
+ t.headings = ['Option'.underline, 'Description'.underline]
125
+ desc_col_width = width - option_col_width - padding
126
+ t.rows = CommandLine.global_options.values.inject([]) do |acc, opt|
127
+ acc << [
128
+ opt.signature,
129
+ description_cell(opt, desc_col_width)
130
+ ]
131
+
132
+ # Add separator unless we're at the very end.
133
+ acc << :separator unless acc.length == 2 * CommandLine.global_options.values.length - 1
134
+ acc
135
+ end
136
+ end
137
+ indent(table.to_s, indentation)
138
+ end
139
+
140
+
141
+ def description_cell(option, col_width)
142
+ [description(option, col_width),
143
+ default(option, col_width),
144
+ choices(option, col_width)].compact.join("\n")
145
+ end
146
+
147
+ def description(option, col_width)
148
+ if option.desc.present?
149
+ hard_wrap(option.desc, col_width) << "\n"
150
+ end
151
+ end
152
+
153
+ def default(option, col_width)
154
+ if option.default.present? && option.show_default?
155
+ hard_wrap("Default: #{option.default}", col_width)
156
+ end
157
+ end
158
+
159
+ def choices(option, col_width)
160
+ if option.choices.present?
161
+ hard_wrap("Options: #{option.choices.join(', ')}", col_width)
162
+ end
163
+ end
164
+
165
+ def parameters_table
166
+ min_width, max_width = 70, 120
167
+ indentation = 5
168
+ tty_cols = [detect_terminal_size.try(:first) || 80, min_width].max
169
+ width = [tty_cols, max_width].min - indentation
170
+ left_col_width = command.parameters.collect{|name, _| name}.collect(&:length).max || 0
171
+ padding = 7
172
+
173
+ table = Terminal::Table.new do |t|
174
+ t.style = {:width => width}
175
+ t.headings = ['Parameter'.underline << "\n#{'*'.color(:cyan)} = required", 'Description'.underline]
176
+ desc_col_width = width - left_col_width - padding
177
+
178
+ t.rows = command.parameters.inject([]) do |acc, hash|
179
+ name = hash.keys.first
180
+ info = hash[name]
181
+
182
+ acc << [
183
+ info['required'] ? ('*'.color(:cyan) << name) : (' ' << name),
184
+ param_description_cell(info, desc_col_width)
185
+ ]
186
+
187
+ # Add separator unless we're at the very end.
188
+ acc << :separator unless acc.length == 2 * command.parameters.length - 1
189
+ acc
190
+ end
191
+ end
192
+ indent(table.to_s, indentation)
193
+ end
194
+
195
+ #TODO:NLA Lots of duplication here (see methods in class Help, above.
196
+ def param_description_cell(param, col_width)
197
+ [param_description(param, col_width),
198
+ param_examples(param, col_width)].compact.join("\n")
199
+ end
200
+
201
+ def param_description(param, col_width)
202
+ if param['description'].present?
203
+ hard_wrap(param['description'], col_width) << "\n"
204
+ end
205
+ end
206
+
207
+ def param_examples(param, col_width)
208
+ if param['examples'].present?
209
+ param['examples'].collect do |example|
210
+ hard_wrap("Example: #{example}", col_width)
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,5 @@
1
+ unless defined? Skytap::VERSION
2
+ module Skytap
3
+ VERSION = '0.2.3'
4
+ end
5
+ end
data/lib/skytap.rb ADDED
@@ -0,0 +1,149 @@
1
+ # Standard library
2
+ require 'net/https'
3
+ require 'ostruct'
4
+ require 'net/https'
5
+ require 'net/ftp'
6
+ require 'uri'
7
+ require 'base64'
8
+ require 'fileutils'
9
+ require 'yaml'
10
+ require 'erb'
11
+ require 'cgi'
12
+ require 'optparse'
13
+ require 'set'
14
+ require 'json'
15
+
16
+ # Gems
17
+ require 'rainbow'
18
+ require 'active_support/core_ext'
19
+ require 'terminal-table'
20
+
21
+ # Skytap files
22
+ require 'skytap/version'
23
+ require 'skytap/core_ext'
24
+ require 'skytap/error'
25
+ require 'skytap/command_line'
26
+ require 'skytap/commands'
27
+ require 'skytap/logger'
28
+ require 'skytap/api_schema'
29
+ require 'skytap/response'
30
+ require 'skytap/subnet'
31
+
32
+ module Skytap
33
+ extend self
34
+
35
+ SCHEMA = Skytap::ApiSchema.get
36
+ BASE_RESOURCES = %w[asset
37
+ configuration
38
+ credential
39
+ export
40
+ import
41
+ ip
42
+ template
43
+ user
44
+ vm]
45
+
46
+ # Returns a numeric code indicating exit status; 0 iff success.
47
+ def exec! #TODO:NLA Rename to something indicating that this is called when running from a command-line context.
48
+ response = begin
49
+ args, global_options, command_options = CommandLine.parse(ARGV)
50
+
51
+ logger = Logger.new(global_options[:'log-level'])
52
+
53
+ # Disable color if needed. We don't unconditionally execute this line so that
54
+ # color is still disabled for non-TTY terminals irrespective of the colorize
55
+ # setting.
56
+ Sickill::Rainbow.enabled = false unless global_options[:colorize]
57
+
58
+ build_response(Commands::Root.go!(logger, args, global_options, command_options))
59
+ rescue SystemExit
60
+ raise
61
+ rescue Interrupt
62
+ return 0
63
+ rescue Exception => ex
64
+ log_exception(ex, args, global_options, command_options)
65
+ build_response(ex)
66
+ end
67
+
68
+ if response.error?
69
+ if logger
70
+ logger.info response.error_message
71
+ else
72
+ $stderr.puts response.error_message
73
+ end
74
+ return 1
75
+ else
76
+ return 0
77
+ end
78
+ end
79
+
80
+ # Invokes the command in a way suitable for Ruby programs which use Skytap as
81
+ # a third-party library, or for Skytap plugins.
82
+ def invoke(username, api_token, args, command_options = {}, global_options = {}, &invoker)
83
+ #TODO:NLA This is hacky, and basically just to get the defaults for global options. FIXME
84
+ _, loaded_global_options, _ = CommandLine.parse([])
85
+ global_options = loaded_global_options.merge(global_options).merge(:username => username, :'api-token' => api_token)
86
+
87
+ if args.is_a?(String)
88
+ args = args.split
89
+ end
90
+
91
+ logger = Logger.new(global_options[:'log-level']).tap do |l|
92
+ l.mute! unless l.log_level == 'verbose'
93
+ end
94
+
95
+ build_response(Commands::Root.go!(logger, args, global_options, command_options, true, &invoker))
96
+ end
97
+
98
+ def invoke!(*args, &block)
99
+ resp = invoke(*args, &block)
100
+ if resp.error?
101
+ raise Skytap::Error.new resp.error_message
102
+ else
103
+ resp.payload
104
+ end
105
+ end
106
+
107
+ def specification
108
+ resources.inject({}) do |acc, resource|
109
+ acc[resource] = SCHEMA[resource] || {}
110
+ acc
111
+ end
112
+ end
113
+
114
+
115
+ private
116
+
117
+ def build_response(result)
118
+ Response.build(result)
119
+ end
120
+
121
+ def resources
122
+ SCHEMA.keys | BASE_RESOURCES
123
+ end
124
+
125
+ def log_exception(ex, args, global_options, command_options)
126
+ begin
127
+ global_options.try(:delete, :'api-token')
128
+ message = "#{Time.now}: -- #{args.inspect} -- #{global_options.inspect} -- " +
129
+ "#{command_options.inspect} -- #{Skytap::VERSION} -- " +
130
+ "#{ex} (#{ex.class.name})\n#{ex.backtrace.join("\n")}\n"
131
+
132
+ File.open(File.expand_path(File.join(ENV['HOME'], '.skytap.log')), 'a') do |f|
133
+ f << message
134
+ end
135
+
136
+ if global_options.try(:[], :'log-level') == 'verbose'
137
+ puts message
138
+ end
139
+ rescue
140
+ # No-op
141
+ end
142
+ end
143
+ end
144
+
145
+ Skytap::Commands::Root.populate_with(Skytap.specification)
146
+
147
+ Dir.glob(File.join(File.dirname(__FILE__), 'skytap', 'plugins', '*.rb')) do |path|
148
+ require path
149
+ end
data/skytap.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'skytap/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "skytap-yf"
8
+ gem.version = Skytap::VERSION
9
+ gem.authors = ["Yonah Forst"]
10
+ gem.email = ["joshblour@hotmail.com"]
11
+ gem.description = %q{integrates with skytap api}
12
+ gem.summary = %q{desc}
13
+ gem.homepage = ""
14
+ gem.add_dependency 'activesupport'
15
+ gem.add_dependency 'json_pure'
16
+ gem.add_dependency 'rainbow'
17
+ gem.add_dependency 'terminal-table'
18
+
19
+
20
+ gem.files = `git ls-files`.split($/)
21
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
22
+ gem.require_paths = ["lib"]
23
+
24
+
25
+ end
data/skytap.rdoc ADDED
@@ -0,0 +1,5 @@
1
+ = skytap
2
+
3
+ Generate this with
4
+ skytap rdoc
5
+ After you have described your command line interface
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skytap-yf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Yonah Forst
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-12-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: json_pure
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rainbow
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: terminal-table
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: integrates with skytap api
79
+ email:
80
+ - joshblour@hotmail.com
81
+ executables:
82
+ - skytap
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .DS_Store
87
+ - Gemfile
88
+ - README.md
89
+ - README.rdoc
90
+ - api_schema.yaml
91
+ - bin/skytap
92
+ - ca-bundle.crt
93
+ - data/.DS_Store
94
+ - lib/skytap.rb
95
+ - lib/skytap/api_schema.rb
96
+ - lib/skytap/command_line.rb
97
+ - lib/skytap/commands.rb
98
+ - lib/skytap/commands/base.rb
99
+ - lib/skytap/commands/help.rb
100
+ - lib/skytap/commands/http.rb
101
+ - lib/skytap/commands/root.rb
102
+ - lib/skytap/core_ext.rb
103
+ - lib/skytap/error.rb
104
+ - lib/skytap/help_templates/help.erb
105
+ - lib/skytap/ip_address.rb
106
+ - lib/skytap/logger.rb
107
+ - lib/skytap/plugins/vm_copy_to_region.rb
108
+ - lib/skytap/plugins/vm_download.rb
109
+ - lib/skytap/plugins/vm_upload.rb
110
+ - lib/skytap/requester.rb
111
+ - lib/skytap/response.rb
112
+ - lib/skytap/skytaprc.rb
113
+ - lib/skytap/subnet.rb
114
+ - lib/skytap/templates.rb
115
+ - lib/skytap/version.rb
116
+ - skytap.gemspec
117
+ - skytap.rdoc
118
+ homepage: ''
119
+ licenses: []
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ! '>='
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 1.8.23
139
+ signing_key:
140
+ specification_version: 3
141
+ summary: desc
142
+ test_files: []
143
+ has_rdoc: