diff options
Diffstat (limited to 'knife/lib/chef/knife/list.rb')
-rw-r--r-- | knife/lib/chef/knife/list.rb | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/knife/lib/chef/knife/list.rb b/knife/lib/chef/knife/list.rb new file mode 100644 index 0000000000..7fc2231c5f --- /dev/null +++ b/knife/lib/chef/knife/list.rb @@ -0,0 +1,177 @@ +# +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require_relative "../chef_fs/knife" + +class Chef + class Knife + class List < Chef::ChefFS::Knife + banner "knife list [-dfR1p] [PATTERN1 ... PATTERNn] (options)" + + category "path-based" + + deps do + require "chef/chef_fs/file_system" unless defined?(Chef::ChefFS::FileSystem) + require "tty-screen" + end + + option :recursive, + short: "-R", + boolean: true, + description: "List directories recursively." + + option :bare_directories, + short: "-d", + boolean: true, + description: "When directories match the pattern, do not show the directories' children." + + option :local, + long: "--local", + boolean: true, + description: "List local directory instead of remote." + + option :flat, + short: "-f", + long: "--flat", + boolean: true, + description: "Show a list of filenames rather than the prettified ls-like output normally produced." + + option :one_column, + short: "-1", + boolean: true, + description: "Show only one column of results." + + option :trailing_slashes, + short: "-p", + boolean: true, + description: "Show trailing slashes after directories." + + attr_accessor :exit_code + + def run + patterns = name_args.length == 0 ? [""] : name_args + + # Get the top-level matches + all_results = parallelize(pattern_args_from(patterns)) do |pattern| + pattern_results = Chef::ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern).to_a + + if pattern_results.first && !pattern_results.first.exists? && pattern.exact_path + ui.error "#{format_path(pattern_results.first)}: No such file or directory" + self.exit_code = 1 + end + pattern_results + end.flatten(1).to_a + + # Process directories + if !config[:bare_directories] + dir_results = parallelize(all_results.select(&:dir?)) do |result| + add_dir_result(result) + end.flatten(1) + + else + dir_results = [] + end + + # Process all other results + results = all_results.select { |result| result.exists? && (!result.dir? || config[:bare_directories]) }.to_a + + # Flatten out directory results if necessary + if config[:flat] + dir_results.each do |result, children| # rubocop:disable Style/HashEachMethods + results += children + end + dir_results = [] + end + + # Sort by path for happy output + results = results.sort_by(&:path) + dir_results = dir_results.sort_by { |result| result[0].path } + + # Print! + if results.length == 0 && dir_results.length == 1 + results = dir_results[0][1] + dir_results = [] + end + + print_result_paths results + printed_something = results.length > 0 + dir_results.each do |result, children| + if printed_something + output "" + else + printed_something = true + end + output "#{format_path(result)}:" + print_results(children.map { |result| maybe_add_slash(result.display_name, result.dir?) }.sort, "") + end + + exit exit_code if exit_code + end + + def add_dir_result(result) + begin + children = result.children.sort_by(&:name) + rescue Chef::ChefFS::FileSystem::NotFoundError => e + ui.error "#{format_path(e.entry)}: No such file or directory" + return [] + end + + result = [ [ result, children ] ] + if config[:recursive] + child_dirs = children.select(&:dir?) + result += parallelize(child_dirs) { |child| add_dir_result(child) }.flatten(1).to_a + end + result + end + + def print_result_paths(results, indent = "") + print_results(results.map { |result| maybe_add_slash(format_path(result), result.dir?) }, indent) + end + + def print_results(results, indent) + return if results.length == 0 + + print_space = results.map(&:length).max + 2 + if config[:one_column] || !stdout.isatty + columns = 0 + else + columns = TTY::Screen.columns + end + current_line = "" + results.each do |result| + if current_line.length > 0 && current_line.length + print_space > columns + output current_line.rstrip + current_line = "" + end + if current_line.length == 0 + current_line << indent + end + current_line << result + current_line << (" " * (print_space - result.length)) + end + output current_line.rstrip if current_line.length > 0 + end + + def maybe_add_slash(path, is_dir) + if config[:trailing_slashes] && is_dir + "#{path}/" + else + path + end + end + end + end +end |