Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions Sources/ProjectSpec/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,21 @@ extension Project: PathContainer {

extension Project {

/// Files excluded from cache tracking to match SourceGenerator's default exclusions.
/// Without this filter, changes to these files cause spurious project regeneration.
private static let defaultExcludedFileNames: Set<String> = [".DS_Store"]
private static let defaultExcludedExtensions: Set<String> = ["orig"]

private static func isTrackedFile(_ path: Path) -> Bool {
if defaultExcludedFileNames.contains(path.lastComponent) {
return false
}
if let ext = path.extension, defaultExcludedExtensions.contains(ext) {
return false
}
return true
}

public var allTrackedFiles: [Path] {
var files: [Path] = []
files.append(contentsOf: configFilePaths)
Expand All @@ -270,7 +285,7 @@ extension Project {
files.append(contentsOf: target.configFilePaths)
for source in target.sources {
let sourcePath = basePath + source.path

let type = source.type ?? options.defaultSourceDirectoryType ?? .group
if type.projectTracksChildren {
let sourceChildren = (try? sourcePath.recursiveChildren()) ?? []
Expand All @@ -279,7 +294,7 @@ extension Project {
files.append(sourcePath)
}
}
return files
return files.filter(Self.isTrackedFile)
}
}

Expand Down
63 changes: 63 additions & 0 deletions Tests/ProjectSpecTests/ProjectSpecTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,69 @@ class ProjectSpecTests: XCTestCase {
}
}

func testAllTrackedFilesExcludesIgnoredFiles() {
describe {
let directoryPath = Path(components: [NSTemporaryDirectory(), ProcessInfo.processInfo.globallyUniqueString])

$0.before {
try? directoryPath.delete()
}

$0.after {
try? directoryPath.delete()
}

$0.it("excludes .DS_Store and .orig files from tracked files") {
// Create source directory with a mix of valid and ignored files
let sourcesDir = directoryPath + "Sources"
try sourcesDir.mkpath()
try (sourcesDir + "main.swift").write("")
try (sourcesDir + ".DS_Store").write("")
try (sourcesDir + "file.swift.orig").write("")

let target = Target(
name: "App",
type: .application,
platform: .iOS,
sources: [TargetSource(path: "Sources")]
)
let project = Project(basePath: directoryPath, name: "Test", targets: [target])
let trackedFiles = project.allTrackedFiles

let trackedFileStrings = trackedFiles.map { $0.string }
let hasDSStore = trackedFileStrings.contains { $0.contains(".DS_Store") }
let hasOrig = trackedFileStrings.contains { $0.hasSuffix(".orig") }
let hasSwift = trackedFileStrings.contains { $0.contains("main.swift") }

try expect(hasDSStore).to.beFalse()
try expect(hasOrig).to.beFalse()
try expect(hasSwift).to.beTrue()
}

$0.it("excludes .DS_Store from fileGroup tracked files") {
// Create fileGroup directory with .DS_Store
let fileGroupDir = directoryPath + "Resources"
try fileGroupDir.mkpath()
try (fileGroupDir + "image.png").write("")
try (fileGroupDir + ".DS_Store").write("")

let project = Project(
basePath: directoryPath,
name: "Test",
fileGroups: ["Resources"]
)
let trackedFiles = project.allTrackedFiles

let trackedFileStrings = trackedFiles.map { $0.string }
let hasDSStore = trackedFileStrings.contains { $0.contains(".DS_Store") }
let hasImage = trackedFileStrings.contains { $0.contains("image.png") }

try expect(hasDSStore).to.beFalse()
try expect(hasImage).to.beTrue()
}
}
}

func testJSONEncodable() {
describe {
$0.it("encodes to json") {
Expand Down