Skip to content

Commit

Permalink
Merge pull request #1191 from benasher44/basher_multiple_paths
Browse files Browse the repository at this point in the history
Support for passing multiple paths to swiftlint lint and autocorrect
  • Loading branch information
marcelofabri authored Jul 23, 2018
2 parents c5c4614 + 32e8c5b commit c7c0ac8
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 21 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@
[Marcelo Fabri](https://github.com/marcelofabri)
[#1871](https://github.com/realm/SwiftLint/issues/1871)

* Support for passing multiple path arguments.
[Ben Asher](https://github.com/benasher44)
[#810](https://github.com/realm/SwiftLint/issues/810)

#### Bug Fixes

* Update `LowerACLThanParent` rule to not lint extensions.
Expand Down
20 changes: 14 additions & 6 deletions Source/swiftlint/Commands/AutoCorrectCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct AutoCorrectCommand: CommandProtocol {
useTabs = options.useTabs
}

return configuration.visitLintableFiles(path: options.path, action: "Correcting",
return configuration.visitLintableFiles(paths: options.paths, action: "Correcting",
quiet: options.quiet,
useScriptInputFiles: options.useScriptInputFiles,
forceExclude: options.forceExclude,
Expand All @@ -53,7 +53,7 @@ struct AutoCorrectCommand: CommandProtocol {
}

struct AutoCorrectOptions: OptionsProtocol {
let path: String
let paths: [String]
let configurationFile: String
let useScriptInputFiles: Bool
let quiet: Bool
Expand All @@ -64,10 +64,16 @@ struct AutoCorrectOptions: OptionsProtocol {
let useTabs: Bool

// swiftlint:disable line_length
static func create(_ path: String) -> (_ configurationFile: String) -> (_ useScriptInputFiles: Bool) -> (_ quiet: Bool) -> (_ forceExclude: Bool) -> (_ format: Bool) -> (_ cachePath: String) -> (_ ignoreCache: Bool) -> (_ useTabs: Bool) -> AutoCorrectOptions {
return { configurationFile in { useScriptInputFiles in { quiet in { forceExclude in { format in { cachePath in { ignoreCache in { useTabs in
self.init(path: path, configurationFile: configurationFile, useScriptInputFiles: useScriptInputFiles, quiet: quiet, forceExclude: forceExclude, format: format, cachePath: cachePath, ignoreCache: ignoreCache, useTabs: useTabs)
}}}}}}}}
static func create(_ path: String) -> (_ configurationFile: String) -> (_ useScriptInputFiles: Bool) -> (_ quiet: Bool) -> (_ forceExclude: Bool) -> (_ format: Bool) -> (_ cachePath: String) -> (_ ignoreCache: Bool) -> (_ useTabs: Bool) -> (_ paths: [String]) -> AutoCorrectOptions {
return { configurationFile in { useScriptInputFiles in { quiet in { forceExclude in { format in { cachePath in { ignoreCache in { useTabs in { paths in
let allPaths: [String]
if !path.isEmpty {
allPaths = [path]
} else {
allPaths = paths
}
return self.init(paths: allPaths, configurationFile: configurationFile, useScriptInputFiles: useScriptInputFiles, quiet: quiet, forceExclude: forceExclude, format: format, cachePath: cachePath, ignoreCache: ignoreCache, useTabs: useTabs)
}}}}}}}}}
}

static func evaluate(_ mode: CommandMode) -> Result<AutoCorrectOptions, CommandantError<CommandantError<()>>> {
Expand All @@ -90,5 +96,7 @@ struct AutoCorrectOptions: OptionsProtocol {
<*> mode <| Option(key: "use-tabs",
defaultValue: false,
usage: "should use tabs over spaces when reformatting. Deprecated.")
// This should go last to avoid eating other args
<*> mode <| pathsArgument(action: "correct")
}
}
18 changes: 13 additions & 5 deletions Source/swiftlint/Commands/LintCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ struct LintCommand: CommandProtocol {
}

struct LintOptions: OptionsProtocol {
let path: String
let paths: [String]
let useSTDIN: Bool
let configurationFile: String
let strict: Bool
Expand All @@ -132,10 +132,16 @@ struct LintOptions: OptionsProtocol {
let enableAllRules: Bool

// swiftlint:disable line_length
static func create(_ path: String) -> (_ useSTDIN: Bool) -> (_ configurationFile: String) -> (_ strict: Bool) -> (_ lenient: Bool) -> (_ forceExclude: Bool) -> (_ useScriptInputFiles: Bool) -> (_ benchmark: Bool) -> (_ reporter: String) -> (_ quiet: Bool) -> (_ cachePath: String) -> (_ ignoreCache: Bool) -> (_ enableAllRules: Bool) -> LintOptions {
return { useSTDIN in { configurationFile in { strict in { lenient in { forceExclude in { useScriptInputFiles in { benchmark in { reporter in { quiet in { cachePath in { ignoreCache in { enableAllRules in
self.init(path: path, useSTDIN: useSTDIN, configurationFile: configurationFile, strict: strict, lenient: lenient, forceExclude: forceExclude, useScriptInputFiles: useScriptInputFiles, benchmark: benchmark, reporter: reporter, quiet: quiet, cachePath: cachePath, ignoreCache: ignoreCache, enableAllRules: enableAllRules)
}}}}}}}}}}}}
static func create(_ path: String) -> (_ useSTDIN: Bool) -> (_ configurationFile: String) -> (_ strict: Bool) -> (_ lenient: Bool) -> (_ forceExclude: Bool) -> (_ useScriptInputFiles: Bool) -> (_ benchmark: Bool) -> (_ reporter: String) -> (_ quiet: Bool) -> (_ cachePath: String) -> (_ ignoreCache: Bool) -> (_ enableAllRules: Bool) -> (_ paths: [String]) -> LintOptions {
return { useSTDIN in { configurationFile in { strict in { lenient in { forceExclude in { useScriptInputFiles in { benchmark in { reporter in { quiet in { cachePath in { ignoreCache in { enableAllRules in { paths in
let allPaths: [String]
if !path.isEmpty {
allPaths = [path]
} else {
allPaths = paths
}
return self.init(paths: allPaths, useSTDIN: useSTDIN, configurationFile: configurationFile, strict: strict, lenient: lenient, forceExclude: forceExclude, useScriptInputFiles: useScriptInputFiles, benchmark: benchmark, reporter: reporter, quiet: quiet, cachePath: cachePath, ignoreCache: ignoreCache, enableAllRules: enableAllRules)
}}}}}}}}}}}}}
}

static func evaluate(_ mode: CommandMode) -> Result<LintOptions, CommandantError<CommandantError<()>>> {
Expand Down Expand Up @@ -164,5 +170,7 @@ struct LintOptions: OptionsProtocol {
usage: "ignore cache when linting")
<*> mode <| Option(key: "enable-all-rules", defaultValue: false,
usage: "run all rules, even opt-in and disabled ones, ignoring `whitelist_rules`")
// This should go last to avoid eating other args
<*> mode <| pathsArgument(action: "lint")
}
}
30 changes: 20 additions & 10 deletions Source/swiftlint/Extensions/Configuration+CommandLine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ private func autoreleasepool(block: () -> Void) { block() }

extension Configuration {

func visitLintableFiles(path: String, action: String, useSTDIN: Bool = false,
func visitLintableFiles(paths: [String], action: String, useSTDIN: Bool = false,
quiet: Bool = false, useScriptInputFiles: Bool, forceExclude: Bool,
cache: LinterCache? = nil, parallel: Bool = false,
visitorBlock: @escaping (Linter) -> Void) -> Result<[File], CommandantError<()>> {
return getFiles(path: path, action: action, useSTDIN: useSTDIN, quiet: quiet, forceExclude: forceExclude,
return getFiles(paths: paths, action: action, useSTDIN: useSTDIN, quiet: quiet, forceExclude: forceExclude,
useScriptInputFiles: useScriptInputFiles)
.flatMap { files -> Result<[Configuration: [File]], CommandantError<()>> in
if files.isEmpty {
let errorMessage = "No lintable files found at path '\(path)'"
let errorMessage = "No lintable files found at paths: '\(paths.joined(separator: ", "))'"
return .failure(.usageError(description: errorMessage))
}
return .success(Dictionary(grouping: files, by: configuration(for:)))
Expand Down Expand Up @@ -105,7 +105,7 @@ extension Configuration {
}

// swiftlint:disable function_parameter_count
fileprivate func getFiles(path: String, action: String, useSTDIN: Bool, quiet: Bool, forceExclude: Bool,
fileprivate func getFiles(paths: [String], action: String, useSTDIN: Bool, quiet: Bool, forceExclude: Bool,
useScriptInputFiles: Bool) -> Result<[File], CommandantError<()>> {
if useSTDIN {
let stdinData = FileHandle.standardInput.readDataToEndOfFile()
Expand All @@ -117,26 +117,36 @@ extension Configuration {
return scriptInputFiles()
}
if !quiet {
let message = "\(action) Swift files " + (path.isEmpty ? "in current working directory" : "at path \(path)")
let filesInfo = paths.isEmpty ? "in current working directory" : "at paths \(paths.joined(separator: ", "))"
let message = "\(action) Swift files \(filesInfo)"
queuedPrintError(message)
}
return .success(lintableFiles(inPath: path, forceExclude: forceExclude))
return .success(paths.flatMap {
self.lintableFiles(inPath: $0, forceExclude: forceExclude)
})
}
// swiftlint:enable function_parameter_count

private static func rootPath(from paths: [String]) -> String? {
// We don't know the root when more than one path is passed (i.e. not useful if the root of 2 paths is ~)
return paths.count == 1 ? paths.first?.absolutePathStandardized() : nil
}

// MARK: Lint Command

init(options: LintOptions) {
let cachePath = options.cachePath.isEmpty ? nil : options.cachePath
let optional = !CommandLine.arguments.contains("--config")
self.init(path: options.configurationFile, rootPath: options.path.absolutePathStandardized(),
self.init(path: options.configurationFile,
rootPath: type(of: self).rootPath(from: options.paths),
optional: optional, quiet: options.quiet,
enableAllRules: options.enableAllRules, cachePath: cachePath)
enableAllRules: options.enableAllRules,
cachePath: cachePath)
}

func visitLintableFiles(options: LintOptions, cache: LinterCache? = nil,
visitorBlock: @escaping (Linter) -> Void) -> Result<[File], CommandantError<()>> {
return visitLintableFiles(path: options.path, action: "Linting", useSTDIN: options.useSTDIN,
return visitLintableFiles(paths: options.paths, action: "Linting", useSTDIN: options.useSTDIN,
quiet: options.quiet, useScriptInputFiles: options.useScriptInputFiles,
forceExclude: options.forceExclude, cache: cache, parallel: true,
visitorBlock: visitorBlock)
Expand All @@ -147,7 +157,7 @@ extension Configuration {
init(options: AutoCorrectOptions) {
let cachePath = options.cachePath.isEmpty ? nil : options.cachePath
let optional = !CommandLine.arguments.contains("--config")
self.init(path: options.configurationFile, rootPath: options.path.absolutePathStandardized(),
self.init(path: options.configurationFile, rootPath: type(of: self).rootPath(from: options.paths),
optional: optional, quiet: options.quiet, cachePath: cachePath)
}

Expand Down
5 changes: 5 additions & 0 deletions Source/swiftlint/Helpers/CommonOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ func pathOption(action: String) -> Option<String> {
usage: "the path to the file or directory to \(action)")
}

func pathsArgument(action: String) -> Argument<[String]> {
return Argument(defaultValue: [""],
usage: "list of paths to the files or directories to \(action)")
}

let configOption = Option(key: "config",
defaultValue: Configuration.fileName,
usage: "the path to SwiftLint's configuration file")
Expand Down

0 comments on commit c7c0ac8

Please sign in to comment.