lib/scss_lint/cli.rb in scss-lint-0.12.1 vs lib/scss_lint/cli.rb in scss-lint-0.13.0

- old
+ new

@@ -3,37 +3,70 @@ module SCSSLint # Responsible for parsing command-line options and executing the appropriate # application logic based on the options specified. class CLI - attr_accessor :options + attr_reader :config, :options + # Subset of semantic exit codes conforming to `sysexits` documentation. + EXIT_CODES = { + ok: 0, + usage: 64, # Command line usage error + data: 65, # User input was incorrect (i.e. contains lints) + no_input: 66, # Input file did not exist or was not readable + software: 70, # Internal software error + config: 78, # Configuration error + } + def initialize(args = []) @args = args @options = {} + @config = Config.default end def parse_arguments - parser = OptionParser.new do |opts| + begin + options_parser.parse!(@args) + + # Take the rest of the arguments as files/directories + @options[:files] = @args + rescue OptionParser::InvalidOption => ex + print_help options_parser.help, ex + end + + begin + setup_configuration + rescue NoSuchLinter => ex + puts ex.message + halt :config + end + end + + def options_parser + @options_parser ||= OptionParser.new do |opts| opts.banner = "Usage: #{opts.program_name} [options] [scss-files]" opts.separator '' opts.separator 'Common options:' + opts.on('-c', '--config file', 'Specify configuration file', String) do |file| + @options[:config_file] = file + end + opts.on('-e', '--exclude file,...', Array, 'List of file names to exclude') do |files| - options[:excluded_files] = files + @options[:excluded_files] = files end opts.on('-i', '--include-linter linter,...', Array, 'Specify which linters you want to run') do |linters| - options[:included_linters] = linters + @options[:included_linters] = linters end opts.on('-x', '--exclude-linter linter,...', Array, "Specify which linters you don't want to run") do |linters| - options[:excluded_linters] = linters + @options[:excluded_linters] = linters end opts.on_tail('--show-linters', 'Shows available linters') do print_linters end @@ -45,49 +78,80 @@ opts.on_tail('-v', '--version', 'Show version') do print_version opts.program_name, VERSION end opts.on('--xml', 'Output the results in XML format') do - options[:reporter] = SCSSLint::Reporter::XMLReporter + @options[:reporter] = SCSSLint::Reporter::XMLReporter end end - - begin - parser.parse!(@args) - - # Take the rest of the arguments as files/directories - options[:files] = @args - rescue OptionParser::InvalidOption => ex - print_help parser.help, ex - end end def run - runner = Runner.new(options) - runner.run(find_files) + runner = Runner.new(@config) + runner.run(files_to_lint) report_lints(runner.lints) - halt(1) if runner.lints? - rescue NoFilesError, NoSuchLinter, Errno::ENOENT => ex + halt :data if runner.lints.any? + rescue NoFilesError, Errno::ENOENT => ex puts ex.message - halt(-1) + halt :no_input + rescue NoSuchLinter => ex + puts ex.message + halt :usage rescue => ex puts ex.message puts ex.backtrace puts 'Report this bug at '.yellow + BUG_REPORT_URL.cyan - halt(-1) + halt :software end private - def find_files - excluded_files = options.fetch(:excluded_files, []) + def setup_configuration + if @options[:config_file] + @config = Config.load(@options[:config_file]) + @config.preferred = true + end - extract_files_from(options[:files]).reject do |file| - excluded_files.include?(file) + merge_command_line_flags_with_config(@config) + end + + def merge_command_line_flags_with_config(config) + if @options[:excluded_files] + @options[:excluded_files].each do |file| + config.exclude_file(file) + end end + + if @options[:included_linters] + config.disable_all_linters + LinterRegistry.extract_linters_from(@options[:included_linters]).each do |linter| + config.enable_linter(linter) + end + end + + if @options[:excluded_linters] + LinterRegistry.extract_linters_from(@options[:excluded_linters]).each do |linter| + config.disable_linter(linter) + end + end + + config end + def files_to_lint + extract_files_from(@options[:files]).reject do |file| + config = + if !@config.preferred && (config_for_file = Config.for_file(file)) + merge_command_line_flags_with_config(config_for_file.dup) + else + @config + end + + config.excluded_file?(file) + end + end + def extract_files_from(list) files = [] list.each do |file| Find.find(file) do |f| files << f if scssish_file?(f) @@ -103,11 +167,12 @@ VALID_EXTENSIONS.include?(File.extname(file)) end def report_lints(lints) sorted_lints = lints.sort_by { |l| [l.filename, l.line] } - reporter = options.fetch(:reporter, Reporter::DefaultReporter).new(sorted_lints) + reporter = @options.fetch(:reporter, Reporter::DefaultReporter) + .new(sorted_lints) output = reporter.report_lints print output if output end def print_linters @@ -125,19 +190,19 @@ end def print_help(help_message, err = nil) puts err, '' if err puts help_message - halt + halt(err ? :usage : :ok) end def print_version(program_name, version) puts "#{program_name} #{version}" halt end # Used for ease-of testing - def halt(exit_status = 0) - exit exit_status + def halt(exit_status = :ok) + exit(EXIT_CODES[exit_status]) end end end