The Capistrano::Shell class is the guts of the “shell” task. It implements an interactive REPL interface that users can employ to execute tasks and commands. It makes for a GREAT way to monitor systems, and perform quick maintenance on one or more machines.
# File lib/capistrano/shell.rb, line 57 57: def read_and_execute 58: command = read_line 59: 60: case command 61: when "?", "help" then help 62: when "quit", "exit" then 63: puts "exiting" 64: return false 65: when /^set -(\w)\s*(\S+)/ 66: set_option($1, $2) 67: when /^(?:(with|on)\s*(\S+))?\s*(\S.*)?/ 68: process_command($1, $2, $3) 69: else 70: raise "eh?" 71: end 72: 73: return true 74: end
Start the shell running. This method will block until the shell terminates.
# File lib/capistrano/shell.rb, line 39 39: def run! 40: setup 41: 42: puts ====================================================================Welcome to the interactive Capistrano shell! This is an experimentalfeature, and is liable to change in future releases. Type 'help' fora summary of how to use the shell.-------------------------------------------------------------------- 43: 44: loop do 45: break if !read_and_execute 46: end 47: 48: @bgthread.kill 49: end
Determine which servers the given task requires a connection to, and establish connections to them if necessary. Return the list of servers (names).
# File lib/capistrano/shell.rb, line 133 133: def connect(task) 134: servers = configuration.find_servers_for_task(task) 135: needing_connections = servers - configuration.sessions.keys 136: unless needing_connections.empty? 137: puts "[establishing connection(s) to #{needing_connections.join(', ')}]" 138: configuration.establish_connections_to(needing_connections) 139: end 140: servers 141: end
Execute the given command. If the command is prefixed by an exclamation mark, it is assumed to refer to another capistrano task, which will be invoked. Otherwise, it is executed as a command on all associated servers.
# File lib/capistrano/shell.rb, line 147 147: def exec(command) 148: @mutex.synchronize do 149: if command[0] == !! 150: exec_tasks(command[1..1].split) 151: else 152: servers = connect(configuration.current_task) 153: exec_command(command, servers) 154: end 155: end 156: ensure 157: STDOUT.flush 158: end
Execute a command on the given list of servers.
# File lib/capistrano/shell.rb, line 173 173: def exec_command(command, servers) 174: command = command.gsub(/\bsudo\b/, "sudo -p '#{configuration.sudo_prompt}'") 175: processor = configuration.sudo_behavior_callback(Configuration.default_io_proc) 176: sessions = servers.map { |server| configuration.sessions[server] } 177: options = configuration.add_default_command_options({}) 178: cmd = Command.new(command, sessions, options.merge(:logger => configuration.logger), &processor) 179: previous = trap("INT") { cmd.stop! } 180: cmd.process! 181: rescue Capistrano::Error => error 182: warn "error: #{error.message}" 183: ensure 184: trap("INT", previous) 185: end
Given an array of task names, invoke them in sequence.
# File lib/capistrano/shell.rb, line 161 161: def exec_tasks(list) 162: list.each do |task_name| 163: task = configuration.find_task(task_name) 164: raise Capistrano::NoSuchTaskError, "no such task `#{task_name}'" unless task 165: connect(task) 166: configuration.execute_task(task) 167: end 168: rescue Capistrano::NoMatchingServersError, Capistrano::NoSuchTaskError => error 169: warn "error: #{error.message}" 170: end
Display a verbose help message.
# File lib/capistrano/shell.rb, line 101 101: def help 102: puts --- HELP! ---------------------------------------------------"Get me out of this thing. I just want to quit."-> Easy enough. Just type "exit", or "quit". Or press ctrl-D."I want to execute a command on all servers."-> Just type the command, and press enter. It will be passed, verbatim, to all defined servers."What if I only want it to execute on a subset of them?"-> No problem, just specify the list of servers, separated by commas, before the command, with the `on' keyword: cap> on app1.foo.com,app2.foo.com echo ping"Nice, but can I specify the servers by role?"-> You sure can. Just use the `with' keyword, followed by the comma-delimited list of role names: cap> with app,db echo ping"Can I execute a Capistrano task from within this shell?"-> Yup. Just prefix the task with an exclamation mark: cap> !deploy 103: end
Process a command. Interprets the scope_type (must be nil, “with”, or “on”) and the command. If no command is given, then the scope is made effective for all subsequent commands. If the scope value is “all”, then the scope is unrestricted.
# File lib/capistrano/shell.rb, line 237 237: def process_command(scope_type, scope_value, command) 238: env_var = case scope_type 239: when "with" then "ROLES" 240: when "on" then "HOSTS" 241: end 242: 243: old_var, ENV[env_var] = ENV[env_var], (scope_value == "all" ? nil : scope_value) if env_var 244: if command 245: begin 246: exec(command) 247: ensure 248: ENV[env_var] = old_var if env_var 249: end 250: else 251: puts "scoping #{scope_type} #{scope_value}" 252: end 253: end
Present the prompt and read a single line from the console. It also detects ^D and returns “exit” in that case. Adds the input to the history, unless the input is empty. Loops repeatedly until a non-empty line is input.
# File lib/capistrano/shell.rb, line 82 82: def read_line 83: loop do 84: command = reader.readline("cap> ") 85: 86: if command.nil? 87: command = "exit" 88: puts(command) 89: else 90: command.strip! 91: end 92: 93: unless command.empty? 94: reader::HISTORY << command 95: return command 96: end 97: end 98: end
Return the object that will be used to query input from the console. The returned object will quack (more or less) like Readline.
# File lib/capistrano/shell.rb, line 189 189: def reader 190: @reader ||= begin 191: require 'readline' 192: Readline 193: rescue LoadError 194: ReadlineFallback 195: end 196: end
Set the given option to value.
# File lib/capistrano/shell.rb, line 212 212: def set_option(opt, value) 213: case opt 214: when "v" then 215: puts "setting log verbosity to #{value.to_i}" 216: configuration.logger.level = value.to_i 217: when "o" then 218: case value 219: when "vi" then 220: puts "using vi edit mode" 221: reader.vi_editing_mode 222: when "emacs" then 223: puts "using emacs edit mode" 224: reader.emacs_editing_mode 225: else 226: puts "unknown -o option #{value.inspect}" 227: end 228: else 229: puts "unknown setting #{opt.inspect}" 230: end 231: end
Prepare every little thing for the shell. Starts the background thread and generally gets things ready for the REPL.
# File lib/capistrano/shell.rb, line 200 200: def setup 201: configuration.logger.level = Capistrano::Logger::INFO 202: 203: @mutex = Mutex.new 204: @bgthread = Thread.new do 205: loop do 206: @mutex.synchronize { process_iteration(0.1) } 207: end 208: end 209: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.