leap_cli 1.2.5

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.
Files changed (72) hide show
  1. data/bin/leap +81 -0
  2. data/lib/core_ext/boolean.rb +14 -0
  3. data/lib/core_ext/hash.rb +35 -0
  4. data/lib/core_ext/json.rb +42 -0
  5. data/lib/core_ext/nil.rb +5 -0
  6. data/lib/core_ext/string.rb +14 -0
  7. data/lib/leap/platform.rb +52 -0
  8. data/lib/leap_cli/commands/ca.rb +430 -0
  9. data/lib/leap_cli/commands/clean.rb +16 -0
  10. data/lib/leap_cli/commands/compile.rb +134 -0
  11. data/lib/leap_cli/commands/deploy.rb +172 -0
  12. data/lib/leap_cli/commands/facts.rb +93 -0
  13. data/lib/leap_cli/commands/inspect.rb +140 -0
  14. data/lib/leap_cli/commands/list.rb +122 -0
  15. data/lib/leap_cli/commands/new.rb +126 -0
  16. data/lib/leap_cli/commands/node.rb +272 -0
  17. data/lib/leap_cli/commands/pre.rb +99 -0
  18. data/lib/leap_cli/commands/shell.rb +67 -0
  19. data/lib/leap_cli/commands/test.rb +55 -0
  20. data/lib/leap_cli/commands/user.rb +140 -0
  21. data/lib/leap_cli/commands/util.rb +50 -0
  22. data/lib/leap_cli/commands/vagrant.rb +201 -0
  23. data/lib/leap_cli/config/macros.rb +369 -0
  24. data/lib/leap_cli/config/manager.rb +369 -0
  25. data/lib/leap_cli/config/node.rb +37 -0
  26. data/lib/leap_cli/config/object.rb +336 -0
  27. data/lib/leap_cli/config/object_list.rb +174 -0
  28. data/lib/leap_cli/config/secrets.rb +43 -0
  29. data/lib/leap_cli/config/tag.rb +18 -0
  30. data/lib/leap_cli/constants.rb +7 -0
  31. data/lib/leap_cli/leapfile.rb +97 -0
  32. data/lib/leap_cli/load_paths.rb +15 -0
  33. data/lib/leap_cli/log.rb +166 -0
  34. data/lib/leap_cli/logger.rb +216 -0
  35. data/lib/leap_cli/markdown_document_listener.rb +134 -0
  36. data/lib/leap_cli/path.rb +84 -0
  37. data/lib/leap_cli/remote/leap_plugin.rb +204 -0
  38. data/lib/leap_cli/remote/puppet_plugin.rb +66 -0
  39. data/lib/leap_cli/remote/rsync_plugin.rb +35 -0
  40. data/lib/leap_cli/remote/tasks.rb +36 -0
  41. data/lib/leap_cli/requirements.rb +19 -0
  42. data/lib/leap_cli/ssh_key.rb +130 -0
  43. data/lib/leap_cli/util/remote_command.rb +110 -0
  44. data/lib/leap_cli/util/secret.rb +54 -0
  45. data/lib/leap_cli/util/x509.rb +32 -0
  46. data/lib/leap_cli/util.rb +431 -0
  47. data/lib/leap_cli/version.rb +9 -0
  48. data/lib/leap_cli.rb +46 -0
  49. data/lib/lib_ext/capistrano_connections.rb +16 -0
  50. data/lib/lib_ext/gli.rb +52 -0
  51. data/lib/lib_ext/markdown_document_listener.rb +122 -0
  52. data/vendor/certificate_authority/lib/certificate_authority/certificate.rb +200 -0
  53. data/vendor/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb +77 -0
  54. data/vendor/certificate_authority/lib/certificate_authority/distinguished_name.rb +97 -0
  55. data/vendor/certificate_authority/lib/certificate_authority/extensions.rb +266 -0
  56. data/vendor/certificate_authority/lib/certificate_authority/key_material.rb +148 -0
  57. data/vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb +144 -0
  58. data/vendor/certificate_authority/lib/certificate_authority/pkcs11_key_material.rb +65 -0
  59. data/vendor/certificate_authority/lib/certificate_authority/revocable.rb +14 -0
  60. data/vendor/certificate_authority/lib/certificate_authority/serial_number.rb +10 -0
  61. data/vendor/certificate_authority/lib/certificate_authority/signing_entity.rb +16 -0
  62. data/vendor/certificate_authority/lib/certificate_authority/signing_request.rb +56 -0
  63. data/vendor/certificate_authority/lib/certificate_authority.rb +21 -0
  64. data/vendor/rsync_command/lib/rsync_command/ssh_options.rb +159 -0
  65. data/vendor/rsync_command/lib/rsync_command/thread_pool.rb +36 -0
  66. data/vendor/rsync_command/lib/rsync_command/version.rb +3 -0
  67. data/vendor/rsync_command/lib/rsync_command.rb +96 -0
  68. data/vendor/rsync_command/test/rsync_test.rb +74 -0
  69. data/vendor/rsync_command/test/ssh_options_test.rb +61 -0
  70. data/vendor/vagrant_ssh_keys/vagrant.key +27 -0
  71. data/vendor/vagrant_ssh_keys/vagrant.pub +1 -0
  72. metadata +345 -0
