require 'pry' require 'collins_shell/util/asset_stache' module CollinsShell; module Console; module Commands Iterators = Pry::CommandSet.new do create_command "ls", "Find assets according to specific criteria" do include CollinsShell::Console::OptionsHelpers include CollinsShell::Console::CommandHelpers command_options :keep_retval => true, :takes_block => true group "Context" # --return (after printing also return value) and --flood (disable paging) def options opt opt.banner <<-BANNER Usage: ls [-d|--delimiter] [-g|--grep] [-F--format] [-f|--flood] [path] ls provides you information based on your current context (either a path or an asset) When in an asset, ls will show you available commands When in a path, ls will show you either assets that match the path or values appropriate for the path When in no context, will show you available tags (to use in a path) Examples: ls /HOSTNAME/.*dev.* ls /HOSTNAME/.*dev.* --format='{{hostname}} {{status}} {{tag}}' --grep=blake You can customize the default format used by ls (when applied to assets) by creating a ~/.pryrc file with contents like: Pry.config.default_asset_format = '{{tag}} {{hostname}} {{status}}' Where the rhs of the default_asset_format is the format you want to use BANNER pager_options opt opt.on :d, "delimiter", "Delimiter for use with --format, defaults to \\n", :argument => true opt.on :r, "return", "Return values as well as outputting them" opt.on :g, "grep", "A regular expression to provide to results", :argument => true, :optional => false opt.on :F, "format", "Provide a format for output", :argument => true, :optional => false end def process # If a pipe is being used, grab the first pipe command first_after_pipe = arg_string.split('|', 2)[1].to_s.split(' ').first # Take a /PATH/FORMAT and convert it to an array path = args.first.to_s.split(/\//).reject{|s| s.empty? || s == "|" } # Account for Filesystem context stack = _pry_.binding_stack.dup fs_node = stack.last.eval('self') # Are we just getting a naked query? display_commands = (fs_node.asset? && args.empty?) # Doing an ls in the stack, relative if not fs_node.root? and not arg_string.start_with?('/') then path.each do |context| case context.chomp when "", "." # blank is empty root node, . is self. Do nothing next when ".." # Up one level fs_node = fs_node.pop else begin fs_node = fs_node.push(context) rescue Exception => e output.puts("#{text.bold('Could not check context:')} #{e}") raise e end end end path = fs_node.stack end if command_block || get_format then details = true else details = false end # Should we just display commands? if display_commands then output.puts("Available commands:") process_values fs_node.available_commands, 8 output.puts() # If we have nothing, grab all tags elsif path.size == 0 then value = get_all_tags process_values value # If we have an odd number, the last one is a tag so grab the values # for that tag elsif path.size % 2 == 1 then if virtual_tags.include?(path.last) then value = ["virtual tags have no values"] else value = get_tag_values(path.last) || [] end process_values value # If we have an even number, grab assets that have these tag/values else assets = find_assets(path, details) process_values assets, 6 end end # Handle faking unix pipes to commands, block invocation, and printing def process_values init_value, size = 4 should_return = opts.return? cmd = arg_string.split('|',2) if cmd.size == 2 then cmds = cmd.last.split('|').map{|s| s.strip} else cmds = [] end formatted = init_value formatter = nil if opts.format? then formatter = opts[:format] elsif Pry.config.default_asset_format then if formatted.any? {|o| o.is_a?(Collins::Asset)} then formatter = Pry.config.default_asset_format end end if formatter then formatted = formatted.map do |v| a = CollinsShell::Util::AssetStache.new(v) a.render formatter end end grep_regex = Regexp.new(opts[:g] || ".") if formatted.respond_to?(:grep) then formatted = formatted.grep(grep_regex) end if cmds.size > 0 then results = formatted while cmd = cmds.shift do results = run(cmd, results).retval end value = results value_s = results.to_s else value = formatted if formatter then delim = Collins::Option(opts[:delimiter]).get_or_else("\n") value_s = value.join(delim) else value_s = format_values(value, size) end end if command_block then command_block.call(value) else # Handle commands like 'more' that should not return a value if not value.nil? and not value_s.empty? then render_output value_s, opts end value if should_return end end def get_format if opts.format? then opts[:format] elsif Pry.config.default_asset_format then Pry.config.default_asset_format else nil end end def format_values array, width = 4 return "" if array.empty? t = Terminal::Table.new t.style = {:border_x => "", :border_y => "", :border_i => ""} line = [] array.each do |o| line << o if line.size >= width then t << line line = [] end end if not line.empty? then t << line end t.to_s end end end # CommandSet end; end; end