summaryrefslogtreecommitdiff
path: root/knife/lib/chef/knife/list.rb
diff options
context:
space:
mode:
Diffstat (limited to 'knife/lib/chef/knife/list.rb')
-rw-r--r--knife/lib/chef/knife/list.rb177
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