Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| #!/usr/bin/env ruby | |
| require 'logger' | |
| require 'optparse' | |
| require 'readline' | |
| require 'shellwords' | |
| require 'rubygems' | |
| require 'einhorn' | |
| module Einhorn | |
| class EinhornSH | |
| class EinhornSHExit < StandardError | |
| end | |
| def initialize(path_to_socket) | |
| @path_to_socket = path_to_socket | |
| @request_id = 0 | |
| reconnect | |
| end | |
| def send_command(hash) | |
| @client.send_command(hash) | |
| while response = @client.receive_message | |
| if response.kind_of?(Hash) | |
| yield response['message'] | |
| return unless response['wait'] | |
| else | |
| puts "Invalid response type #{response.class}: #{response.inspect}" | |
| end | |
| end | |
| end | |
| def run | |
| emit("Enter 'help' if you're not sure what to do.") | |
| emit | |
| emit('Type "quit" or "exit" to quit at any time') | |
| while command_line_sequence = Readline.readline('> ', true) | |
| run_command_line_sequence(command_line_sequence) | |
| end | |
| end | |
| def run_command_line_sequence(command_line_sequence) | |
| command_lines = command_line_sequence.split(";") | |
| command_lines.each do |command_line| | |
| run_command_line(command_line) | |
| end | |
| end | |
| def run_command_line(command_line) | |
| command, args = parse_command_line(command_line) | |
| if command.nil? | |
| return | |
| elsif ['quit', 'exit'].include?(command) | |
| emit("Goodbye!") | |
| raise EinhornSHExit | |
| end | |
| send_command({'id' => request_id, 'command' => command, 'args' => args}) do |message| | |
| $stdout.puts message | |
| $stdout.flush | |
| end | |
| end | |
| def request_id | |
| @request_id += 1 | |
| end | |
| def parse_command_line(command_line) | |
| command, *args = Shellwords.shellsplit(command_line) | |
| [command, args] | |
| end | |
| def reconnect | |
| begin | |
| @client = Einhorn::Client.for_path(@path_to_socket) | |
| rescue Errno::ENOENT => e | |
| # TODO: The exit here is a biit of a layering violation. | |
| Einhorn::EinhornSH.emit(<<EOF, true) | |
| Could not connect to Einhorn master process: | |
| #{e} | |
| HINT: Are you sure you are running an Einhorn master? If so, you | |
| should pass einhornsh the cmd_name (-c argument) provided to Einhorn. | |
| EOF | |
| exit(1) | |
| end | |
| ehlo if interactive? | |
| end | |
| def ehlo | |
| send_command({'command' => "ehlo", 'user' => ENV['USER']}) do |message| | |
| emit(message) | |
| end | |
| end | |
| def self.emit(message=nil, force=false) | |
| $stderr.puts(message || '') if interactive? || force | |
| end | |
| def self.interactive? | |
| $stdin.isatty | |
| end | |
| def emit(*args) | |
| self.class.emit(*args) | |
| end | |
| def interactive? | |
| self.class.interactive? | |
| end | |
| end | |
| end | |
| def main | |
| options = {} | |
| optparse = OptionParser.new do |opts| | |
| opts.banner = "Usage: #{$0} [options] [cmd_name] | |
| Welcome to Einhornsh: the Einhorn shell. | |
| Pass the cmd_name of the Einhorn master you are connecting to either | |
| as a positional argument or using `-c`. If you're running your Einhorn | |
| with a `-d`, provide the same argument here." | |
| opts.on('-h', '--help', 'Display this message') do | |
| Einhorn::EinhornSH.emit(opts, true) | |
| exit(1) | |
| end | |
| opts.on('-c CMD_NAME', '--command-name CMD_NAME', 'Connect to the Einhorn master with this cmd_name') do |cmd_name| | |
| options[:cmd_name] = cmd_name | |
| end | |
| opts.on('-d PATH', '--socket-path PATH', 'Path to the Einhorn command socket') do |path| | |
| options[:socket_path] = path | |
| end | |
| opts.on('-e CMD_LINE_SEQ', '--execute CMD_LINE_SEQ', 'Execute this command outside of interactive mode') do |cmd_line_seq| | |
| options[:cmd_line_seq] = cmd_line_seq | |
| end | |
| end | |
| optparse.parse! | |
| if ARGV.length > 1 | |
| Einhorn::EinhornSH.emit(optparse, true) | |
| return 1 | |
| end | |
| Signal.trap("INT") do | |
| Einhorn::EinhornSH.emit | |
| exit(0) | |
| end | |
| path_to_socket = options[:socket_path] | |
| unless path_to_socket | |
| cmd_name = options[:cmd_name] || ARGV[0] | |
| path_to_socket = Einhorn::Command::Interface.default_socket_path(cmd_name) | |
| end | |
| sh = Einhorn::EinhornSH.new(path_to_socket) | |
| cmd_line_seq = options[:cmd_line_seq] | |
| begin | |
| cmd_line_seq ? sh.run_command_line_sequence(cmd_line_seq) : sh.run | |
| rescue Einhorn::EinhornSH::EinhornSHExit => e | |
| return 0 | |
| end | |
| return 0 | |
| end | |
| # Would be nice if this could be loadable rather than always | |
| # executing, but when run under gem it's a bit hard to do so. | |
| if true # $0 == __FILE__ | |
| ret = main | |
| begin | |
| exit(ret) | |
| rescue TypeError | |
| exit(0) | |
| end | |
| end |