@@ -0,0 +1,166 @@
1
+ require 'paint'
2
+
3
+ ##
4
+ ## LOGGING
5
+ ##
6
+ ## Ugh. This class does not work well with multiple threads!
7
+ ##
8
+
9
+ module LeapCli
10
+ extend self
11
+
12
+ # logging options
13
+ def log_level
14
+ @log_level ||= 1
15
+ end
16
+ def log_level=(value)
17
+ @log_level = value
18
+ end
19
+
20
+ def indent_level
21
+ @indent_level ||= 0
22
+ end
23
+ def indent_level=(value)
24
+ @indent_level = value
25
+ end
26
+
27
+ def log_file
28
+ @log_file
29
+ end
30
+ def log_file=(value)
31
+ @log_file = value
32
+ if @log_file
33
+ if !File.directory?(File.dirname(@log_file))
34
+ Util.bail!('Invalid log file "%s", directory "%s" does not exist' % [@log_file, File.dirname(@log_file)])
35
+ end
36
+ @log_output_stream = File.open(@log_file, 'a')
37
+ end
38
+ end
39
+
40
+ def log_output_stream
41
+ @log_output_stream
42
+ end
43
+
44
+ end
45
+
46
+
47
+ module LeapCli
48
+ module Log
49
+ #
50
+ # these are log titles typically associated with files
51
+ #
52
+ FILE_TITLES = [:updated, :created, :removed, :missing, :nochange, :loading]
53
+
54
+
55
+ #
56
+ # master logging function.
57
+ #
58
+ # arguments can be a String, Integer, Symbol, or Hash, in any order.
59
+ #
60
+ # * String: treated as the message to log.
61
+ # * Integer: the log level (0, 1, 2)
62
+ # * Symbol: the prefix title to colorize. may be one of
63
+ # [:error, :warning, :info, :updated, :created, :removed, :no_change, :missing]
64
+ # * Hash: a hash of options. so far, only :indent is supported.
65
+ #
66
+
67
+ def log(*args)
68
+ level = args.grep(Integer).first || 1
69
+ title = args.grep(Symbol).first
70
+ message = args.grep(String).first
71
+ options = args.grep(Hash).first || {}
72
+ unless message && LeapCli.log_level >= level
73
+ return
74
+ end
75
+
76
+ # prefix
77
+ clear_prefix = colored_prefix = ""
78
+ if title
79
+ prefix_options = case title
80
+ when :error then ['error', :red, :bold]
81
+ when :warning then ['warning:', :yellow, :bold]
82
+ when :info then ['info', :cyan, :bold]
83
+ when :updated then ['updated', :cyan, :bold]
84
+ when :updating then ['updating', :cyan, :bold]
85
+ when :created then ['created', :green, :bold]
86
+ when :removed then ['removed', :red, :bold]
87
+ when :nochange then ['no change', :magenta]
88
+ when :loading then ['loading', :magenta]
89
+ when :missing then ['missing', :yellow, :bold]
90
+ when :skipping then ['skipping', :yellow, :bold]
91
+ when :run then ['run', :magenta]
92
+ when :failed then ['FAILED', :red, :bold]
93
+ when :completed then ['completed', :green, :bold]
94
+ when :ran then ['ran', :green, :bold]
95
+ when :bail then ['bailing out', :red, :bold]
96
+ when :invalid then ['invalid', :red, :bold]
97
+ else [title.to_s, :cyan, :bold]
98
+ end
99
+ if options[:host]
100
+ clear_prefix = "[%s] %s " % [options[:host], prefix_options[0]]
101
+ colored_prefix = "[%s] %s " % [Paint[options[:host], prefix_options[1], prefix_options[2]], prefix_options[0]]
102
+ else
103
+ clear_prefix = "%s " % prefix_options[0]
104
+ colored_prefix = "%s " % Paint[prefix_options[0], prefix_options[1], prefix_options[2]]
105
+ end
106
+ elsif options[:host]
107
+ clear_prefix = colored_prefix = "[%s] " % options[:host]
108
+ end
109
+
110
+ # transform absolute path names
111
+ if title && FILE_TITLES.include?(title) && message =~ /^\//
112
+ message = LeapCli::Path.relative_path(message)
113
+ end
114
+
115
+ log_raw(:log, nil) { [clear_prefix, message].join }
116
+ log_raw(:stdout, options[:indent]) { [colored_prefix, message].join }
117
+
118
+ # run block, if given
119
+ if block_given?
120
+ LeapCli.indent_level += 1
121
+ yield
122
+ LeapCli.indent_level -= 1
123
+ end
124
+ end
125
+
126
+ #
127
+ # Add a raw log entry, without any modifications (other than indent).
128
+ # Content to be logged is yielded by the block.
129
+ # Block may be either a string or array of strings.
130
+ #
131
+ # if mode == :stdout, output is sent to STDOUT.
132
+ # if mode == :log, output is sent to log file, if present.
133
+ #
134
+ def log_raw(mode, indent=nil, &block)
135
+ # NOTE: print message (using 'print' produces better results than 'puts' when multiple threads are logging)
136
+ if mode == :log
137
+ if LeapCli.log_output_stream
138
+ messages = [yield].compact.flatten
139
+ if messages.any?
140
+ timestamp = Time.now.strftime("%b %d %H:%M:%S")
141
+ messages.each do |message|
142
+ LeapCli.log_output_stream.print("#{timestamp} #{message}\n")
143
+ end
144
+ LeapCli.log_output_stream.flush
145
+ end
146
+ end
147
+ elsif mode == :stdout
148
+ messages = [yield].compact.flatten
149
+ if messages.any?
150
+ indent ||= LeapCli.indent_level
151
+ indent_str = ""
152
+ indent_str += " " * indent.to_i
153
+ if indent.to_i > 0
154
+ indent_str += ' - '
155
+ else
156
+ indent_str += ' = '
157
+ end
158
+ messages.each do |message|
159
+ STDOUT.print("#{indent_str}#{message}\n")
160
+ end
161
+ end
162
+ end
163
+ end
164
+
165
+ end
166
+ end
@@ -0,0 +1,216 @@
1
+ #
2
+ # A drop in replacement for Capistrano::Logger that integrates better with LEAP CLI.
3
+ #
4
+
5
+ require 'capistrano/logger'
6
+
7
+ #
8
+ # from Capistrano::Logger
9
+ # =========================
10
+ #
11
+ # IMPORTANT = 0
12
+ # INFO = 1
13
+ # DEBUG = 2
14
+ # TRACE = 3
15
+ # MAX_LEVEL = 3
16
+ # COLORS = {
17
+ # :none => "0",
18
+ # :black => "30",
19
+ # :red => "31",
20
+ # :green => "32",
21
+ # :yellow => "33",
22
+ # :blue => "34",
23
+ # :magenta => "35",
24
+ # :cyan => "36",
25
+ # :white => "37"
26
+ # }
27
+ # STYLES = {
28
+ # :bright => 1,
29
+ # :dim => 2,
30
+ # :underscore => 4,
31
+ # :blink => 5,
32
+ # :reverse => 7,
33
+ # :hidden => 8
34
+ # }
35
+ #
36
+
37
+ module LeapCli
38
+ class Logger < Capistrano::Logger
39
+
40
+ def initialize(options={})
41
+ @options = options
42
+ @level = options[:level] || 0
43
+ @message_buffer = nil
44
+ end
45
+
46
+ def log(level, message, line_prefix=nil, options={})
47
+ if message !~ /\n$/ && level <= 2 && line_prefix.is_a?(String)
48
+ # in some cases, when the message doesn't end with a return, we buffer it and
49
+ # wait until we encounter the return before we log the message out.
50
+ @message_buffer ||= ""
51
+ @message_buffer += message
52
+ return
53
+ elsif @message_buffer
54
+ message = @message_buffer + message
55
+ @message_buffer = nil
56
+ end
57
+
58
+ options[:level] ||= level
59
+ [:stdout, :log].each do |mode|
60
+ LeapCli::log_raw(mode) do
61
+ message_lines(mode, message, line_prefix, options)
62
+ end
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def message_lines(mode, message, line_prefix, options)
69
+ formatted_message, formatted_prefix, message_options = apply_formatting(mode, message, line_prefix, options)
70
+ if message_options[:level] <= self.level && formatted_message && formatted_message.chars.any?
71
+ if formatted_prefix
72
+ formatted_message.lines.collect { |line|
73
+ "[#{formatted_prefix}] #{line.sub(/\s+$/, '')}"
74
+ }
75
+ else
76
+ formatted_message.lines.collect {|line| line.sub(/\s+$/, '')}
77
+ end
78
+ else
79
+ nil
80
+ end
81
+ end
82
+
83
+ ##
84
+ ## FORMATTING
85
+ ##
86
+
87
+ @formatters = [
88
+ # TRACE
89
+ { :match => /command finished/, :color => :white, :style => :dim, :match_level => 3, :priority => -10 },
90
+ { :match => /executing locally/, :color => :yellow, :match_level => 3, :priority => -20 },
91
+
92
+ # DEBUG
93
+ #{ :match => /executing .*/, :color => :green, :match_level => 2, :priority => -10, :timestamp => true },
94
+ #{ :match => /.*/, :color => :yellow, :match_level => 2, :priority => -30 },
95
+ { :match => /^transaction:/, :level => 3 },
96
+
97
+ # INFO
98
+ { :match => /.*out\] (fatal:|ERROR:).*/, :color => :red, :match_level => 1, :priority => -10 },
99
+ { :match => /Permission denied/, :color => :red, :match_level => 1, :priority => -20 },
100
+ { :match => /sh: .+: command not found/, :color => :magenta, :match_level => 1, :priority => -30 },
101
+
102
+ # IMPORTANT
103
+ { :match => /^err ::/, :color => :red, :match_level => 0, :priority => -10 },
104
+ { :match => /^ERROR:/, :color => :red, :match_level => 0, :priority => -10 },
105
+ { :match => /.*/, :color => :blue, :match_level => 0, :priority => -20 },
106
+
107
+ # CLEANUP
108
+ { :match => /\s+$/, :replace => '', :priority => 0},
109
+
110
+ # DEBIAN PACKAGES
111
+ { :match => /^(Hit|Ign) /, :color => :green, :priority => -20},
112
+ { :match => /^Err /, :color => :red, :priority => -20},
113
+ { :match => /^W(ARNING)?: /, :color => :yellow, :priority => -20},
114
+ { :match => /^E: /, :color => :red, :priority => -20},
115
+ { :match => /already the newest version/, :color => :green, :priority => -20},
116
+ { :match => /WARNING: The following packages cannot be authenticated!/, :color => :red, :level => 0, :priority => -10},
117
+
118
+ # PUPPET
119
+ { :match => /^warning: .*is deprecated.*$/, :level => 2, :color => :yellow, :priority => -10},
120
+ { :match => /^warning: Scope.*$/, :level => 2, :color => :yellow, :priority => -10},
121
+ { :match => /^notice:/, :level => 1, :color => :cyan, :priority => -20},
122
+ { :match => /^notice:.*executed successfully$/, :level => 2, :color => :cyan, :priority => -15},
123
+ { :match => /^warning:/, :level => 0, :color => :yellow, :priority => -20},
124
+ { :match => /^Duplicate declaration:/, :level => 0, :color => :red, :priority => -20},
125
+ { :match => /Finished catalog run/, :level => 0, :color => :green, :priority => -10},
126
+ { :match => /^Puppet apply complete \(changes made\)/, :level => 0, :color => :green, :priority => -10},
127
+ { :match => /^Puppet apply complete \(no changes\)/, :level => 0, :color => :green, :priority => -10},
128
+
129
+ # PUPPET FATAL ERRORS
130
+ { :match => /^err:/, :level => 0, :color => :red, :priority => -1, :exit => 1},
131
+ { :match => /^Failed to parse template/, :level => 0, :color => :red, :priority => -1, :exit => 1},
132
+ { :match => /^Parameter matches failed:/, :level => 0, :color => :red, :priority => -1, :exit => 1},
133
+ { :match => /^Syntax error/, :level => 0, :color => :red, :priority => -1, :exit => 1},
134
+ { :match => /^Cannot reassign variable/, :level => 0, :color => :red, :priority => -1, :exit => 1},
135
+ { :match => /^Could not find template/, :level => 0, :color => :red, :priority => -1, :exit => 1},
136
+ { :match => /^Puppet apply complete.*fail/, :level => 0, :color => :red, :priority => -1, :exit => 1},
137
+
138
+ # TESTS
139
+ { :match => /^PASS: /, :color => :green, :priority => -20},
140
+ { :match => /^(FAIL|ERROR): /, :color => :red, :priority => -20},
141
+ { :match => /^SKIP: /, :color => :yellow, :priority => -20}
142
+
143
+ ]
144
+
145
+ def self.sorted_formatters
146
+ # Sort matchers in reverse order so we can break if we found a match.
147
+ @sorted_formatters ||= @formatters.sort_by { |i| -(i[:priority] || i[:prio] || 0) }
148
+ end
149
+
150
+ @prefix_formatters = [
151
+ { :match => /(err|out) :: /, :replace => '', :priority => 0},
152
+ { :match => /\s+$/, :replace => '', :priority => 0}
153
+ ]
154
+ def self.prefix_formatters; @prefix_formatters; end
155
+
156
+ def apply_formatting(mode, message, line_prefix = nil, options={})
157
+ message = message.dup
158
+ options = options.dup
159
+ if !line_prefix.nil?
160
+ if !line_prefix.is_a?(String)
161
+ line_prefix = line_prefix.to_s.dup
162
+ else
163
+ line_prefix = line_prefix.dup
164
+ end
165
+ end
166
+ color = options[:color] || :none
167
+ style = options[:style]
168
+
169
+ if line_prefix
170
+ self.class.prefix_formatters.each do |formatter|
171
+ if line_prefix =~ formatter[:match] && formatter[:replace]
172
+ line_prefix.gsub!(formatter[:match], formatter[:replace])
173
+ end
174
+ end
175
+ end
176
+
177
+ self.class.sorted_formatters.each do |formatter|
178
+ if (formatter[:match_level] == level || formatter[:match_level].nil?)
179
+ if message =~ formatter[:match]
180
+ options[:level] = formatter[:level] if formatter[:level]
181
+ color = formatter[:color] if formatter[:color]
182
+ style = formatter[:style] || formatter[:attribute] # (support original cap colors)
183
+
184
+ message.gsub!(formatter[:match], formatter[:replace]) if formatter[:replace]
185
+ message.replace(formatter[:prepend] + message) unless formatter[:prepend].nil?
186
+ message.replace(message + formatter[:append]) unless formatter[:append].nil?
187
+ message.replace(Time.now.strftime('%Y-%m-%d %T') + ' ' + message) if formatter[:timestamp]
188
+
189
+ if formatter[:exit]
190
+ LeapCli::Util.exit_status(formatter[:exit])
191
+ end
192
+
193
+ # stop formatting, unless formatter was just for string replacement
194
+ break unless formatter[:replace]
195
+ end
196
+ end
197
+ end
198
+
199
+ if color == :hide
200
+ return nil
201
+ elsif mode == :log || (color == :none && style.nil?)
202
+ return [message, line_prefix, options]
203
+ else
204
+ term_color = COLORS[color]
205
+ term_style = STYLES[style]
206
+ if line_prefix.nil?
207
+ message.replace format(message, term_color, term_style)
208
+ else
209
+ line_prefix.replace format(line_prefix, term_color, term_style).strip # format() appends a \n
210
+ end
211
+ return [message, line_prefix, options]
212
+ end
213
+ end
214
+
215
+ end
216
+ end
@@ -0,0 +1,134 @@
1
+ #
2
+ # A class to generate a markdown file with all the information available with the
3
+ # help subcommand.
4
+ #
5
+ # This is adapted from GLI::Commands::RdocDocumentListener
6
+ #
7
+
8
+ require 'stringio'
9
+ require 'gli/commands/help_modules/arg_name_formatter'
10
+
11
+ module LeapCli
12
+ class MarkdownDocumentListener
13
+
14
+ def initialize(global_options,options,arguments)
15
+ @io = File.new(File.basename($0) + ".md",'w')
16
+ @nest = ''
17
+ @commands = [File.basename($0)]
18
+ @arg_name_formatter = GLI::Commands::HelpModules::ArgNameFormatter.new
19
+ end
20
+
21
+ def beginning
22
+ end
23
+
24
+ # Called when processing has completed
25
+ def ending
26
+ @io.close
27
+ end
28
+
29
+ # Gives you the program description
30
+ def program_desc(desc)
31
+ @io.puts "@title = 'Command Line Reference'"
32
+ #@io.puts "# #{File.basename($0)} - #{desc}"
33
+ @io.puts
34
+ end
35
+
36
+ def program_long_desc(desc)
37
+ @io.puts desc
38
+ @io.puts
39
+ end
40
+
41
+ # Gives you the program version
42
+ def version(version)
43
+ #@io.puts "v#{version}"
44
+ #@io.puts
45
+ end
46
+
47
+ def options
48
+ #@io.puts "<div class='options'>"
49
+ @io.puts
50
+ if @nest.size == 0
51
+ @io.puts "# Global Options"
52
+ else
53
+ #@io.puts "#{@nest}# Options"
54
+ @io.puts "**Options**"
55
+ end
56
+ @io.puts
57
+ end
58
+
59
+ # Gives you a flag in the current context
60
+ def flag(name,aliases,desc,long_desc,default_value,arg_name,must_match,type)
61
+ invocations = ([name] + Array(aliases)).map { |_| add_dashes(_) }.join('|')
62
+ usage = "#{invocations} #{arg_name || 'arg'}"
63
+ #@io.puts "#{@nest}## #{usage}"
64
+ @io.puts "* `#{usage}` "
65
+ @io.puts String(desc).strip + " "
66
+ @io.puts String(long_desc).strip + " " if long_desc
67
+ @io.puts "Default Value: #{default_value || 'None'} "
68
+ @io.puts "Must Match: #{must_match.to_s} " unless must_match.nil?
69
+ @io.puts
70
+ end
71
+
72
+ # Gives you a switch in the current context
73
+ def switch(name,aliases,desc,long_desc,negetable)
74
+ if negetable
75
+ name = "[no-]#{name}" if name.to_s.length > 1
76
+ aliases = aliases.map { |_| _.to_s.length > 1 ? "[no-]#{_}" : _ }
77
+ end
78
+ invocations = ([name] + aliases).map { |_| add_dashes(_) }.join('|')
79
+ #@io.puts "#{@nest}## #{invocations}"
80
+ @io.puts "* `#{invocations}` "
81
+ @io.puts String(desc).strip + " "
82
+ #@io.puts
83
+ #@io.puts String(long_desc).strip
84
+ @io.puts
85
+ end
86
+
87
+ def end_options
88
+ #@io.puts "</div>"
89
+ end
90
+
91
+ def commands
92
+ #@io.puts "#{@nest}## Commands"
93
+ #@nest = "#{@nest}#"
94
+ end
95
+
96
+ # Gives you a command in the current context and creates a new context of this command
97
+ def command(name,aliases,desc,long_desc,arg_name,arg_options)
98
+ @commands.push(name)
99
+ #@io.puts "#{@nest}## Command: <tt>#{([name] + aliases).join('|')} #{@arg_name_formatter.format(arg_name,arg_options)}</tt>"
100
+ @io.puts
101
+ @io.puts "#{@nest}# #{@commands.join ' '} #{@arg_name_formatter.format(arg_name,arg_options)}"
102
+ @io.puts
103
+ @io.puts String(desc).strip
104
+ @io.puts
105
+ @io.puts String(long_desc).strip
106
+ @nest = "#{@nest}#"
107
+ end
108
+
109
+ # Ends a command, and "pops" you back up one context
110
+ def end_command(name)
111
+ @nest.gsub!(/\#$/,'')
112
+ @commands.pop
113
+ end
114
+
115
+ # Gives you the name of the current command in the current context
116
+ def default_command(name)
117
+ @io.puts "Default Command: #{name}" unless name.nil?
118
+ end
119
+
120
+ def end_commands
121
+ @nest.gsub!(/\#$/,'')
122
+ end
123
+
124
+ private
125
+
126
+ def add_dashes(name)
127
+ name = "-#{name}"
128
+ name = "-#{name}" if name.length > 2
129
+ name
130
+ end
131
+
132
+
133
+ end
134
+ end
@@ -0,0 +1,84 @@
1
+ require 'fileutils'
2
+
3
+ module LeapCli; module Path
4
+
5
+ def self.platform
6
+ @platform
7
+ end
8
+
9
+ def self.provider_base
10
+ "#{platform}/provider_base"
11
+ end
12
+
13
+ def self.provider_templates
14
+ "#{platform}/provider_templates"
15
+ end
16
+
17
+ def self.provider
18
+ @provider
19
+ end
20
+
21
+ def self.set_provider_path(provider)
22
+ @provider = provider
23
+ end
24
+ def self.set_platform_path(platform)
25
+ @platform = platform
26
+ end
27
+
28
+ #
29
+ # tries to find a file somewhere
30
+ #
31
+ def self.find_file(arg)
32
+ [Path.provider, Path.provider_base].each do |base|
33
+ file_path = named_path(arg, base)
34
+ return file_path if File.exists?(file_path)
35
+ if arg.is_a? String
36
+ file_path = base + '/files/' + arg
37
+ return file_path if File.exists?(file_path)
38
+ end
39
+ end
40
+ return nil
41
+ end
42
+
43
+ #
44
+ # Three ways of calling:
45
+ #
46
+ # - named_path [:user_ssh, 'bob'] ==> 'users/bob/bob_ssh.pub'
47
+ # - named_path :known_hosts ==> 'files/ssh/known_hosts'
48
+ # - named_path '/tmp/x' ==> '/tmp/x'
49
+ #
50
+ def self.named_path(name, provider_dir=Path.provider)
51
+ if name.is_a? Array
52
+ if name.length > 2
53
+ arg = name[1..-1]
54
+ name = name[0]
55
+ else
56
+ name, arg = name
57
+ end
58
+ else
59
+ arg = nil
60
+ end
61
+
62
+ if name.is_a? Symbol
63
+ Util::assert!(Leap::Platform.paths[name], "Error, I don't know the path for :#{name} (with argument '#{arg}')")
64
+ filename = eval('"' + Leap::Platform.paths[name] + '"')
65
+ return provider_dir + '/' + filename
66
+ else
67
+ return name
68
+ end
69
+ end
70
+
71
+ def self.exists?(name, provider_dir=nil)
72
+ File.exists?(named_path(name, provider_dir))
73
+ end
74
+
75
+ def self.relative_path(path, provider_dir=Path.provider)
76
+ if provider_dir
77
+ path = named_path(path, provider_dir)
78
+ path.sub(/^#{Regexp.escape(provider_dir)}\//,'')
79
+ else
80
+ path
81
+ end
82
+ end
83
+
84
+ end; end