Skip to content

Commit

Permalink
RelativePathsRule for #9
Browse files Browse the repository at this point in the history
  • Loading branch information
mattmassicotte committed Jan 24, 2024
1 parent 90e461c commit a35a195
Show file tree
Hide file tree
Showing 8 changed files with 524 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ opt_in_rules:
disabled_rules:
- build_files_ordered # checks that the ordering of techincally-unordered collections Xcode writes out is preserved
- validate_build_settings # checks that build settings have valid values
- relative_paths # checks for any absolute file references
```
## Alternatives
Expand Down
39 changes: 39 additions & 0 deletions Sources/XCLinting/Rules/RelativePathsRule.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Foundation

import XcodeProj

/// Make sure all file references use relative paths.
struct RelativePathsRule {
func run(_ environment: XCLinter.Environment) throws -> [Violation] {
var violations = [Violation]()

// check top-level
for project in environment.project.pbxproj.projects {
guard let group = project.mainGroup else { continue }

violations.append(contentsOf: checkGroup(group))
}

return violations
}

private func checkGroup(_ group: PBXGroup) -> [Violation] {
var violations = [Violation]()

let groupName = group.name ?? group.path ?? "???"

for element in group.children {
let elementName = element.name ?? element.path ?? "???"

if element.path?.starts(with: "/") == true {
violations.append(.init("\(groupName):\(elementName) has an absolute file path"))
}

if let subgroup = element as? PBXGroup {
violations.append(contentsOf: checkGroup(subgroup))
}
}

return violations
}
}
4 changes: 3 additions & 1 deletion Sources/XCLinting/XCLinter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ extension XCLinter {
public static let defaultRuleIdentifiers: Set<String> = [
"build_files_ordered",
"validate_build_settings",
"relative_paths",
]

public static let defaultRules: [Rule] = Array(ruleMap.filter({ defaultRuleIdentifiers.contains($0.0) }).values)
Expand All @@ -81,6 +82,7 @@ extension XCLinter {
"implicit_dependencies": { try ImplicitDependenciesRule().run($0) },
"targets_use_xcconfig": { try TargetsUseXCConfigRule().run($0) },
"projects_use_xcconfig": { try ProjectsUseXCConfigRule().run($0) },
"shared_scheme_skips_tests": { try SharedSchemeSkipsTestsRule().run($0) }
"shared_scheme_skips_tests": { try SharedSchemeSkipsTestsRule().run($0) },
"relative_paths": { try RelativePathsRule().run($0) },
]
}
39 changes: 39 additions & 0 deletions Tests/XCLintTests/RelativePathsRuleTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import XCTest

@testable import XCLinting
import XcodeProj

final class RelativePathsRuleTests: XCTestCase {
func testProjectWithOnlyRelativePaths() throws {
let url = try Bundle.module.testDataURL(named: "StockMacOSApp.xcodeproj")

let project = try XcodeProj(pathString: url.path)

let env = XCLinter.Environment(
project: project,
projectRootURL: url,
configuration: Configuration()
)

let violations = try RelativePathsRule().run(env)

XCTAssertTrue(violations.isEmpty)
}

func testProjectWithOneAbosluteFilePath() throws {
let url = try Bundle.module.testDataURL(named: "AbsolueFileReference.xcodeproj")

let project = try XcodeProj(pathString: url.path)

let env = XCLinter.Environment(
project: project,
projectRootURL: url,
configuration: Configuration()
)

let violations = try RelativePathsRule().run(env)

XCTAssertFalse(violations.isEmpty)
}
}

Loading

0 comments on commit a35a195

Please sign in to comment.