skytap-yf 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: