Module: Rye

Extended by:
Rye
Included in:
Rye
Defined in:
lib/rye.rb,
lib/rye.rb,
lib/rye/box.rb,
lib/rye/cmd.rb,
lib/rye/dsl.rb,
lib/rye/hop.rb,
lib/rye/key.rb,
lib/rye/rap.rb,
lib/rye/set.rb

Overview

vim: set sw=2 ts=2 :

Defined Under Namespace

Modules: Cmd, VERSION Classes: Box, CommandNotFound, Err, Hop, Key, NoBoxes, NoHost, NoPassword, NoPty, NotConnected, Rap, RyeError, Set, Tpl

Constant Summary collapse

HOME =
File.expand_path( File.join(File.dirname(__FILE__), '..') )
DEBUG =
false
@@sysinfo =
nil
@@agent_env =

holds ssh-agent env vars

Hash.new
@@mutex =

for synchronizing threads

Mutex.new

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.sysinfoObject

Accessor for an instance of SystemInfo



75
76
77
78
# File 'lib/rye.rb', line 75

def Rye.sysinfo
  @@sysinfo = SysInfo.new if @@sysinfo.nil?
  @@sysinfo
end

Instance Method Details

#add_keys(*keys) ⇒ Object

Add one or more private keys to the SSH Agent.

  • keys one or more file paths to private keys used for passwordless logins.



146
147
148
149
150
# File 'lib/rye.rb', line 146

def add_keys(*keys)
  keys = keys.flatten.compact || []
  return if keys.empty?
  Rye.shell("ssh-add", keys)
end

#escape(safe, cmd, *args) ⇒ Object

Creates a string from cmd and args. If safe is true it will send them through Escape.shell_command otherwise it will return them joined by a space character.



256
257
258
259
# File 'lib/rye.rb', line 256

def escape(safe, cmd, *args)
  args = args.flatten.compact || []
  safe ? Escape.shell_command(cmd, *args).to_s : [cmd, args].flatten.compact.join(' ')
end

#find_private_keys(path) ⇒ Object

Looks for private keys in path and returns an Array of paths to the files it finds. Raises an Exception if path does not exist. If path is a file rather than a directory, it will check whether that single file is a private key.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/rye.rb', line 123

def find_private_keys(path)
  raise "#{path} does not exist" unless File.exists?(path || '')
  if File.directory?(path)
    files = Dir.entries(path).collect { |file| File.join(path, file) }
  else
    files = [path]
  end

  files = files.select do |file|
    next if File.directory?(file)
    pk = nil
    begin
      tmp = Rye::Key.from_file(file)
      pk = tmp if tmp.private?
    rescue OpenSSL::PKey::PKeyError
    end
    !pk.nil?
  end
  files || []
end

#keysObject

Returns an Array of info about the currently available SSH keys, as provided by the SSH Agent.

Returns: [[bits, finger-print, file-path], …]



157
158
159
160
161
162
163
164
165
166
# File 'lib/rye.rb', line 157

def keys
  # 2048 76:cb:d7:82:90:92:ad:75:3d:68:6c:a9:21:ca:7b:7f /Users/rye/.ssh/id_rsa (RSA)
  # 2048 7b:a6:ba:55:b1:10:1d:91:9f:73:3a:aa:0c:d4:88:0e /Users/rye/.ssh/id_dsa (DSA)
  #keystr = Rye.shell("ssh-add", '-l')
  #return nil unless keystr
  #keystr.collect do |key|
  #  key.split(/\s+/)
  #end
  Dir.glob(File.join(Rye.sysinfo.home, '.ssh', 'id_*sa'))
end

#mutexObject



115
116
117
# File 'lib/rye.rb', line 115

def mutex
  @@mutex
end

#prepare_command(cmd, *args) ⇒ Object

Takes a command with arguments and returns it in a single String with escaped args and some other stuff.

  • cmd The shell command name or absolute path.

  • args an Array of command arguments.

The command is searched for in the local PATH (where Rye is running). An exception is raised if it’s not found. NOTE: Because this happens locally, you won’t want to use this method if the environment is quite different from the remote machine it will be executed on.

The command arguments are passed through Escape.shell_command (that means you can’t use environment variables or asterisks).

Raises:



190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/rye.rb', line 190

