Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a command line option to specify a path to lint #44

Merged
merged 8 commits into from
May 29, 2015
113 changes: 78 additions & 35 deletions Source/swiftlint/LintCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,51 +20,94 @@ struct LintCommand: CommandType {
"(default command)"

func run(mode: CommandMode) -> Result<(), CommandantError<()>> {
println("Finding Swift files in current directory...")
let files = recursivelyFindSwiftFilesInDirectory(fileManager.currentDirectoryPath)
var numberOfViolations = 0, numberOfSeriousViolations = 0
for (index, file) in enumerate(files) {
println("Linting '\(file.lastPathComponent)' (\(index + 1)/\(files.count))")
for violation in Linter(file: File(path: file)!).styleViolations {
println(violation)
numberOfViolations++
if violation.severity.isError {
numberOfSeriousViolations++
return LintOptions.evaluate(mode).flatMap { options in
return self.lint(options.path)
}
}

func lint(path: String) -> Result<(), CommandantError<()>> {
let filesToLint = filesToLintAtPath(path)
if filesToLint.count > 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's an extra space here


if path == "" {
println("Linting Swift files in current working directory")
} else {
println("Linting Swift files at path \(path)")
}

var numberOfViolations = 0, numberOfSeriousViolations = 0
for (index, file) in enumerate(filesToLint) {
println("Linting '\(file.lastPathComponent)' (\(index + 1)/\(filesToLint.count))")
for violation in Linter(file: File(path: file)!).styleViolations {
println(violation)
numberOfViolations++
if violation.severity.isError {
numberOfSeriousViolations++
}
}
}
let violationSuffix = (numberOfViolations != 1 ? "s" : "")
let filesSuffix = (filesToLint.count != 1 ? "s." : ".")
println(
"Done linting!" +
" Found \(numberOfViolations) violation\(violationSuffix)," +
" \(numberOfSeriousViolations) serious" +
" in \(filesToLint.count) file\(filesSuffix)"
)
if numberOfSeriousViolations <= 0 {
return success()
} else {
// This represents failure of the content (i.e. violations in the files linted)
// and not failure of the scanning process itself. The current command architecture
// doesn't discriminate between these types.
return failure(CommandantError<()>.CommandError(Box()))
}
}
let violationSuffix = (numberOfViolations != 1 ? "s" : "")
let filesSuffix = (files.count != 1 ? "s." : ".")
println(
"Done linting!" +
" Found \(numberOfViolations) violation\(violationSuffix)," +
" \(numberOfSeriousViolations) serious" +
" in \(files.count) file\(filesSuffix)"
)
if numberOfSeriousViolations <= 0 {
return success()
} else {
// This represents failure of the content (i.e. violations in the files linted)
// and not failure of the scanning process itself. The current command architecture
// doesn't discriminate between these types.
return failure(CommandantError<()>.CommandError(Box()))
return failure(CommandantError<()>.UsageError(description: "No lintable files found at path \(path)"))
}
}

struct LintOptions: OptionsType {
let path: String

static func create(path: String) -> LintOptions {
return LintOptions(path: path)
}

static func evaluate(m: CommandMode) -> Result<LintOptions, CommandantError<()>> {
return create
<*> m <| Option(key: "path", defaultValue: "", usage: "theff path to the file or directory to lint")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

theff should be the

}
}

func filesToLintAtPath(path: String) -> [String] {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this function could be simplified:

func filesToLintAtPath(path: String) -> [String] {
    let absolutePath = path.absolutePathRepresentation()
    var isDirectory: ObjCBool = false
    if fileManager.fileExistsAtPath(absolutePath, isDirectory: &isDirectory) {
        if isDirectory {
            return fileManager.allFilesRecursively(directory: absolutePath).filter {
                $0.isSwiftFile()
            }
        } else if standardizedPath.isSwiftFile() {
            return [standardizedPath]
        }
    }
    return []
 }

var standardizedPath: String?
var isDirectory: ObjCBool = false

let relativePath = fileManager.currentDirectoryPath.stringByAppendingPathComponent(path)
if fileManager.fileExistsAtPath(relativePath, isDirectory: &isDirectory) {
standardizedPath = relativePath
} else if fileManager.fileExistsAtPath(path, isDirectory: &isDirectory) {
standardizedPath = path
}

if let standardizedPath = standardizedPath {
if isDirectory {
return recursivelyFindSwiftFilesInDirectory(standardizedPath)
} else if standardizedPath.isSwiftFile() {
return [standardizedPath]
}
}
return []
}

func recursivelyFindSwiftFilesInDirectory(directory: String) -> [String] {
let subPaths = fileManager.subpathsOfDirectoryAtPath(directory, error: nil) as? [String]
return map(subPaths) { subPaths in
return reduce(compact((["."] + subPaths).map { dirPath in
let files = fileManager.contentsOfDirectoryAtPath(dirPath, error: nil) as? [String]
return map(files) { files in
return files.map { file in
return directory.stringByAppendingPathComponent(dirPath)
.stringByAppendingPathComponent(file).stringByStandardizingPath
}
}
}), [], +).filter {
subPaths.map { subPath in
return directory.stringByAppendingPathComponent(subPath)
}.filter {
$0.isSwiftFile()
}
} ?? []
}
}