Class: Cognizant::Shell

Inherits:
Object
  • Object
show all
Defined in:
lib/cognizant/shell.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Shell

Returns a new instance of Shell.



11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/cognizant/shell.rb', line 11

def initialize(options = {})
  @app = ""
  @app = options[:app] if options.has_key?(:app) and options[:app].to_s.size > 0

  @path_to_socket = "/var/run/cognizant/cognizantd.sock"
  @path_to_socket = options[:socket] if options.has_key?(:socket) and options[:socket].to_s.size > 0

  @@is_shell = true
  @@is_shell = options[:shell] if options.has_key?(:shell)

  @autocomplete_keywords = []
  connect
end

Class Method Details

.emit(message = nil, force = false) ⇒ Object



124
125
126
# File 'lib/cognizant/shell.rb', line 124

def self.emit(message = nil, force = false)
  $stdout.puts(message || '') if interactive? || force
end

.interactive?Boolean

Returns:

  • (Boolean)


128
129
130
131
132
# File 'lib/cognizant/shell.rb', line 128

def self.interactive?
  # TODO: It is not a tty during tests.
  # $stdin.isatty and @@is_shell
  @@is_shell
end

Instance Method Details

#connectObject



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/cognizant/shell.rb', line 93

def connect
  begin
    @client = Cognizant::Client.for_path(@path_to_socket)
  rescue Errno::ENOENT => e
    # TODO: The exit here is a biit of a layering violation.
    Cognizant::Shell.emit(<<EOF, true)
Could not connect to Cognizant daemon process:

  #{e}

HINT: Are you sure you are running the Cognizant daemon?  If so, you
should pass cognizant the socket argument provided to cognizantd.
EOF
    exit(1)
  end
  ehlo if interactive?
  fetch_autocomplete_keywords
end

#ehloObject



112
113
114
115
116
117
# File 'lib/cognizant/shell.rb', line 112

def ehlo
  response = @client.command('command' => '_ehlo', 'user' => ENV['USER'], 'app' => @app)
  @app = response["use"] if response.is_a?(Hash) and response.has_key?("use")

  emit(response['message'])
end

#emit(*args) ⇒ Object



134
135
136
# File 'lib/cognizant/shell.rb', line 134

def emit(*args)
  self.class.emit(*args)
end

#fetch_autocomplete_keywordsObject



119
120
121
122
# File 'lib/cognizant/shell.rb', line 119

def fetch_autocomplete_keywords
  return unless @@is_shell
  @autocomplete_keywords = @client.command('command' => '_autocomplete_keywords', 'app' => @app)
end

#interactive?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/cognizant/shell.rb', line 138

def interactive?
  self.class.interactive?
end

#parse_command(line) ⇒ Object



88
89
90
91
# File 'lib/cognizant/shell.rb', line 88

def parse_command(line)
  command, *args = Shellwords.shellsplit(line)
  [command, args]
end

#promptObject



61
62
63
# File 'lib/cognizant/shell.rb', line 61

def prompt
  @app.to_s.size > 0 ? "(#{@app})> " : "> "
end

#run(&block) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/cognizant/shell.rb', line 25

def run(&block)
  Signal.trap("INT") do
    Cognizant::Shell.emit("\nGoodbye!")
    exit(0)
  end

  emit("Enter 'help' if you're not sure what to do.")
  emit
  emit("Type 'quit' or 'exit' to quit at any time.")

  setup_readline(&block)
end

#run_command(command, args, &block) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/cognizant/shell.rb', line 65

def run_command(command, args, &block)
  command = command.to_s

  begin
    response = @client.command({'command' => command, 'args' => args, 'app' => @app})
  rescue Errno::EPIPE => e
    emit("cognizant: Error communicating with cognizantd: #{e} (#{e.class})")
    exit(1)
  end

  @app = response["use"] if response.is_a?(Hash) and response.has_key?("use")

  if block
    block.call(response, command)
  elsif response.kind_of?(Hash)
    puts response['message']
  else
    puts "Invalid response type #{response.class}: #{response.inspect}"
  end

  fetch_autocomplete_keywords
end

#setup_readline(&block) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/cognizant/shell.rb', line 38

def setup_readline(&block)
  Readline.completion_proc = Proc.new do |input|
    case input
    when /^\//
      # Handle file and directory name autocompletion.
      Readline.completion_append_character = "/"
      Dir[input + '*'].grep(/^#{Regexp.escape(input)}/)
    else
      # Handle commands and process name autocompletion.
      Readline.completion_append_character = " "
      (@autocomplete_keywords + ['quit', 'exit']).grep(/^#{Regexp.escape(input)}/)
    end
  end

  while line = Readline.readline(prompt, true).to_s.strip
    if line.size > 0
      command, args = parse_command(line)
      return emit("Goodbye!") if ['quit', 'exit'].include?(command)
      run_command(command, args, &block)
    end
  end
end