def prepare_command(cmd, *args)
  args &&= [args].flatten.compact
  found_cmd = Rye.which(cmd)
  raise CommandNotFound.new(cmd || '[unknown]') unless found_cmd
  # Symbols to switches. :l -> -l, :help -> --help
  args.collect! do |a|
    a = "-#{a}" if a.is_a?(Symbol) && a.to_s.size == 1
    a = "--#{a}" if a.is_a?(Symbol)
    a
  end
  Rye.escape(@safe, found_cmd, *args)
end

#reloadObject

Reload Rye dynamically. Useful with irb. NOTE: does not reload rye.rb.



110
111
112
113
# File 'lib/rye.rb', line 110

def reload
  pat = File.join(File.dirname(__FILE__), 'rye')
  %w{key rap cmd box set hop}.each {|lib| load File.join(pat, "#{lib}.rb") }
end

#remote_host_keys(*hostnames) ⇒ Object



168
169
170
171
172
# File 'lib/rye.rb', line 168

def remote_host_keys(*hostnames)
  hostnames = hostnames.flatten.compact || []
  return if hostnames.empty?
  Rye.shell("ssh-keyscan", hostnames)
end

#shell(cmd, *args) ⇒ Object

Execute a local system command (via the shell, not SSH)

  • cmd the executable path (relative or absolute)

  • args Array of arguments to be sent to the command. Each element

is one argument:. i.e. ['-l', 'some/path']

NOTE: shell is a bit paranoid so it escapes every argument. This means you can only use literal values. That means no asterisks too.

Returns a Rye::Rap object.



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/rye.rb', line 231

def shell(cmd, *args)
  args = args.flatten.compact
  cmd = cmd.to_s if cmd.is_a?(Symbol)
  # TODO: allow stdin to be sent to the cmd
  tf = Tempfile.new(cmd)
  cmd = Rye.prepare_command(cmd, args)
  cmd << " 2>#{tf.path}" # Redirect STDERR to file. Works in DOS too.
  # Deal with STDOUT
  handle = IO.popen(cmd, "r")
  stdout = handle.read.chomp
  handle.close
  # Then STDERR
  stderr = File.exists?(tf.path) ? File.read(tf.path) : ''
  tf.delete
  # Create the response object
  rap = Rye::Rap.new(self)
  rap.add_stdout(stdout || '')
  rap.add_stderr(stderr || '')
  rap.add_exit_status($?)
  rap
end

#sshagent_infoObject



261
262
263
# File 'lib/rye.rb', line 261

def sshagent_info
  @@agent_env
end

#strand(len = 8, safe = true) ⇒ Object

Generates a string of random alphanumeric characters.

  • len is the length, an Integer. Default: 8

  • safe in safe-mode, ambiguous characters are removed (default: true):

    i l o 1 0
    


277
278
279
280
281
282
283
# File 'lib/rye.rb', line 277

def strand( len=8, safe=true )
   chars = ("a".."z").to_a + ("0".."9").to_a
   chars.delete_if { |v| %w(i l o 1 0).member?(v) } if safe
   str = ""
   1.upto(len) { |i| str << chars[rand(chars.size-1)] }
   str
end

#sysinfoObject

Accessor for an instance of SystemInfo



81
# File 'lib/rye.rb', line 81

def sysinfo; Rye.sysinfo end

#which(executable) ⇒ Object

An all ruby implementation of unix “which” command.

  • executable the name of the executable

Returns the absolute path if found in PATH otherwise nil.



208
209
210
211
212
213
214
215
216
217
218
# File 'lib/rye.rb', line 208

def which(executable)
  return unless executable.is_a?(String)
  return executable if Rye.sysinfo.os == :windows
  #return executable if File.exists?(executable) # SHOULD WORK, MUST TEST
  shortname = File.basename(executable)
  dir = Rye.sysinfo.paths.select do |path|    # dir contains all of the
    next unless File.exists? path             # occurrences of shortname
    Dir.new(path).entries.member?(shortname)  # found in the paths.
  end
  File.join(dir.first, shortname) unless dir.empty? # Return just the first
end

#without_indent(str) ⇒ Object

Returns str with the leading indentation removed. Stolen from github.com/mynyml/unindent/ because it was better.



267
268
269
270
# File 'lib/rye.rb', line 267

def without_indent(str)
  indent = str.split($/).each {|line| !line.strip.empty? }.map {|line| line.index(/[^\s]/) }.compact.min
  str.gsub(/^[[:blank:]]{#{indent}}/, '')
end